我在C++中使用gcc-4.7在64位小endian Ubuntu12.04LTS和Eclipse和gdb上使用内联程序集。我所要做的工作的总体方向是为一些深奥的基于堆栈的编程语言制作某种字节码解释器。
在本例中,我一次处理指令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;发布于 2012-10-04 18:00:15
请注意gcc内联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-04 15:45:46
你应该能够做到这一点:
fetch:
asm("afetch: mov(%r8), %r9");
...
asm("jz afetch");或者,将标签放在单独的asm("afetch:");中也应该有效。注意避免冲突的不同名称-我不完全确定这是必要的,但我怀疑它是必要的。
https://stackoverflow.com/questions/12730468
复制相似问题