http://www.ibm.com/developerworks/cn/linux/l-pow-inteltopwr/index.html
关于作者:Calvin Sze 是 IBM eServer Solutions Enablement 组织的一名 Linux 顾问。他在得克萨斯州的奥斯汀市工作。Calvin 的主要职责是帮助解决方案开发人员将他们的应用程序引入 Linux on POWER。Calvin 致力于 Linux 和 AIX 平台上的软件开发和系统集成已经 10 多年了。您可以通过 calvins@us.ibm.com 与 Calvin 联系。
32 位环境和 64 位环境中数据类型的长度
Linux 操作系统上的 GCC 和 XL C/C++ 编译器都提供两种不同的编程模型:ILP32 和 LP64。ILP32 代表 integer/long/pointer 32,这是 Linux 上的 32 位编程环境。ILP32 数据模型提供了 32 位的地址空间,其理论内存上限是 4 GB。LP64 代表 long/pointer 64,这是 Linux 上的 64 位编程环境。表 1 给出了在 POWER 和 x86 平台中 ILP32 和 LP64 模型中基本数据类型的宽度。
表 1. POWER 和 x86 平台中 ILP32 和 LP64 模型中基本数据类型的宽度(位数)
POWER | x86 | |||
ILP32 | ILP64 | ILP32 | ILP64 | |
char | 8 | 8 | 8 | 8 |
short | 16 | 16 | 16 | 16 |
int | 32 | 32 | 32 | 32 |
float | 32 | 32 | 32 | 32 |
long | 32 | 64 | 32 | 64 |
long long | 64 | 64 | 64 | 64 |
double | 64 | 64 | 64 | 64 |
long double | 64/128* | 64/128* | 96 | 128 |
pointer | 32 | 64 | 32 | 64 |
* 在 Linux on POWER 中,long double 缺省为 64 位。如果您使用 XL C/C++ 编译器的 -qlongdouble
选项,可以将其设置为 128 位的。
所有有关数字类型的定义在 POWER 和 x86 平台上都可以在 /usr/include/limits.h 中找到。
现在大部分 x86 平台上的 Linux 应用程序都是以 32 位模式运行的。然而,随着 x86 64 位扩展的出现(x86-64),越来越多的程序将会直接编写为 64 位的。在将 x86 应用程序移植到 POWER 平台上时,您应该使用与源环境匹配的 Linux POWER 环境。换言之,在迁移到 POWER 平台上的过程中,要避免从一个 32 位编程模型迁移到 64 位的编程模型,因为这种尝试并不是单纯的移植,而是一次开发任务。如果您将一个 32 位的 x86 应用程序移植到 64 位 POWER 编程模型中,那么可以将这次迁移分为两个步骤:
- 移植到 Linux on POWER 的 32 位环境中(包括测试和验证)。
- 迁移到 64 位环境中。
这就是说,如果一个程序可以满足以下条件,就应该被移植到 64 位环境中:
- 可以利用超过 4 GB 的虚拟地址空间。
- 可以利用更多的物理内存(超过 4 GB),如果用户希望将其部署到一个具有多于 4 GB 物理内存的系统上。
- 可以利用 64 位的 long integer 类型。
- 可以利用全部的 64 位寄存器实现更有效的 64 位数学计算。
- 使用大于 2 GB 的文件。
可以从迁移到 64 位程序中获益的一些程序包括:
- 数据库应用程序,尤其是那些进行数据挖掘的程序
- Web 缓存和 Web 搜索引擎
- CAD/CAE 模拟和建模工具的组件
- 科学计算程序,例如流体力学、遗传仿真
一个程序可以保持是 32 位的,但仍然可以在 64 位的 Linux on POWER 内核上运行,而不需要修改代码。IBM 基于 POWER 处理器的服务器上的 Linux 可以支持在 64 位体系结构上同时运行 32 位和 64 位的应用程序,而不会造成这两种模式的性能降低,这是因为 64 位的 POWER 体系结构中包含了对本地 32 位模式的完全支持。
在不同的平台(从 x86 到 POWER)或编程模式(从 ILP32 到 LP64)之间移植程序时,您应该考虑不同环境中数据宽度和对齐设置的不同,这样才能防止出现可能的性能降低或数据崩溃的问题。
在从 x86 ILP32 移植到 POWER ILP32 上或从 x86 LP64 移植到 POWER LP64 上时,注意在 表 1 中,所有的基本数据类型的宽度都是相同的,long double 例外,对于 64/128 位的 IPL32 来说,它是 96 位;而对于 64/128 位的 LP64 来说,它是 128 位。这意味着您应该尽可能地检查以下代码中与 long double 数据类型有关的地方。如果您计划要使用 XL C/C++ 编译器,请使用-qlongdouble
编译标记来保证 long double 数据类型具有最好的可移植性。
数据对齐
在不同的平台或 32 位和 64 位模式之间移植程序时,要考虑不同环境中对齐设置的不同,从而避免出现可能的性能降低和数据崩溃的问题。最好的实践方法是确保数据都是自然对齐的。自然对齐的意思是说将数据项存储在是其大小的整数倍的地址处(例如,8 字节的数据的地址就应该是 8 的整数倍)。对于 XL C/C++ 编译器来说,聚集类型(C/C++ 结构/联合和 C++ 类)中的每种数据类型都会根据 linuxppc 或位填充规则按照字节边界进行对齐,其中 linuxppc 是缺省值,它是自然对齐的。linuxppc 也是与缺省的 GCC 对齐规则兼容的。表 2 显式了 POWER 和 x86 上的对齐值,以及它们的数据类型的宽度(以字节为单位)。
表 2. POWER 和 x86 上的对齐值(以字节为单位)
POWER | x86 | |||||||
ILP32 | ILP64 | ILP32 | ILP64 | |||||
宽度 | 对齐 | 宽度 | 对齐 | 宽度 | 对齐 | 宽度 | 对齐 | |
char | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
short | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
int | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
float | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
long | 4 | 4 | 8 | 8 | 4 | 4 | 8 | 8 |
long long | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 |
double | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 |
long double | 8/16 | 8 | 8/16 | 8 | 12 | 4 | 16 | 16 |
pointer | 4 | 4 | 8 | 8 | 4 | 4 | 8 | 8 |
GCC 和 XL C/C++ 中的关键字 __alignof__
让您可以了解一个对象是如何对齐的。它的语法与sizeof
类似。例如,如果目标及其要求一个 double 类型的值按照 8 字节边界进行对齐,那么__alignof__
(double) 就是 8。
正如在 表 2 中介绍的一样,long double 类型的变量在 x86 平台上是按照 4 个字节进行对齐的,而在 POWER 平台上则是按照 8 个字节进行对齐的。因此,在不同的平台上,这种结构就有不同的布局。不要将大小和偏移量都在编码中写死了,这一点非常重要。相反,使用 C 语言中的sizeof
操作可以查询基本类型和复杂类型的大小。宏 offsetof
是一个变量,它可以获取结构程序从该结构开始地址处的偏移量。