删除用纯汇编编写的函数的序言

发布于 2024-10-26 10:59:34 字数 412 浏览 8 评论 0原文

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

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

我想告诉 Delphi 不要为这个函数生成序言和尾声,就像 C++ 的 __declspec(naked) 功能一样。

所以没有人浪费时间,我不需要帮助让这些函数与序言一起工作;我已经可以做到了。这不仅带来很大的不便,而且会给维护带来巨大的麻烦。我必须手动检查编译器生成的序言以查看它们的长度,如果发生变化,我的程序将崩溃。

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

I am using Delphi 2010. Is it possible to tell Delphi to not generate a prologue for a function? I'm writing some pure assembly functions like this:

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

and I would like to tell Delphi not to generate a prologue and epilogue for this function, like C++'s __declspec(naked) feature.

And so no one wastes their time, I don't need help getting these functions to work with the prologue; I can already do that. It's just a large inconvenience and will make maintenance an huge hassle. I'll have to manually inspect the prologues generated by the compiler to see their length, and if that changes, my program will crash.

I also know I can write the function as a series of bytes in a byte array, but that would be even worse than having to go find the length of Delphi's prologue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

栩栩如生 2024-11-02 10:59:34

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. 计算这些指令旁边显示的字节数。

Delphi doesn't generate prologues or epilogues for functions having no arguments and declared with the register calling convention. If you want functions without prologues, declare them as zero-argument, register-calling-convention functions. Also, skip the begin-end block and go straight into assembly.

procedure SomeAssembly; // register; (implied)
asm
  // ...
end;

Since you're effectively lying about the nature of the functions, calling them may be tricky. If you've implemented a function as though it received parameters and used a different calling convention, then you'll have to make sure the compiler knows about that at the call site. To do that, declare a function pointer that reflects the "real" type of your function instead of the declared type. For example, if your function is really a two-argument stdcall function, declare something like this:

type
  TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall;
var
  SomeAssemblyProc: TSomeAssemblyProc;

Now, assign that variable so it points at your function:

SomeAssemblyProc := TSomeAssemblyProc(@SomeAssembly);
if SomeAssembly(2, 'foo') then ...

In addition to skipping the prologue and epilogue, the compiler will generate the incorrect RET instruction for this function (because of the different calling convention), so you'll have to make sure you say ret 8 in your code instead of letting the compiler's default ret instruction occur.


Finding the length of Delphi's prologue is trivial, if you have a working debugger:

  1. Set a breakpoint at the start of the function.
  2. Call the function.
  3. When the debugger stops at the breakpoint, switch to the CPU view.
  4. Look at the instructions that make up the prologue.
  5. Count the bytes displayed beside those instructions.
冰魂雪魄 2024-11-02 10:59:34

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

According to the this embarcadero docwiki you can skip the surrounding begin and end and the compiler will skip some of it's stuff. But if you really want pure assembler, why not put your function into a separate assembler file, assemble it with tasm (the exe is named tasm32) and link to it. You'll then use the assembler directive in the delphi code.

浅笑轻吟梦一曲 2024-11-02 10:59:34

不会

procedure SomeAssembly; stdcall;
asm
    ...
end;

有窍门吗?

Doesn't

procedure SomeAssembly; stdcall;
asm
    ...
end;

do the trick?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文