×
嵌入式 > 嵌入式开发 > 详情

Andes SAG应用实例

发布时间:2020-06-17 发布时间:
|

嵌入式开发中,系统软件设计特别是各种存储器的规划是必不可少的一个环节,它也直接体现在链接脚本的撰写上。因链接脚本的语法相对复杂和篇幅较大,前期撰写和后期维护对工程师来讲难度都很大,但对使用AndesCore做开发的工程师来讲,AndesSAG是一大福音,它提供简单直观的描述语言替代了复杂的链接脚本。我们收到的反馈也证明,越来越多的工程师开始采用AndesSAG替代linker,之前我们有一篇技术文章对SAG的语法格式做了介绍并说明如何使用,本文将展示四个实际工程开发的例子,以帮助广大开发者更好的熟悉和理解AndesSAG,同时可以作为开发时的参考。

1.将函数和变量指定到特定地址

第一个例子是如何将函数和变量的地址指定到一个特定的地址,例子中的地址指运行地址——VMA。有这样要求的原因有很多,诸如SOC的运行地址空间不连续,或者需要高效使用某一块效率很高的存储器等情况。解法分为两步:一,在SAG文件中添加自定义的section,将此section的VMA设定到指定地址;二,在C语言中,将需要改变的函数和变量用特定的语法放在自定义的section。

图表1是在SAG中自定义section的例子。第1行关键词USER_SECTIONS表示后面接的这几个sections都是由使用者自定义的sections。

图表1.Samp1.sag文件

图表1中,第4行至8行表示从0x0开始的区域是只读区,包含程序代码(.textsection)及只读数据段(.rodatasection)。第9行,MYRAM0部分表示.mysection0的VMA从0x00014000开始。以此类推,MYRAM1和MYRAM2部分各自表示mysection1和.mysection2的VMA起始位置。第21行的RAM1里放的是.data及.bsssections,执行时期会从0x00010000开始,源代码中须做到将data的LMA地址copy至VMA位置,可以使用__data_lmastart与__data_start来寻址。

指定函数放在自定义section里,在源代码的对应处要使用__attribute__((section(".mysection0")))语法,完整写法请参考图表2a。图表2b是另外一种写法。

图表2a.指定函数放在自定义section

图表2b.指定函数放在自定义section的另一种写法

指定全局变量gdata1放在自定义section.mysection1里,在源代码的对应处要使用__attribute__((section(".mysection1")))语法,完整语法请参考图表3。

图表3.指定变量放在自定义section

将函数和变量这样指定后,编译后的adx(elf)文档可以清晰看到对应Section的LMA与VMA如图表4.

图表4.ELFHeader

2.实现IVB在运行时切换

有一个客户需要系统在开机与正常运行时能有不同的ISR,即是同一个中断的服务函数在开机和正常运行时会不一样。对于这个问题的解法有很多,我们今天介绍是其中一种解决方法:设置一个新的VectorTable,新的VectorTable会跳到新的ISR;通过SAG将新的VectorTable指定到一个特定地址上;当程序开机完成,需要正常运行时,只需要去修改IVBASE(ir3)这个寄存器。

所以完成这个例子的重点是如何在汇编代码中建一个新的vectortable并指定到自定义的section中。表5是实例的写法:

图表5指定Vectortable到自定义section

图表5重点是是第一行,.section是用来定义非标准的section,.nds32_aa即为非标准section的名称,”a”表示allocable,“x”表示executable.因为Andes的标准vectortable一般会放在.nds32_initsection,所以新的vectortable放.nds32_aa里,名称不一样能区别就好。接下来是让新的自定义section.nds32_aa运行在特定地址上,如图表6所示。

图表6指定自定义section到特定地址

这样新的vectortable的首地址会被固定到0x10000的位置,当程序开机完成,只需要将IVBASE设定到这个地址,那么当有中断进来,就会跳到新的VectorTable中。

3.指定一个或几个C档的所有section到指定地址

上两个例子有共同点是通过编程将某一段程序放到自定义section,区别在于一个是指定C语言函数和变量到自定义section,一个指定汇编函数到指定的section,都需要改动源代码。然而对于一些应用场景,比如不提供源代码只有编译好的.o或者.a文件,如果想将.o档里的section指定到特定地址运行,这个时候该如何做呢?请参考图表7A的写法,这表示我们要将hello.o的只读区,包含程序代码(.textsection)及只读数据段(.rodatasection)放在LMA及VMA在0x10000的地址上。

图表7A指定自定义section到特定地址

在整个project中如果将每个.o档都列出来,那么整个SAG文档将变得难以阅读,而且在给后期维护带来麻烦,这种解法不好。如果使用者只需要排除几个.o檔,对于熟悉GNUlinker的读者会想到“EXCLUDE_FILE”这一语法,让使用者可以很方便地在Linker中实现这一需求。AndesSAG也与时俱进地引入这一语法。图表7B正是这样一个例子,它将uart.o中所有的section都放到一个特定地址去运行,而其它的保持不变。

图表7B支持“EXCULDE_FILE”

4、如何避免LMA或VMA的偏差

在前三个例子中,都是举例去说明如何实现将程序的某一部分的LMA或者VMA固定在某一个特定地址上,这是对链接这一动作的基本要求。嵌入式软件工程师需要知道,当某一section的LMA与VMA不相等时,那么在程序初始化时需要将这一section从LMA的地址拷贝到VMA的地址。初始化做拷贝时,这些section的LMA和VMA都是在链接脚本中赋值的,代码中只是去做引用。

AndesSAG同样可以给变量赋值LMA和VMA,但如何赋值呢,是不是一个一个紧凑地排列下来?答案很显然是不。很多工程师都知道,数据存放有Alignment的要求,比如4Byte的Word其存放的首地址需要是4ByteAlign;程序呢,因为优化的需要,比如在Andes编译器在-Os等级下,函数的首地址同样强制4ByteAlign。既然有对齐的要求,就必然有gap存在,当然这里举出的对齐因素只是让读者了解到链接器对某一section的LMA或VMA的数值确定不只是单纯累加,AndesSAG能自动处理好大部分对齐状况。但在一些较复杂的例子中,需要给AndesSAG更多指示,让它工作正确。

首先,我们来看图表7所举出的例子,这一行“LOADADDRNEXT__uart_lmastart”,有一个关键字“NEXT”。它的作用就是让SAG知道,这个变量的取值是下一个Section的开始,而不是上一个Section的结束。为了让读者更明白所表示的含义,我们首先来看依照图表7的SAG编译出的elf(adx)档header信息,如图表8:

图表8adxheader

可以看到.text_*uart.o的LMA应该是0x1c60,上一个section(.bss)的LMA结束地址应为:0x1c48+0x10=0x1c58,所以为了清晰地让SAG知道__uart_lmastart代表.text_*uart.o的LMA开始而不是.bss的LMA结束,我们应该用NEXT去修饰它。

然后,我们再来看图表9的例子,这个例子中,使用“LMA_FORCE_ALIGN”的原因是因为可能某一个section的size只有2Byte(不是4Byte的整数倍),但下一个section的VMA起始地址需要4ByteAlign,这时就会出现冲突,为解决冲突,AndesSAG引入这一关键字“LMA_FORCE_ALIGN”,强制让LMA与VMA用同一个值去做Align。

图表9“LMA_FORCE_ALIGN”example

我们用图表9的SAG例子去编译对应的project,可以看到图表10中section.sbss_b的LMA已经被从0x1d42调整到0x1d44。

图表10“LMA_FORCE_ALIGN”的效果

5、结语

Andes提供通俗易用的SAG工具帮助工程师替代了复杂的链接脚本,可以大大提高在Andescore平台上的软件开发效率。本文从实际例子出发,介绍了AndesSAG工具如何快速解决工程实际问题,说明了AndesSAG强大而且容易上手。然而工具的功能越强大,也就需要工程师多加深入了解功能设计的缘由,这也正是最后一个例子展现出来的道理,即是透彻了解就可以熟能生巧。希望广大读者能熟练掌握AndesSAG这样一把利器,在软件开发中发挥四两拨千斤的作用。

参考文档:

1:BSP321programmingguidelinkgenerator

2:TheGNULinkerManual

 


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ST Bluetooth®5.2认证系统芯片问市.延长电池续航