Dit artikel beschrijft het mechanisme achter de alloca()-functie voor het alloceren van geheugen op de stack. De kern van de uitleg is dat alloca() gebruikmaakt van de functie _chkstk() om de stack te controleren (proben) voordat de stack-pointer wordt aangepast. Dit voorkomt dat grote allocaties onbedoeld over de guard page springen. Met behulp van een C-voorbeeld en de bijbehorende x86-64 assembly-code wordt gedemonstreerd dat __chkstk zowel wordt aangeroepen voor het initiële lokale frame als voor de dynamische allocatie via alloca.
Hoe alloceren functies zoals alloca geheugen van de stack?
Een tijdje geleden besprak ik hoe compilers ervoor zorgen dat grote stack-allocaties niet over de guard page heen springen. Shawn Van Ness was benieuwd hoe dit werkt met alloca. "Voert het de nodige chkstk()-probing uit?"
Ja, de alloca()-functie roept dezelfde chkstk()-functie aan om de stack te controleren (proben) voordat de stack-pointer wordt aangepast voor het gealloceerde geheugen.
Hier is een kunstmatig voorbeeld:
#include <malloc.h>
void consume(void*,void*);
void f(int n)
{
char buffer[16384];
consume(alloca(n), buffer);
}
Op x86-64 resulteert dit in:
push rbp
mov eax, 16416 ; probe for local frame
call __chkstk
sub rsp, rax ; create local frame
lea rbp, [rsp+32]
movsxd rax, ecx ; n
lea rcx, [rax+15] ; round up to multiple of 16
and rcx, -16
mov rax, rcx ; special __chkstk calling convention
call __chkstk
sub rsp, rcx ; allocate n bytes
lea rdx, [rbp] ; rdx -> buffer
lea rcx, [rsp+32] ; rcx -> alloca'd memory
call consume
lea rsp, [rbp+16384] ; clean up local frame
pop rbp
ret 0
Merk op dat dezelfde __chkstk-functie wordt gebruikt, zowel voor het uitvoeren van de initiële stack-probe bij het maken van het lokale frame als voor de alloca().
Hoe alloceren functies zoals alloca geheugen van de stack?
Een tijdje geleden besprak ik hoe compilers ervoor zorgen dat grote stack-allocaties niet over de guard page heen springen. Shawn Van Ness was benieuwd hoe dit werkt met alloca. "Voert het de nodige chkstk()-probing uit?"
Ja, de alloca()-functie roept dezelfde chkstk()-functie aan om de stack te controleren (proben) voordat de stack-pointer wordt aangepast voor het gealloceerde geheugen.
Hier is een kunstmatig voorbeeld:
#include <malloc.h>
void consume(void*,void*);
void f(int n)
{
char buffer[16384];
consume(alloca(n), buffer);
}
Op x86-64 resulteert dit in:
push rbp
mov eax, 16416 ; probe for local frame
call __chkstk
sub rsp, rax ; create local frame
lea rbp, [rsp+32]
movsxd rax, ecx ; n
lea rcx, [rax+15] ; round up to multiple of 16
and rcx, -16
mov rax, rcx ; special __chkstk calling convention
call __chkstk
sub rsp, rcx ; allocate n bytes
lea rdx, [rbp] ; rdx -> buffer
lea rcx, [rsp+32] ; rcx -> alloca'd memory
call consume
lea rsp, [rbp+16384] ; clean up local frame
pop rbp
ret 0
Merk op dat dezelfde __chkstk-functie wordt gebruikt, zowel voor het uitvoeren van de initiële stack-probe bij het maken van het lokale frame als voor de alloca().