Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 同一对象模块中的过程调用是否需要在链接阶段重新定位_C_Linux_Compilation_Linker_Gnu - Fatal编程技术网

C 同一对象模块中的过程调用是否需要在链接阶段重新定位

C 同一对象模块中的过程调用是否需要在链接阶段重新定位,c,linux,compilation,linker,gnu,C,Linux,Compilation,Linker,Gnu,我假设同一对象模块中的过程调用在链接阶段不需要重新定位。e、 g.以下代码 void callee() { printf("Should I be relocated\n"); } void caller() { callee(); } 编译/组装之后,我得到了以下信息 Relocation section '.rel.text' at offset 0x438 contains 3 entries: Offset Info Type Sym

我假设同一对象模块中的过程调用在链接阶段不需要重新定位。e、 g.以下代码

void callee()
{
    printf("Should I be relocated\n");
}
void caller()
{
    callee();
}
编译/组装之后,我得到了以下信息

Relocation section '.rel.text' at offset 0x438 contains 3 entries:
Offset     Info    Type            Sym.Value  Sym. Name
00000009  00000501 R_386_32          00000000   .rodata
0000000e  00000a02 R_386_PC32        00000000   puts
0000001b  00000902 R_386_PC32        00000000   callee
以及拆卸的结果:

Disassembly of section .text:

00000000 <callee>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 18                sub    $0x18,%esp
   6:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
   d:   e8 fc ff ff ff          call   e <callee+0xe>
  12:   c9                      leave  
  13:   c3                      ret    

00000014 <caller>:
  14:   55                      push   %ebp
  15:   89 e5                   mov    %esp,%ebp
  17:   83 ec 08                sub    $0x8,%esp
  1a:   e8 fc ff ff ff          call   1b <caller+0x7>
  1f:   c9                      leave  
  20:   c3                      ret  
节的反汇编。文本:
00000000 :
0:55推力%ebp
1:89 e5 mov%esp,%ebp
3:83 ec 18子$0x18,%esp
6:c7 04 24 00动产$0x0,(%esp)
d:e8 fc ff呼叫e
12:c9离开
13:c3 ret
00000014 :
14:55%推压ebp
15:89 e5 mov%esp,%ebp
17:83 ec 08子$0x8,%esp
1a:e8 fc ff呼叫1b
1f:c9离开
20:c3 ret

为什么同一对象模块中的过程调用(1a:e8 fc ff调用1b)需要重新定位?这取决于我的工具链吗?在同一对象模块内调用过程时,PC相对地址(调用者和被调用者之间的地址偏移)是否有机会更改?如果不是,为什么不将0x1a处的代码修复为“e8 e1 ff ff”

重新定位表必须存储在每个模块内部,对于该实际模块,以允许在加载时重新定位共享LIB

由于(大多数)Unix发行版中的动态链接器可以覆盖共享库中的函数,这意味着即使调用发生在单个模块内,也可以重新定位该函数。像这样的工具受益于这些仪器和泄漏检测功能


因此,如注释中所述,如果您将函数标记为static,那么编译器可以完全跳过这一部分,并对跳转进行硬编码。

您的函数是全局可见的,并且可以从任何其他编译单元调用。因此,编译器创建的代码允许从模块之外的任何地方调用函数。编译器不知道您将只从
调用者中调用它。您可以尝试将函数
设置为静态
,然后再次检查代码。如果被调用方是从其他对象模块调用的,编译器只需在该模块中为被调用方创建一个重新定位项。在我最初的问题中,对被叫方的呼叫来自同一个模块,如果从被叫方到被叫方的PC相对地址不变,则根本不需要重新定位。您是对的,如果被调用方在我的原始代码中被定义为静态的,那么被调用方的重新定位条目将被删除。但问题仍然在于最初的情况,编译器可能使用一种方法调用静态函数,另一种方法调用公共函数。如果这两种方法足够的话,它为什么要发明第三种方法呢?重新定位表存储在每个模块中,用于实际的模块。否则,共享LIB的加载时间重新定位是不可能的。根据架构的不同,在模块内和跨模块进行的函数调用可能还需要不同的方式返回调用方。由于您的函数不限于您的模块,因此它必须能够像跨函数调用一样返回。因此,也必须像从另一个模块调用一样调用它。调用者函数必须使用重定位表中的地址,而不是PC相关操作。是的,该函数可以重定位。在我的示例中,可以重新定位被调用方。但是搬迁发生在这个区域,不是一个单一的功能,对吗?这将保持被调用方和调用方之间的偏移量不变。在我的具体示例中,如果偏移量保持不变,我想不出有必要将调用重新定位到被调用方。