0

我正在使用带有 Eclipse CDT 和 gdb 的 64 位小端 Ubuntu 12.04 LTS 上的 gcc-4.7 在 C++ 中使用内联汇编。我正在尝试做的总体方向是为一些深奥的基于堆栈的编程语言制作某种字节码解释器。

在这个例子中,我一次处理 4 位指令(实际上这将取决于指令),当没有更多非零指令时(因为 0 将是 nop)我读取下一个 64 位字.

不过我想问一下,如何在内联汇编中使用函数范围的标签?

汇编中的标签似乎是全局的,这是不利的,我找不到从汇编语句跳转到 C++ 函数范围标签的方法。

以下代码是我正在尝试做的一个示例(注意注释):

  ...
  register long ip  asm("r8");
  register long buf asm("r9");
  register long op  asm("r10");
  ...
fetch:
  asm("mov (%r8), %r9");
  asm("add $8, %r8");
control:
  asm("test %r9, %r9");
  asm("jz   fetch"); // undefined reference to `fetch'
  asm("shr  $4, %r9");
  asm("mov  %r9, %r10");
  asm("and  $0xf, %r10");
  switch (op) {
  ...
  }
  goto control;
4

2 回答 2

1

请注意 gcc 内联 asm 文档中的以下注释:

说到标签,不支持从一个“asm”跳转到另一个。编译器的优化器不知道这些跳转,因此他们在决定如何优化时无法考虑它们。

您也不能依赖在一个asm中设置的标志在下一个可用,因为编译器可能会在它们之间插入一些东西

使用 gcc 4.5 及更高版本,您可以asm goto用来做您想做的事:

fetch:
  asm("mov (%r8), %r9");
  asm("add $8, %r8");
control:
  asm goto("test %r9, %r9\n\t"
           "jz  %l[fetch]" : : : : fetch);

请注意,您的 asm 的所有其余部分都是完全不安全的,因为它直接使用寄存器而不在其读/写/破坏列表中声明它们,因此编译器可能会决定在其中放入其他内容(尽管 vars 上带有asm声明 -它可能会决定那些已经死了,因为它们从未被使用过)。因此,如果您希望这实际上可以与 -O1 或更高版本一起使用,则需要将其编写为:

  ...
  long ip;
  long buf;
  long op;
  ...
fetch:
  asm("mov (%1), %0" : "=r"(buf) : "r"(ip));
  asm("add $8, %0" : "=r"(ip) : "0"(ip));
control:
  asm goto("test %0, %0\n\t"
           "jz   %l[fetch]" : : "r"(buf) : : fetch);
  asm("shr  $4, %0" : "=r"(buf) : "0"(buf));
  asm("mov  %1, %0" : "=r"(op) : "r"(buf));
  asm("and  $0xf, %0" : "=r"(op) : "r"(op));

此时,将其编写为 C 代码要容易得多:

long *ip, buf, op;

fetch:
  do {
    buf = *op++;
control:
  } while (!buf);
  op = (buf >>= 4) & 0xf;
  switch(op) {
     :
  }  
  goto control;
于 2012-10-04T18:00:15.760 回答
0

你应该能够做到这一点:

fetch:
  asm("afetch: mov(%r8), %r9");
  ...
  asm("jz afetch");

或者,将标签单独放置asm("afetch:");也可以。请注意不同的名称以避免冲突 - 我不完全确定这是必要的,但我怀疑它是必要的。

于 2012-10-04T15:45:46.317 回答