java中的导入gnu,GNU链接脚本使用

GNU链接脚本使用

链接脚本主要作用是描述输入文件的section是如何映射到输出文件的内存布局中。通俗的讲法就是编译完成后的各个obj文件,按照哪种顺序放与bin的哪个地址中;同时将运行时变量符号与VMA关联。

主要参考了下边几个博客:

1. 链接脚本的 __attribute__ 属性

2. GNU-ld链接脚本浅析

使用案例

1. 将变量或函数存放在用户定义的区域

主要目的是可以将变量或函数,运行时链接到用户定义的区域中,比如SRAM,某些CPU比直接放在FLASH中运行快(不一定,比如STM32,片内FLASH在ICODE总线上,指令预取功能使能将实现类似多级流水线的操作,SRAM则不再ICODE上,需要 "取指->译码->执行"无法加速。

主要使用链接脚本语法有:

MEMORY命令定义存储区域,通过输出section描述的 >REGION 显式的将该段限定到具体的存储区域。 如下:最后的区域为stm32f746ng最后64k,用来存放测试的变量。

MEMORY

{

RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K

FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 960K

USER_AREA(rx) : ORIGIN = 0x80F0000, LENGTH = 64K

}

在链接脚本的SECTIONS 段内添加下列描述:

_siusrdata = LOADADDR(.usrdata); /* LOADADDR描述了.usrdata段的LMA,可在程序中声明:extern char _siusrdata; 使用时只能只用_siusrdata的地址:char *src = &_siusrdata; src实际等于0x80F0000*/

.usrdata :

{

. = ALIGN(4);

_susrdata = .; /* create a global symbol at usrdata start;VMA地址*/

*(.usrdata) /* .usrdata sections */

*(.usrdata*) /* .usrdata* sections */

. = ALIGN(4);

_eusrdata = .; /* define a global symbol at usrdata end */

} >RAM AT> USER_AREA

主程序中在声明处使用 attribute属性声明section, 使用extern 声明链接脚本中的变量:

int data_usrarea __attribute__((section(".usrdata"))) = 6666 ;

extern char _siusrdata,_susrdata,_eusrdata;

使用时:

printf("usrarea LMA = %X, VMA = %X\r\n", &_siusrdata, &_susrdata);

printf(usrdata addr = %X, value=%d\r\n", &data_usrarea,data_usrarea);

打印结果如下:

usrarea LMA = 80F0000, VMA = 20000070

usrdata addr = 20000070, value=-536140031

地址是对的,但是value怎么是错的,实际是因为,我们自定义的区域并沒有自己将数据加载到正确的VMA地址。而系统默认的.data区域是由系统启动时加载的,不同的工程实现方法不同,如stm32 cubumx 生成的makefile工程中是这样做的

Reset_Handler:

ldr sp, =_estack /* set stack pointer */

/* Copy the data segment initializers from flash to SRAM */

movs r1, #0

b LoopCopyDataInit

CopyDataInit:

ldr r3, =_sidata

ldr r3, [r3, r1]

str r3, [r0, r1]

adds r1, r1, #4

LoopCopyDataInit:

ldr r0, =_sdata

ldr r3, =_edata

adds r2, r0, r1

cmp r2, r3

bcc CopyDataInit

ldr r2, =_sbss

b LoopFillZerobss

这段汇编的目的就是加载.data区至SRAM中,即已初始化的全局变量区。我们也可以在汇编中添加自己的代码,但是最好还是在main函数中去实现不破坏原有文件的完整性。

char *srcdata_ptr = &_siusrdata;

char *dstdata_ptr = &_susrdata;

while(dstdata_ptr < &_eusrdata)

{

*dstdata_ptr++ = *srcdata_ptr++;

}

添加上述代码完成.usrdata区域从 LMA处加载到VMA处,以后就可以快乐的运行了,打印信息如下。

usrarea LMA = 80F0000, VMA = 20000070

usrdata addr = 20000070, value=6666

思考,有了这个功能,实际上我们可以将程序分段更新,如定义一些配置参数存放在特定区域,然后在更新时可以直接这个区域更新。更加灵活的完成在线升级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值