32位应用程序和64位库能够一起工作吗?

21
64位库能在32位应用程序中工作吗?例如,我的应用程序GUI使用32位Qt。而我的业务核心是一个64位库。操作系统是64位的。它们能够一起工作吗?如何实现?

你的内核是32/64位内核。你的内核不是一个库。 - MSalters
2
为什么你们都会立刻想到Linux和操作系统内核呢?通过“内核”,他可能指的是他自己的库,这是他应用程序中的一种核心类型(是的,这确实是一种不太规范的称呼方式,但有些人确实这样做)。为了组合起来,他有一个32位应用程序,其中只包含GUI和一个单独的64位库,其中包含一些逻辑。 - Alexander Shukaev
那么,在这个上下文中,“kernel”究竟是什么意思呢?是你的应用程序正在使用的库,还是操作系统内核,或者其他什么东西? - Mats Petersson
@Mats Petersson:这是实现他应用程序的业务逻辑的核心库,即GUI和业务逻辑分为两个部分。因此,我猜这一切都归结于正确的链接,而在不同寻址的情况下这是不可能的。 - Alexander Shukaev
这是应用程序核心,包括执行商业领域特定任务的关键功能。例如,用于信号处理的FFT函数。 - user1899020
显示剩余3条评论
4个回答

23
简而言之:你不能将32位的应用程序链接到64位的库中。
你可以在64位操作系统上运行32位应用程序,使用32位共享库(至少对于所有流行的32/64位处理器,如AMD、Intel和Sparc)。但是这并不涉及任何库。
更详细的答案是:我曾经参与(在边缘)设计x86 64位Linux内核的一些团队。关于如何在技术上使这项工作发生,有一些短暂的讨论(与整个项目相比,这些讨论持续了相当长的时间)。这个问题的简要总结是,在64位中有一些在32位中不可用的寄存器。还存在内存地址和寄存器中额外32位的问题。只要库本身“知道”它是一个32位兼容库,所有这些问题都可以得到解决。但是,那么我们基本上就有了一个被编写成32位库的64位库,并且我们失去了重点。
“更多寄存器”可能不适用于某些处理器,但是寄存器的更大地址/位范围绝对适用于所有32位和64位兼容处理器。我不知道是否有任何单个处理器允许32位代码调用64位共享库或静态库。除非代码专门编写以处理此问题,否则它根本行不通,这有悖于具有支持32位应用程序的通用64位库的目的。
编辑:
以上讨论链接一个可执行单元(例如可执行文件、共享库或静态库)。它必须是全部“一位性”,要么是32位的,要么是64位的 - 不能混合使用。
当一个进程与另一个进程通信时(例如一个GUI应用程序显示来自非GUI进程的状态),只要两个进程使用相同的协议[通常,IPC不允许传递指针,因此32位/64位转换并不是一个大问题],您可以有一个进程是32位的,另一个进程是64位的。

Amiga系统上存在一些混合二进制代码执行的情况,可以运行包含68k和PPC代码的fat二进制文件。当执行从一个CPU切换到另一个CPU时,存根被链接以执行上下文切换。但是,如果我没记错的话,两者都在32位模式下运行。 - Jens
“简而言之,不是这样的。”这是错误的。在64位Windows上运行的所有32位程序最终都会利用64位服务,因为它们正在64位操作系统中运行。为了弥合与64位库之间的差距,您可以使用任何数量的技术,包括COM。 - Cheers and hth. - Alf
2
@Alf:COM是RPC。通过RPC,您可以弥合32位和57位之间的差距。这并不特别。就库而言,64位Windows仍然使用其库(DLL)的32位版本在WoW子系统中提供,这正是因为您不能在单个进程中混合位数。 - MSalters
1
我已经编辑了我的答案以澄清我回答的内容,似乎问题并不完全清楚,我读到了一件事,而 Alf 读到了另一件事。 - Mats Petersson
原问题混淆了库和内核。添加RPC只会使事情更加复杂。它们在交互方面都有不同的规则。 - MSalters

7
是的,但这是一个很大的麻烦。
首先,内核(kernel)与库(library)不同。通常,库在你的进程虚拟地址空间中可见;它与你自己的代码共享地址空间。调用库程序只是一个子例程调用。
相比之下,要从内核请求服务,你的进程需要执行特殊指令来生成一个陷阱(trap)。这个陷阱会导致处理器执行一些特殊操作,包括将你的进程寄存器和其他状态保存在内存中(或在你通常无法访问的特殊处理器寄存器中),改变处理器中的各种模式,使它们适合于内核,并将程序计数器改变为指向内核的指令。然后内核正在运行。此时,内核可能在64位模式下运行,而你的进程在32位模式下运行。但是,内核被设计为了解这些区别。当内核检查你的进程以查看你的请求时,它会查找信息和数据结构,知道你的进程是在32位模式下运行的。内核可以支持32位和64位进程,它只是会分别处理每种类型的进程。
当然,这假定你使用的64位内核支持32位进程。
通常,当你调用库时,你希望它与你的代码处于相同的模式,因为普通库调用只是一个子例程调用;它不会生成陷阱,并且不会改变处理器模式。如果有必要从32位进程中调用64位库中的例程,那么你可以创建一个帮助器64位进程。你的32位进程会将库调用请求打包并通过某种形式的进程间通信发送到64位帮助器进程。该帮助器进程将调用库例程并将结果发送回来。
当然,这会给每个库调用增加重大开销,因此只有在没有更好的选择且非常需要时才应这样做。

+1 我会点赞的,即使内核调用的描述过于具体(这是典型的情况,但绝不是唯一可能的情况)。 - Cheers and hth. - Alf

2
我正在开发一个可以实现此功能的应用程序。应用程序的核心是x64(使用Qt),但必须与某些设备通信,该设备只提供了来自制造商的32位库。我实现的方法是有两个应用程序,64位用于核心和GUI,32位用于控制设备并使用QSharedMemory与主应用程序通信。两个应用程序都基于Qt(分别为64位和32位)。

1
如果你使用的是Windows系统,那么编译为32位的应用程序可以在Windows 64位主机上运行:看一下内置在64位Windows中的WOW64子系统。
话虽如此,你不能混合编译为32位和64位的代码。这意味着一个编译为32位的库无法与64位代码链接,反之亦然(不同的调用约定、堆栈帧布局、异常展开等)。

是的,但那不是链接到库,而是一个系统调用接口,它从32位代码调用系统调用进入64位内核。那是完全不同的问题。(在上面添加第二段之前写的,解释了我的观点) - Mats Petersson
@MatsPetersson:OP并不需要“链接到库”,也没有要求以无法工作的方式完成任务X;相反,OP要求提供可行的方法。 - Cheers and hth. - Alf
“64位库可以在32位应用程序中运行吗?”是什么意思? - Mats Petersson
@dunno MatsPetersson:不知道,但是,提示一下,为什么不继续阅读OP的第二句话,他在那里提供了一个例子来澄清呢? - Cheers and hth. - Alf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接