Linux ldd 中的“静态链接”和“不是动态可执行文件”有什么区别?

2023-11-27

考虑这个 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 and not a dynamic executable?如果我的二进制文件已经静态链接,为什么添加-static影响什么?


这里有两件事:

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

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


您的海湾合作委员会是如此配置-pie是默认值,并且 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 case.
  • 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 or -static, and -static-pie必须明确指定才能得到它。

gcc -static-pie调用ld -static -pie, so ld必须知道那意味着什么。与非 PIE 情况不同,在非 PIE 情况下,您不必显式请求动态可执行文件,如果通过,您只需得到一个ld any .so图书馆。我认为这就是为什么你碰巧从gcc -nostdlib -no-pie- GCC 不需要做任何特别的事情,只是ld做那个优化。

But ld不启用-static隐式地当-pie已指定,即使没有要链接的共享库。


Details

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

GCC 最终运行ld -pie exit.o指定了动态链接器路径,并且没有库。 (还有大量其他选项来支持可能的 LTO 链接时间优化,但这里的关键是-dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie. collect2只是一个包装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 段以及 ld.so 的 text / data / bss 映射到 ASLRed 虚拟地址)。

file和 readelf 更具描述性。

PIE 非静态可执行文件gcc -nostdlib

$ 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 +++

vs. -static and -static-pie在用户空间中执行的第一条指令是您的_start(您也可以使用 GDB 检查starti).

$ 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 
   ...

这些是所有的程序头;与pie / static-pie不同,我不会遗漏任何内容,只是readelf的其他整个部分-a output.

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


ldd显然,只有在以下情况下才报告“不是动态可执行文件”:

  • 没有 ELF 解释器(动态链接器)路径
  • ELF 类型 = EXEC
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux ldd 中的“静态链接”和“不是动态可执行文件”有什么区别? 的相关文章

随机推荐

  • Rabbitmq Consumer_Timeout 行为未按预期工作?

    我很难证明consumer timeout设置正在按预期工作 我可能做错了或者误解了consumer timeout行为 我所有的测试代码都可以在这里找到 https github com Rafarel rabbitmq tests 基本
  • instance_eval 的块参数 - 已记录?目的?

    刚刚意识到instance eval yields self作为关联块的参数 1 9 2 版本中的错误除外 http www ruby forum com topic 189422 1 9 3p194 003 gt class C end
  • 如何从 LINQ to XML 中的 XElement 读取特定元素值

    我有一个XElement其中有这样的内容
  • HTML:如何创建“另存为”按钮?

    在浏览器中 当您想要保存当前正在查看的 HTML 页面时 通常会转到 文件 菜单并单击 另存为 我可以在 HTML 页面底部添加一个具有相同功能的小按钮吗 因此 我希望我的用户能够单击按钮将页面保存到磁盘上 而不是转到 文件 菜单 gt 另
  • EF Core 2.0 Identity - 添加导航属性

    在 EF Core 2 0 中 默认情况下不包含 Identity 导航属性 因此在升级后 我添加了它们 因此 对于用户和角色之间的多对多关系以及角色和 RoleClaim 之间的一对多关系 我添加了以下导航属性 public class
  • 如何扩展Spring注解@Transactional

    我必须在我的网络应用程序中使用 3 个不同的事务管理器 所以我根据以下内容编写了自己的注释弹簧参考 第 10 5 6 3 节自定义快捷方式注释 一个注释 用于使用一个特定的事务管理器 如下所示 import java lang annota
  • 使用 PHP 删除文件夹中的所有文件?

    例如 我有一个名为 Temp 的文件夹 我想使用 PHP 删除或刷新该文件夹中的所有文件 我可以这样做吗 files glob path to temp get all file names foreach files as file it
  • Numpy 融合乘法和加法以避免浪费内存

    是否可以将两个 ndarray A 和 B 相乘并将结果添加到 C 而无需为 A 乘以 B 创建一个大型中间数组 Numpy 对于 C A 乘 B 的情况有 out 关键字参数 numpy multiply A B out C C A 乘以
  • SQL Server SORT 顺序与 ASCII 代码顺序不对应

    我正在使用 SQL Server 2012 并且我有一个数据库SQL Latin1 General CP1 CI AS整理 create table testtable c nvarchar 1 null insert into testt
  • 通过 USB 安装应用程序 [安装被用户取消]

    我可以通过 USB 将应用程序安装到我的 Android 设备上 但是 当 Android 上显示允许 拒绝安装弹出窗口时 我错误地单击了 拒绝 并选中了 记住我的选择 现在 每次尝试通过 USB ADB 安装应用程序都失败并出现错误com
  • UrlHelper.GenerateUrl 的 ASP.NET MVC 公共替代方案

    我想在我的页面中嵌入一个指向控制器操作的链接 以便我可以从 javascript 使用它 就像是 var pollAction Mycontroller CheckStatus 现在我很高兴对其进行硬编码 但如果有一种可以用来创建 URL
  • python中的快速寻峰和质心

    我正在尝试用 python 开发一种快速算法 用于查找图像中的峰值 然后找到这些峰值的质心 我使用 scipy ndimage label 和 ndimage find objects 编写了以下代码来定位对象 这似乎是代码中的瓶颈 在 5
  • Pojo 到 xsd 生成

    是否有一个库可以从 java 类生成 xsd 模式 Google 产生了很多相反的结果 来自 xsd 的 java 类 JAXB 2 0 允许您从带注释的 Java 类创建 XML 模式 您可以在以下位置找到一些示例AMIS 博客并在Jav
  • 如何在 iOS 推送通知上增加徽章

    我目前正在从有效负载中获取徽章 但我怎样才能更新这个值 aps alert Notification Hub test notification2 badge 1 sound Default 当我发送此消息时 徽章编号中始终显示 1 但是当
  • 批处理参数 %~s1 给出了错误的 8.3 短名称

    我正在尝试在 Windows XP 中编写一个批处理文件 该文件接受完全限定的路径名 并输出 8 3 短名称版本 echo off echo s1 我遇到过一种特殊情况 它输出不正确的路径和文件 C gt test bat C Docume
  • Angular-ui + D3:如何实现上下文菜单(弹出框与模式)?

    给出以下用例 我使用 D3js 来渲染由 AngularJS 管理的对象 我想为 D3 图表添加交互性 当单击 svg 元素时 我希望有一种弹出菜单 允许修改对象属性 这些属性是 AngularJS 所必需的 但 D3 不会呈现 D3 An
  • sys.path 与 $PATH

    我想从 python 程序内部访问 PATH 变量 到目前为止我的理解是 sys path 给出了 Python 模块搜索路径 但我想要的是 PATH 环境变量 有没有办法从Python内部访问它 为了提供更多背景知识 我最终想做的是找出用
  • 为什么“using”作用域可以在 Start-Job 本地工作,但不能与 Invoke-Command 一起工作?

    为什么 PowerShell 不允许使用using使用时范围Invoke Command本地 根据文档 the using修饰符只能用于远程命令 去引用 从 PowerShell 3 0 开始 您可以使用Using范围修饰符来标识远程命令中
  • 使用 rmongodb 在 R 中运行高级 MongoDB 查询

    由于 MySQL 让我抓狂 我试图让自己熟悉我的第一个 NoSQL DBMS 而它恰好是MongoDB 我通过以下方式连接到它rmongodb 我玩得越多rmongodb 关于运行高级查询的疑问 问题就越多 首先 我先展示一些示例数据 然后
  • Linux ldd 中的“静态链接”和“不是动态可执行文件”有什么区别?

    考虑这个 AMD64 汇编程序 globl start start xorl edi edi movl 60 eax syscall 如果我编译它gcc nostdlib并运行ldd a out 我明白了 statically linked