文章

和gemini对话

以下是关于您在 C++ 软件开发中遇到的 DLL 依赖、Windows 架构及编译链接流程的所有问题及其详细解答。

💡 问题一:DLL 搜索路径的困惑与解析

❓ 用户问题

osgdb_daerd.dll 依赖 collada-dom2.4.dll。osgdb_daerd.dll 位于插件目录,exe 位于主目录。

  1. 为什么将 collada-dom2.4.dll 放在 osgdb_daerd.dll 的同级目录(插件目录)中没有用?
  2. 只有放在 exe 目录中才会正确加载?
  3. 我在链接时设置了 .lib 路径,为什么运行时不找这个路径下的 .dll

✅ 核心解答:DLL 运行时搜索顺序

这是因为 Windows 运行时 DLL 加载器严格遵循以 主 EXE 进程 为起点的搜索顺序,并不会默认查找 当前正在加载的 DLL 的同级目录

阶段文件类型查找路径设定影响对象
链接 (编译时).lib (导入库)链接器 $\to$ 附加库目录告诉链接器符号信息
运行 (运行时).dll (动态库)Windows DLL 搜索顺序告诉 OS 实际代码位置

链接时的 .lib 路径信息不会被写入到最终的 DLL 中,因此运行时查找的是 DLL 文件名,并从以下路径开始搜索:

  1. 进程可执行文件所在的目录 (您的 EXE 目录)
  2. 系统目录 (System32)
  3. Windows 目录 (C:\Windows)
  4. 当前工作目录 (CWD)
  5. PATH 环境变量中列出的目录

您的插件目录 不在此默认列表中


🔒 问题二:DLL 搜索安全机制与目录区分

❓ 用户问题

  1. DLL 劫持: 如果恶意 DLL 放在 EXE 目录,不是优先级更高吗?
  2. 系统目录: 为什么会去系统目录找?什么是系统目录?
  3. Windows 目录: Windows 目录是什么?与系统目录的区别?
  4. 目录区别: 当前工作目录 (CWD) 和进程可执行文件目录的区别?
  5. PATH 作用: PATH 环境变量在 DLL 查找中起什么作用?

✅ 详细解答

1. DLL 劫持与 EXE 目录

  • EXE 目录优先级高是事实,但 EXE 目录通常位于 Program Files 等受保护的目录,非管理员用户无法写入,安全门槛较高。
  • 插件目录 往往位于用户可写入的路径,是 DLL 劫持的常见目标。Windows 移除插件目录的默认搜索,主要是为了防止在用户可写目录中发生的恶意注入,增强系统安全。

2. 系统目录 (%SystemRoot%\System32)

  • 为什么查找: 为了实现 系统级共享兼容性,避免“DLL Hell”。
  • 什么是系统目录: 主要指 %SystemRoot%\System32,存放 Windows 核心系统 DLL 文件(如 kernel32.dll)。

3. Windows 目录 (%SystemRoot%)

特性系统目录 (System32)Windows 目录 (C:\Windows)
主要功能存放核心系统 DLL 和驱动文件。存放 Windows 的配置、日志、字体等文件。
DLL 优先级高于 Windows 目录。低于 系统目录。

4. CWD 与 EXE 目录的区别

目录类型进程可执行文件所在的目录当前工作目录 (CWD)
路径固定不变 (EXE 文件的物理位置)。可变 (取决于启动方式或 SetCurrentDirectory 函数)。
DLL 查找优先级 No.1优先级较低 (在系统目录之后)。

5. PATH 环境变量在 DLL 查找中的作用

  • PATH 是 DLL 查找顺序中 优先级最低 的搜索路径。
  • 作用: 如果 DLL 没有在固定路径(EXE 目录、系统目录、CWD)中找到,加载器会按顺序扫描 PATH 列表中的所有目录。

💻 问题三:架构、目录和编译流程

❓ 用户问题

  1. 64 位和 32 位有什么区别?
  2. 为什么 64 位 DLL 在 System32 目录里?
  3. 在 Windows 目录下怎么看到其他软件的名字?
  4. 编译、链接、运行的关系,以及 .lib, .dll, .exe 的联系?

✅ 详细解答

1. 64 位 (x64) 和 32 位 (x86) 的区别

区别方面64 位 (x64)32 位 (x86)开发者感知
内存限制理论巨大 (常见 128GB+)严格 (单个进程通常限制在 2GB 或 4GB)可以处理大规模数据集。
性能更高 (更多寄存器,高级指令集)较低优化性能,使用 SSE2/AVX 等指令集。
兼容性可通过 WoW64 运行 32 位程序。无法运行 64 位程序。必须为目标平台编译对应版本。

2. 64 位 DLL 在 System32 的原因

这是一个 历史路径兼容性 问题。

  • 64 位 操作系统中:
    • C:\Windows\System32 目录中存放的是 64 位 的核心系统 DLL 文件。
    • C:\Windows\SysWOW64 目录中存放的是 32 位 的系统 DLL 文件(用于支持 32 位程序)。

3. 软件文件位置

软件的安装文件通常位于 Program Files 目录下,而不是 C:\Windows 目录下:

  • 64 位软件: %ProgramFiles%
  • 32 位软件: %ProgramFiles(x86)%

4. 编译、链接、运行的关系及文件联系

阶段作用输入文件输出文件文件关系
编译将源代码翻译成机器码。.cpp, .h.obj 
链接解决符号引用,合并代码。.obj, .lib (导入库/静态库).exe.dll.lib 告诉链接器外部代码的位置,将信息写入到 .exe.dll 的导入表。
运行OS 加载 .exe,加载器处理依赖。.exe, .dll内存中的进程.exe.dll 运行时需要找到 .dll 文件来提供实际的执行代码。

总结: 您的链接依赖于 .lib 文件(编译阶段),而您的运行时依赖于 .dll 文件(运行阶段)。两者是不同的文件,遵循不同的路径查找规则。

本文由作者按照 CC BY 4.0 进行授权