如何在GCC C ++中编写多行内联汇编代码?

12

这看起来不太友好:

__asm("command 1"
      "command 2"
      "command 3");

我真的必须在每一行周围都加上双引号吗?

而且...由于GCC不支持多行字符串字面量,我也无法使用这种方法进行欺骗。


我可以在同一行上写多个汇编指令吗? - phuclv
2个回答

18

我经常在互联网上看到一些人手动插入制表符和换行符,而不是使用\t和\n,然而这对我并没有用。不太确定你的例子是否能通过编译...但是这是我做的方式:

asm volatile(           // note the backslash line-continuation
   "xor %eax,%eax          \n\t\
    mov $0x7c802446, %ebx  \n\t\
    mov $1000, %ax         \n\t\
    push %eax              \n\t\
    call *%ebx             \n\t\
    add $4, %esp           \n\t\
    "
    : "=a"(retval)        // output in EAX: function return value
    :
    : "ecx", "edx", "ebx"   // tell compiler about clobbers
  // Also x87 and XMM regs should be listed.
 );

或者在每行周围加上双引号,而不是使用\进行行续。C字符串文字单独只有通过空格(包括换行符)连接成一个长的字符串文字。(这就是为什么你需要在其中使用\n,因此当它被汇编器看到时,它是分开的行)。

这样做不那么丑陋,并且可以在每行上放置C注释。

asm volatile(
    "xor %eax,%eax          \n\t"
    "mov $0x7c802446, %ebx  \n\t"
    "mov $1000, %ax         \n\t"
    "push %eax              \n\t"  // function arg
    "call *%ebx             \n\t"
    "add $4, %esp           \n\t"  // rebalance the stack: necessary for asm statements
  : "=a"(retval)
  :
  : "ecx", "edx", "ebx"    // clobbers.  Function calls themselves kill EAX,ECX,EDX
  // function calls also clobber all x87 and all XMM registers, omitted here
);

谢谢,伙计。这大概就是我在例子中看到的,但是肯定还是“不太好看”的!这让我写汇编的动力消失了。 - johnny-john
如此之少,但仍然丑陋!谢谢! :) - bigjosh
5
“\t\n”的替代方案是使用分号来分隔指令。然而,“\t\n”更好,因为生成的汇编代码输出不会很混乱。通常使用“insn \n\t”、“insn2 \n\t”等等进行字符串连接工作,而不是在每行末尾使用反斜杠。 - Peter Cordes
1
非常丑陋的方法也是意外不起作用的方法,尽管较少丑陋的方法也存在这个问题。 - Ross Ridge

6

C++多行字符串字面值

有趣的是这个问题让我找到了答案:

main.cpp

#include <cassert>
#include <cinttypes>

int main() {
    uint64_t io = 0;
    __asm__ (
        R"(
incq %0
incq %0
)"
        : "+m" (io)
        :
        :
    );
    assert(io == 2);
}

编译并运行:

g++ -o main -pedantic -std=c++11 -Wall -Wextra main.cpp
./main

另请参阅:C++多行字符串字面量

GCC还添加了与C扩展相同的语法,只需使用-std = gnu99 而不是-std = c99

main.c

#include <assert.h>
#include <inttypes.h>

int main(void) {
    uint64_t io = 0;
    __asm__ (
        R"(
incq %0
incq %0
)"
        : "+m" (io)
        :
        :
    );
    assert(io == 2);
}

编译并运行:

gcc -o main -pedantic -std=gnu99 -Wall -Wextra main.c
./main

参见:如何在C/Objective-C中将字符串面值跨多行拆分?

这种方法的一个缺点是我不知道如何在汇编中添加C预处理器宏,因为它们不会在字符串内展开。 另请参见:带有字符串的多行内联汇编宏

在Ubuntu 16.04,GCC 6.4.0,binutils 2.26.1上测试通过。

.incbin

如果您要使用大块的汇编代码,则应该了解这个GNU GAS指令:使用GCC嵌入可执行文件中的资源

汇编将位于单独的文件中,因此这不是直接的答案,但仍然值得了解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接