ARM64基础10:GNU LD链接器介绍

链接器Linker:是一个程序,将一个或多个编译器或汇编生成的目标文件,及依赖库,链接为一个可执行文件。

GNU Linker采用AT&T链接脚本语言;

链接脚本文件:包含ld程序链接的规则,其决定输出可执行文件的内存布局;

LD命令:arm64版本的连接器是aarch64-linux-gnu-ld
查看命令参数:

aarch64-linux-gnu-ld --help

LD命令的参数有很多,常用的如下:

$(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -Map xxx.map -o $(BUILD_DIR)/xxx.elf  $(OBJ_FILES)

常用参数:
-T: 指定连接脚本;
-Map:输出一个符号表文件;
-o: 输出最终可执行二进制文件;

基本概念

输入段(input section),输出段(output section)
每个段包括name和大小;

段的属性:
loadable:运行时会加载这些段内容到内存中;
allocatable:运行时不加载段的内容;

段的地址:
VMA(virtual memory address):虚拟地址,运行地址;
LMA(load memory address):加载地址
通常ROM的地址为加载地址,而RAM地址为VMA;

链接脚本命令

Entry(symbol): 设置程序的入口函数;
GNU-AS程序入口点有以下几种:
a.使用-e参数;
b.使用ENTRY(symbol);
c.在.text的最开始的地方;
d.0地址;

INCLUDE filename:引入filename的链接脚本;

OUTPUT filename:输出二进制文件,类似命令行的"-o filename"

OUTPUT_FORMAT(bfd):输出BFD格式;
OUTPUT_ARCH(bfdarch): 输出处理器体系架构格式

OUTPUT_ARCH(aarch64)
ENTRY(_text)

赋值符号

符号可以像C语言一样赋值;
"."表示当前位置;

symbol = expression;
symbol += expression;
symbol -= expression;
symbol *= expression;
symbol /= expression;
symbol <<= expression;
symbol >>= expression;
symbol &= expression;
symbol |= expression;

符号的引用

在C语言定义一个变量并初始化,编译器会分配一个符号,且在内存中分配空间存储;

在链接脚本中定义的变量,仅仅是在符号表里定义这个符号,没有分配存储空间;

xxx.ld
start_of_ROM = .ROM;
end_of_ROM = .ROM + sizeof(.ROM)

可以在每个段中设置一些符号,以方便C语言访问每个段的起始地址和结束地址;

C语言中,对链接脚本里定义的符号引用
extern char start_of_ROM[],end_of_ROM[];
char buf[4096];
memcpy(buf, start_of_ROM, end_of_ROM - start_of_ROM);//引用的是地址

SECTIONS命令

告诉链接器如何把输入段(input sections)映射到输出段(output sections),决定输出程序的内存布局;

输出section的描述符:
在这里插入图片描述

LMA加载地址

每个段都有VMA和LMA;
在输出段描述符中使用“AT”指定LMA, 如果没有指定,通常LMA=VMA;
构造一个基于ROM的映像文件,常常会设置输出端的虚拟地址和加载地址不一样;

SECTIONS
{
	.text 0x1000:{*(.text)_etext=.;}
	.mdata 0x2000:
	AT(ADDR(.text)+SIZEOF(.text))  //指定加载地址
	{
		_data=.;
		*(.data);
		_edata=.;  //_data和_edata只是一个符号,用来记录mdata段的VMA地址
	}
	.bss 0x3000;
	{
		_bstart=.;
		*(.bss)*(COMMON);
		-bend=.;
	}
}

mdata段的加载地址和链接地址不一样,因此程序初始化代码需要把data段内容复制到SDRAM中的虚拟地址中;
在这里插入图片描述

常见的内建函数(builtin functions)

ADDR(section):返回前面已经定义过的段的VMA地址;
ALIGN(n): 返回下一个与n字节对齐的地址;
SIZEOF(section):返回一个段的大小;
MAX/MIN(exp1,exp2):返回较大/较小值;

实例练习:设置代码段的LMA!=VMA

TEXT_ROM = 0X90000;
SECTIONS
{
	/*
	 * -->location, current addr
	 * 	0x80000 is entrance address
	 */
	. = 0x80000,
	/*
	 * first instruction
	 **/
	_text_boot = .;
	.text.boot : { *(.text.boot) }  
	_etext_boot = .;

	/*
	 * code segment
	 */
	_text = .;
	.text : AT(TEXT_ROM)
	{ *(.text) }
	_etext = .;

	/*
	 * readonly data segment
	 */
	_rodata = .;
	.rodata : AT(ADDR(.rodata))
	{ *(.rodata) }
	_erodata = .;

	/*
	 * data segment
	 */
	_data = .;
	.data : { *(.data) }
	_edata = .;

	/*
	 * bss segment
	 * 8bytes algine
	 */
	. = ALIGN(0x8);
	_bss = .;
	.bss : { *(.bss*) } 
	_ebss = .;


	/*
	 * alloc a page memory, store page table
	 * aligne 4096
	 */
	. = ALIGN(4096);
	init_pg_dir = .;
	. +=4096;
}

在启动代码,将代码段从LMA(ROM地址)拷贝到VMA(SDRAM地址)

master:
/*
 * copy code segment from rom(LMA) TO ram(VMA)
 */
	adr x0, TEXT_ROM
	adr x1, _text
	adr x2, _etext
1:
	ldr x4, [x0], #8
	str x4, [x1], #8
	cmp x1, x2
	b.cc 1b


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值