谁确定“#:abs_g3:main”的值

时间:2018-11-04 11:53:58

标签: assembly linker glibc arm64

我遇到了一个奇怪的错误,并试图理解。特别是,至少,我想确定我应该研究的软件:链接器,glibc,汇编器,编译器或其他。

我确实知道减少测试用例至关重要。但是,对无法这样做感到抱歉。它不会在x86中复制。它可以在arm64和特定的Linux发行版上重现,但我不确定是否对公众开放。我对测试用例本身还不够了解,无法简化测试用例。

可执行文件在__libc_start_main处出现分段错误。在那里的原因是控件试图跳转到有效保存在寄存器x0中的地址,该地址奇怪地为0。x0在_start函数中设置。

// in sysdep/aarch64/start.S of glibc
MOVL (0, main)

MOVL宏似乎在同一目录的sysdep.h中定义如下:

# define MOVL(R, NAME)                                  \
    movz    PTR_REG (R), #:abs_g3:NAME;             \
    movk    PTR_REG (R), #:abs_g2_nc:NAME;          \
    movk    PTR_REG (R), #:abs_g1_nc:NAME;          \
    movk    PTR_REG (R), #:abs_g0_nc:NAME;

因此,我猜#:abs_g0_nc:main和朋友应该是一些非零值,但定义为0。

所以,我的问题是应该归咎于哪个部分。可执行文件来自Go源代码。 Go工具无需外部链接程序的帮助即可构建共享库。然后,Go工具会编译Go源代码,并将其链接到Go共享库以及其他带有外部链接器的库,以及带有gcc链接器的gcc。

我确实在start.S中看到了_start与最终的可执行文件类似。只是#:abs_g *事情消失了。谁用数值(在这种情况下为0)替换宏(?)?

gcc或编译器是否已经预先编译_start并将已编译/汇编的二进制文件放在/ usr / lib {64}之类的地方?或者,当链接程序完全链接时,链接程序是否将宏替换为某个数值?如果在通过链接构建有问题的可执行文件时链接器这样做,则链接器依赖于什么来计算#:abs_g0_nc和朋友的值?

1 个答案:

答案 0 :(得分:2)

哪个组件发生故障?主程序还是共享对象?

sysdep/aarch64/start.S不应链接到动态共享库中,因为它是主要可执行文件启动代码的一部分。大多数程序没有main的动态符号,因此即使使用了正确的重定位,绑定也会失败。 (#:abs_gX重定位与共享对象所需的位置无关代码不兼容。)

如果主程序失败,则可能是许多问题。您的问题中确实没有足够的信息来提供坚定的建议。我的猜测是某种PIE /非PIE不匹配,导致选择了错误版本的启动代码。请注意,start.S在glibc构建过程中以不同的预处理器标志进行了多次组装,并链接到crt1.o(非PIE / ET_EXEC可执行文件),Scrt1.o(PIE)中。 / ET_DYN可执行文件)和gcrt1.o(分析)。