繁体   English   中英

汇编标签地址在32位处理器上不正确

[英]Assembly label address incorrect on 32-bit processors

我有一些简单的代码可以找到两个程序集标签之间的区别:

#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

然而,这是存在于64位x86和ARM64的组件的输出。 我迷上了删除非惰性指针并在昨天直接处理标签的方法,但无济于事。 关于发生这种情况的任何想法?

编辑:

似乎为32位处理器编译时,foo_start []和foo_end []指向main 我...。我很困惑。

我没有检查真实代码,但怀疑您是指令重新排序的受害者。 只要您没有定义适当的内存屏障,编译器就可以自由地在函数内移动代码,因为标签和printf()调用之间没有相互依赖关系。

尝试在您的asm语句中添加::: "memory" ,这应该将它们钉在您编写它们的位置。

我终于找到了解决方案(或者,我想是替代方案)。 显然,&&运算符可用于获取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测试)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM