qemu-基础篇——链接脚本(五)

链接脚本

qemu - 基础篇——arm 裸机调试环境搭建 (二) 中使用 -Ttext 可以指定链接地址,但是如果需要链接多个文件需要手动指定,很不方便,这时候就可以使用链接脚本。

声明

本文部分内容来自网上,侵删。

程序编译过程

一般而言,程序编译经历四个阶段,链接是编译的最后一步,无论是在 PC 上编译代码,还是在 PC 上使用嵌入式 gcc 工具交叉编译嵌入式代码,编译过程都是如下几步。

  • 预处理(Preprocessing,预处理器 cpp,作用:.c/s -> .i
  • 编译(Compilation),编译器 ccl ,作用:.i -> .s
  • 汇编(Assembly),汇编器 as,作用:.s -> .o
  • 链接(Linking),链接器 ld,作用:.o -> elf 可执行文件

链接脚本

链接过程是将各式各样的 .o 文件链接为一个文件的过程。链接脚本描述链接器如何将这些输入文件 (.o) 文件映射为一个输出文件的,并且定义了输出文件的 memory layout。几乎所有的链接脚本都是在做这些事情。

在使用 ld 的时候,通过 -T 选项,可以使用自己写的链接脚本完成链接过程,例如 -T link.lds,如果为指定,会使用默认的链接脚本。

arm-none-linux-gnueabihf-ld --verbose 可以查看默认的链接脚本

链接脚本相关概念

  • 连接器将输入文件组合为一个单独的输出文件。输入文件和输出文件的数据类型是我们熟知的 object file format。每个文件被称为 object file。输出文件不仅仅可以称为 object file,有时也会叫他 executable 可执行文件,出于我们描述的目的,我们依旧称他为 object file。

  • 每一个 object,有很多其他的信息,但是最重要的是 section 的列表。这也是着重要谈的。大多数时候,我们会把输入的 Object 文件里面的 section 称之为 input section。链接输出的单个 Object 文件里面的 section 称之为 output section。

  • 在 Object 文件中,每一个 section 有一个名字还有对应的 size 信息,几乎所有的 section 都有一个数据关联块(associated block of data)。

  • section 可以被标记为 loadable,意味着当输出文件运行起来的时候,这个 section 的 content 信息应当被加载到 memory 中。

  • section 没有 content 信息,并且被标记为 allocatable,意味着会有一块内存会被创建,但是却没有任何内容放在上面,程序运行起来的时候无需要加载任何信息到 memory 中。

  • 如果 section 既不是 loadable 也不是 allocatable,那么意味着它包含了一些 debug 的信息。

  • 链接脚本的输出文件是一个 Object 文件,里面包含了多个 section,包括 loadable 的 section,也包括 allocatable section。每一个 section 包含两个地址,分别是 VMA 以及 LMA。

  • VMA 是 virtual memory address,LMA 是 load memory address。大多数两类地址是相同的,但是在嵌入式开发中不大相同,LMA 是 flash 地址,而 VMA 是将 flash 加载到 ram 里面运行的 ram 地址。

  • 例如下述的嵌入式 C 代码,显然全局变量 test_data1 在编译成 bin 的时候是烧写进 flash 的,但是程序运行起来之后 a 的数据是需要加载进 ram 的,因为 a 是一个变量,不排除程序运行过程中代码会改变他的值。因此 flash 会存放他的初始值,运行的时候从 ROM 加载到 RAM,他在 ROM 中的地址是 LMA,在 RAM 中的地址是 VMA。

    test_data1 = 1;
    
  • 每个 object 文件拥有一个 symbols 列表,里面包含的 symbol 可以是被定义或者未被定义的。每一个 symbol 有名字和地址。如果是 C/C++ 程序编译出来的. o 文件。所有的函数和全局静态变量都处于 defined 的状态,在输入文件中引用的每个未定义的函数或全局变量都将成为一个未定义的符号。

格式

  • 链接脚本是 text 文件,
  • 空格会被忽略,
  • 一般以 .lds.ld 结尾
  • 注释使用 /* xxx */ 类似 C 语言的注释

示例

假设连接器的输入 object 里面只有代码 .text 段,只读数据 .rodata段,数据 .data 段,未初始化的 data 段 .bss

假设代码希望放在 0x00900000, 数据希望放在 0x80000000。下面代码将会描述这样的链接脚本。

SECTIONS
{
    
    
    . = 0x00900000;
    .text :
    {
    
    
        *(.text)
        *(.text*)
    }

    .rodata :
    {
    
    
        *(.rodata)
        *(.rodata*)
    }

    . = 0x80000000;
    .data :
    {
    
    
        *(.data)
        *(.data*)
    }

    .bss :
    {
    
    
        *(.bss)
        *(.bss*)
    }
}
  • 使用 . 给 memory map 定位地址。如果不使用 . 来指定开始地址,那么将会从 0 开始分配地址。
  • 第二行定义了一个 output scetion,名字叫 .text,后面花括号里面的内容是其他 .o 文件里面作为输入的 section 名称,其他文件的输入 section 会被存放到该 output section 中。
  • * 是通配符的含义,可以匹配任意文件名 ,*(.text) 意味着所有输入文件中的 .text 段。
  • 因为 location counter 被配置为 0x00900000,因此链接器会把 text 的内容存放到 0x00900000 中。
  • 后面的几行与 text 段同理,…rodata,.data 段和. bss 段都是从 0x8000000 开始的,并且是紧紧挨在一起的。
  • 链接器会保证每个段的对齐方式,以此作为依据来增加 loaction counter。

程序段

嵌入式程序中常有如下几个段

.text

代码段

.text.xxx

使用 -O 优化时,通常会有此段。

.rodata

只读变量段
.rodata.xxx

使用 -O 优化时,通常会有此段。

.data

存放已经初始化,且数据不为 0 的数据

.data.xxx

使用 -O 优化时,通常会有此段。

.bss

未初始化的 data 段,存放初始化为 0 的数据
.bss.xxx

使用 -O 优化时,通常会有此段。

.comment

存放一下通用信息,例如编译器版本等,例如

Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c63  .GCC: (GNU Toolc
 0010 6861696e 20666f72 20746865 20412d70  hain for the A-p
 0020 726f6669 6c652041 72636869 74656374  rofile Architect
 0030 75726520 31302e33 2d323032 312e3037  ure 10.3-2021.07
 0040 20286172 6d2d3130 2e323929 29203130   (arm-10.29)) 10
 0050 2e332e31 20323032 31303632 3100      .3.1 20210621.  

.ARM.attributes

存放 ARM 相关属性信息,例如

Contents of section .ARM.attributes:
 0000 41340000 00616561 62690001 2a000000  A4...aeabi..*...
 0010 05372d41 00060a07 41080109 020a030c  .7-A....A.......
 0020 01120414 01150117 03180119 011a021c  ................
 0030 011e0622 01                          ...".           

.debug_info

调试信息段,使用 -g 编译参数才有此段

常用命令

  • objdump -h (header)指令查看 object 文件里面的 section,以及对应的 VMA 和 LMA。
  • objdump -t (symbol table)指令可以查看对应 object 的 symbols
  • objdump -d (disassemble) 反汇编可以执行文件
  • objdump -s 显示所有段的全部内容
arm-none-linux-gnueabihf-objdump --help

返回结果如下:

Usage: arm-none-linux-gnueabihf-objdump <option(s)> <file(s)>
 Display information from object <file(s)>.
 At least one of the following switches must be given:
  -a, --archive-headers    Display archive header information
  -f, --file-headers       Display the contents of the overall file header
  -p, --private-headers    Display object format specific file header contents
  -P, --private=OPT,OPT... Display object format specific contents
  -h, --[section-]headers  Display the contents of the section headers
  -x, --all-headers        Display the contents of all headers
  -d, --disassemble        Display assembler contents of executable sections
  -D, --disassemble-all    Display assembler contents of all sections
      --disassemble=<sym>  Display assembler contents from <sym>
  -S, --source             Intermix source code with disassembly
      --source-comment[=<txt>] Prefix lines of source code with <txt>
  -s, --full-contents      Display the full contents of all sections requested
  -g, --debugging          Display debug information in object file
  -e, --debugging-tags     Display debug information using ctags style
  -G, --stabs              Display (in raw form) any STABS info in the file
  -W[lLiaprmfFsoORtUuTgAckK] or
  --dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
          =frames-interp,=str,=str-offsets,=loc,=Ranges,=pubtypes,
          =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
          =addr,=cu_index,=links,=follow-links]
                           Display DWARF info in the file
  --ctf=SECTION            Display CTF info from SECTION
  -t, --syms               Display the contents of the symbol table(s)
  -T, --dynamic-syms       Display the contents of the dynamic symbol table
  -r, --reloc              Display the relocation entries in the file
  -R, --dynamic-reloc      Display the dynamic relocation entries in the file
  @<file>                  Read options from <file>
  -v, --version            Display this program's version number
  -i, --info               List object formats and architectures supported
  -H, --help               Display this information

 The following switches are optional:
  -b, --target=BFDNAME           Specify the target object format as BFDNAME
  -m, --architecture=MACHINE     Specify the target architecture as MACHINE
  -j, --section=NAME             Only display information for section NAME
  -M, --disassembler-options=OPT Pass text OPT on to the disassembler
  -EB --endian=big               Assume big endian format when disassembling
  -EL --endian=little            Assume little endian format when disassembling
      --file-start-context       Include context from start of file (with -S)
  -I, --include=DIR              Add DIR to search list for source files
  -l, --line-numbers             Include line numbers and filenames in output
  -F, --file-offsets             Include file offsets when displaying information
  -C, --demangle[=STYLE]         Decode mangled/processed symbol names
                                  The STYLE, if specified, can be `auto', `gnu',
                                  `lucid', `arm', `hp', `edg', `gnu-v3', `java'
                                  or `gnat'
      --recurse-limit            Enable a limit on recursion whilst demangling.  [Default]
      --no-recurse-limit         Disable a limit on recursion whilst demangling
  -w, --wide                     Format output for more than 80 columns
  -z, --disassemble-zeroes       Do not skip blocks of zeroes when disassembling
      --start-address=ADDR       Only process data whose address is >= ADDR
      --stop-address=ADDR        Only process data whose address is < ADDR
      --no-addresses             Do not print address alongside disassembly
      --prefix-addresses         Print complete address alongside disassembly
      --[no-]show-raw-insn       Display hex alongside symbolic disassembly
      --insn-width=WIDTH         Display WIDTH bytes on a single line for -d
      --adjust-vma=OFFSET        Add OFFSET to all displayed section addresses
      --special-syms             Include special symbols in symbol dumps
      --inlines                  Print all inlines for source line (with -l)
      --prefix=PREFIX            Add PREFIX to absolute paths for -S
      --prefix-strip=LEVEL       Strip initial directory names for -S
      --dwarf-depth=N        Do not display DIEs at depth N or greater
      --dwarf-start=N        Display DIEs starting with N, at the same depth
                             or deeper
      --dwarf-check          Make additional dwarf internal consistency checks.
      --ctf-parent=SECTION     Use SECTION as the CTF parent
      --visualize-jumps          Visualize jumps by drawing ASCII art lines
      --visualize-jumps=color    Use colors in the ASCII art
      --visualize-jumps=extended-color   Use extended 8-bit color codes
      --visualize-jumps=off      Disable jump visualization

arm-none-linux-gnueabihf-objdump: supported targets: elf32-littlearm elf32-littlearm-fdpic elf32-bigarm elf32-bigarm-fdpic elf32-little elf32-big srec symbolsrec verilog tekhex binary ihex plugin
arm-none-linux-gnueabihf-objdump: supported architectures: arm armv2 armv2a armv3 armv3m armv4 armv4t armv5 armv5t armv5te xscale ep9312 iwmmxt iwmmxt2 armv5tej armv6 armv6kz armv6t2 armv6k armv7 armv6-m armv6s-m armv7e-m armv8-a armv8-r armv8-m.base armv8-m.main armv8.1-m.main arm_any

The following ARM specific disassembler options are supported for use with
the -M switch:
  reg-names-raw            Select raw register names
  reg-names-gcc            Select register names used by GCC
  reg-names-std            Select register names used in ARM's ISA documentation
  force-thumb              Assume all insns are Thumb insns
  no-force-thumb           Examine preceding label to determine an insn's type
  reg-names-apcs           Select register names used in the APCS
  reg-names-atpcs          Select register names used in the ATPCS
  reg-names-special-atpcs  Select special register names used in the ATPCS
  coproc<N>=(cde|generic)  Enable CDE extensions for coprocessor N space
Report bugs to <https://bugs.linaro.org/>.

猜你喜欢

转载自blog.csdn.net/tyustli/article/details/130588581