gpt4 book ai didi

linux - Linux ldd 中的 "statically linked"和 "not a dynamic executable"有什么区别?

转载 作者:行者123 更新时间:2023-12-02 09:37:52 25 4
gpt4 key购买 nike

考虑这个 AMD64 汇编程序:

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

如果我用 gcc -nostdlib 编译它并运行 ldd a.out ,我明白了:
        statically linked

如果我改为使用 gcc -static -nostdlib 编译它并运行 ldd a.out ,我明白了:
        not a dynamic executable
statically linked有什么区别和 not a dynamic executable ?如果我的二进制文件已经静态链接,为什么还要添加 -static影响什么?

最佳答案

这里有两件事:

  • 是否请求 ELF 解释器 (ld.so)。
    #!/bin/sh但对于二进制文件,在您的 _start 之前运行.
    这是静态与动态可执行文件之间的区别。
  • 用于加载 ld.so 的动态链接库列表恰好是空的。
    这显然是什么ldd调用“静态链接”,即您可能在构建时链接的任何库都是静态库。

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

    您的 GCC 是 configured so -pie is the default ,并且 gcc 不会为没有动态库的特殊情况制作静态饼图。
  • gcc -nostdlib只是制作一个碰巧不链接到任何库但与普通 PIE 相同的 PIE,指定一个 ELF 解释器。
    ldd令人困惑地称之为“静态链接”。 file :ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2 ...
  • gcc -nostdlib -static覆盖 -pie默认并生成真正的静态可执行文件。file :ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked ...
  • gcc -nostdlib -no-pie还选择制作静态可执行文件作为根本没有动态库的情况的优化。由于无论如何都无法对非 PIE 可执行文件进行 ASLRed,因此这是有道理的。逐字节与 -static 相同案件。
  • gcc -nostdlib -static-pie 制作一个不需要 ELF 解释器的 ASLRable 可执行文件。默认情况下,GCC 不会为 gcc -pie -nostdlib 执行此操作,不像它选择回避的无馅饼情况ld.so当不涉及动态链接库时。file :ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), statically linked ...-static-pie晦涩、很少使用且较旧 file不会将其识别为静态链接。
  • -nostdlib并不意味着 -no-pie-static , 和 -static-pie必须明确指定才能得到它。
    gcc -static-pie调用 ld -static -pie ,所以 ld必须知道这意味着什么。与非 PIE 情况不同,您不必明确要求动态可执行文件,如果您通过 ld 就可以得到一个。任何 .so图书馆。我认为这就是为什么您碰巧从 gcc -nostdlib -no-pie 获得了一个静态可执行文件的原因。 - GCC 不需要做任何特别的事情,它只是 ld做那个优化。

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

    细节

    使用 gcc --version 生成的示例gcc (Arch Linux 9.3.0-1) 9.3.0 ld --version GNU ld (GNU Binutils) 2.34(readelf 也是 binutils) ldd --version ldd (GNU libc) 2.31 file --version file-5.38 - 请注意静态饼图检测在最近的补丁中发生了变化,Ubuntu 挑选了一个未发布的补丁。 (感谢@Joseph 的侦探工作)- this in 2019检测到动态 = 有一个 PT_INTERP 来处理静态饼图,但它是 reverted基于 PT_DYNAMIC 进行检测,因此共享库计为 dynamic . debian bug #948269 . static-pie是一个晦涩的很少使用的功能。

    GCC 最终运行 ld -pie exit.o指定了动态链接器路径 ,并且没有图书馆。 (还有一大堆其他选项来支持可能的 LTO 链接时间优化,但这里的关键是 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -piecollect2 只是 ld 的包装器。)
    $ 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

    您将获得一个不依赖于其他库的动态 PIE。运行它仍然会调用“ELF 解释器” /lib64/ld-linux-x86-64.so.2在它跳到你之前运行的 _start . (尽管内核已经将可执行文件的 ELF 段映射到 ASLRed 虚拟地址,以及 ld.so 的 text/data/bss)。
    file和 readelf 更具描述性。

    来自 gcc -nostdlib 的 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 +++

    对比 -static-static-pie在用户空间中执行的第一条指令是您的 _start (您也可以使用 starti 与 GDB 核对)。
    $ strace ./exit-static-pie 
    execve("./exit-static-pie", ["./exit-static-pie"], 0x7ffcdac96dd0 /* 51 vars */) = 0
    exit(0) = ?
    +++ exited with 0 +++
    gcc -nostdlib -static-pie
    $ 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 留给内核。

    令人惊讶的是,ldd并不是说它不是动态可执行文件。 这可能是一个错误,或者是某些实现细节的副作用。
    gcc -nostdlib -static传统的非 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
    ...

    这些都是程序头;与馅饼/静态馅饼不同,我不会遗漏任何内容,只是阅读的其他整个部分 -a输出。

    还要注意程序头中的绝对虚拟地址,这些地址不会让内核选择在虚拟地址空间中映射文件的位置。这是 ELF 对象的 EXEC 和 DYN 类型之间的区别。 PIE 可执行文件是具有入口点的共享对象,允许我们获取主可执行文件的 ASLR。实际的 EXEC 可执行文件具有链接时选择的内存布局。
    ldd显然只有在以下两种情况下才报告“不是动态可执行文件”:
  • 无 ELF 解释器(动态链接器)路径
  • ELF 类型 = EXEC
  • 关于linux - Linux ldd 中的 "statically linked"和 "not a dynamic executable"有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61553723/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com