相关疑难解决方法(0)

x86-64 Linux中不再允许32位绝对地址?

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位绝对地址?

linux gcc x86-64 linker-errors relocation

21
推荐指数
1
解决办法
5787
查看次数

x86-64 GAS Intel 语法中像“[RIP + _a]”这样的 RIP 相关变量引用如何工作?

考虑 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)

assembly x86-64 gnu-assembler intel-syntax addressing-mode

14
推荐指数
1
解决办法
2893
查看次数

x86-64汇编语言中的ELF共享对象

我正在尝试在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编译了,那有什么不对?

assembly linker gcc x86-64 shared-libraries

7
推荐指数
2
解决办法
4765
查看次数

为什么要将全局偏移表用于共享库本身中定义的符号?

考虑以下简单的共享库源代码:

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)

c++ assembly symbols dynamic-linking got

5
推荐指数
1
解决办法
377
查看次数