编写汇编函数时,序言和尾声是强制性的吗?

时间:2017-02-13 15:49:16

标签: c assembly nasm

最近我在程序集中重写了一些libc函数,对于其中一些函数(不需要任何调用 syscall 指令,如strlen),我抛弃序幕和尾声,因为没有它我的测试没有失败(也许我没有足够复杂的测试)。 在同行评审期间,有人告诉我丢弃它是一种不好的做法,但无法解释为什么。

所以,当我调用没有prologue / epilogue组合的asm函数时,我遇到了问题吗?

即使堆栈上不需要额外的空间,添加它也是一个好习惯吗?

如果出于某些原因强制要求,为什么编译器(我使用过nasm)不会处理它?<​​/ p>

感谢您阅读

2 个答案:

答案 0 :(得分:4)

如果没有设置正确的堆栈帧,调试器很难知道你现在的功能是什么。在ELF目标上,如果没有明确设置堆栈帧,则必须手动提供CFI数据(参见this article)。没有CFI数据,堆栈展开不起作用,调试器可能无法找到您所使用的功能。除非您想手动添加CFI数据(这有点单调乏味且容易出错),我建议你接受轻微的性能损失,只需设置一个完整的堆栈框架。

答案 1 :(得分:2)

编写汇编函数时,序言和结尾是必需的吗?

对于纯汇编,您甚至不需要“功能”,例如您可以拥有一段具有多个不同入口点和一个“ ret”的代码(这相当于在一个不错的编译器进行“ tail call”优化后可能会得到的结果)。

用于编写与其他人的调用约定兼容的功能;您必须遵守其他人的通话约定。如果那些调用约定说(例如)某些寄存器必须由被调用方保留,则被调用方必须保留这些寄存器(通过保存在序言中并以结尾载入),否则,您可能会导致意外的数据损坏(因为编译器希望该值保持不变,但是..)。

请注意,对于80x86,没有任何调用约定都需要堆栈帧(如EBP或RBP)-这只是历史遗忘,这是由于古老的调试器设计不佳所致,并且在调试器切换到更好的技术大约20年后就不再理智以前。

如果出于某些原因是强制性的,为什么汇编程序(我使用nasm)不负责?

组装者通常不知道您要遵循哪种调用约定(如果有)。