Recent

Author Topic: Call SetLength from assembler block  (Read 424 times)

LemonParty

  • Hero Member
  • *****
  • Posts: 562
Call SetLength from assembler block
« on: June 07, 2026, 04:13:10 pm »
Let's say we have a function:
Code: Pascal  [Select][+][-]
  1. type
  2.   TPointers = array of Pointer;
  3. function F1: TPointers; assembler;
  4. asm
  5.   {how to set the size of Result here?}
  6. end;
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

runewalsh

  • Full Member
  • ***
  • Posts: 130
Re: Call SetLength from assembler block
« Reply #1 on: June 07, 2026, 04:47:51 pm »
Rule of thumb: if you don’t know how to do that, don’t use assembler — you won’t do anything useful with it anyway.

Write a helper function that calls SetLength, and call it with call.

LemonParty

  • Hero Member
  • *****
  • Posts: 562
Re: Call SetLength from assembler block
« Reply #2 on: June 07, 2026, 06:44:23 pm »
I test with this program (Windows):
Code: Pascal  [Select][+][-]
  1. type
  2.   TPointers = array of Pointer;
  3.  
  4. function SetLen(Arr: TPointers; Len: SizeInt): TPointers;
  5. begin
  6.   SetLength(Arr, Len);
  7.   Result:= Arr;
  8. end;
  9.  
  10. function F1: TPointers;assembler;{ nostackframe; }
  11. asm
  12.   mov rcx,0
  13.   mov rdx,5
  14.   call SetLen
  15. end;
  16.  
  17. var
  18.   Arr: TPointers;
  19. begin
  20.   Arr:= F1;
  21.   Writeln(Length(Arr));
  22. end.
SIGSEGV occurs after call SetLen line. What I missing?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

runewalsh

  • Full Member
  • ***
  • Posts: 130
Re: Call SetLength from assembler block
« Reply #3 on: June 07, 2026, 07:12:51 pm »
Implement your F1 function in Pascal, set a breakpoint inside it, run it, and look at the disassembly (Ctrl-Alt-D in Lazarus).

LemonParty

  • Hero Member
  • *****
  • Posts: 562
Re: Call SetLength from assembler block
« Reply #4 on: June 07, 2026, 08:00:30 pm »
That is a correct instructions:
Code: Pascal  [Select][+][-]
  1. function F1: TPointers;assembler;nostackframe;
  2. asm
  3.   mov r8d,5
  4.   xor edx,edx
  5.   call SetLen
  6. end;
But I do not uderstand why r8 and rdx. rdx is the second argument in calling convention and r8 is the third one (rcx is the first one). Somewhy the first argument is omitted.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

runewalsh

  • Full Member
  • ***
  • Posts: 130
Re: Call SetLength from assembler block
« Reply #5 on: June 07, 2026, 09:20:21 pm »
Obviously because the function with a signature F3: TPointers; (already) gets a pointer to its result as its first argument.

This is why you really shouldn’t use assembler here: if you’ve decided to implement a function in assembler, it had better be a semantically simple function with simple parameters, like memory buffers; for functions that allocate memory or manage managed types, this is a clear dead end.

Thaddy

  • Hero Member
  • *****
  • Posts: 19464
  • Glad to be alive.
Re: Call SetLength from assembler block
« Reply #6 on: June 08, 2026, 09:00:36 am »
Since fpc_dynarray_setlength is an internal compiler intrinsic it does not make sense to try and call it directly from assembler.
Since dynamic arrays also need RTTI generated, the compiler produces already near optimal code(X86_64):
Code: ASM  [Select][+][-]
  1. # [8] setlength(p,5);
  2.         movq    $5,-8(%rbp)
  3.         leaq    -8(%rbp),%r9
  4.         leaq    RTTI_$P$REDIRECTS_$$_TPOINTERS(%rip),%rdx
  5.         leaq    U_$P$REDIRECTS_$$_P(%rip),%rcx
  6.         movq    $1,%r8
  7.         call    fpc_dynarray_setlength
I would take @runewalsh advice.

fpc_dynarray_setlength is not accessible outside of the compiler itself, because it is not exported.
Compilerprocs seldom are.

fpc_dynarray_setlength does three things very efficiently:
- It sets up the data for the managed type: length/size and refcount
- It (re-) allocates memory
- performs a copy if needed (if the size grows)

Because of that, there is little if any speed to gain anyway. Any bottleneck would be in fpc_dynarray_setlength.

You should know how to read the compiler sources too if you want to use assembler efficiently...
There is no reason to document all that apart from in the sources.

Any perceived assembler shortcuts may break your code in any next generation of the compiler.
Since all that is implementation detail. (And not exported for that reason!)
« Last Edit: June 08, 2026, 09:35:05 am by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

 

TinyPortal © 2005-2018