谷动谷力

 找回密码
 立即注册
查看: 1456|回复: 0
打印 上一主题 下一主题
收起左侧

LD链接脚本浅析

[复制链接]
跳转到指定楼层
楼主
发表于 2023-10-13 18:22:49 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
LD链接脚本浅析

链接脚本主要描述如何将输入文件中的各个部分映射到输出文件中,并控制输出文件的内存布局。

对于复杂的工程我们一般都采用链接脚本来告知Linker输出文件的布局,对于简单功能的工程,也可以通过链接选项设置。

以E907SDK内的链接脚本gcc_csky.ld为例,对链接脚本的基本构成及相关语法做简要介绍

1- 链接脚本的基本构成

一般分成两部分,MEMORY命令定义了当前平台的内存分布;SECTION命令定义了输出文件在内存的布局。

2- 链接脚本具体构成

2.1 MEMORY

MEMORY命令主要定义了当前平台上的内存,比如在E907 SDK内,smartL平台内对地址空间的分配如下,



在示例工程内,定义了4个不同的内存区域,分别用来存放代码段和不同的数据段。

MEMORY
{
I-SRAM : ORIGIN = 0x0        , LENGTH = 0x40000   /* I-SRAM  256KB /
D-SRAM : ORIGIN = 0x20000000 , LENGTH = 0xc0000   / D-SRAM  768KB /
O-SRAM : ORIGIN = 0x50000000 , LENGTH = 0x800000   / off-chip SRAM 8MB /
SRAM   : ORIGIN = 0x60000000 , LENGTH = 0x20000   / on-chip SRAM 128KB */
}

通过MEMORY命令中的ORIGIN和LENGTH关键字定义了内存的起始地址和长度。

为了便于区分每一段的作用,在示例工程的ld文件内还通过REGION_ALIAS为内存分配了别名。

REGION_ALIAS("REGION_TEXT",    I-SRAM);
REGION_ALIAS("REGION_RODATA",  I-SRAM);
REGION_ALIAS("REGION_DATA",    D-SRAM);
REGION_ALIAS("REGION_BSS",     D-SRAM);

2.2- 可执行文件起始点

Linker可以通过几种不同的方式来决定可执行文件的入口地址,即第一条被执行指令的地址。Linker将按以下方式循序搜寻,如找到相关定义就停止搜寻并采用该入口点。



  • linker选项”-e”定义


  • 链接脚本内通过ENTRY命令定义


  • 目标定义的关键符号,对于大多数目标来说是start


  • ”.text”段内的第一个byte地址


  • 地址0x0



在示例工程中,通过在链接脚本中用ENTRY定义文件入口,

ENTRY(Reset_Handler)

2.3- 输出文件的布局

通过SECTIONS命令定义输出文件的内存布局。

在我们的示例工程中,主要包含以下的文件段,代码段(.text),只读数据段(.rodata),数据段(.data),全局变量段(.bss),堆数据段(.user_heap)。

以定义.data输出段为例。通过*.data : { }*定义了.data 段,data段的VMA和LMA地址不一样,通过”> REGION_DATA”指定了运行时该段的地址,”AT > REGION_RODATA”指定了加载时该段的地址。如果该段的LMA和VMA相同,则只需要通过”> REGION_DATA”指定即可。

在.data定义的段内,定义了.data段在内存中如何放置。

对于常见的一些符号,参见注释。

.data : {

. = ALIGN(0x4) ; /强制地址对齐,返回当前地址,此处是4-byte对齐/
__sdata = . ;  /定义符号 sdata,其值为当前地址。”.”表示当前地址/
data_start = . ;
data_start = . ;
KEEP(startup.o(.vectors*))   /保留startup.o文件名字包含vectors的段,即中断向量表,并将其放在.data段的起始位置/
*(.got.plt)
*(.got)
(.gnu.linkonce.r)
*(.data)
(.data)
*(.data1)
(.data.)
......
__edata = .;
data_end = .;
. = ALIGN(0x4) ;
} > REGION_DATA AT > REGION_RODATA      /运行时,.data 段将放置在REGION_DATA,存储时将存放在REGION_RODATA区域,在初始化时,将对数据进行搬移/

在startup.S文件内可以看到相关数据搬移代码。

/* Load data section */
la      a0, __erodata         //end of .rodata(REGION_RODATA, I-SRAM)
la      a1, data_start   //start of .data(REGION_DATA, D-SRAM)
la      a2, data_end    //end of .data
bgeu    a1, a2, 2f           //拷贝完成,跳出循环
1:
lw      t0, (a0)

sw      t0, (a1)

addi    a0, a0, 4
addi    a1, a1, 4
bltu    a1, a2, 1b    //a1<=a2, 拷贝未完成,继续循环
//REGION_DATA(VMA):.data运行时的地址
//REGION_RODATA(LMA):.data加载时的地址,
//.rodata 放在 REGION_RODATA, 范围是__srodata ~ __erodata
//.data 放在 .rodata后面, 拷贝到 __data_start开始的区域

2.4- 堆栈地址初始化

示例工程中,在链接脚本内对堆做了内存地址分配。

._user_heap : {
. = ALIGN(0x4) ;
__heap_start = .;    /定义了符号,值为堆的起始地址,可以在后续堆的操作中引用/
. += __min_heap_size;  /堆的大小做了预留/
. = ALIGN(0x4) ;
} > REGION_BSS AT > REGION_BSS

在实际工程创建中,可以根据系统需求,在连接文件内进行堆或栈的初始化操作。

具体的链接脚本可以参考SDK内的对应脚本

+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-11-24 17:19 , Processed in 0.315388 second(s), 42 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表