代码之家  ›  专栏  ›  技术社区  ›  Joseph Sible-Reinstate Monica

“静态链接”和“非动态可执行文件”有什么区别?

  •  0
  • Joseph Sible-Reinstate Monica  · 技术社区  · 5 年前

    .globl _start
    _start:
        xorl %edi, %edi
        movl $60, %eax
        syscall
    

    gcc -nostdlib 然后跑 ldd a.out

            statically linked
    

    如果我用 gcc -static -nostdlib ,我明白了:

            not a dynamic executable
    

    有什么区别 statically linked not a dynamic executable ? 如果我的二进制文件已经静态链接,为什么要添加 -static 有什么影响吗?

    0 回复  |  直到 5 年前
        1
  •  8
  •   Peter Cordes    5 年前

    这里有两件事:

    • 请求ELF解释程序(路易斯安那州)或者不。
      #!/bin/sh 但对于二进制文件,在 _start .
      这是静态和动态的区别 .
    • 的动态链接库列表路易斯安那州加载碰巧是空的。
      ldd 调用“静态链接”,即在构建时链接的任何库都是静态库。

    其他工具,如 file readelf 提供更多信息并使用符合您期望的术语。


    configured so -pie is the default ,并且gcc不会为没有动态库的特殊情况创建静态饼图。

    • gcc -nostdlib 只需创建一个饼图,该饼图碰巧没有链接到任何库,但在其他方面与普通饼图相同,并指定一个ELF解释器。
      令人困惑地称之为“静态连接”。
      文件 : ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2 ...
    • gcc -nostdlib -static -派
      文件 : ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked ...
    • gcc -nostdlib -no-pie -static
    • gcc -nostdlib -static-pie 生成一个不需要ELF解释器的ASLRable可执行文件。GCC在默认情况下不会为 gcc -pie -nostdlib ,与它选择回避的无馅饼情况不同 ld.so 当不涉及动态链接库时。
      文件 : ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), statically linked ...

      -static-pie 晦涩难懂,很少使用,而且更老 文件 不会将其标识为静态链接。

    -nostdlib -no-pie -静态的 ,和 必须显式指定才能获取。

    gcc -static-pie 调用 ld -static -pie ,所以 ld 必须知道那意味着什么。与不需要显式请求动态可执行文件的非PIE情况不同,只要通过 ld 任何 .so 图书馆。我想这就是为什么你碰巧从 gcc-nostdlib-无馅饼 -海合会不需要做什么特别的事,只是 进行优化。

    但是 ld 不启用 隐式当 -派 指定,即使没有要链接的共享库。


    细节

    生成的示例 gcc --version
    ld --version GNU ld(GNU Binutils)2.34(同时readelf is Binutils)
    ldd --version
    file --version 文件-5.38-注意,最近的补丁中静态派检测已经改变,Ubuntu cherry选择了一个未发布的补丁。(感谢@Joseph的侦探工作)- this in 2019 检测到动态=有一个PT_INTERP来处理静态pie,但是 reverted 基于PT_DYNAMIC的检测,因此共享库计数为 dynamic debian bug #948269 . static-pie 是一个模糊的很少使用的功能。

    ld -pie exit.o 指定了动态链接器路径 ,没有库。(还有很多其他选项来支持可能的LTO链路时间优化,但这里的关键是 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie . collect2 只是个包装 .)

    $ gcc -nostdlib exit.s -v      # output manually line wrapped with \ for readability
    ...
    COLLECT_GCC_OPTIONS='-nostdlib' '-v' '-mtune=generic' '-march=x86-64'
     /usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/collect2  \
    -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/liblto_plugin.so \
    -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/lto-wrapper \
    -plugin-opt=-fresolution=/tmp/ccoNx1IR.res \
    --build-id --eh-frame-hdr --hash-style=gnu \
    -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie \
    -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0 \
    -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/../../../../lib -L/lib/../lib \
    -L/usr/lib/../lib \
    -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/../../.. \
    /tmp/cctm2fSS.o
    

    /lib64/ld-linux-x86-64.so.2 在跳到你的 _开始 . (尽管内核已经将可执行文件的ELF段映射到ASLRed虚拟地址,以及路易斯安那州的文本/数据/bss)。

    文件

    PIE非静态可执行文件来自 海湾合作委员会-诺斯特利布

    $ gcc -nostdlib exit.s -o exit-default
    $ ls -l exit-default 
    -rwxr-xr-x 1 peter peter 13536 May  2 02:15 exit-default 
    $ ldd exit-default 
            statically linked
    $ file exit-default
    exit-default: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05a4d1bdbc94d6f91cca1c9c26314e1aa227a3a5, not stripped
    
    $ readelf -a exit-default
    ...
      Type:                              DYN (Shared object file)
      Machine:                           Advanced Micro Devices X86-64
      Version:                           0x1
      Entry point address:               0x1000
    ...
    Program Headers:
      Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
      PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                     0x00000000000001f8 0x00000000000001f8  R      0x8
      INTERP         0x0000000000000238 0x0000000000000238 0x0000000000000238
                     0x000000000000001c 0x000000000000001c  R      0x1
          [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
      LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                     0x00000000000002b1 0x00000000000002b1  R      0x1000
      LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                     0x0000000000000009 0x0000000000000009  R E    0x1000
      ...   (the Read+Exec segment to be mapped at virt addr 0x1000 is where your text section was linked.)
    

    $ gcc -nostdlib exit.s -o exit-default
    $ strace ./exit-default
    execve("./exit-default", ["./exit-default"], 0x7ffe1f526040 /* 51 vars */) = 0
    brk(NULL)                               = 0x5617eb1e4000
    arch_prctl(0x3001 /* ARCH_??? */, 0x7ffcea703380) = -1 EINVAL (Invalid argument)
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9ff5b3e000
    arch_prctl(ARCH_SET_FS, 0x7f9ff5b3ea80) = 0
    mprotect(0x5617eabac000, 4096, PROT_READ) = 0
    exit(0)                                 = ?
    +++ exited with 0 +++
    

    与。 -静态的 在用户空间中执行的第一条指令是 _开始 (您也可以使用 starti

    $ strace ./exit-static-pie 
    execve("./exit-static-pie", ["./exit-static-pie"], 0x7ffcdac96dd0 /* 51 vars */) = 0
    exit(0)                                 = ?
    +++ exited with 0 +++
    

    gcc-nostdlib-静态派

    $ gcc -nostdlib -static-pie exit.s -o exit-static-pie
    $ ls -l exit-static-pie
    -rwxr-xr-x 1 peter peter 13440 May  2 02:18 exit-static-pie
    peter@volta:/tmp$ ldd exit-static-pie
            statically linked
    peter@volta:/tmp$ file exit-static-pie
    exit-static-pie: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=daeb4a8f11bec1bb1aaa13cd48d24b5795af638e, not stripped
    
    $ readelf -a exit-static-pie 
    ...
      Type:                              DYN (Shared object file)
      Machine:                           Advanced Micro Devices X86-64
      Version:                           0x1
      Entry point address:               0x1000
    ...
    
    Program Headers:
      Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
      LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                     0x0000000000000229 0x0000000000000229  R      0x1000
      LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                     0x0000000000000009 0x0000000000000009  R E    0x1000
      ... (no Interp header, but still a read+exec text segment)
    

    请注意,这些地址仍然是相对于映像库的,而ASLR则由内核决定。

    令人惊讶的是, 并不是说它不是一个动态的可执行文件。 这可能是一个bug,或者是一些实现细节的副作用。


    gcc-nostdlib-静态 传统的非PIE旧式静态可执行文件

    $ gcc -nostdlib -static exit.s -o exit-static
    $ ls -l exit-static
    -rwxr-xr-x 1 peter peter 4744 May  2 02:26 exit-static
    peter@volta:/tmp$ ldd exit-static
            not a dynamic executable
    peter@volta:/tmp$ file exit-static
    exit-static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=1b03e3d05709b7288fe3006b4696fd0c11fb1cb2, not stripped
    peter@volta:/tmp$ readelf -a exit-static
    ELF Header:
    ...
      Type:                              EXEC (Executable file)
      Machine:                           Advanced Micro Devices X86-64
      Version:                           0x1
      Entry point address:               0x401000
    ...   (Note the absolute entry-point address nailed down at link time)
          (And that the ELF type is EXEC, not DYN)
    
    Program Headers:
      Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
      LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                     0x000000000000010c 0x000000000000010c  R      0x1000
      LOAD           0x0000000000001000 0x0000000000401000 0x0000000000401000
                     0x0000000000000009 0x0000000000000009  R E    0x1000
      NOTE           0x00000000000000e8 0x00000000004000e8 0x00000000004000e8
                     0x0000000000000024 0x0000000000000024  R      0x4
    
     Section to Segment mapping:
      Segment Sections...
       00     .note.gnu.build-id 
       01     .text 
       02     .note.gnu.build-id 
       ...
    

    这些都是程序头;与pie/static pie不同,我没有遗漏任何内容,只是readelf的其他部分 -a

    还要注意程序头中的绝对虚拟地址,这些地址不能让内核选择在虚拟地址空间中映射文件的位置。这就是ELF对象的EXEC和DYN类型之间的区别。PIE可执行文件是具有入口点的共享对象,允许我们获取主可执行文件的ASLR。实际的可执行文件有一个链接时间选择的内存布局。


    ldd公司

    • 没有ELF解释器(动态链接器)路径
    • ELF type=执行