首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

将Linux C/C++应用程序从x86平台移植到IBM PowerLinux(2)

将Linux C/C++应用程序从x86平台移植到IBM PowerLinux(2)

处理字节顺序
        本节将介绍如何识别代码中依赖于字节顺序的区域,并将它们转换为正确的字节顺序格式的方法。
        依赖于字节顺序的代码
        数据引用上的非一致性是 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 所示。
        清单 3. 使用指令让字节顺序效果中立化
#include <stdio.h>#define BIG_ENDIAN 1#define LITTLE_ENDIAN 0#define BYTE_ORDER (( htonl(1)==1) )   //  returns 1 or 0 depending on platformunion {  int val;  unsigned char c[sizeof(int)];}u;int main(void) {  u.val = 0x89ABCDEF;  #if (BYTE_ORDER == BIG_ENDIAN)  printf("%X.%X.%X.%X\n", u.c[0], u.c[1], u.c[2], u.c[3]);  #else /*!BYTE_ORDER == BIG_ENDIAN*/  printf("%X.%X.%X.%X\n", u.c[3], u.c[2], u.c[1], u.c[0]);  #endif /*BYTE_ORDER == BIG_ENDIAN*/  exit(0);}        清单 4. 使用宏交换字节(对在运行时确定字节顺序很有用)
//  Useful Endian Neutral Macros#include <endian.h>        #if __BYTE_ORDER == __BIG_ENDIAN// No translation needed for big endian system#define sw2Bytes(val) val#define sw4Bytes(val) val#define sw8Bytes(val) val#else//  Little Endian:Translate// Swap 2 byte, 16 bit values:#define sw2Bytes(val) \ ( (((val) >> 8) & 0x00FF) | (((val) << 8) & 0xFF00) )// Swap 4 byte, 32 bit values:#define sw4Bytes(val) \ ( (((val) >> 24) & 0x000000FF) | (((val) >>  8) & 0x0000FF00) | \   (((val) <<  8) & 0x00FF0000) | (((val) << 24) & 0xFF000000) )// Swap 8 byte, 64 bit values:#define sw8Bytes(val) \ ( (((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) | \   (((val) >> 24) & 0x0000000000FF0000) | (((val) >>  8) & 0x00000000FF000000) | \   (((val) <<  8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) | \   (((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000) )#endifint main(void) {  int a=0x11121314;  int b;  b = sw4Bytes(a);      // b is 0x12 in LE and BE}
  •                 使用编译时选项
                    实现此目的的另一种方式是在编译器命令行上将 BYTE_ORDER 的值定义为 -DBYTE_ORDER=BIG_ENDIAN。在一个具有不同字节顺序的新平台上编译时,这会消除编辑设备驱动程序或应用程序中的每个文件的需求。只需编译用于构建该驱动程序或应用程序的 makefile。
        字节顺序:特定于 Linux
        事实证明,Linux 内核提供了一组特定的系统宏,它们可以从低位优先到高位优先和从高位优先到低位优先执行 16、32 和 64 位交换。这些宏对从 Linux x86 移植到 Linux on Power 以及让您大代码对字节顺序中立都很方便,无需担忧会在代码中编写大量 #ifdef __LITTLE_ENDIAN 条件指令。
        例如:
        cpu_to_le16(u16); // converts CPU endianness 4 bytes to little-endian
        le16_to_cpu(u16); // converts little-endian 4 bytes to CPU endianness
        这两个宏将一个值从 CPU 使用的字节顺序转换为一种无符号、低位优先、32 位数字,或者执行反向转换。例如,在 Linux on Power 系统上,le16_to_cpu(u16) 将低位优先转换为高位优先,而 cpu_to_le16(u16) 将高位优先转换为低位优先。根据使用的宏和运行的是哪个系统,如果没有工作要做,那么它们将会返回原始值。
        这些宏和其他许多宏位于: /usr/include/linux/byteorder/big_endian.h> 和 /usr/include/linux/byteorder/little_endian.h 中。
        您可以查看这些头文件来找到您需要的宏。您还可以根据名称中的模式推断出它们的用途。
        您可以使用预定义的 GNU_C 预处理器指令,轻松地包含正确的 include 文件,如下所示:
#include <endian.h>#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__   #include <linux/byteorder/big_endian.h>#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__   #include <linux/byteorder/little_endian.h>#else   //  …user defined endian header#endif        其他字节顺序考虑因素
        从 x86 移植到 Power 时,不依赖于外部数据文件并且遵守严格的 C ANSI 编程标准的高级应用程序或许能够顺利地移植到 Linux on Power,且不会出现字节顺序问题。但是,字节顺序是一个需要理解的重要概念,而且在代码中识别这些漏洞的能力能够使得向 Linux on Power 的迁移变得很容易。
        此外,在下一节中,我们将重点介绍 IBM Linux SDK 中提供的其他代码分析工具,它们可以帮助识别字节顺序问题。
返回列表