在不受支持的体系结构上未使用的asm()的行为

时间:2018-08-22 19:19:31

标签: c++ assembly x86 arm

.two { position: fixed; }代码块在未使用但不受支持的体系结构中的行为是什么?例如,如果我在ARM上编译以下代码,会发生什么情况

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="position: fixed;">1</div>
<div class="two">2</div>
<div></div>

这是有效的C ++吗?代码会编译吗?标准是否对这种情况有任何说明?

2 个答案:

答案 0 :(得分:5)

这取决于如何处理。来自[dcl.asm]

  

asm声明的格式为

asm-definition:
    attribute-specifier-seq opt asm ( string-literal ) ;
     

asm声明是有条件支持的; 其含义是实现定义的。 asm定义中的可选attribute-specifier-seq与asm声明有关。 [注:通常,它用于将信息通过实现传递给汇编器。 —尾注]

强调我的

也就是说,您可以将代码放入#if #endif中,使用SFINAE或使用if constexpr。如果不满足条件,所有这些都将删除代码。

答案 1 :(得分:2)

是的,只要false绝对是一个编译时常量,就可以在gcc和clang上使用。它将无法在完全不支持asm(""); 的MSVC等编译器上进行编译。

不过,我不建议这样做。使用预处理器进行特定于拱和特定于实现的代码选择更为正常。


ISO C ++基本上没有什么可说的。 asm是特定于实现的扩展,因此,即使在死代码中,实现也可以自由拒绝未汇编的asm。但是问题是我们实际使用的编译器是否像这样。

唯一有意义的问题是您关心的实际编译器会发生什么。


例如,在MSVC上,不支持asm("");语法,无论字符串文字的内容如何。因此,到处都是编译时的语法错误。 您不能使用if(false){}保护甚至无法编译的代码,就像在模板元编程中那样(不幸的是)一样。


在支持GNU扩展的编译器(最广泛使用的ISO C或C ++扩展,其中包括asm("")样式的语法)上,让我们来看一下{{3 }} 。

我之所以选择on the Godbolt compiler explorer,是因为它是一条有效指令,不需要任何输入或输出操作数,因为它不会修改任何寄存器。而且与nop之类的东西不同,它不会在非x86上汇编。 (volatile对于mfence是隐式的,没有输出操作数。)

void nobarrier() {
    //int condition = 0;  if(condition) // wouldn't work at -O0
    if(false) {
        // only an error with MSVC
        asm("mfence" ::: "memory");
    }
}

#ifdef UNCONDITIONAL
void barrier() {
    // gcc compiles separately from assembling
    // clang/LLVM's built-in assembler chokes at compile time
    asm("mfence" ::: "memory");
}
#endif

即使禁用优化,GCC和clang甚至都不会尝试在asm()内组装if(false)语句。

当然,-O0阻止他们将int cond=0; if(cond){}始终视为错误,因为为了进行一致的调试,它们使asm假定每个变量在内存中被(由调试器)修改,每个陈述。 (所有存储/重新加载的部分原因是未优化的代码如此之慢)。

使用ARM或AArch64 gcc,nobarrier()可以很好地进行编译,汇编成的asm也可以。例如

@ gcc7.2 -O3 for ARM32.  Similar output with -O0
nobarrier():
    bx      lr

GCC甚至没有尝试解析asm模板的内容,因此它将为AArch64 编译 barrier(),但是它包含的指令不会组装。

@ gcc6.3 -O0 -DUNCONDITIONAL
barrier():
    mfence
    nop
    ret

如果您关心编译和汇编之间的区别,那么clang就不同了。

clang6.0 -O0 -target mips -DUNCONDITIONAL

<source>:13:9: error: unknown instruction
    asm("mfence" ::: "memory");
        ^

<inline asm>:1:2: note: instantiated into assembly here
        mfence
        ^
1 error generated.
Compiler returned: 1

如果您只关心C ++->目标文件,而不关心.s asm源输出,则这无关紧要。为此,它的行为与gcc相同。 if(false)确实使用非MIPS指令保护了asm语句,使其不会被解析:

@ clang6.0 -O0 -target mips
nobarrier():                          # @nobarrier()
    addiu   $sp, $sp, -8
    sw      $fp, 4($sp)             # 4-byte Folded Spill
    move    $fp, $sp
    move    $sp, $fp
    lw      $fp, 4($sp)             # 4-byte Folded Reload
    addiu   $sp, $sp, 8
    jr      $ra
    nop