Blog icon indicating copy to clipboard operation
Blog copied to clipboard

aarch64体系结构与编程3--GNU LD链接器

Open jason--liu opened this issue 4 years ago • 0 comments

链接器Linker

  • 链接器(Linker)是一个程序,将一个或多个由编译器或汇编器生成的目标文件外加 库链接为一个可执行文件。
  • GNU Linker采用AT&T链接脚本语言
  • 官方文档:最新版本v2.34
  • 链接脚本最终会把一大堆编译好的二进制文件(.o文件)综合生成最终二进制可执行文件,也就是把每一个二进制文件整合到一个大文件中。这个大文件有一个总的text/data/bss段。

ld命令

  • aarch64-linux-gnu-ld:arm64版本的链接器命令
  • 命令参数查看: aarch64-linux-gnu-ld --help 常用参数: -T: 指定链接脚本 -Map:输出一个 符号表 文件 -o: 输出最终可执行二进制文件

基本概念

  • 输入段(input section),输出段(output section)
  • 每个段包括 name和大小
  • 段的属性
    • loadable:运行时会加载这些段的内容到内存中
    • allocatable:运行时不会加载段的内容,
  • 段的地址:
    • VMA(virtual memory address):虚拟地址,运行地址
    • LMA (load memory address):加载地址
    • 通常 ROM的地址为加载地址,而RAM的地址为VMA

链接脚本命令

  • ENTRY(symbol):设置程序的入口函数。
  • 链接程序有如下几种方式来确定入口点:
    • 使用-e参数
    • 使用ENTRY(symbol)
    • 在.text的最开始的地方
    • 0地址
  • INCLUDE filename:引入filename的链接脚本
  • OUTPUT filename:输出二进制文件,类似在命令行里使用“-o filename”
  • OUTPUT_FORMAT(bfd): 输出BFD格式
  • OUTPUT_ARCH(bfdarch):输出处理器体系结构格式

符号赋值

  • 符号也可以像 C语言一样赋值 image
  • “.” 表示 location counter,表示当前位置 image

符号的引用

  • 高级语言(C语言) 常常需要引用 链接脚本定义的符号
  • 在C语言里,定义一个变量并初始化变量。 例如
    • 编译器会在符号表中定义了一个符号foo -编译器会在内存中为符号foo存储100.
  • 在链接脚本中定义一个变量 链接器仅仅在符号表里定义这个符号,没有分配内存来存储变量的值
  • 访问链接脚本定义的变量:访问的是变量的地址,不能访问变量的值 image
  • 我们可以在每个段中设置一些符号,以方便C语言访问每个段的起始地址和结束地址 image

section命令

  • SECTIONS命令:告诉链接器如何把输入段(input sections)映射到输出段(output sections),以及如何在内存中摆放这些 输出段。 image
  • 输出section的描述符: image

LMA加载地址

  • 每个段有VMA (虚拟地址,运行地址)以及 LMA(加载地址)
  • 在输出段描述符中使用 “AT” 来指定 LMA
  • 如果没有通过”AT”来指定 LMA,通常 LMA = VMA
  • 构建一个基于ROM的映像文件常常会设置输出段的虚拟地址和加载地址不一致

例子

下面的链接文件会创建3个段,其中

  • text段的虚拟地址和加载地址为0x1000
  • mdata段的虚拟地址设置为0x2000,但是通过AT符号指定了加载地址是在text段的结束地址,_data指定了data段的虚拟地址为0x2000
  • bss段的虚拟地址是在0x3000 image
  • data段的加载地址和链接地址(虚拟地址)不一样,因此程序的初始化代码需要把data段从ROM的加载地址复制到SDRAM中的虚拟地址中
  • 数据段加载地址在_etext起始的地方,数据段的运行地址是在_data起始的地方,数据段的大小为“_edata - _data”,下面这段代码把数据段从_etext起始的地方复制到_data起始的地方。

常见的内建函数(builtin functions)

  • ADDR(section) : 返回前面已经定义过的段的VMA地址 image

  • ALIGN(n) : 返回 下一个与n字节对齐的地址,它是基于当前的位置(location counter)来计算对齐地址的。

  • 注意这里是n个字节,而不是2^n个字节。 image

  • SIZEOF(section):返回一个段的大小 image

  • MAX(exp1, exp2)/ MIN(exp1,exp2):返回两个表达式的最大值或者最小值

jason--liu avatar Nov 29 '20 10:11 jason--liu