内联(x86)程序集如何影响程序流?

时间:2015-10-29 17:44:03

标签: c visual-c++ gcc x86 inline-assembly

我试图了解在运行时如何调用此类代码段:

__asm{
    PUSH ES
    MOV CX,0
    //... More x86 assembly
};

不会调整寄存器会破坏程序流程执行吗?

例如:如果上面的CX保留了某个值,那么这不意味着该寄存器值将不再有效吗?

编译器是否会处理这些依赖项,或者在特殊情况下是否会执行代码段?

在哪些编译器中内联汇编的使用不透明?

2 个答案:

答案 0 :(得分:3)

GCC

GCC 中,必须明确指定受影响的寄存器,以防止影响exectution流:

asm [volatile] ( AssemblerTemplate
                  : OutputOperands
                  [ : InputOperands
                  [ : Clobbers ] ])
  

虽然编译器知道输出中列出的条目的更改   操作数,内联asm代码可能不仅仅修改   输出。[......]计算可能需要额外的登记册,[...]   将它们列在clobber列表中。

如果您的代码执行了对已经列出的其他项目的读取或写入,请使用“memory” clobber参数。

  

“memory”clobber告诉编译器汇编代码   对内存以外的项目执行内存读取或写入操作   输入和输出操作数

参考https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

MSVC

另一方面,在 MSVC 中,您不需要保留通用寄存器:

  

使用__asm在C / C ++函数中编写汇编语言时,你   不需要保留EAX,EBX,ECX,EDX,ESI或EDI寄存器。 [...]

     

您应该保留您使用的其他寄存器(例如DS,SS,SP,BP,   和标志寄存器)用于__asm块的范围。你应该   保留ESP和EBP寄存器除非您有某些理由   改变它们。

参考: https://msdn.microsoft.com/en-us/library/k1a8ss06.aspx

编辑:将 更改为gcc,并添加了关于“memory”clobber参数的说明,并附上了Olafs建议。

答案 1 :(得分:1)

可以将一些其他标志传递给内联汇编代码。其中一个是“clobber list”,它向C / C ++编译器指示将由汇编代码块修改的寄存器列表。

请注意,指定这些附加标志的方式取决于编译器(在Microsoft Visual C ++,GCC等中完全不同...)

对于GCC,请参阅:

https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#ss5.3