weiqi7777

静态程序编译链接与装载(一)问题的引入以及工具介绍

0
阅读(1544)

关于程序的编译链接与装载,有一些问题一直没有弄得很清楚。这次花了不少精力,把这些问题,好好研究了一番。在学习的过程中,熟读了<<程序员的自我修养-链接、装载与库>>这本书,收获良多。强烈推荐这本书。

此次系列文章,是针对静态编译,动态编译太多复杂,目前仍有很多问题,没有解决。

在开始之前,带有如下的一些问题:

  • 程序是如何编译成可执行程序?
  • 跨模块之间,如何知道其他模块的函数以及变量地址?
  • linux下,可执行程序elf,长什么样?
  • 对于任意一个elf,如何查看该elf的信息?
  • 反汇编中,程序的地址,以及符号,是如何得到的?
  • 为什么程序,以section为单位进行组织?
  • section与segment的区别是什么?
  • ELF中的VMA与LMA的区别是什么?链接视图与执行视图区别是什么?
  • 在EDA仿真中,elf,是如何装载到环境中去运行的?
  • 在linux中,elf程序,是如何装载到内存中运行的?
  • 链接脚本的AT,MEMORY关键字,到底有什么用?

    通过查看资料,以及自己做实验,对这些问题,有了清晰的答案。希望通过本系列博文,也能让大家,对这些问题,也有清晰的答案。

    一、工具介绍

    首先是介绍下,之后会用到的一些工具:

  • aarch64工具链,包括如下:
    • aarch64-none-elf-gcc:arm-gcc编译器
      • -S参数:将源程序转换成.s
      • -c参数:将源程序转换成.o
    • aarch64-none-elf-as: 汇编器,将.s转换成.o
    • aarch64-none-elf-ld: 链接器,将 .o 链接成elf
    • aarch64-none-elf-objdump: 反汇编,将elf反汇编
  • readelf工具,用于查看elf文件内容
    • -a: 查看elf文件的所有信息
    • -h: 查看elf文件的头信息
    • -l: 查看program段信息
    • -S: 查看section段信息
    • -s: 查看符号表信息
    • -r: 查看可重定位表信息
  • gvim工具,-b参数,表示查看的文件是二进制文件
    • :%!xxd,该命令,在gvim中查看二进制数据
  • hexdump工具,直接查看二进制文件

    借助以上的一些工具,就便于之后分析.o文件,.elf文件。

    二、示例程序

    首先,先介绍使用的示例程序。

    两个程序:

  • a.c:
  • 2个全局变来那个,一个有赋初值,一个没有赋初值
  • 2个局部静态变量,一个有赋初值,一个没有赋初值
  • 调用了b.c中的swap函数
  • b.c:
  • 引用a.c中的一个全局变量
  • 定义了一个全局变量
  • 定义了swap函数,供a.c调用
  • 在swap函数中,更改了a.c中定义的全局变量

    程序如下图所示:

    之后,便以编译这两个c文件,成最终的可执行程序out.elf为例,来进行详细的分析。

    Makefile脚本如下:

    后面的 .o和.elf文件的分析,就是基于这个示例程序进行分析的。