我试图在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. 因此,返回地址不会被放回堆栈.