是否可以成功包装退出方法?

我目前正在使用gcc 4.1.2并且我有一个用例,我想使用链接器选项来包装exit方法。 让我们立即抛开所有典型的回答/评论,“为什么你甚至想要那样做?”

我想知道的是,甚至可以做到这一点。 我之前使用链接器包装了其他方法,没有任何问题。 下面是我正在使用的__wrap_exit函数的快速示例:

void __wrap_exit(int _status) { return; } 

当调用exit时,确实调用了这个包装器。 但是,程序在__wrap_exit返回后立即遇到分段错误。

  • 即使没有调用真正的退出函数并且只有包装器版本,gcc会在幕后做一些事情,例如在调用exit时发出信号吗?
  • 可以提供幕后发生的一些细节吗?

gcc有一个名为__noreturn__的语言扩展属性。 在 ,您可能有一个类似的声明:

 extern void exit (int __status) __THROW __attribute__ ((__noreturn__)); 

此属性表示函数永远不会以正常方式返回的承诺。 (也许它结束了这个过程,或者它可能是longjmp s,或者它可能抛出一个C ++exception,或者它可能有一个无休止的循环…)

因此,在编译调用exit代码时,gcc可以进行一些优化,例如可能不需要设置和/或清理堆栈指针以使其可以返回到调用函数。

例如,这是一个调用库函数的简单函数,然后是x86上的汇编,没有指定-O标志。

 void func1(void) { srand(1); } .globl func1 .type func1,@function func1: pushl %ebp movl %esp, %ebp subl $8, %esp subl $12, %esp pushl $1 call srand addl $16, %esp leave ret 

一个几乎完全相同的函数调用exit

 void func2(void) { exit(0); } .globl func2 .type func2,@function func2: pushl %ebp movl %esp, %ebp subl $8, %esp subl $12, %esp pushl $0 call exit 

它开始时相同,但只是跳过addlleaveret指令,在func1告诉CPU如何返回执行任何名为func1函数。

当你偷偷地替换exit并破坏这个承诺时,指令指针可能会进入没有合理代码的地方,或者堆栈结构可能无效等等。在示例函数func2 ,函数程序集实际上在调用exit ,所以当你返回并且指令指针返回时,它将指向程序映像中接下来的任何数据,甚至根本不是可执行代码。