为什么在同一节中引用全局函数的函数只能在 link 时解决,而局部函数将在编译时解决?

Why function that refers to a global function in the same section can only be solved at link time while local functions will be solve at compile time?

我有这个汇编文件 prog.S :

    .text
#------------------------------main----------------------------------
    .globl main
    .type main,@function
main:
pushl %ebp
movl %esp, %ebp
call myGlobalFunction   # call to my global func
call myLocalFunction    # call to my local func 
popl %ebp
ret
.Lmain_end:
    .size main, .Lmain_end-main
#-------------------------myGlobalFunction---------------------------
    .globl myGlobalFunction
    .type myGlobalFunction,@function
myGlobalFunction:
pushl %ebp
movl %esp, %ebp
movl , %eax           # return 1
popl %ebp
ret
.LmyGlobalFunction_end:
    .size myGlobalFunction, .LmyGlobalFunction_end-myGlobalFunction
#-------------------------myLocalFunction---------------------------
    .type myLocalFunction,@function
myLocalFunction:
pushl %ebp
movl %esp, %ebp
movl , %eax           #return 2
popl %ebp
ret
.LmyLocalFunction:
    .size myLocalFunction, .LmyLocalFunction-myLocalFunction

这三个函数位于同一个 .text 部分,main 调用全局函数,然后调用局部函数。

当我用 clang 编译这个文件时:

clang.exe -target i386-none prog.S -o prog.o -c

这是我得到的部分:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .strtab           STRTAB          00000000 0000a0 000041 00      0   0  1
  [ 2] .text             PROGBITS        00000000 000034 000023 00  AX  0   0  4
  [ 3] .rel.text         REL             00000000 000098 000008 08   I  4   2  4
  [ 4] .symtab           SYMTAB          00000000 000058 000040 10      1   2  4

重定位节 '.rel.text' :

Relocation section '.rel.text' at offset 0x98 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
00000004  00000302 R_386_PC32        0000000f   myGlobalFunction

符号table:

Symbol table '.symtab' contains 4 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000019    10 FUNC    LOCAL  DEFAULT    2 myLocalFunction
     2: 00000000    15 FUNC    GLOBAL DEFAULT    2 main
     3: 0000000f    10 FUNC    GLOBAL DEFAULT    2 myGlobalFunction

和 .text 部分反汇编代码

00000000 <main>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <main+0x4>
   8:   e8 0c 00 00 00          call   19 <myLocalFunction>
   d:   5d                      pop    %ebp
   e:   c3                      ret

0000000f <myGlobalFunction>:
   f:   55                      push   %ebp
  10:   89 e5                   mov    %esp,%ebp
  12:   b8 01 00 00 00          mov    [=16=]x1,%eax
  17:   5d                      pop    %ebp
  18:   c3                      ret

00000019 <myLocalFunction>:
  19:   55                      push   %ebp
  1a:   89 e5                   mov    %esp,%ebp
  1c:   b8 02 00 00 00          mov    [=16=]x2,%eax
  21:   5d                      pop    %ebp
  22:   c3                      ret

从反汇编代码可以看出局部函数已经解决了PC相对调用,但是全局函数在链接过程中还没有解决..

我不明白的是为什么汇编程序无法解决与主函数在同一部分的全局函数调用(因此,据我了解,将始终位于与 main 相同的相对位置,因为它们位于同一部分)。

显然,如果 'main' 和 'myGlobalFunction' 不在同一节中,则汇编器无法解决 PC 相对调用,因为链接器可以将不同的节放在 'where it want'(或者我们想要的链接描述文件)。

编辑:有类似的 question 但没有正确的答案

汇编程序可以解决jumping/callingmyGlobalFunction在asm-time的同一部分中定义,有时它会这样做,如[=22= 】 调查。 但是,由于该函数被声明为 global,因此假定它也可以从其他部分获得。

汇编程序认为文件 prog.o 中的 .text 部分可能在 link 时对其他程序静态 link 可用。你是对的,在这种情况下 other.omyGlobalFunction 声明为 external,搬迁记录应该生成到 other.o,搬迁 [=16] =] 在 prog.o 中是多余的。也许 clang.exe 假设符号 myGlobalFunction 可能是 并且它可以在 link 时用 [=] 中定义的同名全局符号替换19=],也 link 与 other.oprog.o

同一节中全局函数的调用可以在编译时解决。我的猜测是 Clang 将此延迟到 link 时间并生成 RIP 相对重定位,以便将来能够从其他模块替换目标函数。