为什么我们需要在内联汇编中删除寄存器列表? [英] Why we need Clobbered registers list in Inline Assembly?

查看:10
本文介绍了为什么我们需要在内联汇编中删除寄存器列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的导游手册上写着:

在内联汇编中,已清除的寄存器列表用于告知 我们正在使用的寄存器的编译器(这样它就可以在 那个)。

我完全不明白,为什么编译器要知道这个?让这些登记簿保持原样有什么问题?他们是否打算在汇编代码后备份和还原它们。

希望有人能提供一个例子,因为我花了几个小时阅读有关损坏的寄存器列表,但没有明确的答案。

推荐答案

未能告知编译器您所修改的寄存器的问题与您在ASM中编写修改某些调用保留寄存器的函数完全相同1。请参阅Why should certain registers be saved? What could go wrong if not?

中的更多说明和部分示例

在GNU内联ASM中,假定保留了所有寄存器,但编译器为"=r"/"+r"或其他输出操作数挑选的寄存器除外。编译器可能会在任何寄存器中保存循环计数器,或者在稍后要读取的任何其他寄存器中保存循环计数器,并期望它仍然具有在ASM模板的指令之前放在那里的值。(在禁用优化的情况下,编译器不会跨语句将变量保留在寄存器中,但当您使用-O1或更高版本时,它会这样做。)

除作为"=m""+m"内存输出操作数一部分的位置外,所有内存都相同。(除非您使用"memory"套头衫。)有关详细信息,请参阅How can I indicate that the memory *pointed* to by an inline ASM argument may be used?

脚注1:
与函数不同,您应该在ASM模板内使用自己的指令而不是保存/恢复任何寄存器。只需告诉编译器,这样它就可以在内联后保存/恢复at the start/end of the whole function,并避免在其中包含任何它需要的值。事实上,在带有红色区域(如x86-64 System V)的ABI中,在ASM内使用push/pop将是破坏性的:Using base pointer register in C++ inline asm


GNU C内联ASM的设计理念是,它使用与编译器内部机器描述文件相同的语法。标准用例用于包装单个指令,这就是为什么如果模板字符串中的ASM代码在写入某些寄存器之前没有读取其所有输入,则需要早期销毁声明。

模板对于编译器来说是一个黑匣子;它取决于您向优化编译器准确地描述它。任何错误实际上都是未定义的行为,并为编译器留下空间来扰乱周围代码中的其他变量,如果您修改了编译器没有以其他方式使用的调用保留寄存器,甚至可能在调用此变量的函数中也是如此。

这使得仅通过测试来验证正确性是不可能的。您无法区分";正确&和";碰巧使用的是周围的代码和一组编译器选项";。这就是为什么您应该避免内联ASM的原因之一,除非它的好处大于缺点和错误风险。https://gcc.gnu.org/wiki/DontUseInlineAsm

GCC只需对模板字符串进行字符串替换,非常类似于printf,然后将整个结果(包括纯C代码的编译器生成的指令)作为单个文件发送给汇编器。请看一下https://godbolt.org/;即使您在内联ASM中有无效指令,编译器本身也不会注意到。只有当你真正组装的时候才会有问题。(编译器资源管理器站点上的二进制模式。)


有关指南的更多链接,请参阅https://stackoverflow.com/tags/inline-assembly/info

这篇关于为什么我们需要在内联汇编中删除寄存器列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆