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

ARM裸机程序研究 - 编译和链接

ARM裸机程序研究 - 编译和链接

1. Linux下的二进制可执行文件。
    如果世界很简单,那么二进制可执行文件也应该很简单,只包括CPU要执行的指令就可以了。可惜,世界并不简单……。Linux下的二进制可执行文件(以下简称可执行文件),也并不是只包括了指令,还包括了很多其他的信息,比如,执行需要的数据,重定位信息,调试信息,动态链接信息,等等。 所有这些信息都按照一个预定的格式组织在一个可执行文件里面。Linux下叫ELF可执行文件。
    举一个最简单的例子,假设有下面这个程序:
    int main()
    {
         return 0;
    }
    这个连“Hello World”都不能打印的程序,自然是什么都做不了。当然,如果只是把这个文件保存为文本文件,是无论如何也执行不了得。还需要两个重要的步骤:编译和链接,才能把它转换为可执行的ELF格式。
    先来看看编译,也就是把C语言翻译成机器语言的过程。很简单,用下面的命令:
    gcc -c test.c -o test.o     <假设源文件名为test.c>
    -c 参数告诉gcc,我们只需要编译这个文件,不需要连接。这样就会生成一个test.o文件。这个文件包含了上面源程序翻译后的机器指令和其他一些信息。这个test.o也属于ELF格式。如何看test.o里面的内容,可以用objdump命令:
    objdump -x test.o
    会有类似下面的输出:

[html] view plaincopy

  • test.o:     file format elf32-i386  
  • test.o  
  • architecture: i386, flags 0x00000010:  
  • HAS_SYMS  
  • start address 0x00000000  

  • Sections:  
  • Idx Name          Size      VMA       LMA       File off  Algn  
  •   0 .text         0000000a  00000000  00000000  00000034  2**  
  •                   CONTENTS, ALLOC, LOAD, READONLY, CODE  
  •   1 .data         00000000  00000000  00000000  00000040  2**2  
  •                   CONTENTS, ALLOC, LOAD, DATA  
  •   2 .bss          00000000  00000000  00000000  00000040  2**2  
  •                   ALLOC  
  •   3 .comment      0000002b  00000000  00000000  00000040  2**0  
  •                   CONTENTS, READONLY  
  •   4 .note.GNU-stack 00000000  00000000  00000000  0000006b  2**0  
  •                   CONTENTS, READONLY  
  • SYMBOL TABLE:  
  • 00000000 l    df *ABS*  00000000 test.c  
  • 00000000 l    d  .text  00000000 .text  
  • 00000000 l    d  .data  00000000 .data  
  • 00000000 l    d  .bss   00000000 .bss  
  • 00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack  
  • 00000000 l    d  .comment       00000000 .comment  
  • 00000000 g     F .text  0000000a main  


    test.o 主要包含了文件头和节。"节“是ELF文件的重要组成部分,一个节就是某一类型的数据。objdump的-x参数会打印出test.o中所有的节,也就是上面的"Sections". 其中.text节包含了可执行代码,.data节包含了已经初始化的数据,.bss节包含了未初始化数据。其他的节先忽略掉(其实是因为我也了解不多⋯⋯)


    如果要看看test.o是不是包含源文件的编译结果, 可以将其反汇编查看。使用objdump -d 命令。 默认情况下,该命令只返回目标文件的可执行部分,在这里就是.text节。 objdump -d test.o 得到的结果如下:
[plain] view plaincopy

  • test.o:     file format elf32-i386  


  • Disassembly of section .text:  

  • 00000000 <main>:  
  •    0:   55                      push   %ebp  
  •    1:   89 e5                   mov    %esp,%ebp  
  •    3:   b8 00 00 00 00          mov    $0x0,%eax  
  •    8:   5d                      pop    %ebp  
  •    9:   c3                      ret  


   可以看见这里就是一些栈的操作,没有做什么事情。当然,源码里面确实也没做什么事情。这个.o文件还不能执行,还需要经过链接。通常,我们可以用gcc一步完成编译链接过程,也就是我们最常用的:
    gcc test.c -o test


    如果再次用objdump -d 反编译生成的test文件:
    objdump -d test
    额……会发现多了一堆东西。这是因为,c程序通常都是链接到c运行库的。在main函数执行前,c运行库需要初始化一些东西。这也说明,main()并不是程序的真正入口点。真正的入口点可以用objdump -f 查看test的文件头:


[plain] view plaincopy

  • test:     file format elf32-i386  
  • architecture: i386, flags 0x00000112:  
  • EXEC_P, HAS_SYMS, D_PAGED  
  • start address 0x080482e0  
继承事业,薪火相传
返回列表