【发布时间】:2019-12-27 16:03:36
【问题描述】:
我在汇编中有一段书面代码,在某些地方,我想跳转到C 中的标签。所以我有以下代码(缩短版本,但我仍然有同样的问题):
#include <stdio.h>
#define JE asm volatile("jmp end");
int main(){
printf("hi\n");
JE
printf("Invisible\n");
end:
printf("Visible\n");
return 0;
}
这段代码可以编译,但是反汇编版本的代码中没有end标签。
如果我将标签名称从 end 更改为任何其他名称(比如说 l1,在 asm 代码 (jmp l1) 和 C 代码中),编译器会这样说
main.c:(.text+0x6b): undefined reference to `l1'
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'main' failed
make: *** [main] Error 1
我尝试了不同的东西(不同的长度、不同的大小写、上、下等),我认为它只能用end 标签编译。使用end 标签,我收到分段错误,因为反汇编版本中没有end 标签。
编译: gcc -O0 main.c -o main
反汇编代码:
000000000000063a <main>:
63a: 55 push %rbp
63b: 48 89 e5 mov %rsp,%rbp
63e: 48 8d 3d af 00 00 00 lea 0xaf(%rip),%rdi # 6f4 <_IO_stdin_used+0x4>
645: e8 c6 fe ff ff callq 510 <puts@plt>
64a: e9 c9 09 20 00 jmpq 201018 <_end> # there is no _end label!
64f: 48 8d 3d a1 00 00 00 lea 0xa1(%rip),%rdi # 6f7 <_IO_stdin_used+0x7>
656: e8 b5 fe ff ff callq 510 <puts@plt>
65b: 48 8d 3d 9f 00 00 00 lea 0x9f(%rip),%rdi # 701 <_IO_stdin_used+0x11>
662: e8 a9 fe ff ff callq 510 <puts@plt>
667: b8 00 00 00 00 mov $0x0,%eax
66c: 5d pop %rbp
66d: c3 retq
66e: 66 90 xchg %ax,%ax
所以,问题是:
- 我做错了吗?我见过这种跳跃(从 汇编为 C) 的代码。我可以提供示例链接。
- 为什么编译器/链接器找不到
l1,但可以找到end?
【问题讨论】:
-
编译器会在某些符号前添加下划线。所以 C 中的标签
end将是汇编器中的标签_end。 -
这就是
asm goto的用途。 GCC Inline Assembly: Jump to label outside block -
@PaulOgilvie:不仅仅是
_end。它可能类似于_main.end,或者更可能只是一个常见的自动编号标签,例如.L123: -
它没有;内联 asm 引用的
end标签位于.data部分中,并且恰好由编译器或链接器定义以标记该部分的结尾。asm volatile("je end")与该函数中的 C 标签无关。我注释掉了其他函数中的一些代码,让它在没有“cacheutils.h”头文件的情况下编译,但这并不影响oop()函数的那部分;见godbolt.org/z/jabYu3 -
@kyurt7 可能适用于禁用优化的一些玩具实验,但它是未定义的行为,并且可能仅通过启用优化而中断。
标签: c gcc x86 inline-assembly goto