13

我正在考虑将一个为 Windows 编写的脚本引擎移植到 Linux;它用于Winamp的可视化平台AVS。我不确定目前是否有可能。据我所知,代码正在获取 C 函数的地址nseel_asm_atan并将nseel_asm_atan_end它们存储在一个表中,它可以在代码执行期间引用该表。

我查看了 MS 的文档,但我不确定__declspec(naked)真正的作用。文档中提到的 prolog 和 epilog 代码是什么?这与 Windows 调用约定有关吗?这是便携的吗?知道任何使用类似技术的基于 Linux 的示例吗?

static double (*__atan)(double) = &atan;
__declspec ( naked ) void nseel_asm_atan(void)
{
  FUNC1_ENTER

  *__nextBlock = __atan(*parm_a);

  FUNC_LEAVE
}
__declspec ( naked ) void nseel_asm_atan_end(void) {}
4

2 回答 2

11

基本上,函数序言为局部变量设置了一个堆栈框架,并且结尾负责清理它。这通常由编译器自动完成。如果您使用__declspec(naked),则设置此堆栈框架将由您决定,因此它为您提供更多灵活性。

有很多参考资料:hereherealso here 等等。

GNU gcc 编译器也支持裸机,但显然不支持 x86:在页面中搜索“裸机” (我没有尝试查看它是否适用于 x86)

于 2010-06-12T11:49:35.790 回答
11

来自维基百科功能序言和结语:

在汇编语言编程中,函数序言是函数开头的几行代码,用于准备堆栈和寄存器以供在函数内使用。类似地,函数结尾出现在函数的末尾,并将堆栈和寄存器恢复到调用函数之前的状态。

为确保编译器不会在您的函数中自动生成额外代码,请始终使用__declspec(naked)约定声明函数。

让我们看一下这个函数:

void myTrampoline()
{
__asm {
  PUSHFD
  PUSHAD
  CALL jumpHookCallback
  POPAD
  POPFD
  POP EAX
  MOV AL, 1
  POP EDI
  POP ESI
  JMP [restoreJumpHook]
 }
}

现在编译器将生成代码来操作函数的堆栈帧,称为函数的序言和尾声,结果将如下所示

;Prologue
push ebp
mov ebp, esp
sub esp, N

PUSHFD
PUSHAD
CALL jumpHookCallback
POPAD
POPFD
POP EAX
MOV AL, 1
POP EDI
POP ESI
JMP [restoreJumpHook]

;Epilogue
mov esp, ebp
pop ebp
ret

但是如果我们使用 __declspec(naked)就不 Prologue会有 Epilogue

void __declspec(naked) myTrampoline()
{
__asm {
  PUSHFD
  PUSHAD
  CALL jumpHookCallback
  POPAD
  POPFD
  POP EAX
  MOV AL, 1
  POP EDI
  POP ESI
  JMP [restoreJumpHook]
 }
}

结果将如下所示:

    PUSHFD
    PUSHAD
    CALL jumpHookCallback
    POPAD
    POPFD
    POP EAX
    MOV AL, 1
    POP EDI
    POP ESI
    JMP [restoreJumpHook]
于 2018-08-21T12:45:46.697 回答