【问题标题】:How to use StackAlloc in x64?如何在 x64 中使用 StackAlloc?
【发布时间】:2015-01-06 23:31:12
【问题描述】:

我正在尝试在 X64 的 DelphiXE7 中使用来自 Graphics32StackAlloc,但是它会因错误而崩溃。我尝试将NOFRAME 添加到代码中,但也没有帮助。

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.

【问题讨论】:

  • 你确定你有最新的 GR32 1.9.1 版本吗?因为我的版本看起来很不一样。
  • @iamjoosy 是的,我得到了graphics32-1-9-1-fixes-r2148.zip
  • 你应该试试这个:GR32_LowLevel 它是 r2187
  • 忘记我最后的评论了,r2187也坏了

标签: delphi delphi-xe7


【解决方案1】:

您的StackAlloc 版本在x64 版本末尾缺少PUSH R8。 因此,返回地址不会放回堆栈。

【讨论】:

    猜你喜欢
    • 2022-11-11
    • 1970-01-01
    • 2020-10-12
    • 2011-05-14
    • 2010-10-24
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多