我在装配中的知识有限,但我至少可以通读它并与相应的C或C++代码匹配。我可以看到函数参数是通过将它们推入堆栈或通过寄存器传递的,函数体使用一些寄存器来执行操作。但它似乎也使用了调用者使用的相同寄存器。这是否意味着调用者不能保证函数调用后寄存器的状态是相同的?如果在编译期间函数的整个主体是未知的,该怎么办?编译器如何处理这个问题?函数调用后寄存器的状态是什么?
回答
编译器生成的汇编代码遵循calling convention。调用约定通常指定
- 如何传递给函数的参数
- 返回值是如何从被调用函数传递给调用者
- 哪些寄存器要保存一个函数调用内可以进行修改
如果被调用的所有函数遵循相同的调用约定,则不会发生使用相同寄存器的问题。
正如评论所暗示的那样,事实是没有这方面的标准。它完全留给你正在使用的特定C++编译器的实现者。
一个更明确的问题,如下所示:“使用ABI E编译带有编译器选项B的编译器A的版本N,为目标CPU D调用C的函数签名时,有什么保证,可见寄存器保存?“
在这种情况下,该特定工具集的专家(或手册)可以回答。你可以推断,对于任何类型的工业强度项目,这是一个错误的问题,因为随着编译器的发展,答案将会改变,而且你不希望这个事实影响你的可靠性程序。
这是一个很好的问题,因为很高兴知道编译器正在做什么 - 它有助于学习。但总的来说,黄金法则是在程序中向编译器表达清晰的简单逻辑,并允许编译器处理将该逻辑转换为优化机器代码的细节,在此代码中现代编译器非常出色。
它不仅仅是编译器,而是大多数语言,体系结构/ CPU和操作系统。对于某些体系结构,有多个ABI(例如,ARM,x86 - 在Windows或Linux(OS-X?)上)。 – Olaf
@Olaf的确如此,我的意思是“编译器”这个术语能够捕捉到所有这些,但我会在答案中明确指出。 –
好吧,你是让它太泛泛......如果我在Windows上的x86架构上用C调用约定来声明函数foo(),那么......我会一直知道会发生什么,无论如何编译器版本(或其选项)。如果不是这样,你甚至不能调用OS库函数。 –
- 1. 启动后的寄存器状态
- 2. 什么是约翰逊计数器中的寄生状态机
- 3. 什么函数保存树的状态?
- 4. dart调试器的状态是什么?
- 5. 什么是专用寄存器?
- 6. 为什么MOVWF不影响状态寄存器?
- 7. 函数调用后,llvm调用者保存的寄存器未重新载入
- 8. 什么是被调用者和调用者保存的寄存器?
- 9. PIC寄存器(%ebx)是做什么的?
- 10. 在<C-r>函数调用后恢复寄存器
- 11. 伪随机数发生器中的状态函数是什么?
- 12. 跳转后寄存器和变量未保存状态
- 13. 什么是ESP和EBP寄存器?
- 14. 调用后的python中的线程锁状态是什么subprocess.popen
- 15. ARM程序状态寄存器
- 16. Z80状态标志寄存器
- 17. EBX寄存器用于内存访问的模式是什么?
- 18. 为什么地址寄存器后置是(A0)+
- 19. 为什么在调用main()时,avr-gcc会不自觉地保存寄存器状态?
- 20. 80x86状态位。哪些寄存器是可读的?
- 21. 调用__device__函数是否会影响CUDA中使用的寄存器数量?
- 22. 在函数调用之前保存XMM寄存器
- 23. 寄存器和临时寄存器有什么区别?
- 24. 什么是通用寄存器的一些特殊用途
- 25. 为什么在调用一个函数后,这段代码会跳入同一个寄存器?
- 26. MIPS中的浮点寄存器是哪些数字寄存器?
- 27. 新的X86_64处理器寄存器的名称是什么?
- 28. MIPS中$零寄存器的用途是什么?
- 29. 通用寄存器的内容是什么?
- 30. 什么是在Windows上使用的GS寄存器?
它取决于函数的[调用约定](https://en.wikipedia.org/wiki/Calling_convention)。对于x86 cdecl,EAX是返回值,ECX和EDX必须由调用者保存;其余的必须由被调用者保存。 –
不仅是调用约定,还有特定编译器关于优化的策略以及它自己的特性。 – Robinson
答案主要取决于编译器和操作系统。 –