64 位库可以在 32 位应用程序中工作吗?例如,我的应用程序 GUI 使用 32 位 Qt。而我的业务核心是一个 64 位的库。操作系统是 64 位的。他们可以一起工作吗?如何工作?谢谢。
4 回答
简而言之:您不能将 32 位应用程序链接到 64 位库。
您可以在 64 位操作系统(至少所有流行的 32/64 位处理器,如 AMD、Intel 和 Sparc)上使用 32 位共享库来运行 32 位应用程序。但这不涉及任何库。
更长的答案:我参与了一些为 x86 设计 64 位 Linux 内核的团队(在郊区)。有简短的(与整个项目相比,讨论持续了好几个小时)关于如何在技术上完成这项工作的一些讨论。对此的简短总结是,在 64 位中有一些寄存器在 32 位中不可用。还有内存地址和寄存器中额外的 32 位的问题。假设库本身“知道”它是一个 32 位兼容库,所有这些都可以解决。但是我们基本上有一个 64 位库,它被写成一个 32 位库,我们有点迷失了方向。
“更多寄存器”可能不适用于某些处理器,但更大的寄存器地址/位范围肯定适用于所有 32 位和 64 位兼容处理器。而且我不知道有任何单个处理器允许 32 位代码调用 64 位共享库或静态库。除非专门编写代码来解决这个问题,否则它是行不通的,这违背了拥有通用 64 位库来支持 32 位应用程序的目的。
编辑:
以上讨论了链接一个可执行单元,例如可执行文件、共享库或静态库。那必须是所有“一位”,无论是 32 还是 64 - 没有混合。
当一个进程与另一个进程通信时(例如,一个显示非 GUI 进程状态的 GUI 应用程序),只要两个进程使用相同的协议 [通常,IPC 无论如何都不允许传递指针,所以32-/64 位转换不是一个大问题],您可以拥有一个 32 位进程和另一个 64 位进程。
是的,但这是一个大麻烦。
首先,内核不同于库。通常,库在进程的虚拟地址空间中可见;它与您自己的代码共享地址空间。调用库例程只是一个子例程调用。
相反,要向内核请求服务,您的进程会执行一条特殊指令来生成陷阱。这个陷阱会导致处理器做一些特殊的事情,包括将进程的寄存器和其他状态保存在内存中(或在您通常无法访问的特殊处理器寄存器中),更改处理器中的各种模式以使其适合内核,以及更改程序计数器以指向内核的指令。然后内核运行。此时,内核可能在 64 位模式下运行,而您的进程在 32 位模式下运行。但是,内核被设计为意识到这些差异。当您的内核检查您的进程以查看您的请求时,它会查找知道您的进程在 32 位模式下运行的信息和数据结构。
当然,这假定您使用的 64 位内核支持 32 位进程。
通常,当您调用一个库时,您希望它与您的代码具有相同的模式,因为正常的库调用只是一个子程序调用;它不会产生陷阱,也不会改变处理器模式。如果迫切需要从 32 位进程调用 64 位库中的例程,那么您可以创建一个帮助程序 64 位进程。您的 32 位进程将打包一个库调用请求,并通过某种形式的进程间通信将该请求发送到 64 位助手进程。该辅助进程将调用库例程并将结果发回。
自然,这会为每个库调用增加大量开销,因此只有在非常需要且没有更好的选择时才需要这样做。
我正在开发一个可以做到这一点的应用程序。应用程序核心是 x64(并使用 Qt),但它必须与一些设备通信,为此我只有制造商的 32 位库。我实现它的方式是有两个应用程序 64 位用于核心和 GUI,32 位控制设备并使用 QSharedMemory 与主要应用程序通信。这两个应用程序都基于 Qt(对应 64 位和 32 位)。
如果您在 Windows 上运行,那么为 32b 编译的应用程序可以在 Windows 64b 主机系统上运行:看看64b Windows 中内置的WOW64子系统。
话虽如此,您不能将为 32b 编译的代码与为 64b 编译的代码混合使用。这意味着为 32b 构建的库不能与 64b 代码链接,反之亦然。(不同的调用约定,堆栈框架布局,展开除外,...)