这看起来不太友好:
__asm("command 1"
"command 2"
"command 3");
我真的必须在每一行周围都加上双引号吗?
而且...由于GCC不支持多行字符串字面量,我也无法使用这种方法进行欺骗。
这看起来不太友好:
__asm("command 1"
"command 2"
"command 3");
我真的必须在每一行周围都加上双引号吗?
而且...由于GCC不支持多行字符串字面量,我也无法使用这种方法进行欺骗。
我经常在互联网上看到一些人手动插入制表符和换行符,而不是使用\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
);
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嵌入可执行文件中的资源
汇编将位于单独的文件中,因此这不是直接的答案,但仍然值得了解。