




已阅读5页,还剩20页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux on POWER 中的 GNU C C自:如有侵权,请告之Matthew Davis,Linux Power技术顾问,IBMGary Hook(),高级技术顾问,IBM简介:在本文中,您将学习有关Linux on POWER中GNU工具链的知识。本文将重点介绍可用于使用Linux on POWER上的GNU编译器(compiler)、链接器(linker)和加载器(loader)的一些常用选项,还将讨论GNU binutils,重点考虑特定于Linux on POWER的一些考虑事项,以及SUSE Linux Enterprise Server Version 9和Red Hat Enterprise Linux Version 4中提供的一些新特性。标记本文!发布日期:2005年6月13日级别:初级访问情况140次浏览建议:0(添加评论)平均分(共0个评分)简介GNU软件的一个显著优点是它来自严格的开发者社区,具有很好的可移植性。GNU开发工具链(toolchain)是指GNU Compiler Collection、GNU libc以及用来编译、测试和分析软件的GNU binutils。这些工具遵守PowerOpen ABI和64位的PowerPC ELF ABI Supplement规范,从而确保与其他类似工具的二进制兼容性。此外,它们是Linux on POWER的默认开发工具链。尽管GNU工具重点强调的是兼容性,但是与其他通用开发平台相比,它们在POWER架构上仍然有一些特有的区别。POWER上的指令集与其他架构有所不同,GNU toolchain负责处理这些区别。开发人员应该理解使用GNU toolchain for Linux on POWER的细节。例如,在Linux on POWER ABI和其他通用的ABI之间有所差异,开发人员必须知道在开发和移植软件时,这些差异会对自己的代码产生什么影响。值得一提的是IBM XL C/C+和Fortran编译器也会使用GNU toolchain来生成二进制文件。在这些相关的地方,我们将针对XL C/C+对GNU toolchain进行讨。通过逐步解决基本操作、特定于POWER的操作、潜在的缺陷和GNU toolchain一些新开发的特性,本文解决了GNU toolchain for Linux on POWER的软件开发和可移植性需求问题。本文还对GCC C/C+编译器、GNU链接器和汇编程序以及其他一些GNU binutils进行了探索。虽然还有很多平台都没有介绍,但GNU手册通常都会引用一些完整介绍这些主题的资料。本文并没有讨论Linux on POWER系统中其他GCC编译器、IBM XL C/C+、Fortran或Java开发的一些细节问题。我们从GCC编译器和编译驱动器入手开始介绍,依次介绍GNU链接器、GNU汇编程序和其他的binutils。本文没有明确地对GNU CLibrary进行讨论,因为特定于POWER的变体很少,应该不会影响到用户,C Library通常也被认为是GNU Toolchain的一部分。在合适的地方,我们给出了在Linux on POWER上发现的一些细微区别,为那些熟悉其他平台上的Linux或者在POWER架构上运行的AIX的开发人员提供帮助。(例如,x86和POWER之间就有一些区别:前者的汇编程序不同,后者在ELF和XCOFF ABI之间也有所不同。)回页首GNU Compiler Collection从历史传统上来说,GCC是代表GNU CCompiler,但是现在它代表GNU Compiler Collection。GCC是用于C、C+、Objective-C、Java、Fortran和Ada编程语言的一个编译器集。不过本文的讨论仅仅局限于C和C+编译器,尤其是那些GCC的操作和选项、特定于POWER架构的GCC特性操作和受GCC支持的最新特性,这些特性是随Linux for POWER架构的两个领先发行版本(Red Hat Enterprise Server AS和SUSE LINUX Enterprise Server)一起打包的。GCC的基本操作GCC的基本操作驱动着预处理、编译、汇编和链接的过程。传递给GCC的大部分选项实际上都会被重定向给工具链中的其他组件。有些选项,例如平台的选择、调试和优化标记,会为编译器和其他组件同时提供参数。输入选项编译器必须知道要处理的是哪种类型的输入数据。例如,C源程序文件的处理就与C+文件不同。对于编译器来说,有一个基本的隐式选项:源程序文件的扩展名。该选项将决定调用哪一个GCC编译器。例如,file.c调用的是C编译器,而foo.C或foo.cxx则会调用C+编译器。在GCC手册中列出了可接收源代码文件的扩展名的完整列表。下图展示了GNU Toolchain生成可执行程序或共享对象所应采取的步骤。GCC驱动器通过接受一些选项对整个toolchain间接进行控制。图1.生成可执行程序或共享对象的步骤输出选项编译器还必须知道用户期望获得哪种类型的输出。GCC驱动器可以为整个工具链的其他部分产生一些指令,从而生成最终的可执行程序,或者在生成一些中间文件时就停止。您可以使用源程序的文件扩展名或命令行选项来控制编译器的输出。表1对输出文件的选项进行了总结。表1.输出文件的选项标记操作输出格式-c汇编,但不链接.o文件-S编译,但不汇编.s文件-E预处理,但不编译对.c文件进行预处理后的结果例如,下面的命令可以对源文件hello.c进行预处理和编译,生成hello.s文件:$gcc-S hello.c所生成的文件hello.s就已经可以进行汇编生成对象文件了。另外一组输出现象影响的是编译器的输出信息,而不是输出文件的格式。de-vde选项会显示编译过程的详细信息,de-#de选项的作用是显示这些详细信息,但是并不执行这些命令。后面这个选项在创建编译脚本时尤其有用。Dialect和标准选项正如前面介绍的一样,GCC可以为很多种语言编译二进制文件。这些语言都有一些特定变体,即方言,这些变体被概括为特殊的语言约定。GCC可以接受一些选项来指定编译器所使用的方言。这包括标准选项,以及对标准限定进行修改的更具体的标记。GCC支持1990年发布的ANSI CStandard,并支持1995年所添加的扩展,以及部分支持C99修正标准。de-anside和de-stdde标记可以用来对编译器强制施加一些限制。de-anside标记会禁用GNU的扩展(请参看下面的表2),例如de inlinede和de asmde。注意其他的GNU关键字,例如de _inline_de和de _asm_de依然可以继续使用,不过这会破坏对语言标准规范的遵守。de-anside选项还会禁止在C语言中使用C+风格的注释。de-std=de选项可以指定标准等级或GNU对该标准的扩展等级。这些选项在下表中进行了总结。可以在GCC手册的3.4节中看到所有可用规范的完整列表。(请参阅参考资料。)表2.标准和标准扩展选项-std=标记标准或标准扩展c89或iso9899:1990ISO C90(与-ansi相同)iso9899:199409 ISO C90,1994 amendment c99,c9x,iso9899:1999,or iso9899:199xISO C99(并不完全支持)gnu89ISO C90 with GNU extensions(默认)gnu99或gnu9xISO C99 with GNU extensions c+98Amended 1998 ISO C+standard gnu+98Amended 1998 ISO C+standard,with GNU extensions(默认)更新标准的特性如果与以前的C标准并不冲突,那就可以使用。即使不指定de-std=de标记,情况也是如此。例如,即使不指定de-std=c99de,也可以使用de _restrict_ de,条件是它不会与所指定的旧标准冲突。有一些更加具体的标记,例如de-fno-asmde,可以用来强制是否遵从某种标准。这种类型的标记提供了一些强制关键字、通用有符号数据类型,并可以显示数据元素是保存在二进制文件的什么地方,以及其他一些信息。关于C和C+的dialect选项的完整信息,请分别参阅GCC手册的3.4节和3.5节(请参阅参考资料)。除了ANSI标准之外,GCC还支持GNU对C和C+语言的一些扩展,这些扩展在ANSI标准中并不支持。在本文中并没有对这些扩展过多进行讨论,但是如果开发人员希望自己的代码可以在其他GNU平台之间可以很好地移植,我们强烈建议开发人员要了解这些区别。在下面的清单1中给出了一个主要的扩展,这是因为这种用法非常常见,而且这是一个很好的可移植扩展的例子。GNU扩展可以使用前后的双下划线进行标记。例如,de _asm_de就是GNU对de asmde的扩展,它可以在规范中允许指令的操作数使用C表达式。现在请考虑下面这个例子,它来自于Linux内核的源代码,使用了GNU的扩展:清单1.GNU扩展static _inline_ void atomic_sub(int a,atomic_t*v)int t;_asm_ _volatile_(1:lwarx%0,0,%3#atomic_subnsubf%0,%2,%0nPPC405_ERR77(0,%3)stwcx.%0,0,%3nbne-1b:=&r(t),=m(v-counter):r(a),r(&v-counter),m(v-counter):cc);注意,在这个例子中使用了inline、de asmde和volatile关键字的另外一种可替代形式:前后都使用了双下划线。de _GNUC_de宏定义通常是为GCC进行预定义的,可以用来检查在编译代码时是否使用了对GNU扩展的支持。您可以认为这就像是在询问某一个编译器是否是GCC一样。我们建议您使用GNU的扩展关键字来检查是否存在GNU扩展,从而保证与其他编译器的可移植能力。例如:#ifndef _GNUC_#define _asm_ asm#endif这会检查是否存在GNU的扩展,如果不存在,就将后面的代码中会出现的一些关键字定义为其他编译器可以识别的关键字。当使用pedantic警告信息调用GNU编译器时,所有的GNU扩展都会被报告为警告信息。通过在所有使用GNU扩展关键字的表达式之前都加上de _extension_de关键字,可以解决这个问题。记住,这是GNU扩展及其用法的一个例子。其他编译器也有很多特性,其中有一些都是类似的非标准特性。严谨的开发计划包括对这些扩展在可移植性和性能影响方面的理解。在GCC手册中完整介绍了所有的可用扩展。(请参阅参考资料。)警告选项GCC在报告错误消息时可以使用不同的粒度。在GCC手册中的3.8节列出了警告和错误选项。请参阅参考资料。)除了能够打开或关闭每种类型的警告信息之外,还有几个元选项来控制警告和错误消息的类型。这样可以让编译器进行一些严格的检查。de-fsyntax-onlyde选项会通知编译器只关心那些真正不符合语法规发的地方。这是编译器最松散的一种状态,与de-pedanticde选项正好相反。de-pedanticde选项会产生选定的ISO标准所希望的所有警告信息。这个标记还会禁用扩展,de _keywords_de和以de _extension_de标识符开始的表达式除外。de-pedantic-errorsde选项会导致编译器编译器在碰到每个警告信息时就停止,仿佛遇到的是一个错误。de-Wallde现象会使用很多警告信息,但是只有警告信息,没有其他信息。de-Wallde究竟会产生哪些消息是一个经验问题。正如在GCC手册中介绍的一样,这个选项会启用所有有关那些某些用户认为存在问题而且很容易避免的结构的警告信息请参阅参考资料)。de-Wextrade选项则会通知编译器要报告所有其他认为可能较少出现问题的警告消息。在GCC手册的3.8节中,可以看到这些标记可以捕捉到的所有警告信息的完整清单。(请参阅参考资料。)如果一个标准可以同时使用de-std=de选项和de-pedanticde选项来测试代码是否遵守某个标准,那会很有吸引力。然而,这在实践中却并不怎样。虽然-pedantic选项实际上会对标准所希望产生警告的每个结构都产生警告信息,但是它并没有解决标准中的所有情况,因此它会替换成实际的标准遵守测试。调试选项交互式调试程序可以极大地加速代码中问题的分析。GNU Project Debugger,或称为gdb,可以在程序中任何给定的地点停止,跟踪程序的执行过程,检查程序执行过程中到底发生了什么;如果程序没有正常结束,还可以修改程序的执行过程。为了在Linux on POWER上使用gdb,必须使用调试选项来编译代码。在使用de-gde或de-ggdbde选项编译代码时,会产生DWARF和DWARF2格式的信息。de-pedanticde标记会产生DWARF信息供gdb使用。但是与大部分调试器不同,gdb可以同时使用de-gde和de-Ode标记(基本优化标记)。这是gdb特有的一个特性,在其他很多调试器中都没有这个特性,因为经过优化之后,代码的组织和执行都会发生变化。然而您也要有所准备,因为同时使用de-Ode和de-gde会可能对代码重新进行调整,这在使用调试器时会受到影响。如果给GCC传递de-ggdbde选项,GDB就可以使用意义更加丰富的DWARF 2格式。这同时会启用gdb的扩展。de-gde和de-ggbdde选项都可以接受一个级别参数(例如,de-ggdb1de标识级别1)。从直观上来看,这个级别越高(一共有3个),调试器中可以使用的调试信息就越多。这是一个折中:调试信息越多,程序就越大,执行速度也就越慢。gcc还有很多标记可以用来进行配置。这包括de gprofde和de gcovde用来搜集数据的一些选项,以及用来报告内存使用情况、优化信息的标记,等等。很多这种选项通常都是用来调试程序的,而不是用来编译代码的。最后一组调试标记是有关编译环境的。诸如de-print-file-name=de之类的选项用来验证所提供的编译环境是不是我们所希望的环境。完整的调试标记,请参阅GCC手册的3.9节。(请参阅参考资料。)优化选项GCC为C/C+代码和所支持的其他语言提供了一个后台优化器。由于Linux on POWER是一个性能很高的平台,因此对于开发人员来说,理解这个优化器的操作非常重要。注意,并不是所有的优化程序都被详细记录,而是只有那些可以使用命令行选项调用的程序会有被记录。此处,介绍的这些选现并不是从它们性能的角度进行讨论的,而是从它们的移植和调试角度进行讨论的。完整的优化选项,请参考GCC手册的3.10节。(请参阅参考资料。)分组优化标记可以让编译器使用一个标记来选择一组优化选项。它们用来对代码的性能或大小进行不同级别的优化。de-Ode或de-O1de标记是第一个组优化标记,它包括包括了一些不用多少编译时间就可以实现的优化步骤。de-O2de实现的是那些可以用来提高性能但却不会增加程序大小的优化;比较de-O3de与de-O2de,针对性能进一步进行优化,而不管是否会影响程序的大小。de-Osde是对程序的大小进行优化,即使会影响程序的性能也在所不惜。注意,并没有一个分组选项可以选择使用编译器中所有可用的性能优化选项。还有一个值得注意的事项是,对于GCC来说,de-Ode与de-O1de是完全相同的。但对于其他一些编译器来说,情况并非如此,这些编辑器包括IBM XL C/C+编译器,该编辑器也可以在Linux on POWER上使用。注意,有些选项对于编译器来说是明智的,因为它们会影响到开发的各个方面,例如调试。de-fomit-frame-pointerde就是一个这种选项,在所有的-O级别中都会启用这个选项,它会在不需要的地方删除frame指针。这个选项可以提高性能,但是这个标记的规范却并不担保实现了优化。在de-fomit-frame-pointerde的例子中,这是因为POWER平台上的堆栈指针就是一个frame指针,在使用de alloca()de机制在堆栈中动态分配内存时更是如此。在这些情况中,frame指针必须保留,以便提供反向的跟踪。这是一个启发式优化有害的例子,因此编译器会将其忽略。POWER架构中有一个分支计数寄存器,GCC有一个利用这种特性的选项:de-fbranch-count-regde。该特性利用了POWER架构可以对计数寄存器进行消耗和分支的能力,而不是采用消耗(和0作比较)和有条件的分支。在从SPARC往Linux on POWER上移植程序时,要确认启用了这个选项,因为SPARC并不支持这种特性。如果启用了de-O2de,那么de-fbranch-count-regde标记默认情况下是启用的。再次重申,在某些上下文中,编译器是不会应用这种优化的。在这种情况中,不包含函数调用的循环可以从这个选项中获益良多,但是在函数调用之前复制计数寄存器的内容所带来的负载可能会超过使用计数寄存器操作所带来的优点。预处理选项GNU的预处理器是与编译器一起对源文件进行处理,它们将源程序中的文本转换成一些指令用来进行编译。GNU预处理器是在GCC驱动器的控制之下自动进行操作的,GCC驱动器中有几个选项可以用来引导预处理器的行为。与GCC所驱动的其他工具链工具一样,预处理器可以使用de-Wpde选项向预处理器传递预定义的选项,或者使用de-Xpreprocessorde选项向预处理器显式地传递外部指定的选项。Linux on POWER没有GCC驱动器标记不能使用的预处理器选项。也就是说,我们没有什么理由去使用de-Xpreprocessorde标记,而不使用de-Wpde标记。de-undefde选项可以取消GCC或目标平台所特有的宏定义。在计划进行移植时,这非常有用,因为它可以帮助确定移植的问题。de-Mde选项通常也非常有用,因为它可以用来显示源文件所需要的所有依赖关系。这种依赖关系乐意用来检查源代码和目标平台的可用性。de-Ide选项用来包含要搜索的头文件所在的目录。如果一个依赖关系是使用de-Ide选项直接指定的,并且这个包含的路径没有成功,那么需要确保系统中已经安装了所有的更新包,并应用了所有的服务包。在较低版本的Linux on POWER上,安装程序有些问题,没有完全安装部分系统库和头文件。具体地说,Red Hat Enterprise Linux Version 3上64位的标准和兼容库就存在这个问题。RHEL3的所有问题在RHEL3 Update 3中已经得以修正。汇编程序选项与预处理器类似,GNU汇编程序也可以接受GCC能够识别和不能识别的一些选项:它们分别是de-Wade和de-Xassemblerde标记。这两个选项在后文的GNU汇编程序一节中会深入进行介绍。链接器选项链接器也可以使用类似于de-Wade和de-Xassemblerde的选项:de-Wlde和de-Xlinkerde。然而,与汇编程序选项不同,GCC驱动器可以接受一些直接对链接器行为产生影响的选项。Linux on POWER上有两种编译器:GCC和XL C/C+for Linux on POWER。由于这两种编译器都使用了GNU工具链,因此它们生成的对象是完全兼容的。对象名的清单可以作为参数传递给GCC驱动器,这会告诉链接器在链接成可执行文件时包含这个对象文件。在将多个编译器产生的对象链接为可执行程序时,这个选项非常有用。例如,可以考虑这样一个应用程序:它有很多进程组件,其中一些进程需要考虑可移植性的问题。那些对性能至关重要的代码可以使用XL C/C+进行编译,以便获得更好的性能;其余的代码可以使用GCC进行编译。这种方法最大限度地利用了编译器的性能、GNU工具链的灵活性以及可以将这两个编译器编译出来的对象链接成可执行程序的优点。GCC驱动器也可以接受一些参数,指定在链接时包含哪些库。de-lde选项可以接受库的名称,可以直接使用,也可以作为遵守POSIX规范的一个单独参数。这个参数的排序规则非常重要。库是按照指定的顺序进行搜索的。因此要确保其他库或对象所依赖的库要首先列出。虽然从理论上来说,将32位对象和64位对象链接在一起是可行的,但是目前GNU工具链还没有实现这种功能。从架构上来说,存在一些原因可以解释为什么没有实现这种功能。在POWER平台上,将整个应用程序都编译成64位的并不会降低程序的性能。代码生成选项有些与机器平台无关的选项可以影响生成代码的方式,在Linux on POWER可能会有一些特殊的影响。在将程序从Linux on Intel移植到Linux on POWER时,一个常见的变化就是对位置无关的代码的考虑。de-fpicde选项用来生成与位置无关的代码,用来在GCC中使用共享库使用。在很多平台上,这个选项是必须指定的,但是在POWER架构上,这要取决于到底是使用32位模式还是采用64位模式来编译应用程序。在64位模式中,所有的对象都是与位置无关的;而在32位模式中,您必须指定de-fpicde选项。Makefile和编译脚本在为Linux on POWER配置编译标记时,就应该考虑这个问题。堆栈的反向跟踪(stack backtrace)可以用来研究程序究竟是如何执行的。如果程序出错,那么反向跟踪可以提供一些内幕信息,说明究竟是哪个函数调用应该对这个问题负责。即使程序执行成功了,反向调用也可以用来研究程序是否是按照程序员所想象得那样执行。反向跟踪依赖于构成程序的对象中的frame指针。为对象生成frame指针,既不需要32位的ABI for Linux on POWER,也不需要64位的ABI for Linux on POWER。这会使得调试变得更为复杂,尤其是建立反向跟踪之后。frame的信息在GCC中可以使用de-fexceptionsde标记来产生。这个选项会告诉GCC来实现在使用调试程序展开堆栈时所需要的反向跟踪信息。虽然这会增加数据的大小,但是应该不会影响程序的执行。de-fexceptionsde标记对于C+程序默认是启用的,而对于C程序默认是禁用的(这可能会需要与C+对象中的异常处理程序进行交互)。因此,如果如果C代码希望处理C+程序所触发的异常,那么就必须在C程序的编译标记中加上de-fexceptionsde标记。在某些架构上,异常处理必须使用Call Frame Information指令进行管理。这些指令用来在汇编中引导异常的处理。在Linux on POWER上也可以使用这些指令,由于某些原因(例如,代码的可移植性),GCC所成城的异常处理信息还是不够的。特定于POWER架构的选项尽管GNU工具链的重点是可移植性,但是每种架构都有自己特殊的优点,开发人员必须理解如何充分地利用这些优点来实现最佳的性能。这一节将介绍GCC Linux on POWER可以接受的特定于架构的一些选项。Power架构家族和GCC POWER和PowerPC处理器从IBM 801到POWER5已经经历了一段漫长的路程,并广泛应用于各个领域:从手表到企业级的服务器无所不在。POWER是最初的架构的名字,PowerPC则起源于Apple、IBM、Motorola在1990年的合作项目。这两个系列是单独进行开发的,但是从发布以来,POWER5和PowerPC970FX的结果就领先了业界10年之上。不管在多么广泛的产品中采用,这两个架构系列所具有的通用指令都可以为代码提供很好的可移植性。虽然IBM还会不断推出更新的与POWER架构类似的芯片,但是对于GCC来说,PowerPC也包含了所有最新的处理器。架构标记GCC对于POWER架构可以使用两类扩展指令。第一个集合是为早期的RS/6000架构设计的,可以使用de-mpowerde标记启用。最近的POWER或PowerPC硬件不能使用这个标记。相反,它们使用de-mpowerpcde选项,或者它们的64位对应的选项de-mpowerpc64de,来使用现代POWER和PowerPC硬件所通用的指令。对于那些希望仍然对传统的POWER硬件提供支持的开发人员来说,要么同时使用de-mpowerde和de-mpowerpcde标记,要么一个标记也不使用,这是因为这两个标记每个都只启用了针对每一个处理器系列的扩展。如果这两个标记一个都不使用,那么就只会使用那些这两种架构所通用的那些指令。然而,要想对性能进行优化,我们建议您使用CPU特有的标记。CPU特有的架构标记CPU特有的优化标记比处理器系列标记更能提高程序的性能。这些标记会通知编译器为某个特定的CPU生成最优化的代码,不过这些代码可能并不能在其他平台上运行。de-mtune=de标记用来为一种给定的CPU指定调度参数,但是它并不会设置架构的类型、寄存器的用法以及记忆变量。这些是通过de-mcpu=de标记进行控制的。de-mtune=de标记的用法如下:$gcc-O3-mtune=power5-o foo foo.c foo2.c这个例子引导编译器将源文件foo.c和foo2.c编译成一个可执行文件,使用优化级别3,并使用为POWER5 CPU定制的调度参数。de-mcpu=de标记的用法如下:$gcc-O3-mcpu=power5-o foo foo.c foo2.c这个例子引导编译器将源文件foo.c和foo2.c编译成一个可执行文件,使用优化级别3,并使用为POWER5 CPU定制的调度参数、记忆变量、架构类型以及寄存器的用法。熟悉IBM XL C/C+的开发人员可能会注意到此处的一个差别。使用XL C/C+时,对应的标记是de-qtune=de和de-qarch=de,分别对应de-mtune=de和de-mcpu=de。de-mtune=de和de-mcpu=de都可以使用common选项,这样会选择Power和PowerPC架构处理器通用的一个指令集。例如:$gcc-O3-mtune=common-mcpu=common-o foo foo.c foo2.c这个例子会从源文件foo.c和foo2.c生成一个使用级别3进行优化的二进制文件,它可以在任何POWER和PowerPC处理器上运行,只使用了这两个架构所通用的一些指令。然而,这个二进制文件的性能可能不如使用CPU特有的标记进行优化所得到的二进制文件的性能好。另外,de powerpcde、de powerpc64de和de powerde选项都可以用来指定自己的CPU属性。这两个选项的全部合法范围包括对旧集合和新机器的支持。然而,POWER架构上的企业级Linux发行版只支持常见的de power3de、de power4de、de power5de、de 970de、de powerpcde和de powerpc64de选项,因为它们都有为企业级硬件所设计的相关指令集。请参阅GCC手册中对所支持的指令集和处理器的详细清单。(请参阅参考资料。)Vector Multimedia eXtension Vector Multimedia eXtension,简称VMX,是POWER处理器的单指令多数据(SIMD)架构的扩展。VMX是由Apple、IBM、Motorola PowerPC联合开发的,每个成员都使用一个不同的名字在市场上进行销售。IBM称之为VMX,这是这种技术最原始的代号;而Apple称之为Velocity Engine;Motorola使用的名字是AltiVec。GCC并不能识别这种技术的商标名,但是它实现了对这些处理器指令的支持,它使用AltiVec作为相关标记的名字。VMX提供了32个附加128位的寄存器来保存向量数据,这可以提供16个8位的值、8个16位的值或者4个32位的值。(注意VMX寄存器不能操作64位的值。)这些寄存器和对其进行操作的162条处理器指令就是为什么在处理特殊类型数据时VMX可以极大提高性能的原因。例如,我们可以使用向量来并行处理4个整数,这需要为此目的而特殊编写代码。虽然VMX为某些算法提供了巨大的优点,但是代码的编写必须实现向量化。不幸的是,对于编译器来说,没有什么魔力可以在后台实现自动向量化(autovectorization)。C语言中有一些指令可以对底层寄存器的选择提供控制。这些指令、原型以及宏都是在GNU的altivec.h文件中定义的,可以用来帮助实现这个任务。注意在使用IBM XL C/C+时,并不用显式地在源程序中包含altivec.h,而在使用GCC时,则必须显式地包含这个文件。GCC为AltiVec的内置函数在GCC手册的5.4节中进行了介绍。(请参阅参考资料。)向量通常需要采用新颖的方法才能形成一个好的算法,只有程序员仔细规划代码才可以实现这种功能。实际上,编写得不好的向量代码的运行速度通常比普通的代码都慢,因为它进行对齐的效率很低。VMX寄存器中处理的数据必须按照4个字进行对齐(128位),程序员要负责确保这些指令所处理的数据缓冲区都是对适当的地址进行对齐的。这需要特别注意通过在32位模式中动态内存分配所创建的缓冲区,因为它们只能保证是按照双字进行对齐的。然而,在64位模式中,malloc子系统返回的是按照4个字进行对齐的地址。在线教程Introduction to Altivec-Ten Easy Ways to Vectorize Your Code(PDF)对代码的向量化详尽地进行了介绍。(请参阅参考资料。)这篇文章讨论了向量化编码对循环展开和像素操作等所带来的巨大好处。在GCC中,VMX的功能是使用de-maltivecde和de-mabi=altivecde标记来启用的。值得注意的是,Apple的Mac OS X操作系统上的GCC也支持了它们自己的AltiVec扩展的实现,但是稍有区别。区别之一是向量声明的语法,这会影响代码在这些平台之间的迁移。在GCC for Linux on POWER中,向量位于花括号中,而在GCC for OS X中,向量则是位于圆括号()中。IBM XL C/C+可以同时支持这两种方法。有关这个问题以及VMX实现之间的差异的更多信息,请参阅About Compilers with VMX Support的Web主页。(请参阅参考资料。)表3.向量的语法VMX向量语法GCC for LinuxIBM XLC C/C+GCC for Mac OS X花括号.支持支持不支持圆括号(.)不支持对齐选项GNU toolchain for Linux on POWER可以使用数据对齐选项来调整基于POWER和PowerPC实现(例如,嵌入式处理器)的数据宽度范围,以及与其他架构之间的互操作能力。尽管默认的对齐模式是针对64位的POWER架构进行优化的,但是实际上还可以使用一种自然的对齐选项。自然对齐方式放弃了平台上根据long double类型进行对齐的优点,因此是最有效的一种内存对齐方式。不过,为了保证与其他平台上编译的对象之间的互操作能力,可能会需要使用自然对齐方式。de-malign-powerde标记为POWER架构指定优化的对齐方式,这对于GCC来说是默认的。de malign-naturalde标记用来指定自然对齐方式。TOC选项POWER处理器在执行模式中利用了一个称为Table of Contents(简称TOC)的概念。TOC是每个模块的一个定位点,用作查找该模块中全局数据、静态数据以及与位置无关的代码的一个引用点。每个模块(例如,主程序或共享库)都包含有自己的TOC。这个系统特有的属性是由64位的PowerPC ELF ABI定义的,可以使用r2寄存器进行访问。在构造TOC项时,GCC驱动器可以接受一些选项来控制链接器的行为。这些选项会在后文中的GNU链接器一节中进行介绍。回页首GNU Binutils GNU binutils包括一套用来构造和使用二进制文件所需要的工具。其中两个最为关键的binutils是GNU链接器ld和GNU汇编程序as。这两个工具是GNU工具链中的两个完整部分,通常是由GCC前端进行驱动的。然而,了解如何直接引导GNU工具链的这些组件将非常有用。本节将介绍如何控制这两个工具并选择其他binutils以便易于移植,并介绍POWER架构特有的一些功能,以及常见的一些问题和误解。GNU链接器链接是创建一个可执行程序的最后一个步骤。GNU链接器可执行程序,或者称为链接编辑器,是ld,它的角色是将对象文件合并成可执行程序,同时指定程序在运行时是如何执行的。GNU链接器使用一个命令语言脚本来控制链接过程;默认情况下,ld是由一组内部命令进行控制的,这些命令可以进行扩展或覆盖。强调可移植性和灵活性在GCC的功能中是非常明显的一条,它可以为很多不同的编译环境生成链接脚本,并向ld传递定制过的链接脚本,而不用手工进行干预。相反,在其他某些系统中,链接编辑器则很难实现这一点。例如,AIX的链接器就需要自己处理定制过程,而不是在一个预链接的编译步骤中来完成。本节将介绍GCC驱动器与链接器之间的交互,提供64位PowerPC ELF ABI的一些详细信息,并探索Linux on POWER上链接器实现的一些异常之处。由于链接器的角色是将对象代码集合在一起,并产生一个可执行模块,因此编译器驱动器会将所期望的参数传递给ld。这包括:应用程序对象文件,启动代码(在进程启动且调用main()之前所运行的代码),可能有用的包和所依赖的共享模块清单,库搜索路径(在链接时和调用时使用),已经平台所需要的实现特有的选项。ld会从左到右遍历命令行,并使用这个顺序来确定如何查找/引用哪些符号。Linux on POWER对象文件Linux on POWER使用ELF对象文件格式。这种灵活且可扩展的格式可以很好地满足平台的需要,另外还有几个特殊的段。表4列出了这些特殊的段,并对其进行了介绍:表4.特殊的段段描述.glink包含对全局链接代码的支持。模块间的函数调用(例如主程序和libc.so)需要加载一个函数描述符,其中这个描述符波包含了目标程序的地址和目标模块的TOC值。(详细信息请参看下面的TOC。)这种机制是由过程链接表(.plt)段和.glink段实现的。.toc这是TOC的一部分,每个模块都有这样一个段,它是加载全局信息使用的一个字典。作为TOC的一部分,.toc段包含了初始化信息。.tocbss其作用类似于一个.bss段,但是为TOC保存了一个尚未初始化的数据区。.got全局偏移量表(Global Offset Table)保存在.got段中,由此可以访问全局数据项(在本模块之外也是可见的)。注意,尽管数据可以加载到.toc或.tocbss段中,但是全局数据通常都是通过GOT进行寻址的。.plt包含了对模块间调用的支持。每个模块(主程序,共享对象)都包含了自己的TOC,因此也都有自己的TOC定位点。这个段的内容是由动态链接器进行填充的,它支持一个用来支持惰性符号解析的简单函数描述符集合(特例)。以下节选自64-bit PowerPC ELF ABI Supplement(请参阅参考资料):ELF处理器特有的实现通常会定义一个GOT(Global Offset Table)段用来保存位置无关的代码。有些ELF处理器特有的实现,包括32位的PowerPC Processor Supplement,定义了一个小的数据段。有时会使用相同的寄存器来对GOT和这个小的数据段进行寻址。64位的PowerOpen ABI定义了一个TOC(Table of Contents)段。TOC结合了GOT和这个小数据段的功能。您可以看到虽然32位和64位的模块提供了相同的功能,但是它们的组织方式却是不同的。由于64位模块在ELF中引入了这个TOC的概念(这来自于AIX),请考虑以下细节。内容列表正如前文中介绍的一样,每个64位模块都包含一个TOC。这就意味着您的hello,world!至少包含两个模块:main程序和libc,因此包含两个TOC。每个TOC都有一个知名的TOC定位点,这通常可以在进程运行时从寄存器2中找到;TOC寄存器的值会随着执行过程从一个模块跳到另外一个模块而发生变化。这个定位点支持访问一个模块的各种全局数据的机制(例如全局的外部变量、全局静态变量以及函数描述符)。使用TOC意味着要使用两级间接寻址。例如,要访问一个全局变量,程序要使用TOC定位点(rc2)来查找指向这个变量的指针的位置。在为一个模块外部的调用查找函数描述符时,又会发生同样的操作。不过可以将数据保存在TOC(而不是使用一个指向数据的指针),这样就避免了另外一级的间接寻找。记住,(在64位模式中)TOC中保存的每个数据不管是指针还是实际数据,都必须是8个字节或少于8个字节。现在请考虑一下这对TOC大小的影响。TOC相对寻址使用了一条指令,它限定于只能使用16位的偏移量。TOC可以保存65,536个字节,在64位模式中,这可以用来存放8,192个GOT项。对于大型应用程序来说,您可能会看到这些空间还不够用。GNU链接器有几个选项来处理超过TOC最大值的应用程序。从2.15.90版本的GNU Binutils开始,TOC如果溢出,在链接时会自动被分隔为多个TOC,但是对于一个特殊的结果,我们也可以使用在表5中列出的选项。此处,这些选项通常都是作为GCC驱动程序的参数指定的。表5.TOC选项TOC选项描述-mfull-toc这个选项是处理TOC使用的默认值。它会让链接器为可执行程序或共享对象(换而言之,就是一个模块)分配一个TOC。如果目前的64K空间不足以实现链接编辑的功能,那么链接器就会报告一个错误消息说TOC空间已经溢出了。-mno-fp-in-toc这个标记可以减少TOC中使用的空间。通常,编译器会将浮点值直接放到TOC中。(AIX/GCC开发人员可能会在自己的32位开发经验中见过这个选项。)这个标记可以防止将这些值保存到小数据段中,从而空出一些TOC空间给其他项使用。与此有关的一个标记是de no-sum-in-tocde。-mno-sum-in-toc这个标记通知GCC在运行时生成代码来计算一个地址和一个常量之和,而不是将它们的和放到TOC中。这个选项(还有de no-fp-in-tocde选项)都可以用来保留一部分TOC空间,但是所生成的代码更大、速度更慢。-mminimal-toc如果使用de no-fp-in-tocde和de no-sum-in-tocde标记还不能释放足够的TOC空间,那么就可以使用de minimal-tocde标记为每个(对象)文件生成一个单独的TOC。这会生成很多很小的TOC项。虽然这解决了TOC溢出的问题(因为现在有无穷个TOC了,每个都是64K),但是这样所生成的代码会更大、速度也更慢。使用TOC来指定函数地址的优点从根本上被遗弃了。longcall POWER指令集提供了bl(或称为分支链接)指令给模块内部的子程序调用使用。这种格式的指令可以使相对寻址范围达到64MB,或226(从调用位置开始计算)。然而,有时可能会达到这个限制,因此必须使用另外一种机制实现从A处到B处的寻址。de mlongcallde选项就可以使用函数指针机制(用于模块间的调用)。换言之,每个函数调用都类似于一个模块外调用。这突破了64M相对地址的限制,代价是可能会稍微增加函数调用的负载。它还支持longcall的用法,其优先级比de-mlongcallde选项更高。de longcall(1)de会对所有后续函数声明都应用这个属性;de longcall(0)de可以停止对后续函数应用这个属性。对于开发人员来说,幸运的是GNU for Linux on POWER上的链接器可以快速生成需要实现这个解决方案所需要的代码。正如AIX链接器一样,在64位模式中,并不需要担心de mlongcallde。这个特性对于32位的GNU链接器来说是不可用的,包括SLES9和RHEL4。然而,在可以自由下载的GCC源代码中包括了这个特性。如果您有一个32位的应用程序在SLES9或RHEL4上运行,它调用的位置超过了64MB的限制,那么您就只能重新编写代码,或者将其编译为64位模式。由于32位和64位应用程序在Linux on POWER运行时是可以并存的,因此在这种情况中,我们建议您将其编译为64位模式。链接器脚本GNU链接器提供了一种命令语言,可以用来控制链接编辑的操作。虽然对于那些早已熟悉GCC开发工具的人来说,这并没有什么奇怪;但是对于AIX开发人员来说,他们需要理解AIX和Linux on POWER上所存在的区别。尽管(XCOFF)对象文件的定义和AIX链接器的行为都是自动的,但是GNU ld可以对如何以及在何处合并对象文件的各个段进行更加灵活的控制。让我们来考虑一下这种脚本的基本属性。GNU ld会自动对一个内部脚本进行操作。您可以添加或替换这些内部命令。在特定的条件下(例如,使用只出现一次的命令),必须使用定制的链接器脚本提供完整的命令集;否则,可以使用脚本为链接器添加常用的操作。在添加定制操作时,您可以在命令行中对链接器脚本简单地进行命令(链接器假设所有非对象文件都是链接器脚本)。在替换链接器默认的(内部)命令时,您可以使用de-Tde或de-script=de选项。检查默认的链接器脚本的工作可以通过一个链接器选项发送到标准错误设备上。使用一个简单的hello,world程序,加上verbose选项,您就可以捕获这些内部的命令:$cc-o hello hello.c-Wl,-verbose 2hello.ldscript这会创建一个256行的脚本,它可以处理最常见的链接情况(我们期望如此)。AIX开发人员应该注意这是de bbindcmds:de选项的结果,不过我们早已说过,AIX链接器要更加自动化。因此您可能会问:为什么
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025企业股权质押借款合同模板
- 公司短期入股合同范本
- 2025股权质押借款合同范本
- 租赁加工设备合同范本
- 殴打赔偿合同范本
- 上海临时用工合同范本
- 全款买房定金合同范本
- 2025解除合同协议书模板
- 农村门窗购买合同范本
- 山场木材运输合同范本
- 外研版八年级下册英语知识点、语法总结
- GB/T 18910.4-2024液晶显示器件第4部分:液晶显示模块和屏基本额定值和特性
- 催收物业费培训课件
- 收购资产计划书
- 意大利米兰整骨技术的案例分享-之评估篇
- 煤矿岗位标准化作业流程
- LOI意向书中英文模板
- 传染病学课件:新发和再现传染病
- 成人癌性疼痛护理指南解读
- 浅谈实现小学语文单元整体教学的有效策略
- 手动液压叉车安全技术培训
评论
0/150
提交评论