我正在使用带有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;
答案 0 :(得分: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都是完全不安全的,因为它直接使用寄存器而不在其读/写/破坏列表中声明它们,因此编译器可能决定在其中添加其他内容(尽管有{{{ 1}}对它们的声明 - 它可能决定那些已经死亡,因为它们从未被使用过)。因此,如果您希望实际使用-O1或更高版本,则需要将其写为:
asm
此时,将其编写为C代码更容易:
...
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));
答案 1 :(得分:0)
你应该可以这样做:
fetch:
asm("afetch: mov(%r8), %r9");
...
asm("jz afetch");
或者,将标签放在单独的asm("afetch:");
中也应该有效。注意不同的名称以避免冲突 - 我不完全确定这是必要的,但我怀疑它是。