文章目录
链接脚本
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/>.