【问题标题】:How to write multiline inline assembly code in GCC C++?如何在 GCC C++ 中编写多行内联汇编代码?
【发布时间】:2021-01-19 01:41:09
【问题描述】:

这看起来不太友好:

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

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

另外...由于多行字符串文字在 GCC 中不起作用,所以我也无法作弊。

【问题讨论】:

标签: gcc assembly inline-assembly


【解决方案1】:

我总是在 Internet 上找到一些示例,即该人手动插入制表符和换行符而不是 \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.
 );

或者在每一行加上双引号,而不是使用\ line-continuation。 C 字符串文字仅由空格(包括换行符)单独连接成一个长字符串文字。 (这就是为什么你需要 \n 在里面,所以当它被汇编器看到时它是单独的行)。

这样不那么难看,并且可以在每一行放置 C cmets。

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
);

【讨论】:

  • 谢谢伙计,这或多或少是我在示例中看到的,但是,它仍然只是“不那么难看”!让我没有写 asm 的动力。
  • 如此少但仍然丑陋!谢谢! :)
  • \t\n 的替代方法是用分号分隔指令。 \t\n 更好,因为生成的 asm 输出不会一团糟。通常使用 "insn \n\t" "insn2 \n\t" 等,并让字符串连接起作用,而不是用反斜杠结束每一行。
  • 非常丑陋的方式也是will-unexpectedly-not-work方式,虽然不太丑陋的方式也存在这个问题。
【解决方案2】:

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++ multiline string literal

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

另见:How to split a string literal across multiple lines in C / Objective-C?

这种方法的一个缺点是我看不到如何在程序集中添加 C 预处理器宏,因为它们没有在字符串内部展开,另请参阅:Multi line inline assembly macro with strings

在 Ubuntu 16.04、GCC 6.4.0、binutils 2.26.1 上测试。

.incbin

如果您要使用大量程序集,则该 GNU GAS 指令是您应该关注的另一件事:Embedding resources in executable using GCC

程序集将在一个单独的文件中,因此不是直接答案,但仍然值得了解。

【讨论】:

    猜你喜欢
    • 2012-02-12
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-30
    • 2012-10-20
    • 1970-01-01
    • 2010-12-12
    相关资源
    最近更新 更多