精华内容
下载资源
问答
  • 3、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)4、以下为Linux下的32位C程序,请计算sizeof的值。5、请写出bool flag 与“零值”比较的if 语句6、请写出int 变量n 与“零值”比较的if...

    1、已知一个数组table,用一个宏定义,求出数据的

    元素个数。

    #define NTBL(table) (sizeof(table)/sizeof(table[0]))
    

    2、对于一个频繁使用的短小函数,在C 语言中应用什么实现,在C++ 中应用什么实现?

    c用宏定义,c++ 用inline函数

    3、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

    #define SECONDS_PER_YEAR (60 * 60 * 24 * 365ul)
    

    注意末尾的UL。

    4、以下为Linux下的32位C程序,请计算sizeof的值。

    char str[] = “Hello” ;                               
    char *p = str ;                                      
    int n = 10;         
    void Func ( char str[100])                           
    {                                                                                                 
    }                                                                              
    void * p = malloc( 100 );                                                                                       
    

    请计算
    (1)sizeof (str ) = (2)sizeof ( p ) =
    (3)sizeof ( n ) =
    (4)sizeof( str ) =
    (5)sizeof ( p ) =
    答案:
    (1)6、(2)4 、(3 )4 (4)4 (5)4

    5、请写出bool flag 与“零值”比较的if 语句

    if ( flag )    if ( !flag )
    

    6、请写出int 变量n 与“零值”比较的if 语句

    if ( n == 0 )   if ( n != 0 ) 
    

    7、请写出char *p 与“零值”比较的if 语句

     if (p == NULL)    if (p != NULL) 
    

    8、以下是求一个数的平方的程序,请找出错误

    #define SQUARE(a) ((a)*(a))
    int a = 5;
    int b;
    b = SQUARE(a++);
    

    宏在预编译时会以直接替换的形式展开。涉及到宏的地方,谨慎使用++-- ,该程序的结果为30。

    9、有符号数转无符号数

    #define Max_CB 500
    void LmiQueryCSmd(StructMSgCB * pmsg)
    {
    	unsigned char ucCmdNum;
    	......  
    	for(ucCmdNum=0;ucCmdNum<  Max_CB;ucCmdNum++)
    	{
    	......;
    	}                    
    }
    

    这段代码执行有什么问题?
    死循环。
    unsigned char //无符号字符型表示范围0~255
    char // 有符号字符型 表示范围-128~127

    10、怎么判断单向链表中是否有环?

    答:用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步;当p2 指针追上p1的时候,就表明链表当中有环路了。

    int testLinkRing(Link *head)
    {
    	Link *t1=head,*t2=head;
    	while( t1->next && t2->next)
    	{
    		t1 = t1->next;
    		if (NULL == (t2 = t2->next->next))
    			return 0; // 无环
    		if (t1 == t2)
    			return 1;
    	}
    	return 0;
    }
    

    11、下面的代码输出是什么,为什么?

    void foo(void)
    {
    	unsigned int a = 6;
    	int b = -20;
    	(a+b> 6)? puts("> 6") : puts("<= 6");
    }
    

    这个问题测试你是否懂得C 语言中的整数自动转换原则,
    当表达式中存在有符号类型和无符号类型时,所有的数都自动转换为无符号类型。因此-20 变成了一个非常大的正整数,所以该表达式计算出的结果大于6 。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。

    12、switch()的参数类型可以是实型吗?

    不可以。

    13、头文件包含

    #include <filename.h> 和#include “filename.h” 有什么区别?
    对于#include <filename.h> ,编译器从标准库路径开始搜索filename.h ;
    对于#include “filename.h” ,编译器从用户的工作路
    径开始搜索filename.h 。

    14、头文件中的ifndef/define/endif 干什么用?

    防止该头文件被重复引用。

    15、嵌入式系统经常要求程序员去访问某特定的内存位置。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。

    int * ptr;
    ptr=  (int *)0x67a9;
    *ptr = 0xaa55;
    
    展开全文
  • +《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000一、实验要求实验部分(以下命令实验楼64位Linux虚拟机环境适用,32位Linux环境可能会稍有不同)写一个简单的C程序,将其编译成...

    何金龙 + 原创作品转载请注明出处 +《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

    一、实验要求

      实验部分(以下命令为实验楼64位Linux虚拟机环境下适用,32位Linux环境可能会稍有不同)

    写一个简单的C程序,将其编译成汇编代码,并分析汇编代码的工作过程中堆栈的变化。

    二、实验过程

    1、写一个简单的C程序

    main.c

    main.c

    2、将C程序编译成汇编代码

    使用下面的命令

    gcc –S –o main.s main.c -m32 命令编译成汇编代码

      将C程序编译成汇编代码,将所有开头带.的代码删除

    main.s

    main.s

    三、实验分析

    1、主函数工作过程中堆栈的变化

    这里写图片描述

    2、f(int x)函数工作过程中堆栈的变化

    这里写图片描述

    3、g(int x)函数工作过程中堆栈的变化

    这里写图片描述

      最后通过leave、ret,返回到main中,eax加48,并返回。

    四、实验总结

    目前计算机的工作模型基本上都是来自或改进于冯诺依曼体系结构。

    1. 从硬件角度看,这种存储程序计算机工作模型由两大部分硬件组成,CPU和内存,总线连接两个硬件,负责信息的传递。

      这里引用老师上课所画的示意图:

      这里写图片描述

    2. 从程序员角度来看,CPU就是一直不停的工作,只要有指令产生,就依次执行,内存中存放着各种指令和数据,总线将两者相连接

    3. 为什么需要掌握汇编代码
        在计算机中的数据都是由二进制的01串组成,进行01字符串的编码难度极大,高级语言的产生对底层进行屏蔽,只需要掌握基本的语法就能编程,然而却无法更加深刻地理解计算机底层的工作原理,因此,在第一次实验中,我们学习了如何反汇编一个简单的C程序,通过一行一行细致的解读汇编代码,对于计算机的工作模型有了一个较为感性的认识,特别是程序在内存中的状态和工作方式。

    4. 汇编指令的执行
        在汇编程序中,每一个函数就有一个函数栈,里面存放着汇编指令,CPU会首先从main函数中根据指令一条一条地执行,各种寄存器会紧密合作。遇到需要跳转访问子函数堆栈,首先做的工作就是保存当前指令的下一个位置,为了能够在子函数执行完后还能够继续当前函数指令的执行。用eax收集函数返回值,以便对于需要子函数的返回值时候,让函数从寄存器中去读取。

    总结

    • 采用冯诺依曼体系结构,CPU通过总线与内存连接,CPU中有IP负责执行语句并移动至下一个指令,内存中存放着具体指令和数据。
    • 寄存器分为通用寄存器和段寄存器,通用寄存器负责记录累加值、基地址、堆栈基地址与顶地址、变址、计数值等,段寄存器负责记录代码段、数据段、附加段和堆栈段。
    • IP指向代码段寄存器,随着逐条执行IP,代码段寄存器(CS)中的指令被一一执行,而CS也可以影响IP的指向,从而更改执行的流程,组成复杂的控制结构。
    展开全文
  • 本文将介绍如何使用以下直观分步流程将 Linux® C/C++ 应用程序从 x86 平台(Intel® 或 AMD)移植到 IBM® PowerLinux™。我们首先要了解需要移植做准备工作,然后我们将介绍一些让 32 和 64 代码在 ...

    本文将介绍如何使用以下直观的分步流程将 Linux® C/C++ 应用程序从 x86 平台(Intel® 或 AMD)移植到 IBM® PowerLinux™。我们首先要了解需要为移植做的准备工作,然后我们将介绍一些让 32 位和 64 位代码在 PowerLinux 上运行的实现技巧。

    参考

    http://www.ibm.com/developerworks/cn/linux/l-port-linux-on-x86-application/

    简介

    在大多数情况下,将 Linux 应用程序从 x86 平台移植到 Linux on Power 很简单,因为两个平台都基于来自 Novell SUSE 或 Red Hat 的同一个 Linux 版本。移植常常只需要执行一次 GNU Compiler Collection (GCC) 再编译,对一些编译器和链接器开关稍作更改。

    但是,为解决突然出现的未知问题做好准备是拥有一个成功端口的重要优势。通常,如果重点关注的是移植,将优化放在以后进行,那么本文中介绍的指南、技术和工具可以最大程度地降低(甚至可能消除)移植到 Linux on Power 的难度。

    在某些情况下,当您单独在一种特定硬件架构(比如 x86)上设计应用程序时,有时可能需要做一些额外的修改。本文会重点介绍与将 x86 系统上运行的 LInux 应用程序移植到基于 IBM POWER® 处理器的系统相关的一些差异,本文还提供了让 x86 代码为移植到 Linux on Power 做好准备的一些建议。

    • 您应用程序的字节顺序
    • 32 位和 64 位数据类型(长度和对齐方式)
    • 理解可用的编译器选择 - GCC(分发和 Advance Toolchain)和 IBM XL C/C++ 编译器。
    • 使用 IBM SDK for Linux 和 IBM Rational Developer for Power Systems - 使用 GNU C/C++ 编译器构建大型程序。

    应用程序开发人员可以在 Power Linux 上使用一些高级工具和技术,其中包括 IBM Software Development Kit for PowerLinux (SDK),这是一个免费、基于 Eclipse 的集成开发环境 (IDE)。该 SDK 集成了 C/C++ 源代码开发与 Advance Toolchain、链接后优化和经典的 LInux 性能分析工具(包括 OProfile、Perf 和 Valgrind)。

    计划移植

    将应用程序移植到一个新平台时,恰当的计划不可或缺。要为移植做好充足的准备,您应该:

    1. 以可视方式扫描代码,尤其需要注意那些可能错误匹配的赋值运算,以及位操作和比较。
    2. 理解 IBM Power® 平台架构要点,以及 x86 与 IBM POWER 处理器架构之间的差异 - 特别是您应用程序的字节顺序。
    3. 确定使用哪个 Linux on Power 发行版:Red Hat Enterprise Linux 或 Novell SUSE Linux、CentOS 还是 Ubuntu。
    4. 考虑使用 GNU Make 构建系统。
    5. 确定要使用哪个编译器:GCC 或 IBM XL C/C++ for Linux。
    6. 获取一个用于开发的 IBM Power 服务器。下面列出了一些选择:
    7. 查看下面的程序,确定是否有个程序可以帮助加快移植并取得成功。

    Power Development Cloud
    这个完全自动化的 IBM Power Development Cloud 是一个免费的平台即服务 (PaaS),可用于使用 IBM 平台开发和演示软件解决方案。您可以利用 IBM Linux on Power 开发堆栈,它已预先配置和安装了针对从 x86 移植到 Linux on Power 的开发工具。

    IBM Hardware Mall – 租赁和折扣
    Hardware Mall 旨在激励独立软件供应商 (ISV) 在 IBM 平台上开发软件解决方案,为他们提供了系统硬件和适用软件的重要购买折扣和低租赁费率。

    IBM Systems Application Advantage for Linux (Chiphopper)
    IBM Chiphopper™ 产品是一个应用程序移植或重新托管程序,旨在免费帮助 IBM 业务合作伙伴启动、测试和支持其在竞争平台上运行的现有 Linux 应用程序向运行 LInux 和中间件平台的 IBM Power Systems™ 的移植。

    IBM Innovation Center
    IBM Innovation Center 提供了培训和一对一指导,涉及从构建到营销和销售解决方案的方方面面。IBM Innovation Center 团队随时准备帮助您实现开发目标

    您可以在 解决方案开发硬件 网站上找到并利用所有这些服务。

    理解 Power 平台的差异

    您要移植到的 Power 硬件平台,确定了您在编译应用程序时想要使用的优化选项。您应考虑以哪个处理器版本为基础,例如 IBM POWER5、IBM POWER6®、IBM POWER7® 或 IBM POWER8™。为基于 POWER 处理器的系统开发一般性的代码非常容易,最终的应用程序将在多个系统上正常运行。针对 IBM 较新的几代 POWER 产品开发应用程序也很容易。一个重要的选择是选择使用 GCC 编译器还是 XL C/C++ 编译器。更多细节将在本文后面讨论。

    编译器:

    多年来,GCC 技术已得到显著改进,能够为基于 IBM POWER7 和 POWER8 处理器的服务器提供经过调优的应用程序。此外,如果性能是终极目标,那么 IBM XL 编译器可以实现更高的性能。

    • 如果在 Linux on x86 上使用 GCC,推荐使用 GCC 完成初始移植。Linux on Power 上的 GCC 技术已显著改进,熟悉 GCC 会使得以它为基础进行移植变得更轻松。
    • 如果需要的话,您还可以使用 IBM XL C/C++ 编译器。
    • 如果在 Linux on x86 上使用 Java™,那么推荐从 IBM 网站下载并使用合适的 IBM Java 工具包。

    有关 Power Systems 上的虚拟化的更多信息,请查阅 Linux on Power:针对开发人员的概述(developerWorks,于 2011 年 7 月更新)或参阅 执行简报 了解使用 Power Systems 进行服务器整合的可能性。

    编译器标志:

    移植到基于 POWER 处理器的服务器时,可以在 XL C/C++ 编译器中对 -qarch-qtune 使用不同标志,或者在 GCC 编译器编译器中对-mcpu-mtune 使用不同标志来优化应用程序。但是,对于初始移植,为了最大限度降低难度,最好使用基于 Power 的最常见的–qtune=ppc–mcpu=power。具体的标志和使用它们的时机将在本文后面讨论。

    确定使用哪个 Linux on Power 发行版

    来自 Novell 和 Red Hat 的最新的操作系统产品(本文发表时)提供了完成企业级部署所需的技术、支持和可靠性。首选产品的选择通常在一个公司或组织内要考虑的事项。

    • SUSE Linux Enterprise Server (SLES)。有关 SLES 的更多信息,请参阅 参考资料 部分。
    • Red Hat Enterprise Linux (RHEL)。有关 RHEL 或 CentOS 的更多信息,请参阅 参考资料 部分。

    使用 SLES 还是 RHEL 的决定不会对移植过程产生直接影响。但是,SUSE 和 Red Hat 拥有不同的发布和更新周期,在二进制兼容性上具有不同的策略,从长远角度讲,这些可能影响您的应用程序更新决策。此外,Red Hat 和 SUSE 发行版按相同的时间表发布对 Intel® 和 Power 的支持。

    迁移到 GNU Make

    如果目前尚未使用 GNU Make 构建应用程序,那么您可以考虑迁移到该应用程序。一种不错的编程实践是:使用一个能控制可执行文件的生成的工具,而不依赖于脚本或直接调用编译器来生成可执行文件。大多数 C 和 C++ 编程人员都使用 Make 作为这样的工具。切换到 GNU Make,这样您就能通过同一个构建控件makefile 在多个平台上执行一致的构建操作。GNU Make 同时具有 SLES11 和 RHEL6 版本。有关 GNU Make 的更多信息,请参阅 “参考资料” 部分。

    假设您的 Linux on x86 应用程序是使用 GCC 构建的,那么我们推荐首先使用 GCC 在 Power 上重新编译的简单方法。后续步骤将会添加简单的调优和优化选项供考虑。如果需要的话,接下来的一个步骤将是考虑 IBM XL 编译器,以便实现针对特定 IBM Power Architecture® 级别调优的更高性能。

    理解 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 所示。

    清单 3. 使用指令让字节顺序效果中立化

    #include <stdio.h>
    
    #define BIG_ENDIAN 1
    #define LITTLE_ENDIAN 0
    #define BYTE_ORDER (( htonl(1)==1) )   //  returns 1 or 0 depending on platform
    
    
    union {
      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) )
    #endif
    int 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 中提供的其他代码分析工具,它们可以帮助识别字节顺序问题。

    选择要使用哪些迁移工具

    类似于机械领域,移植工程师的 “技术” 工具箱中必须有许多工具,而且知道使用哪个工具可用来最大限度降低移植的难度。IBM Linux on Power SDK 和 IBM Rational Developer for Power Systems 都是独立、完整的集成开发环境 (IDE),可用于简化 Power 服务器上的移植和开发,是开发人员在移植到 Linux on Power 时可以使用的优秀技术工具。

    IBM SDK for PowerLinux with Migration Advisor

    IBM Software Development Kit for PowerLinux (SDK) 是一个免费、基于 Eclipse 的 IDE。该 SDK 集成了 C/C++ 源代码开发与 Advance Toolchain、链接后优化工具(比如 FDPR)和经典的 LInux 性能分析工具(包括 OProfile、Perf 和 Valgrind)。此外,IBM SDK for PowerLinux 中有一个叫做 Migration Advisor 的工具。Migration Advisor 工具的一个特性是代码检查器代码修复 特性,该工具可以分析代码中的 Linux/x86 漏洞,为您提供快速修复代码中的漏洞的选项或者提供手动修复它的建议。例如,下面的转换是从 x86 Linux 移植到 Linux on Power 时一种典型的字节顺序潜在问题。消息 “Cast with endianness issue checker” 表示存在这样的漏洞。

    void foo() {
        short int val = 0xFF00;
        char *char_pointer = (char *) &val;     
        //This prints 0 in x86 (or x86_64) machines and ff in ppc (or ppc64) machines.
        printf("%x\n", *char_pointer);
    }

    Migration Advisor 使用 Eclipse CDT Code Analyzer (Codan) 源代码分析器来查找 C/C++ 源代码中的潜在迁移问题,比如可能在 x86 和 POWER 服务器上运行时生成不同结果的代码块。要查找源代码中的问题,Codan 会分析 C/C++ 源代码抽象语法树 (AST),查找可能与 Power Architecture 不兼容的代码段。在找到潜在问题时,Migration Advisor 会保存该问题在代码中的位置,并在源代码中的这个特定位置添加一条警告。目前,Migration Advisor 仅兼容 C/C++ 代码。

    以下是在 IBM SDK for PowerLinux 中使用 Migration Advisor 的屏幕截图。

    图 2. 运行 Migration Advisor ‘Union with Endianness Issues’ 检查器
    运行 Migration Advisor ‘Union with Endianness Issues’ 检查器

    Migration Advisor:快速修复特性

    Migration Advisor 还为一些迁移问题提供了快速修复方法,能够将依赖于架构的代码块替换为与 POWER 处理器兼容的指令。可以通过两种方式触发快速修复:右键单击源代码中的警告并选择快速修复选项;或者打开 Migration Advisor Eclipse View,右键单击一个特定问题,然后选择快速修复选项。

    Migration Advisor 所提供的快速修复仅适用于:

    • 特定于 x86、内置的编译器的使用
    • 内联程序集的使用
    • 性能降级

    您可以选择可激活或可停用的检查器。每次您修改源代码后,Migration Advisor 都将重新检查代码并更新结果,使您在对项目执行完成的重新构建之前有机会快速识别和解决问题。图 3 显示了 Migration Advisor 窗口,其中已激活所有检查器。

    图 3. 激活所有检查器
    激活所有检查器

    激活 Migration Advisor 检查其后,右键单击项目并单击 Run Migration Advisor。然后,Migration Advisor 会使用启用的检查器分析代码,并在 Eclipse 视图中显示找到的潜在问题的结果(参见图 4)。

    图 4. Migration Advisor 视图
    Migration Advisor 视图

    图 5 显示了一个不受 Power 平台支持的内置插件所导致的一个真实迁移问题的示例。为了修复该问题,可以在 Migration Advisor Eclipse 视图中双击它。然后将打开源代码视图,突出显示问题的准确位置。如果将鼠标移动到突出显示的代码上方并按 Ctrl+1,则会打开另一个弹出窗口,如图 5 所示。

    图 5. 使用 Migration Advisor 进行快速修复
    使用 Migration Advisor 进行快速修复

    选择第一个选项 Builtin quick fix。应用快速修复后的结果代码如图 6 所示。

    图 6. 应用 Migration Advisor 快速修复后的代码
    应用 Migration Advisor 快速修复后的代码

    其他有用的 Migration Advisor 检查包括:

    • 特定于 x86 的程序集检查器
    • 包含位字段的结构的检查器
    • Long double 使用检查器
    • 性能降级检查器
    • 特定于 x86 的编译器内置检查器的使用

    关于这些方便的检查的完整列表,请参阅 IBM 知识中心。

    Linux Cross-platform Tool (LCT)
    SDK for PowerLinux 还提供了另一个可以在任何现有的 Intel x86 平台上运行的方便工具。它是一个命令行工具,用于识别应用程序的潜在可移植性。这样,在移植到 Linux on Power 之前,您能够快速了解源代码中的潜在问题。在安装 IBM SDK for PowerLinux 后,可以在该工具的 README 部分中找到 LCT 文档。

    IBM Rational Developer for Power Systems
    IBM Rational Developer for Power Systems 也提供了一个富桌面集成开发、移植和优化环境,用于多平台开发(IBM i、AIX 或 Linux on Power)。它的特性还包括各种移植工具,比如 Code Analysis 工具、Performance Advisor 工具和 Migration Assistant,类似于 IBM SDK for PowerLinux,这些工具可以检测 32 位到 64 位迁移问题、字节顺序问题,以及其他可能阻碍移植的操作系统问题。

    JVM
    Java 虚拟机 (JVM) 在所有平台上都以高位优先模式运行,因此常常对处理器架构带来的影响免疫。

    数据类型和对齐方式

    应用程序二进制接口 (ABI) 中重要的 有符号/无符号字符 细微差异。

    在 x86/x86_64 下,“char” 的默认值为 “signed char”,而 Power Systems 上的默认值为 “unsigned char”。在 Power Systems 上,可以使用 GCC 指令-fsigned-char 覆盖该默认值。等效的 IBM XL 指令为 -qchars=signed

    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
    默认值:x86 上为 signed - POWER 上为 unsigned
    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
    指针 32 64 32 64

    *Linux on Power 上的 long double 的默认大小现在为 128 位。如果使用编译器选项 -qnoldb128 和 XL C/C++ 编译器,那么它们可以减少到 64 位。

    在 Power 和 x86 平台上的 /usr/include/limits.h 中,可以找到数字值的所有定义。

    许多遗留 Linux x86 应用程序在 32 位下运行。对于最新的 x86 架构(支持并鼓励采用 64 位应用程序),更多的 x86 应用程序是在 64 位模式下原生地更新或编写的。在将 x86 应用程序移植到 Power Systems 的练习中,可采用 Linux on Power 环境作为目标来匹配您的来源环境。换句话说,我们推荐首先完成初始移植,然后再考虑移植到 64 位编程模型。如果希望将 32 位 x86 应用程序移植到 64 位 Power Systems 编程模型,那么可以将迁移分为两步:

    1. 移植到 Linux on Power 32 位环境(包括测试和验证它)。
    2. 然后迁移到 64 位环境。

    如果应用程序满足以下条件:那么工程师应考虑将应用程序移植到 64 位:

    • 能从超过 4GB 的虚拟地址空间受益
    • 能够从更多物理内存(大于 4GB)受益,以及用户可能将它部署在具有超过 4GB 物理内存的系统上
    • 能够从 64 位大小的长整数受益
    • 能够使用完整的 64 位寄存器来执行高效的 64 位算法
    • 使用大于 2GB 的文件

    一些可通过迁移到 64 位而受益的应用程序示例包括:

    • 数据库应用程序,尤其是执行数据挖掘的应用程序
    • Web 缓存和 Web 搜索引擎
    • 计算机辅助设计 (CAD)/计算机辅助工程 (CAE) 模拟和建模工具的组件
    • 科学和技术计算应用程序,比如计算流体动力学、遗传模拟等

    应用程序可保留 32 位并仍在 64 位 Linux on Power 内核上运行,无需任何代码更改。基于 IBM Power 处理器的服务器支持 32 位和 64 位应用程序同时在 64 位架构上运行

    在不同平台(从 x86 到 Power)或编程模型(从 ILP32 到 LP64)之间移植应用程序时,需要考虑不同环境中提供的数据宽度和对齐设置之间的差异,以避免可能的性能降级和数据损坏。

    在从 x86 ILP32 移植到 POWER ILP32 或从 x86 LP64 移植到 POWER LP64 时,您可能注意到,在表 1 中,所有基本数据类型的宽度都保持相同,除了 long double 96 位变为 IPL32 上的 64/128 位,128 位变为 LP64 上的 64/128 位。这意味着您应该检查与 long double 数据类型相关的代码部分。如果计划使用 XL C/C++ 编译器,那么可以使用-qlongdouble 编译标志在 long double 数据类型上实现最高的兼容性。

    数据对齐

    在平台之间或 32 位与 64 位模型之间移植应用程序时,需要考虑不同环境中提供的对齐设置之间的差异,以避免可能的性能降级和数据损坏。最佳实践是对数据项执行自然对齐。自然对齐表示将数据项存储在是其大小的倍数的地址上(例如,8 字节数据项存储在一个为 8 的倍数的地址中)。对于 XL C/C++ 编译器,依据 linuxppc 或位包装规则,聚合中的每种数据类型(C/C++ 结构/union 和 C++ 类)将与字节边界对齐,其中 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
    指针 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 Systems 上与 8 字节对齐。因此,不同平台上的结构将具有不同的布局。不要硬编码任何大小和偏移,这很重要。相反,您应该使用 C 运算符sizeof 来查询基础和复杂类型的大小。宏 offsetof 可用于从结构开头获取结构成员的偏移。

    确定要使用哪个编译器:GCC 或 IBM XL C/C++

    有两个 C/C++ 编译器可用于 Linux on Power:GCC 和 IBM XL C/C++ 编译器。GCC 针对 Linux 上的编译提供了可靠的代码移植功能,而在使用更高级的优化时,与 GCC 相比,IBM XL 编译器显著提升了性能。两种编译器都提供了 32 位和 64 位编译模式,Linux on Power 环境支持在不降低性能的情况下同时运行 32 位和 64 位代码。

    使用 GCC 编译器集进行移植

    如果项目跨多个平台而开发,而且其中 GCC 编译器是原始的编译器,那么 GCC 编译器常常用于部署针对 Linux on Power 的应用程序。性能不那么关键的应用程序(比如小型实用程序)通常属于这种情况。GCC 还允许使用一些只有 GCC 能够理解的代码原型,比如特定于 GCC 的宏。但要注意的是,许多特定于 GCC 的特性都合并在 XL C/C++ 编译器中。

    一般而言,使用 GCC 移植代码应该很简单。在大部分情况下,只需简单地重新编译和键入 make 命令即可。架构可能有所不同,而且有时可能存在库版本差异。但从很大程度上讲,它在哪个架构上运行并不重要。我们不鼓励您在 Power Linux 上编译特定于架构的标志,比如-m486-mpowerpc64,因为 GCC 没有针对这些架构上的优化例程的丰富的处理器映射。同样地,如果不使用特定于架构的标志,那么不同 POWER 硬件模型上的二进制兼容性会更高。

    SLES 11 和 RHEL 6 中包含的 GCC 编译器同时支持 32 位和 64 位应用程序。在= SLES 11 和 RHEL 6 版中,默认编译模式为 64 位。

    在所有架构上,库必须使用 -fPIC 来编译;x86 默认情况下会在 GCC 中应用此标志。在 POWER 上,此标志指定将生成的代码用在一个共享对象中。请查阅 GCC 编译器手册,以便了解有关的更多信息(参见 “参考资料”)。

    使用 IBM XL C/C++ 编译器进行移植

    XL C/C++ 使用了 GNU C 和 C++ 头文件,而且结果应用程序被链接到 GCC 提供的 C 和 C++ 运行时库。这意味着 XL C/C++ 编译器生成了 GNU Executable and Linking Format (ELF) 对象,这些对象完全兼容 GCC 编译器生成的对象。XL C/C++ 包含对称多处理 (SMP) 运行时库,以便支持 XL C/C++ 的自动并行化和 OpenMP 特性。

    从 GCC 移植到针对 Linux on Power 的 XL C/C++ 很简单。XL C/C++ 通过提供选项 -qinfo=por 来帮助完成此任务,帮助您过滤掉省略的诊断消息,进现实与可移植性问题相关的消息。此外,XL C/C++ 支持 gcc 和 gcc-c++ 的 GNU 扩展的一个子集。

    请参阅 “XL C/C++ for Linux on pSeries 编译器参考”,了解受支持的特性的完整列表,以及那些被接受但拥有忽略了的语义的特性。

    要对 C 代码使用受支持的特性,可以指定 -qlanglvl=extended-qlanglvl=extc89。在 C++ 中,默认情况下会接受所有受支持的 GNU gcc/gcc-c++ 特性。此外,gxlc 和 gxlc++ 有助于最小化对使用 GCC 编译器构建的现有应用程序的 makefile 的更改

    XL C/C++ 中的优化选项

    XL C/C++ 提供了一些专门针对 IBM 硬件的优化选项。对于 Linux on Power,与使用 GCC 编译的应用程序相比,许多使用 XL C/C++ 并利用正确的优化标志组合而编译的应用程序都有巨大的性能改进。请注意,不是所有优化对所有应用程序都有利。通常,您需要在编译器完成的优化程度与编译时间的增加和调试能力的降低之间进行权衡。

    优化级别
    优化级别由编译器选项来指定。下表总结了每个优化级别上的编译器行为。

    表 3. 每个优化级别上的编译器行为

    选项 行为
    -qnoopt 提供快速编译和完全调试支持。
    -O2(与 -O 相同) 执行被编译器开发人员视为编译速度和运行时性能的最佳组合的优化。此设置会暗中使用-qstrict-qstrict_induction,除非使用
    -qnostrict_induction-qnostrict 进行明确否定。
    -O3 执行更多内存密集型和/或编译时间密集型的优化。在运行时改进比最小化编译资源的利用更重要时,推荐执行这些优化。
    -O4 和 -O5 执行过程间优化、循环优化和自动机器调优。

    应避免的旧 Power 选项

    从 x86 移植到 Linux on Power 时,来自旧 Power Architecture 的一些选项应避免使用且有害

    • 使用 -mminimal-toc-mfull-toc 的 PPC64 构建版本应替换为 -mcmodel=medium(这是默认值)
    • -ffloat-store,不会在 Power 上使用

    目标机器选项告知编译器生成能够在给定微处理器或架构家族上最优地执行的代码。通过选择合适的目标机器选项,可通过优化来适应最广泛的目标处理器、给定处理器架构家族的许多处理器,或者一个特定的处理器。以下选项会控制影响目标机器的各个方面的优化:

    表 4. 影响目标机器的各个方面的优化选项

    选项 行为
    -qarch 选择应针对其生成指令代码的一个处理器架构家族。默认值为 -qarch=auto。还提供了以下子选项:ppc64grsq、pwr3、pwr4、pwr5、ppc970、ppc64、ppcgr、rs64b 和 rs64c。
    -qtune 针对在给定微处理器上执行而进行的基础优化,没有暗示要用作目标的指令集架构的任何信息。Linux 上的默认值为-qtune=auto。可用的子选项包括:pwr3、pwr4、pwr5、pwr6、pwr7、pwr8、ppc970、rs64b 和 rs64c。但是,在许多情况下,此设置会基于–qarch 的设置而自动设置。
    -qcache 定义一种特定的缓存或内存几何结构。如果使用了 -qcache,则与它一起使用-qhot-qsmp
    -qhot 高阶转换属于专门通过交换 (interchange)、熔合 (fusion) 和展开 (unroll) 等技术来改善循环性能的优化。指定-qhot 时,-qhot=vector 是默认选项。您可以尝试将 -qhot-O2-O3 结合使用。它的设计目标是在没有转换机会时产生一种中立效果。
    -qsmp 生成共享内存并行处理所需的多线程代码。指定 -qsmp 时,-qsmp=auto 是默认选项。如果您在编译一个 OpenMP 程序且不想要自动并行化,那么可以使用-qsmp=omp:noauto。使用 -qsmp 时始终使用 _r 编译器调用。

    要最充分地利用目标机器选项,您应该:

    • 使用 -qarch,指定您希望代码能在其上良好运行的最小的机器系列。
    • 使用 -qtune,指定应具有最佳性能的机器。例如,如果将在基于 POWER8 处理器的系统及更高版本的系统的 Power 服务器上运行应用程序,那么可以使用-O3 -qarch=pwr8 -qtune=pwr8

    IBM Power 平台支持其他平台上所没有的机器指令。XL C/C++ 提供了一组内置的函数,它们直接对应于某些 POWER 处理器指令。使用这些函数能消除函数调用-返回成本、参数传递、堆栈调整和所有其他与函数调用相关的成本。有关支持的内置函数的完整列表,请参阅 XL C/C++ C++ for Linux on pSeries 编译器参考 安装文档。

    但是,在使用 IBM XL C/C++ 编译器重新编译时,最初打算使用 GCC 编译器编译的软件可能需要更多地进行关注。您需要编辑 makefile 来反映 XL C/C++ 编译器的正确路径,该路径默认为 /opt/ibmcmp/。还需要设置针对特定架构的正确的优化标志(比如-03 -qarch=pwr8 -qtune=pwr8 用于 IBM POWER8 处理器)。

    除了针对各种 Power Architecture 衍生产品的优化模式,还可以告诉 XL C/C++ 编译器在通用模式下编译软件。这可以确保跨所有 Power Architecture 衍生产品的兼容性,但会牺牲通过特定于架构的优化所获得的性能优势。在编译 64 位代码时,必须为编译器提供针对 64 位构建版本的标志(即-q64),因为它在默认情况下为 32 位模式。

    下面列出了使用 XL C/C++ 编译器编译面向 GCC 的代码的一些技巧:

    • 在默认情况下,GCC 允许在 C 文件中使用 C++ 风格的注释,但这不适合 XL C 编译器 XLC。因为更改一组源文件中的所有注释来遵守 C 风格的注释格式不太合算,所以 XLC 提供了一个-q 参数来允许使用这些注释:-q cpluscmt。在使用此标志编译 C 代码时,会解释 C 和 C++ 风格的注释。
    • 环境变量常常是配置构建脚本的最简单的方式。无需手动编辑配置脚本和 makefile,您应该设置相关的环境变量,比如 $CC$CFLAGS,以便允许通过配置脚本来生成 makefile,而无需手动编辑。
    • 配置脚本还需要知道正确的平台类型。平台类型将为 linux-powerpc-unknown-gnu 或 linux-powerpc64-unknown-gnu。您应该通过将-target= 标志被附加到配置脚本中,为使用 GCC 或 XL C/C++ 的编译设置此平台类型。
    • 尽管 IBM XL C/C++ 编译器有许多文档,您仍然可以运行该编译器而不使用参数在控制台显示参数列表,例如 $COMPILER_PATH/bin/cc

    编译器选项比较

    下表比较了来自 GCC 和 XL C/C++ 的常用编译器选项。

    表 5. 来自 GCC 和 XL C/C++ 的常用编译器选项

    GCC XL C/C++ 描述
    -v -v、-V、-# 打开详细模式。
    -p/-profile -p 设置编译器生成的对象文件,以进行分析。
    -m32、-m64 -q32、-q64,或者设置 OBJECT_MODE 环境变量 创建 32 或 64 位对象
    -fsyntax-only -qsyntaxonly 执行语法检查而不生成对象文件。
    -fpic -qpic=small 生成与位置无关的代码,以便在共享库中使用它们。在 XL C/C++ 中,全局偏移表的大小不大于 64 KB。如果指定了-qpic 而没有任何子选项,则假设使用了 -qpic=small。如果指定了 -qmkshrobj 编译器选项,则会启用-qpic 选项。
    -fPIC -qpic=large 允许全局偏移表大于 64 KB。
    -pthread -qthreaded 或 _r invocation 模式 创建在多线程环境中运行的程序。
    -fno-rtti -qnortti 禁止生成运行时类型标识 (RTTI) -qrtti 来进行异常处理,并且禁止typeiddynamic_cast 运算符使用 RTTI。在 XL C/C++ 上,默认选项为 -qnortti
    -static -qstaticlink 阻止此选项生成的对象与共享库链接。
    -static-libgcc -qstaticlink=libgcc 告诉编译器与 libgcc 的静态版本链接。
    -shared -qmkshrobj 告诉编译器生成一个共享对象。
    -shared-libgcc -qnostaticlink=libgcc 告诉编译器与 libgcc 的共享版本链接。
    -Wl、-rpath -Wl、-rpath 或 -R 传递一个冒号分隔的目录列表,用它来指定一个运行时链接所搜索的目录。
    -fno-implicit-templates、-frepo -qtempinc、-qtemplateregistry、-qtemplaterecompile 实例化模板。
    -w -w 禁止警告消息。
      -warn64 启用对长整型到整型的截断操作的检查。
      -qinfo=< > 生成包含信息的消息。
    -fpack-struct -qalign=bit_packed 使用 bit_packed 对齐规则。
      -qalign=linuxppc 使用默认 GCC 对齐规则保持与 GCC 对象的兼容性。这是默认设置。
    -O、-O2、-O3 -O、-O2、-O3、-O4、-O5 用于设置优化级别。
    Ofast、Og   Ofast – 提供速度优化,不完全符合标准
    Og – 提供优化,但允许在需要时执行一些有效的调试。
    -mcpu、-mtune -qarch、-qtune、-qcache 用于设置一个特定处理器的优化选项。

    使用 GCC 构建大型程序

    客户有时需要构建一个在运行时生成的非常大的可执行文件。清单 5 中给出了一条常见的错误消息。

    清单 5. 构建大型可执行文件时的错误消息

    modelfile.cxx.o:(.text+0x212012):
           relocation truncated to fit: 
    R_PPC64_TOC16_DS against `.toc'+10000

    这是大型程序和旧 GCC 编译器的一个常见问题。旧 GCC 编译器乐观地假设目录 (table of contents, TOC) 不会溢出单个加载指令的 64 KB 范围。在这种情况下,该程序很大,需要的所有 TOC 条目的总和超过 16 位 (TOC16_DS)。

    有两个解决方案。

    1. 对于 Advance Toolchain 3.0 和旧编译器,可以使用 -mminimal-toc 进行重新编译。
    2. 对于 Advance Toolchain 4.0 和更高版本的编译器,可以使用 -mcmodel=medium 进行重新编译。-mcmodel=medium 应具有更好的性能,但需要升级。

    有关的更多细节,请参阅 GCC PowerPC 选项。

    移植步骤

    完成每个计划步骤后,应该已经准备为执行移植做好了准备。本节将介绍成功将应用程序移植到 Linux on Power 的推荐步骤。

    1. 将构建系统迁移到 GNU Make(如果有必要)
      这是构建一个或多个 makefile 的过程。您还可以利用 GNU 的程序构建自动化实用程序,比如 Autoconf、Automake 和 Buildtool,以便最大程度地提高您的程序跨不同 UNIX® 平台移植的能力。GNU 的程序构建自动化实用程序位于 directory.fsf.org/devel/build/。
    2. 修改依赖于架构的代码(如果有必要)
      考虑字节顺序、32 位和 64 位模型下的数据长度,以及不同平台上的数据对齐方式,这些已经在 理解 x86 与 Power Architecture 衍生产品之间的差异 一节中介绍过。
    3. 构建
      构建 makefile 并修改了所有程序后,构建流程很简单,只需发出一个命令,比如 make。如果在构建过程中遇到错误,这些错误通常是编译器和链接器错误,以及程序语法错误。通过 makefile 修改编译器选项或修改代码中的引起问题的语法,通常可以修复错误。编译器参考菜单和编程指南是此阶段的最佳参考资料。对于 IBM XL C/C++,请参阅 XL C/C++ for Linux 编译器参考 (compiler.pdf) 和 XL C/C++ for Linux 编程指南 (proguide.pdf)。对于 GCC,编译藏靠和编程指南都在 gcc.gnu.org/onlinedocs 上。
    4. 测试和问题排除
      成功构建程序后,测试其中是否有运行时错误。运行时错误通常与此阶段的程序逻辑相关。编写多个测试程序来验证应用程序的输出是否满足预期,总是一种不错的想法。
    5. 调优性能
      移植的代码已在 Power 平台上运行后,可监视它以确保它按预期执行。如果不符合预期,您需要完成性能调优。可使用以下工具套件识别应用程序中的性能问题,显示应用程序与 Linux 内核的交互情况。
      • OProfile
        OProfile 工具分析基于硬件相关事件的代码,比如缓存遗漏理器周期。例如,OProfile 可帮助确定导致大部分缓存遗漏错误的来源例程。OProfile 使用了许多处理器中提供的硬件性能计数器,包括 IBM POWER6 和 POWER7。有关 OProfile for Power Linux 的更多信息,请访问 OProfile 网站(参见 参考资料)。
      • 链接后优化 - 也称为 FDPRpro
        链接后优化工具通过在程序用于执行一些典型工作负载时收集程序的行为信息,优化该程序的可执行镜像。然后,它会重新分析该程序(结合收集的概要文件),应用全局优化(包括程序重构),以及创建一个针对该工作负载而优化的新程序版本。该优化器生成的新程序通常比原始程序运行得更快,使用的真实内存更少。有关更多信息,请访问链接后优化网站(参见 参考资料)。

    6. 如果移植的应用程序将是一个商业产品,或者想要将该应用程序分发给第三方来安装,那么您需要打包移植的应用程序,包含库、文档,有时还包含源代码。Linux 提供了多种方式来打包应用程序,比如 .tar 文件、自安装的 shell 脚本,以及 RPM。RPM 是用于 Linux 的最流行的打包工具之一。

    图 7. 上述 1 至 6 步中描述的移植活动流

    结束语

    Linux on Power 提供了一个企业级 Linux 环境,其中同时包含 32 位和 64 位应用程序环境和工具链。Linux on Power 提供了两组编译器,它们简化了开源代码的移植和对屡获殊荣的 Power Architecture 的高性能的利用。通过将 Linux on x86 应用程序移植到 Linux on Power,您可以利用 Power Architecture 上提供的应用程序性能,这一性能现在还得到了 Linux 操作系统上之前从未提供过的开发工具的增强。总之,Linux on Power 是一个部署高性能 Linux 应用程序的领先平台。

    致谢

    感谢 Calvin Sze 提供原始文章,感谢 Linda Kinnunen 提供原始文章模板和很有帮助的评审,感谢 IBM Linux on Power 团队提供技术帮助和审阅本文。

    感谢 Otavio Busatto Pontes 针对新的 IBM SDK for Linux on Power 而更新了本文。访问 Linux on Power 社区 了解针对该 SDK 的更多链接,以及来自 Wainer dos Santos Moschetta 的有关该 SDK 的博客文章。

    感谢 Roberto Guimaraes Dutra de Oliveira/Brazil/IBM@IBMBR 和 Leonardo Rangel Augusto/Brazil/IBM@IBMBR 更新 IBM SDK for PowerLinux 中的 Migration Advisor。


    展开全文
  •  为了适应现在越来越流行64位系统,经常需要将代码分别编译为32位版和64位版。其次,除了需要生成debug版用于开发测试外,还需要生成release版用于发布。本文介绍了如何利用makefile条件编译来生成这些版本,而且...

    作者:zyl910

      为了适应现在越来越流行的64位系统,经常需要将代码分别编译为32位版和64位版。其次,除了需要生成debug版用于开发测试外,还需要生成release版用于发布。本文介绍了如何利用makefile条件编译来生成这些版本,而且不仅兼容Linux下的GCC,还支持MinGW、TDM-GCC等Windows下的GCC编译器。


    一、C程序代码

      为了测试条件编译的效果,以下面这个C语言程序为例(gcc64_make.c)——

    #include <stdio.h>
    #include <assert.h>
    
    // 获取程序位数(被编译为多少位的代码)
    int GetProgramBits()
    {
        return sizeof(int*) * 8;
    }
    
    int main(int argc, char* argv[])
    {
        printf("bits:\t%d\n", GetProgramBits());
        assert( argc>1 );
        return 0;
    }

     

      main函数中,前两条语句的含义为——
    第一条语句用于显示当前程序的位数。如果编译为32位版,将会显示“bits: 32”;如果编译为64位版,将会显示“bits: 64”。
    第二条语句是一条断言,需要argc变量大于1。如果编译为debug版,若运行时未加命令参数,该断言失败,于是输出错误信息并终止程序;如果编译为release版,所有断言被屏蔽,不会有错误信息。


    二、GCC命令行参数

      复习一下GCC命令行参数,看看各个版本的区别——
    32位版:加上 -m32 参数,生成32位的代码。
    64位版:加上 -m64 参数,生成64位的代码。
    debug版:加上 -g 参数,生成调试信息。
    release版:加上 -static 参数,进行静态链接,使程序不再依赖动态库。加上 -O3 参数,进行最快速度优化。加上-DNDEBUG参数,定义NDEBUG宏,屏蔽断言。

      当没有-m32或-m64参数时,一般情况下会生成跟操作系统位数一致的代码,但某些编译器存在例外,例如——
    32位Linux下的GCC,默认是编译为32位代码。
    64位Linux下的GCC,默认是编译为64位代码。
    Window系统下的MinGW,总是编译为32位代码。因为MinGW只支持32位代码。
    Window系统下的MinGW-w64(例如安装了TDM-GCC,选择MinGW-w64),默认是编译为64位代码,包括在32位的Windows系统下。


    三、makefile代码

      makefile的代码为——

    # flags
    CC = gcc
    CFLAGS = -Wall
    LFLAGS = 
    
    # args
    RELEASE =0
    BITS =
    
    # [args] 生成模式. 0代表debug模式, 1代表release模式. make RELEASE=1.
    ifeq ($(RELEASE),0)
        # debug
        CFLAGS += -g
    else
        # release
        CFLAGS += -static -O3 -DNDEBUG
        LFLAGS += -static
    endif
    
    # [args] 程序位数. 32代表32位程序, 64代表64位程序, 其他默认. make BITS=32.
    ifeq ($(BITS),32)
        CFLAGS += -m32
        LFLAGS += -m32
    else
        ifeq ($(BITS),64)
            CFLAGS += -m64
            LFLAGS += -m64
        else
        endif
    endif
    
    
    .PHONY : all clean
    
    # files
    TARGETS = gcc64_make
    OBJS = gcc64_make.o
    
    all : $(TARGETS)
    
    gcc64_make : $(OBJS)
        $(CC) $(LFLAGS) -o $@ $^
    
    
    gcc64_make.o : gcc64_make.c
        $(CC) $(CFLAGS) -c $<
    
    
    clean :
        rm -f $(OBJS) $(TARGETS) $(addsuffix .exe,$(TARGETS))

     

      为了控制条件编译,定义了RELEASE、BITS这两个变量,分别赋初值。然后用ifeq判断RELEASE、BITS变量的值,分别加上不同的参数。
      因赋有初值,直接执行“make”时,编译得到的是默认位数的debug版。
      若在执行make时给变量赋值,将会得到不同的版本——
    make RELEASE=0:(默认位数的)debug版。
    make RELEASE=1:(默认位数的)release版。
    make BITS=32:32位(的debug)版。
    make BITS=64:64位(的debug)版。
    make RELEASE=0 BITS=32:32位的debug版。
    make RELEASE=0 BITS=64:64位的debug版。
    make RELEASE=1 BITS=32:32位的release版。
    make RELEASE=1 BITS=64:64位的release版。


      该makefile的代码风格是精心设计的,可以很方便的扩展——
    需要增加代码文件或依赖关系时,修改“# files”之后的内容。
    需要调整编译参数时,修改前半部分的参数变量。
    需要增加新的条件编译参数时,在“# args”定义一个变量并赋初值,然后再在后面用“ifeq”判断变量来调整编译参数。

      最后的“rm -f $(OBJS) $(TARGETS) $(addsuffix .exe,$(TARGETS))”是为了兼容MinGW、TDM-GCC等Windows下的GCC编译器而设计的——
    装好MSYS,再配置一下PATH环境变量,Windows中也可以使用rm命令删除文件。
    因Windows下的可执行文件的扩展名是exe,所以使用了addsuffix函数增加“.exe”扩展名。
    因Linux下不会生成.exe可执行文件,而Windows下不会生成无扩展名的可执行文件,导致rm会因找不到文件而报错。这时可以加上-f参数忽略该错误。


    四、测试结果

    4.1 Fedora 17 64位版下的 GCC 4.7.0

      打开终端,使用cd命令进入程序所在目录,并执行以下命令——

    make clean
    make
    ./gcc64_make
    make clean
    make RELEASE=1
    ./gcc64_make
    make clean
    make BITS=32
    ./gcc64_make
    make clean
    make RELEASE=1 BITS=32
    ./gcc64_make
    gcc --version

     

      运行结果——


    4.2 Windows XP SP3 32位版下的 GCC 4.6.2(MinGW (20120426))

      打开命令提示符,使用cd命令进入程序所在目录,并执行以下命令——

    make clean
    make
    gcc64_make
    make clean
    make RELEASE=1
    gcc64_make
    make clean
    make BITS=64
    gcc --version

     

      运行结果——


    4.3 Windows 7 SP1 64位版下的 GCC 4.6.1(TDM-GCC (MinGW-w64))

      打开命令提示符,使用cd命令进入程序所在目录,并执行以下命令——

    make clean
    make
    gcc64_make
    make clean
    make RELEASE=1
    gcc64_make
    make clean
    make BITS=32
    gcc64_make
    make clean
    make RELEASE=1 BITS=32
    gcc64_make
    gcc --version

     

      运行结果——

     

     

    参考文献——
    《跟我一起写 Makefile》. 陈皓. http://blog.csdn.net/haoel/article/details/2886
    《Makefile条件编译debug版和release版》. 功夫Panda. http://www.cnblogs.com/caosiyang/archive/2012/06/13/2548051.html
    《assert()函数用法总结》. Glroy. http://www.cnblogs.com/ggzss/archive/2011/08/18/2145017.html
    《Windows版GCC之TDM-GCC 4.5.2》. 单鱼游弋. http://www.cnblogs.com/wxxweb/archive/2011/05/30/2063434.html


    源码下载——
    http://files.cnblogs.com/zyl910/gcc64_make.rar

    展开全文
  • 3、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)4、以下为Linux下的32位C程序,请计算sizeof的值。5、请写出bool flag 与“零值”比较的if 语句6、请写出int 变量n 与“零值”比较的if...
  • 反汇编一个简单的C程序 攥写人:杨光 学号:20135233 (*原创作品转载请注明出处*) ... 实验部分(以下命令实验楼64位Linux虚拟机环境适用,32位Linux环境可能会稍有不同) 使用 gcc –S ...
  • C语言面试题(一)

    2020-03-12 15:37:52
    1、以下为Linux下的32 位C 程序,请计算sizeof 的值。 char str[] = “Hello” ; char *p = str ; int n = 10; int a2[3]; 请计算 (1)sizeof (str) = (2)sizeof § = (3)sizeof (n) = (4)sizeof (a2) = ...
  • 姓名:mqy学号:20135234 (*原创作品转载请注明出处*) ( 学习课程:《Linux内核分析》MOOC课程...(以下命令实验楼64位Linux虚拟机环境适用,32位Linux环境可能会稍有不同) 使用gcc –S –o main.s main....
  • 1.判断字符变量x是小写字母符的C语言表达式是 if(x&gt;'a' &amp;&amp; x&lt; 'z') return TRUE; 2.设有定义“char buffer[x];”,要将字符串...3.以下为Linux下的32位C程序,请计算sizeof...
  • 3_7_DOUBLEWEI

    2012-03-08 20:15:11
    以下为linux下的32位C程序,请计算sizeof的值     char str[] = “Hello” ;   char *p = str ;   int n = 10;   请计算   sizeof (str ) = 6        sizeof ( p ) = 4
  •  1996 2.0 以32位编译器核心,支持C/S数据库开发  1997 3.0 语法:加入接口(Interface)机制。IDE:首次提供了(Code Insight)  1998 4.0 语法:加入动态数组和方法覆盖等支持。IDE:增强调试能力,提供代码...
  • 在64位的linux终端通过执行命令gcc–S–omain.smain.c-m32得到对应汇编代码文件 去掉main.s中以.开头链接符号得到如下所示汇编代码: ​ 通过上面汇编代码我们知道堆栈是向增长,函数调用对应...
  •  (占用0扇区)GRUB4DOS0.4.5c/0.4.6a(FAT/FAT32/NTFS/ExFAT)分区引导扇区上的GRUB4DOS引导程序, 引导根目录下的 GRLDR.(占用4扇区)NTLDR引导程序(FAT/FAT32/NTFS)Windows2000/XP/2003引导程序, 引导根目录下的...
  • 一.Linux下的网络服务.......................................................................................................24 二.几种重要的配置文件......................................................
  • 在Qt Creator 的安装目录的qt 文件下的bin 文件夹下(我安装在了D 盘, 所以路径是D:\Qt\2009.04\qt\bin),可以找到所有的相关.dll 文件。在这里 找到mingwm10.dll 文件,将其复制到C:\WINDOWS\system 文件夹下,...
  • 100条经典C语言笔试题目整理

    千次阅读 2014-11-01 16:43:54
    2、以下为Linux下32位C程序,请计算sizeof值。
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    本文以Mandrake Linux 9.1(Kenrel 2.4.21)例,介绍Linux下的安装和登录命令。 immortality按:请用ctrl+f在本页中查找某一部分的内容或某一命令的用法。 ----------------------------------------------------...
  • ATMEL有比较便宜AT91SAM7S32 和AT91SAM7S64 专8应用产品量身定做,价格很便宜好象《3刀吧。和PHILIP21XX差不多,资料太少,项目中选还不错。 其他两家上面说了不多说了吧 2 ARM9 这个玩2410和2440多...
  • 修改BUG:高级表格在列类型数值型时,添加新行且省略标题情况,会导致程序异常。 16. 修改BUG:数值计算支持库“大数.四舍五入()”命令在最高进位时,会导致程序异常。 17. 修改BUG:办公组件支持库打印...
  • mongodb安装

    千次阅读 2013-05-08 14:55:00
    本文以32位的程序为例,去http://www.mongodb.org/下载安装程序,mongodb-linux-i686-2.4.1.tgz 把下载文件放在/home文件夹 解压文件 tar -zxvf mongodb-linux-i686-2.4.1.tgz 在/home文件夹生成了以下...
  • 过去,网络软件开发都采用C/S(client)模式,在这种模式,主要业务逻辑都集中于客户端程序,因此,必然导致以下问题: 系统安装、调试、维护和升级困难。由于客户端硬件配置可能存在差异,软件环能各不相同...
  •  error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。 exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。 19、...
  • 操作系统(内存管理)

    热门讨论 2009-09-20 12:55:25
    文将对 Linux™ 程序员可以使用内存管理技术进行概述,虽然关注重点是 C 语言,但同样也适用于其他语言。文中将您提供如何管理内存细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半...
  • ELDK使用与开发手册

    2018-03-07 10:53:39
    Makalu板串口默认配置是波特率115200/8N1(115200bps,每个字符8bit,无奇偶校验,1bit停止,无握手)。 如果你主机是Linux操作系统,我们建议你用kermit或者cu作为终端控制程序。确定硬件和软件控制流都已经...
  • 它要完成以下三件事:将分配程序标识已经初始化,找到系统中最后一个有效内存地址,然后建立起指向我们管理内存指针。这三个变量都是全局变量: 清单 1. 我们简单分配程序的全局变量 int has_...
  • 上篇基本上是第一版修订,只是做了一个调整,那便是在兼顾 Windows和Linux两方面用户基础上,默认在Linux下建立开发环境来编写我们操作系统。至于这样做原因,在本书第 2章有比较详细说明。当然,开发环境...
  • 上篇基本上是第一版修订,只是做了一个调整,那便是在兼顾 Windows和Linux两方面用户基础上,默认在Linux下建立开发环境来编写我们操作系统。至于这样做原因,在本书第 2章有比较详细说明。当然,开发环境...
  • Windows XP(包括 Windows 2000)的控制台命令是在系统出现一些意外情况下的一种非常有效的诊断和测试以及恢复系统功能的工具。小编的确一直都想把这方面的命令做个总结,这次辛苦老范给我们整理了这份实用的秘笈。 ...
  • 关,如果没有定义这个宏,系统调用 drivers/nand/nand.c nand_init();否则调用自己在 本文件中 nand_init()函数,本例使用后者。fs2410.c代码如下: #if defined(CONFIG_CMD_NAND) typedef enum { NFCE_...

空空如也

空空如也

1 2 3
收藏数 41
精华内容 16
关键字:

以下为linux下的32位c程序

linux 订阅