7

我正在使用 Delphi 2010。是否可以告诉 Delphi 不要为函数生成序言?我正在写一些像这样的纯汇编函数:

procedure SomeAssembly; stdcall;
begin
    asm
        ...
    end;
end;

我想告诉Delphi不要为这个函数生成序言和结语,就像C++的__declspec(naked)特性一样。

所以没有人浪费他们的时间,我不需要帮助来让这些功能序言一起工作;我已经可以做到了。这只是一个很大的不便,并且会使维护变得非常麻烦。我必须手动检查编译器生成的序言以查看它们的长度,如果发生变化,我的程序将崩溃。

我也知道我可以将函数编写为字节数组中的一系列字节,但这比必须找到 Delphi 序言的长度还要糟糕。

4

3 回答 3

20

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 序言的长度是微不足道的:

  1. 在函数开始处设置断点。
  2. 调用函数。
  3. 当调试器在断点处停止时,切换到 CPU 视图。
  4. 查看构成序言的说明。
  5. 计算这些指令旁边显示的字节数。
于 2011-03-27T17:34:41.590 回答
1

根据this embarcadero docwiki,您可以跳过周围beginend内容,编译器将跳过其中的一些内容。但是如果你真的想要纯汇编,为什么不把你的函数放到一个单独的汇编文件中,用 tasm 汇编(exe 名为 tasm32)并链接到它。然后,您将assembler在 delphi 代码中使用该指令。

于 2011-03-27T17:37:30.990 回答
0

procedure SomeAssembly; stdcall;
asm
    ...
end;

做这个把戏?

于 2011-03-27T17:34:30.570 回答