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位绝对地址?
考虑 x64 Intel 程序集中的以下变量引用,其中变量a在.data节中声明:
mov eax, dword ptr [rip + _a]
Run Code Online (Sandbox Code Playgroud)
我很难理解这个变量引用是如何工作的。既然a是对应于变量运行时地址的符号(带重定位),如何[rip + _a]解引用正确的内存位置a?事实上,rip保存当前指令的地址,它是一个大的正整数,所以加法会导致错误的地址a?
相反,如果我使用 x86 语法(非常直观):
mov eax, dword ptr [_a]
Run Code Online (Sandbox Code Playgroud)
,我收到以下错误:64 位模式不支持 32 位绝对寻址。
有什么解释吗?
1 int a = 5;
2
3 int main() {
4 int b = a;
5 return b;
6 }
Run Code Online (Sandbox Code Playgroud)
编译gcc -S -masm=intel abs_ref.c -o abs_ref::
1 .section __TEXT,__text,regular,pure_instructions
2 .build_version macos, 10, 14
3 …Run Code Online (Sandbox Code Playgroud) 我正在尝试在ASM中创建一个共享库(*.so),我不确定我是否正确...
我的代码是:
.section .data
.globl var1
var1:
.quad 0x012345
.section .text
.globl func1
func1:
xor %rax, %rax
# mov var1, %rcx # this is commented
ret
Run Code Online (Sandbox Code Playgroud)
要编译它我运行
gcc ker.s -g -fPIC -m64 -o ker.o
gcc ker.o -shared -fPIC -m64 -o libker.so
Run Code Online (Sandbox Code Playgroud)
我可以访问变量var1并使用dlopen()和dlsym()从C中的程序调用func1.
问题在于变量var1.当我尝试从func1访问它时,即取消注释该行,编译器会生成错误:
/usr/bin/ld: ker.o: relocation R_X86_64_32S against `var1' can not be used when making a shared object; recompile with -fPIC
ker.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
我不明白.我已经用-fPIC编译了,那有什么不对?
考虑以下简单的共享库源代码:
library.cpp:
static int global = 10;
int foo()
{
return global;
}
Run Code Online (Sandbox Code Playgroud)
用-fPICclang中的option 编译,它会导致以下对象汇编(x86-64):
foo(): # @foo()
push rbp
mov rbp, rsp
mov eax, dword ptr [rip + global]
pop rbp
ret
global:
.long 10 # 0xa
Run Code Online (Sandbox Code Playgroud)
由于符号是在库中定义的,因此编译器按预期使用PC相对地址: mov eax, dword ptr [rip + global]
但是,如果我们更改static int global = 10;为int global = 10;具有外部链接的符号,则结果汇编为:
foo(): # @foo()
push rbp
mov rbp, rsp
mov rax, qword ptr [rip + global@GOTPCREL]
mov eax, dword ptr [rax] …Run Code Online (Sandbox Code Playgroud) assembly ×3
x86-64 ×3
gcc ×2
c++ ×1
got ×1
intel-syntax ×1
linker ×1
linux ×1
relocation ×1
symbols ×1