ARM64基础10:GNU LD链接器介绍 您所在的位置:网站首页 摄像头lD是什么意思 ARM64基础10:GNU LD链接器介绍

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

2024-07-02 06:52| 来源: 网络整理| 查看: 265

链接器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; 符号的引用

在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


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有