dynamically allocating on the stack
Steven Schveighoffer
schveiguy at yahoo.com
Sun Apr 22 11:16:24 UTC 2018
On 4/22/18 3:17 AM, Cym13 wrote:
> On Sunday, 22 April 2018 at 05:29:30 UTC, Mike Franklin wrote:
>> On Sunday, 22 April 2018 at 00:41:34 UTC, Nicholas Wilson wrote:
>>
>>> You're not using the C library version of it, the compiler does the
>>> stack space reservation inline for you. There is no way around this.
>>
>> I'm not convinced. I did some no-runtime testing and eventually found
>> the implementation in druntime here:
>> https://github.com/dlang/druntime/blob/master/src/rt/alloca.d
>>
>> Mike
>
> The first assertion ("the C library isn't called") is easily apperent from
> that assembly dump. The second is interesting but not so evident.
>
> It might be clearer looking at actual assembly.
>
> The doSomething function starts as such:
>
> ; sym._D4test11doSomethingFmZv (int arg_1h);
> ; prologue, puts the old stack pointer on the stack
> 0x563d809095ec 55 push rbp
> 0x563d809095ed 488bec mov rbp, rsp
> ; allocate stack memory
> 0x563d809095f0 4883ec20 sub rsp, 0x20
> ; setup arguments for the alloca call
> ; that 0x20 in rcx is actually the size of the current stack
> allocation
> 0x563d809095f4 48c745e82000. mov qword [local_18h], 0x20 ; 32
> 0x563d809095fc 48ffc7 inc rdi
> 0x563d809095ff 48897de0 mov qword [local_20h], rdi
> 0x563d80909603 488d4de8 lea rcx, [local_18h]
> ; calls alloca
> 0x563d80909607 e830010000 call sym.__alloca
>
> The alloca function works as such:
>
> ;-- __alloca:
> ; Note how we don't create a stack frame by "push rbp;mov rbp,rsp"
> ; Those instructions could be inlined, it's not a function per se
> ;
> ; At that point rcx holds the size of the calling functions's stack
> frame
> ; and eax how much we want to add
> 0x563d8090973c 4889ca mov rdx, rcx
> 0x563d8090973f 4889f8 mov rax, rdi
> ; Round rax up to 16 bytes
> 0x563d80909742 4883c00f add rax, 0xf
> 0x563d80909746 24f0 and al, 0xf0
> 0x563d80909748 4885c0 test rax, rax
> ,=< 0x563d8090974b 7505 jne 0x563d80909752
> | 0x563d8090974d b810000000 mov eax, 0x10
> `-> 0x563d80909752 4889c6 mov rsi, rax
> ; Do the substraction in rax which holds the new address
> 0x563d80909755 48f7d8 neg rax
> 0x563d80909758 4801e0 add rax, rsp
> ; Check for overflows
> ,=< 0x563d8090975b 7321 jae 0x563d8090977e
> | ; Replace the old stack pointer by the new one
> | 0x563d8090975d 4889e9 mov rcx, rbp
> | 0x563d80909760 4829e1 sub rcx, rsp
> | 0x563d80909763 482b0a sub rcx, qword [rdx]
> | 0x563d80909766 480132 add qword [rdx], rsi
> | 0x563d80909769 4889c4 mov rsp, rax
> | 0x563d8090976c 4801c8 add rax, rcx
> | 0x563d8090976f 4889e7 mov rdi, rsp
> | 0x563d80909772 4801e6 add rsi, rsp
> | 0x563d80909775 48c1e903 shr rcx, 3
> | 0x563d80909779 f348a5 rep movsq qword [rdi], qword
> ptr [rsi]
> ,==< 0x563d8090977c eb02 jmp 0x563d80909780
> |`-> 0x563d8090977e 31c0 xor eax, eax
> | ; Done!
> `--> 0x563d80909780 c3 ret
>
> So as you can see alloca isn't really a function in that it doesn't
> create a
> stack frame. It also needs help from the compiler to setup its arguments
> since the current allocation size is needed (rcx in the beginning of
> alloca)
> which isn't a parameter known by the programmer. The compiler has to detect
> that __alloca call and setup an additionnal argument by itself. Alloca then
> just ("just") modifies the calling frame.
>
>
> (I really hope I didn't mess something up)
Thanks, I didn't realize there was an implementation outside the
compiler. I had thought the compiler did all this for you.
I also didn't realize there was an actual function (stack frame or no
stack frame, you are calling and returning).
Literally, I thought alloca just bumped the stack pointer and loaded the
result into your target. Seems really complex for what it's doing, but
maybe that's because it's a function call that's not really normal.
-Steve
More information about the Digitalmars-d-learn
mailing list