CS_APP 读书笔记:链接(1)AT&T 汇编、目标文件、链接器、ELF 的基础概念

401 阅读4分钟

本篇仅记录最基础的内容,后续笔记中会逐渐补充完善。

AT&T 汇编

主流的 x86 汇编语言格式有两种,分别是 Intel 格式(用于 Windows、MSDOS )和 AT&T 格式(多用于 Linux、UNIX )

因为大学的微机原理课讲的基本都是 Intel 格式,所以这里先记录一下 AT&T 格式的常见区别

  • 注释以 # 开头,伪指令以 . 开头;
  • 寄存器名要加前缀 % ,立即数要加前缀 $
  • 操作数字长一般直接作为后缀连接在指令名的后面。b:byte(8),w:word(16),l:long(32)。eg. pushl %eax
  • 左边的是源操作数,右边的是目的操作数。eg. addl $1, %eax
  • ljump $section. $offset :远跳转,相当于 Intel 的 jump far section:offset
  • lcall $section, $offset :远调用,相当于 Intel 的 lcall $section, $offset
  • lret $stack_adjust :远返回,相当于 Intel 的 ret far stack_adjust

寻址方式

  • 直接寻址(绝对寻址):movl $0x8000, %eax:地址 0x8000 处的值写 eax

  • 间接寻址:movl (%eax), %ebx :将 eax 值作为地址查内存,将对应内存地址的值写 ebx;

  • 变址寻址:

    • 变址寻址:将两个寄存器中的值的和加上一个常数得到最终地址,并将地址上的值写寄存器:

      movl $0x8000, %eax	# 立即数寻址
      movl $0x4, %ebx		# 立即数寻址
      movl (%eax, %ebx), %ecx		# 变址寻址,将 0x8004 (8000+4)的值写 ecx
      movl 4 (%eax, %ebx), %ecx	# 变址寻址,将 0x8008 (8000+4+4)的值写 ecx
      
    • 比例变址寻址:一个寄存器中的值加上另一个寄存器中的值,乘上一个比例因子,再加上一个常数得到最终地址,并将地址上的值写寄存器

      movl $0x2000, %eax
      movl $0x2, %ebx
      movl (, %eax, 4), %ecx	 # 0x8000 (即 0x2000 * 4) 的值写 ecx
      movl 6 (, %eax, 4), %ecx # 0x8006 (即 0x2000*4+6 ) 的值写 ecx
      movl 6 (%ebx, %eax, 4), %ecx # 0x8008 (即 0x2 + 0x2000*4 + 0x6) 的值写 ecx
      
  • 基址寻址:以寄存器中的值作为基址,加上一个值作为最终地址

    movl 4 (%eax), %ebx
    

目标文件

目标文件分为以下三种:

  • 可重定位目标文件:一般后缀名为 .o。含二进制代码和数据,可以和其他可重定位目标文件合并,生成可执行目标文件;
  • 可执行目标文件:简称可执行文件,一般后缀名为 .out。含二进制代码和数据,可以被直接复制到内存中执行;
  • 共享目标文件:特殊的可重定位目标文件。可在程序加载或程序运行过程中被加载进内存并链接。

目标文件由不同的代码和数据节(Section)组成,每个 Section 是一个连续的字节序列。

使用汇编器(as)对汇编语言进行汇编后,会生成可重定位目标文件。再经过链接器链接后,就能生成可执行文件。

目标模块与目标文件

  • 目标模块(Object Module)指的是一个字节序列
  • 目标文件(Object File)指的是一个以文件形式存在硬盘上的目标模块

链接器

目标文件中定义和引用符号(Symbol),每个符号对应一个函数 / 全局变量 / 静态(Static)变量。

链接器(ld)有两个任务:符号解析和重定位。

1. 符号解析

目标文件中定义和引用符号(Symbol),每个符号对应一个函数 / 全局变量 / 静态(Static)变量。

符号解析的工作,就是将每个符号的引用与该符号的定义联系起来

2. 重定位

链接器将每个符号的定义与一个内存位置相关联,然后再重定位 Section,修改所有对符号的引用至指向前面关联过的内存位置。

重定位由链接器根据汇编器产生的重定位条目的详细指令进行。

链接器的工作,说白了就是【组装程序】:一个稍大的软件都会被拆成若干个模块进行开发,将这些模块组装成一个整体就是链接。链接可以分为静态链接和动态链接,前者是把用到的代码模块拼装成一个单一的可执行文件,在运行的时候被整个加载进内存;后者是让各个模块单独存在,在需要运行的时候再分别加载进内存,到内存中再成为一个整体来运行。

更详细的内容会在后续笔记中展开。

ELF:Executable and Linkable Format

从 ELF 文件的第一个字节开始,一个 ELF 文件由数个节(Section)组成,节及节的内容如下图所示