I am trying to use StackAlloc
from Graphics32
in DelphiXE7 in X64
however it crashes with erorr. I tried adding NOFRAME
to the code and that didn't help either.
First chance exception at $000000000013FF10. Exception class $C0000005 with message 'c0000005 ACCESS_VIOLATION'. Process Stack.exe (4536)
program Stack;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes;
function StackAlloc(Size: Integer): Pointer; register;
asm
{$IFDEF CPUX86}
POP ECX // return address
MOV EDX, ESP
ADD EAX, 3
AND EAX, not 3 // round up to keep ESP dword aligned
CMP EAX, 4092
JLE @@2
@@1:
SUB ESP, 4092
PUSH EAX // make sure we touch guard page, to grow stack
SUB EAX, 4096
JNS @@1
ADD EAX, 4096
@@2:
SUB ESP, EAX
MOV EAX, ESP // function result = low memory address of block
PUSH EDX // save original SP, for cleanup
MOV EDX, ESP
SUB EDX, 4
PUSH EDX // save current SP, for sanity check (sp = [sp])
PUSH ECX // return to caller
{$ELSE}
.NOFRAME
MOV RAX, RCX
POP R8 // return address
MOV RDX, RSP // original SP
ADD ECX, 15
AND ECX, NOT 15 // round up to keep SP dqword aligned
CMP ECX, 4092
JLE @@2
@@1:
SUB RSP, 4092
PUSH RCX // make sure we touch guard page, to grow stack
SUB ECX, 4096
JNS @@1
ADD ECX, 4096
@@2:
SUB RSP, RCX
MOV RAX, RSP // function result = low memory address of block
PUSH RDX // save original SP, for cleanup
MOV RDX, RSP
SUB RDX, 8
PUSH RDX // save current SP, for sanity check (sp = [sp])
{$ENDIF}
end;
{ StackFree pops the memory allocated by StackAlloc off the stack.
- Calling StackFree is optional - SP will be restored when the calling routine
exits, but it's a good idea to free the stack allocated memory ASAP anyway.
- StackFree must be called in the same stack context as StackAlloc - not in
a subroutine or finally block.
- Multiple StackFree calls must occur in reverse order of their corresponding
StackAlloc calls.
- Built-in sanity checks guarantee that an improper call to StackFree will not
corrupt the stack. Worst case is that the stack block is not released until
the calling routine exits. }
procedure StackFree(P: Pointer); register;
asm
{$IFDEF CPUX86}
POP ECX { return address }
MOV EDX, DWORD PTR [ESP]
SUB EAX, 8
CMP EDX, ESP { sanity check #1 (SP = [SP]) }
JNE @Exit
CMP EDX, EAX { sanity check #2 (P = this stack block) }
JNE @Exit
MOV ESP, DWORD PTR [ESP+4] { restore previous SP }
@Exit:
PUSH ECX { return to caller }
{$ELSE}
POP R8 { return address }
MOV RDX, QWORD PTR [RSP]
SUB RCX, 16
CMP RDX, RSP { sanity check #1 (SP = [SP]) }
JNE @Exit
CMP RDX, RCX { sanity check #2 (P = this stack block) }
JNE @Exit
MOV RSP, QWORD PTR [RSP + 8] { restore previous SP }
@Exit:
PUSH R8 { return to caller }
{$ENDIF}
end;
var
SL: ^TStringList;
begin
SL := StackAlloc(SizeOf(TStringList)); // Crashes here.
SL^ := TStringList.Create;
SL^.Add('sda');
FreeAndNil(SL^);
StackFree(sl);
Readln;
end.
Your version of StackAlloc
lacks PUSH R8
at the end of x64 version.
Due to this, the return address is not put back on the stack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With