加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 如何在x64中使用StackAlloc?

发布时间:2020-12-15 10:12:54 所属栏目:大数据 来源:网络整理
导读:我试图在X64中的DelphiXE7中使用Graphics32中的StackAlloc但是它与erorr崩溃了.我尝试将NOFRAME添加到代码中,这也没有帮助. 第一次机会异常在$000000000013FF10.消息’c0000005 ACCESS_VIOLATION’的异常类$C0000005. Process Stack.exe(4536) program Stack
我试图在X64中的DelphiXE7中使用Graphics32中的StackAlloc但是它与erorr崩溃了.我尝试将NOFRAME添加到代码中,这也没有帮助.

第一次机会异常在$000000000013FF10.消息’c0000005 ACCESS_VIOLATION’的异常类$C0000005. 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.

解决方法

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读