Linux on POWER 中的 GNU C/C 工具链(7)
2008-02-23 05:41:12来源:互联网 阅读 ()
GNU 汇编程式
汇编程式的任务是接受使用人们可读的格式编写的输入文档,并生成包含机器级指令的文档。然后将一个或多个文档中的对象代码传递给链接器,后者负责生成可执行模块。GNU 汇编程式能够支持很多平台;虽然每个平台都能够使用很多命令行选项,但是也有一些平台只能支持一些系统特有的特性。
和其他平台相同, GCC 驱动器能够接受使用高级语言编写的输入文档 -- 他能够产生汇编代码,然后再使用 GNU 汇编程式转换成目标代码。幸运的是,大部分研发人员都无需直接使用汇编语言,GCC 驱动器会为研发人员隔离这些具体的实现细节。然而,当需求提高时,理解如何和汇编程式进行交互会很有用;GCC 能够让汇编程式接受一些使用逗号分隔的选项来支持这种功能,他使用的语法为 -Wa [选项]。例如:
$ gcc -O -Wa,-Z,-v foo.c -o foo
这条命令使用 GCC 驱动器将文档 foo.c 编译成二进制文档 foo,并打印汇编程式的版本,即便碰到错误也是如此。
虽然您可能会发现在 Linux on POWER 上,GCC、链接器、汇编程式等的用法都和其他平台很类似,但是汇编语言本身却有很大的区别。注意一些细节问题:RISC 架构和 CISC 架构相比,通常需要多条指令来完成一个特定的任务;POWER 也不例外。假如您查看一下 GCC 所生成的汇编代码,就会注意到其中会有很多 load 和 store 指令,同时更有其他类型的指令。熟悉汇编语言的一种有用的方法是使用高级语言(例如 C)来编写代码,并使用 GCC 的 -S 选项来保存所生成的汇编文档,或使用 objdump 对目标代码进行反汇编。
二进制文档的组织
在上文中有关 ld 的 “GNU 链接器” 一节中,我们曾介绍了 ELF 对象文档的一些段;这些段就是链接器最感兴趣的地方,他们就是用来生成可执行模块的。然而,几乎编译器所生成的每个对象文档中都有这些有趣的段,他们构成了您的程式的各个部分(使用对象代码格式),如 表 6 所示,因此链接器知道如何对他们进行合并,从而创建一个程式或共享模块。
表 6. 二进制文档的组织
段 描述.text 可执行指令(汇编代码所转换成的指令)通常就保存在这个段中。只读常量(例如字符串常量)也能够在这个段中找到。这个平台上的文本段是只读的,这就意味着程式不能对自己进行修改;这个属性允许可执行文档的文本区能够在此程式的任何运行实例之间共享。例如,bash shell 的每个正在运行的拷贝都会共享 bash 文档的 .text 段的一份拷贝。
.data 这就是为可执行程式保存初始化过的数据的地方。从定义中我们能够看出,数据段是可读写的,进程能够对这个段中的内容(在内存中)如何操作进行完全控制。举例来说,C 语言中那些使用编译时的值进行初始化的全局变量都能够在这个段中找到。
.bss bss 段中包含了尚未初始化的数据;这个段不在对象文档中占据任何空间,但是他定义了一段内存区域,他们在运行时被清零。C 语言中那些没有给定初始化值的全局变量在程式启动时都被定义为 0;这些变量都能够在 bss 段中找到。
链接编辑器会从指定的对象文档中搜集任何的 .text 段的内容,并合并他们来创建可执行程式的代码,任何的 .data 段都被搜集起来用来创建最终的数据段,任何的 .bss 段被合并起来创建最终的 bss 段。还要注意,每个可执行模块都包含自己的段;例如,共享模块就有自己的 .text 段和 .data 段。
汇编版本的 Hello, World!
考虑一下这个 32 位的非 PIC 汇编版本的 "Hello, World!" 他首次出现在 Hollis Blanchard 所编写的“PowerPC assembly: Introduction to assembly on the PowerPC” 一文中(developerWorks,2002 年 7 月):
清单 2. ia32 assembly
.data # section declaration - variables only
.align 3 # make double-word aligned
msg:
.string "Hello, world!\n"
len = . - msg # length of our dear string
.text # section declaration - begin code
.align 3 # ensure alignment
.global _start
_start:
# write our string to stdout
li 0,4 # syscall number (sys_write)
li 3,1 # first arg: file descriptor (stdout)
# second arg: pointer to message to write
lis 4,msg@ha # load top 16 bits of &msg
addi 4,4,msg@l # load bottom 16 bits
li 5,len # third argument: message length
sc # call kernel
# and exit
li 0,1 # syscall number (sys_exit)
li 3,1 # first argument: exit code
sc # call kernel
注意数据段位于最上面,其中定义了 printf 要打印的字符串 -- 他能够于 .text 段中的内容相同简单,因为他是被当作一个常量来对待的。
文本段是有许多指令组成的,因为这个程式要使用几个系统调用(而不是使用 libc 中的程式,例如 printf)来完成工作。write 系统调用是在寄存器 0 中指定的,目标文档是在寄存器 3 中指定的,指向字符串的指针是在寄存器 4 中指定的,字符串的长度是在寄存器 5 中指定的。在输出字符串之后,又要将寄存器领配置为 exit 的系统调用,并传递值 "1" 作为退出代码。
这个例子会被传递给汇编程式,从而创建一个对象文档;所生成的对象文档又被传递给链接器,后者生成一个可执行文档的映像。这一系列操作对于具备 AIX 和 Linux 背景的程式员来说会感觉很熟悉。
汇编中的 CFI 指令
假如您发现自己要将 C 程式和汇编程式合并在一起,那么就能够使用 CFI(Call Frame Information)指令来使用异常处理的支持。这些指令会生成一些堆栈展开信息,这样使用汇编编写的程式就能够和使用 C 或其他语言编写的程式很好地结为一体了。
GNU 汇编程式中所支持的 CFI 指令在“CFI support for GNU assembler (GAS)” Web 页面上进行了周详的介绍(请参阅 参考资料)。对于 Linux on POWER 来说,CFI 指令所感兴趣的是 start_proc 和 end_proc。当把这些指令放到汇编代码中的每个函数两端时,就会生成 .eh_frame 信息。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇: GCC 4.0 的新特性
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash
