我有一些简单的代码可以找到两个程序集标签之间的区别:
#include <stdio.h>
static void foo(void){
__asm__ __volatile__("_foo_start:");
printf("Hello, world.\n");
__asm__ __volatile__("_foo_end:");
}
int main(void){
extern const char foo_start[], foo_end[];
printf("foo_start: %p, foo_end: %p\n", foo_start, foo_end);
printf("Difference = 0x%tx.\n", foo_end - foo_start);
foo();
return 0;
}
现在,这段代码在64位处理器上完全 ,就像你期望的那样。但是,在32位处理器上,foo_start的地址与foo_end相同。
我确定它与32到64位有关。在i386上,它导致0x0,而x86_64导致0x7。在ARMv7(32位)上,它产生0x0,而在ARM64上,它产生0xC。 (64位结果是正确的,我用反汇编程序检查了它们)
我正在使用Clang + LLVM进行编译。
我想知道它是否与非惰性指针有关。在上面提到的两个32位处理器拱的汇编输出中,它们在最后有类似的东西:
L_foo_end$non_lazy_ptr:
.indirect_symbol _foo_end
.long 0
L_foo_start$non_lazy_ptr:
.indirect_symbol _foo_start
.long 0
但是,x86_64和ARM64的程序集输出中存在 not 。我昨天直接删除了非懒惰的指针并直接寻址标签,但无济于事。关于为什么会发生这种情况的任何想法?
编辑:
当为32位处理器编译时,foo_start []和foo_end []似乎指向 main 。我....我很困惑。
答案 0 :(得分:1)
我没有检查真实代码,但怀疑你是指令重新排序的受害者。只要你没有定义适当的内存障碍,编译器就可以自由地在函数中移动代码,因为标签和printf()调用之间没有相互依赖。
尝试将::: "memory"
添加到您的asm语句中,这些语句应该将它们钉在您编写它们的位置。
答案 1 :(得分:0)
我终于找到了解决方案(或者,替代方案,我想)。显然,&amp;&amp;运算符可用于获取C标签的地址,根本不需要我使用内联汇编。我不认为它符合C标准,但看起来Clang支持它,而且我也听说GCC也支持它。
#include <stdio.h>
int main(void){
foo_start:
printf("Hello, world.\n");
foo_end:
printf("Foo has ended.");
void* foo_start_ptr = &&foo_start;
void* foo_end_ptr = &&foo_end;
printf("foo_start: %p, foo_end: %p\n", foo_start_ptr, foo_end_ptr);
printf("Difference: 0x%tx\n", (long)foo_end_ptr - (long)foo_start_ptr);
return 0;
}
现在,这仅适用于标签属于同一功能的情况,但对于我打算使用它的情况,它是完美的。不再是ASM,它不会留下任何符号。它似乎工作正常我需要它。 (未在ARM64上测试)