Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use StackAlloc in x64?

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.
like image 221
John Lewis Avatar asked Jan 06 '15 23:01

John Lewis


1 Answers

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.

like image 140
nullptr Avatar answered Nov 15 '22 06:11

nullptr