64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.
这种变化的后果是必须重新编译旧库并破坏传统汇编代码.
现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?
我有一堆在没有该-fPIC选项的情况下编译的目标文件。因此对函数的调用不使用@PLT. (源代码是 C 语言并用 编译clang)。
我想将这些对象文件链接到一个共享库中,我可以使用dlopen. .so我需要这样做,因为在加载实际内容之前我必须进行大量设置。
但每次我尝试链接该-shared选项时,都会收到错误 -
创建共享库时不能使用
R_X86_64_PC32针对符号的重定位;splay_tree_lookup重新编译-fPIC
我从源代码重新编译没有任何问题。但我不想使用-fPIC. 这是我们正在开发自定义编译器的研究项目的一部分。PIC 不适用于我们试图在编译器中提供的保证类型。
是否有一些我可以使用的标志,ld以便它生成加载时重定位库。事实上,我没有搬家,也没什么问题。我可以为库提供基地址,dlopen如果虚拟地址不可用,则可能会失败。
我用来编译c文件的命令相当于 -
clang -m64 -c foo.c
Run Code Online (Sandbox Code Playgroud)
为了链接我正在使用
clang -m64 -shared *.o -o foo.so
Run Code Online (Sandbox Code Playgroud)
我说等效是因为它是一个自定义编译器(forked off clang)并且有一些额外的步骤。但它是等价的。