【问题标题】:From Object Code To executable从目标代码到可执行文件
【发布时间】:2014-03-09 18:14:30
【问题描述】:

我想知道当我们使用链接器获取目标代码的可执行版本时会发生什么。

我认为链接器作业对于 Linux 和窗口都不相同,我在 Linux 上。

【问题讨论】:

    标签: assembly compiler-construction linker


    【解决方案1】:

    对象代码缺少有关全局的信息。它包含函数的可执行代码,但所有对其他外部函数以及全局数据的引用都不能成为实际指令的一部分,因为它们的地址是未知的。因此,所有这些引用都留空(例如,在目标代码中只填充零字节)并用 符号名称 进行注释。

    链接器的工作是查看所有丢失的符号名称并将它们与所有导出的名称(即目标文件提供的函数和全局数据)进行匹配,然后为每个数据找到一个永久位置,最后重写所有将零字节替换为最终存储数据(函数和全局变量)的实际地址的代码。


    例如,考虑这段 C 代码:

    extern int a;
    extern int bar(int);     // "extern" is redundant here
    static int zip(int);
    
    int foo(int x, int y)
    {
        return 2 * x + 3 * y + zip(x - y) + a * bar(x + y);
    }
    
    int zip(int n)
    {
        return 2 * (n + 1) - (n - 1) / 2;
    }
    

    此代码导出一个符号foo,它提供给在此翻译单元中链接的任何人。它还缺少两个符号,abar。在实现foo 的代码中,对abar 的引用留空,只有在链接器知道这些实际数据所在的位置时才能由链接器填写。

    这是 GCC 使用 -O3 为 x86 生成的机器代码:

    0000000000000000 <foo>:
       0:   89 f9                   mov    ecx,edi
       2:   8d 04 76                lea    eax,[rsi+rsi*2]
       5:   53                      push   rbx
       6:   29 f1                   sub    ecx,esi
       8:   8d 51 ff                lea    edx,[rcx-0x1]
       b:   8d 1c 78                lea    ebx,[rax+rdi*2]
       e:   01 f7                   add    edi,esi
      10:   89 d0                   mov    eax,edx
      12:   c1 e8 1f                shr    eax,0x1f
      15:   01 c2                   add    edx,eax
      17:   d1 fa                   sar    edx,1
      19:   f7 da                   neg    edx
      1b:   8d 44 4a 02             lea    eax,[rdx+rcx*2+0x2]
      1f:   01 c3                   add    ebx,eax
      21:   e8 00 00 00 00          call   26 <foo+0x26>
      22:                                  R_X86_64_PC32       bar-0x4
      26:   0f af 05 00 00 00 00    imul   eax,DWORD PTR [rip+0x0]        # 2d <foo+0x2d>
      29:                                  R_X86_64_PC32       a-0x4
      2d:   01 d8                   add    eax,ebx
      2f:   5b                      pop    rbx
      30:   c3                      ret    
    

    注意字节 22 和 29:操作数保留为零,但有一个注释告诉链接器要填充的符号名称。

    【讨论】:

      【解决方案2】:

      此外,Kerrek 的回答是:链接器的工作在某种程度上取决于操作系统。例如,处理外部引用(来自 .so 或 .dll 文件)的方式取决于操作系统,不同段(数据、代码等)在文件中的放置方式也可能取决于操作系统。

      可执行文件的标头(也由链接器生成)是特定于操作系统的,它定义了文件的类型以及在哪里可以找到不同的段。 Linux 中的可执行文件以“ELF”标头开头,在 Windows 中以“MZ”标头开头(这些是可以在文件开头找到的标识字符)。

      【讨论】:

        【解决方案3】:

        我认为 Linux 和 Windows 的链接器作业并不相同

        只是对 Kerrek SB 的回答的一些补充:

        链接器在所有操作系统上的工作方式都相同。只有对象文件和二进制文件的文件格式不同。

        【讨论】:

        • 是的,总的来说... PMF 很好地说明了库的共享对象和加载时加载(与链接时加载相反),不同的平台提供不同的机制。例如,在 Linux 上,链接器为共享库设置过程链接表 (PLT) 和蹦床函数......许多细节:-)
        • @Kerrek,我在哪里可以找到有关所有这些的文档
        猜你喜欢
        • 1970-01-01
        • 2023-03-24
        • 2016-04-28
        • 2012-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多