繁体   English   中英

为什么GCC内联汇编程序需要blobbering信息,但MSVC不需要

[英]Why does GCC inline assembler require clobbering information, but MSVC doesn't

我不明白这是怎么回事。

GCC内联汇编程序很难做到,但是对于标记符号信息非常具体,因此编译器知道你正在做什么。

Microsoft Visual C ++的inline assember非常容易使用(它似乎总是Just Work),但我不知道它对你的代码有什么样的保证或假设。

VC ++是否试图“自动检测”哪些寄存器被破坏? 它如何知道如何更改寄存器和堆栈指针? 它做出任何假设吗? 如果是这样,你如何解决这些假设?

至于为什么海湾合作委员会不像MSVC那样做,有几个原因:

  1. GCC是一个可重定向的编译器,但汇编语法只是原始文本。 为了使clobber检测自动化,GCC必须解析汇编语言以了解哪些寄存器被破坏(包括由操作码未命名寄存器的指令隐式破坏的寄存器)。 这必须适用于所有架构。 目前,GCC不解析汇编语言; 在执行%替换后,它只是将其粘贴到程序集输出中。 我们的想法是生成并避免解析。

  2. 在GCC内联汇编语言中, clobbering寄存器是例外而不是规则 原因是它是一种比MSVC更复杂的语言。 GCC的内联汇编语言为您分配寄存器。 所以你通常不直接使用%eax类的东西,而是使用像%0这样的代码,GCC代替可用的寄存器。 (要做到这一点,编译器不必理解汇编语言!你表达了约束,这些约束确保GCC用适当的寄存器替换适合用法的%0 。) 如果你的汇编代码被重写,你只需要clobber - 编码寄存器,而不是它覆盖GCC为您分配的输出操作数

请注意,使用GCC内联汇编时,您不必编写从生成其初始值的C表达式加载汇编语言操作数的代码,也不必将结果操作数存储到C目标中。 例如,您只是表示存在类型为"r" (寄存器)的输入操作数,该操作数派生自表达式foo->bar + 1 GCC分配寄存器并生成代码以从foo->bar + 1加载它,然后将汇编模板中%0出现替换为该寄存器的名称。

文档引用:

使用__asm在C / C ++函数中编写汇编语言时,不需要保留EAX,EBX,ECX,EDX,ESI或EDI寄存器。 例如,在使用内联汇编编写函数的POWER2.C示例中,power2函数不会保留EAX寄存器中的值。 但是,使用这些寄存器会影响代码质量,因为寄存器分配器不能使用它们来跨__asm块存储值。 此外,通过在内联汇编代码中使用EBX,ESI或EDI,可以强制编译器在函数序言和结尾中保存和恢复这些寄存器。

您应该保留您使用的其他寄存器(例如DS,SS,SP,BP和标志寄存器)作为__asm块的范围。 您应该保留ESP和EBP寄存器,除非您有某些理由更改它们(例如,切换堆栈)。 另请参阅优化内联汇编

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM