Delphi新版本汇编代码内存错误:为何Delphi7正常10.4报错?
核心原因有这几点:
硬编码函数地址完全无效
代码里把ChatPrint赋值为固定地址$009E0C30,这个地址只在Delphi7编译的目标程序中对应目标聊天打印函数。Delphi10.4的内存布局、编译器生成的代码结构和Delphi7完全不同,这个地址要么是无效内存,要么指向无关代码,直接调用必然触发内存错误。汇编代码的参数传递逻辑错误
Delphi默认使用register调用约定(32位环境下),第一个参数会通过EAX寄存器传递,但你的汇编代码里却把参数的地址lea edx, [ChatPrintMSG]压栈,完全不符合Delphi的调用规范。Delphi7可能因为编译器优化或栈帧的宽松处理没暴露问题,但Delphi10.4对栈帧和调用约定的检查更严格,直接导致参数传递错误,引发内存访问异常。嵌套过程的变量访问不规范
嵌套的ChatPrintASM过程直接用[ChatPrint]访问外层的ChatPrint变量,不同Delphi版本的栈帧布局存在差异,高版本Delphi对嵌套过程的栈帧管理更规范,没有正确计算外层变量的栈偏移,就会访问到错误的内存区域。字符串类型的隐式转换差异
Delphi7默认字符串是ANSI编码的ShortString,PChar等价于PAnsiChar;但Delphi10.4默认是Unicode编码的UnicodeString,PChar等价于PWideChar。如果目标ChatPrint函数期望ANSI字符串指针,Delphi10.4中传递宽字符指针会导致函数处理时内存访问错误。
- 放弃硬编码函数地址:如果是调用外部程序或DLL中的函数,通过
GetProcAddress动态获取函数地址,不要写死固定值。 - 修正汇编调用逻辑:按照Delphi的
register调用约定正确传递参数,32位下第一个参数放入EAX,直接调用函数地址即可,不需要手动压栈(除非是stdcall/cdecl约定)。示例代码:procedure ChatPrintASM(ChatPrintMSG: PChar); assembler; asm mov eax, [ChatPrintMSG] // register约定下,第一个参数通过EAX传递 call [ChatPrint] end; - 明确字符串类型:如果目标函数需要ANSI字符串,将参数改为
PAnsiChar,调用时显式转换:ChatPrintf(PAnsiChar('it: works')); - 规范嵌套变量访问:可以把
ChatPrint改为全局变量,或者通过参数传递给嵌套过程,避免直接访问外层栈变量导致的偏移错误。
内容的提问来源于stack exchange,提问作者Waloszek

