UNIX/Linux 平台可执行文件格式分析(2)

  8:动态连接器把控制传递给程序,从 ELF 文件头部中定义的程序进入点开始执行。在 a.out 格式和ELF格式中,程序进入点的值是显式存在的,在 COFF 格式中则是由规范隐含定义。

  从上面的描述可以看出,加载文件最重要的是完成两件事情:加载程序段和数据段到内存;进行外部定义符号的重定位。重定位是程序连接中一个重要概念。我们知道,一个可执行程序通常是由一个含有 main() 的主程序文件、若干目标文件、若干共享库(Shared Libraries)组成。(注:采用一些特别的技巧,也可编写没有 main 函数的程序,请参阅参考资料 2)一个 C 程序可能引用共享库定义的变量或函数,换句话说就是程序运行时必须知道这些变量/函数的地址。在静态连接中,程序所有需要使用的外部定义都完全包含在可执行程序中,而动态连接则只在可执行文件中设置相关外部定义的一些引用信息,真正的重定位是在程序运行之时。静态连接方式有两个大问题:如果库中变量或函数有任何变化都必须重新编译连接程序;如果多个程序引用同样的变量/函数,则此变量/函数会在文件/内存中出现多次,浪费硬盘/内存空间。比较两种连接方式生成的可执行文件的大小,可以看出有明显的区别。

  a.out 文件格式分析
  a.out 格式在不同的机器平台和不同的 UNIX 操作系统上有轻微的不同,例如在 MC680x0 平台上有 6 个 section。下面我们讨论的是最"标准"的格式。
  a.out 文件包含 7 个 section,格式如下:
  exec header(执行头部,也可理解为文件头部)
  text segment(文本段)
  data segment(数据段)
  text relocations(文本重定位段)
  data relocations(数据重定位段)
  symbol table(符号表)
  string table(字符串表)
  执行头部的数据结构:
  struct exec {
  unsigned long a_midmag; /* 魔数和其它信息 */
  unsigned long a_text; /* 文本段的长度 */
  unsigned long a_data; /* 数据段的长度 */
  unsigned long a_bss; /* BSS段的长度 */
  unsigned long a_syms; /* 符号表的长度 */
  unsigned long a_entry; /* 程序进入点 */
  unsigned long a_trsize; /* 文本重定位表的长度 */
  unsigned long a_drsize; /* 数据重定位表的长度 */
  };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/28562.html