将Linux C/C++应用程序从x86平台移植到IBM PowerLinux(2)
- UID
- 1029342
- 性别
- 男
|
将Linux C/C++应用程序从x86平台移植到IBM PowerLinux(2)
理解 x86 与 Power Architecture 衍生产品之间的差异
在将 x86 Linux 应用程序移植到 Power Systems 之前,您应该知道一些特定于架构的差异。在接下来的两节中,我们将详细介绍一些特别值得注意的架构差异:
- 字节顺序
- 32 位和 64 位应用程序环境中的数据类型长度
- 架构中的数据对齐方式差异
我们稍后将会介绍对比 x86 和 Power 应用程序时的一些额外的考虑因素。优化考虑因素示例包括使用多个线程优化吞吐量,评估简单锁定模式的使用,等等。
字节顺序
尽管 POWER 处理器可同时支持高位优先和低位优先(字节排序模式),但最新的实现都使用一种高位优先架构,而 x86 处理器使用了一种低位优先架构。本节介绍字节顺序问题,以及处理它们的技术。在将低级 应用程序、设备驱动程序或数据文件从 x86 架构移植到 Power Architecture 期间,开发人员通常会遇到一些字节排序问题。高级 应用程序在移植时很少遇到字节顺序问题,但在从 x86 移植到 Power 时需要解决此问题。
字节排序会影响整数和浮点数据,但不会影响字符串,因为它们会保持编程人员看到和想要的字符串顺序。所以,原始 ASCII 文本文件可正常使用,但与机器独立的数据文件可能受到硬件字节顺序问题的影响。例如,JPEG 文件被存储为高位优先格式,而 GIF 和 BMP 文件被存储为低位优先格式。
高位优先和低位优先
字节顺序指数据元素和它的各个字节在内存中存储和寻址的方式。在多位数中,具有更高数量级的位被视为更重要的位。例如,在 4 位数 8472 中,4 比 7 更重要。类似地,在多字节数字数据中,字节持有的值越大,它就越重要。例如,十六进制值 0x89ABCDEF 可拆分为 4 个字节:0x89、0xAB、0xCD 和 0xEF,分别具有算术值 0x89000000、0xAB0000、0xCD00 和 0xEF。显然,字节 0x89 是最大的值;因此它是最重要的字节,而字节 0xEF 是最小的部分,因此是最不重要的字节。
将一个数字放在内存中时,从最低的地址开始,只有两个有意义的选项:
- 首先放置最不重要的字节(低位优先)。
- 首先放置最重要的字节(高位优先)。
下图显示了高位优先和低位优先处理器如何将 32 位十六进制值(比如 0x89ABCDEF)放入内存中:
图 1. 存储十六进制值的高位优先和低位优先处理器
0x89 是最重要的字节,而 0xEF 是最不重要的字节。在高位优先系统上,最重要的字节放在最低的内存地址上。在低位优先系统上,最不重要的字节放在最低的内存地址上。
如果程序将一个单词写入内存中,然后读取相同位置作为一个单词,那么字节排序不存在问题,因为在采用一致的方式引用某个变量时,看到的会是同一个值。如果程序尝试一次读取同一个值的一个字节(在写入一个单词时),根据处理器采用低位优先还是高位优先格式,它可能获得不同的结果。
IBM POWER 处理器系列是使用高位优先数据布局的系统示例,而 x86 处理器系列是使用低位优先数据布局的系统示例。识别依赖于字节顺序的代码段,并将它们转换为等效的高位优先格式,这在将 x86 应用程序迁移到 Power 平台期间很重要。
处理字节顺序
本节将介绍如何识别代码中依赖于字节顺序的区域,并将它们转换为正确的字节顺序格式的方法。
依赖于字节顺序的代码
数据引用上的非一致性是 C 语言的优势,这使得它在编程系统级软件(包括操作系统和设备驱动程序)中变得很流行。此优势包括类型转换、指针操作、union、位字段、结构和灵活的类型检查。但是,同样是这些特性,它们也可能是字节顺序可移植性问题的来源。作为示例,请考虑以下两个代码清单:
清单 1. 使用指针的非一致数据引用
#include <stdio.h>int main(void) { int val; unsigned char *ptr; ptr = (char*) &val; val = 0x89ABCDEF; /* four bytes constant */ printf("%X.%X.%X.%X\n", ptr[0], ptr[1], ptr[2], ptr[3]); exit(0);} 清单 2. 使用 union 的非一致数据引用
#include <stdio.h>union { int val; unsigned char c[sizeof(int)];} u;int main(void) { u.val = 0x89ABCDEF; /* four bytes constant */ printf("%X.%X.%X.%X\n", u.c[0], u.c[1], u.c[2], u.c[3]); exit(0);} 在 x86 系统上,结果为:
EF.CD.AB.89 在基于 POWER 处理器的系统上,结果为:
89.AB.CD.EF 字节顺序问题表现为 val,它从最重要的字节开始逐个字节地读取数据。
如何确定系统的字节顺序
在 Linux 中,GNU_C 预处理器通常会自动提供一组常用的预定义宏,它们的名称以双下划线开始和结束。一组对确定使用的系统的字节顺序最有用的宏是 __BYTE_ORDER__、__ORDER_LITTLE_ENDIAN__ 和 __ORDER_BIG_ENDIAN__。
/* Test for a big-endian machine */#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__/* Do big endian processing */ 编写字节顺序中立的代码
如果程序模块在跨具有不同字节顺序的平台移植时能够保留其功能,那么它就是字节顺序中立的。换句话说,它的功能与运行它的平台的字节顺序无关。以下是一些编写字节顺序中立的代码的建议:
- 使用宏和指令
要让代码变得可移植,可以使用宏和条件编译指令,如清单 3 和清单 4 所示。
|
|
|
|
|
|