Delphi 不会为没有参数并使用寄存器调用约定声明的函数生成序言或结语。如果您想要没有序言的函数,请将它们声明为零参数、寄存器调用约定函数。另外,跳过begin
-end
块并直接进行组装。
procedure SomeAssembly; // register; (implied)
asm
// ...
end;
由于您实际上是在对函数的性质撒谎,因此调用它们可能会很棘手。如果您已经实现了一个函数,就好像它接收参数并使用了不同的调用约定,那么您必须确保编译器在调用站点知道这一点。为此,请声明一个反映函数“真实”类型而不是声明类型的函数指针。例如,如果您的函数确实是一个有两个参数的 stdcall 函数,请声明如下内容:
type
TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall;
var
SomeAssemblyProc: TSomeAssemblyProc;
现在,分配该变量,使其指向您的函数:
SomeAssemblyProc := TSomeAssemblyProc(@SomeAssembly);
if SomeAssembly(2, 'foo') then ...
除了跳过序言和结尾之外,编译器还会RET
为这个函数生成不正确的指令(因为不同的调用约定),所以你必须确保你ret 8
在你的代码中说,而不是让编译器的默认ret
指令出现。
如果您有一个工作调试器,那么查找 Delphi 序言的长度是微不足道的:
- 在函数开始处设置断点。
- 调用函数。
- 当调试器在断点处停止时,切换到 CPU 视图。
- 查看构成序言的说明。
- 计算这些指令旁边显示的字节数。