Andes SAG 应用实例

Facebook
Twitter
LinkedIn

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

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

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

图表 1. Samp1.sag 文件

  图表 1 中,第 4 行至 8 行表示从 0x0 开始的区域是只读区,包含程序代码(.text section)及只读数据段(.rodata section)。第 9 行,MYRAM0 部分表示.mysection0 的 VMA 从 0x00014000 开始。以此类推,MYRAM1 和 MYRAM2 部分各自表示mysection1 和.mysection2 的 VMA 起始位置。第 21 行的 RAM1 里放的是.data 及.bss sections,执行时期会从 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. ELF Header

2. 实现 IVB 在运行时切换
  有一个客户需要系统在开机与正常运行时能有不同的 ISR,即是同一个中断的服务函数在开机和正常运行时会不一样。对于这个问题的解法有很多,我们今天介绍是其中一种解决方法:设置一个新的 Vector Table,新的 Vector Table 会跳到新的 ISR;通过 SAG 将新的 Vector Table 指定到一个特定地址上;当程序开机完成,需要正常运行时,只需要去修改 IVBASE (ir3)这个寄存器。
  所以完成这个例子的重点是如何在汇编代码中建一个新的 vector table 并指定到自定义的 section 中。表5是实例的写法:

图表 5  指定 Vector table 到自定义 section

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

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

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

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

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

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

图表 7B 支持“EXCULDE_FILE”

4. 如何避免 LMA 或 VMA 的偏差
  在前三个例子中,都是举例去说明如何实现将程序的某一部分的 LMA 或者VMA 固定在某一个特定地址上,这是对链接这一动作的基本要求。嵌入式软件工程师需要知道,当某一 section 的 LMA 与 VMA 不相等时,那么在程序初始化时需要将这一 section 从 LMA 的地址拷贝到 VMA 的地址。初始化做拷贝时,这些 section 的 LMA 和 VMA 都是在链接脚本中赋值的,代码中只是去做引用。 
  Andes SAG 同样可以给变量赋值 LMA 和 VMA,但如何赋值呢,是不是一个一个紧凑地排列下来?答案很显然是不。很多工程师都知道,数据存放有Alignment 的要求,比如 4 Byte 的 Word 其存放的首地址需要是 4 Byte Align;程序呢,因为优化的需要,比如在 Andes 编译器在-Os 等级下,函数的首地址同样强制 4 Byte Align。既然有对齐的要求,就必然有 gap 存在,当然这里举出的对齐因素只是让读者了解到链接器对某一section 的 LMA 或 VMA 的数值确定不只是单纯累加,Andes SAG 能自动处理好大部分对齐状况。但在一些较复杂的例子中,需要给 Andes SAG 更多指示,让它工作正确。
   首先,我们来看图表 7 所举出的例子,这一行“LOADADDR NEXT
uart_lmastart”,有一个关键字“NEXT”。它的作用就是让 SAG 知道,这个变量的取值是下一个 Section 的开始,而不是上一个 Section 的结束。为了让读者更明白所表示的含义,我们首先来看依照图表 7 的SAG 编译出的 elf (adx)档 header信息,如图表 8:

图表 8      adx header

  可以看到.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 只有 2 Byte(不是 4 Byte 的整数倍), 但下一个 section 的 VMA 起始地址需要 4 Byte Align,这时就会出现冲突,为解 决冲突,Andes SAG 引入这一关键字“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 工具帮助工程师替代了复杂的链接脚本,可以大大提高在 Andes core 平台上的软件开发效率。本文从实际例子出发,介绍了Andes SAG 工具如何快速解决工程实际问题,说明了 Andes SAG 强大而且容易上手。然而工具的功能越强大,也就需要工程师多加深入了解功能设计的缘由, 这也正是最后一个例子展现出来的道理,即是透彻了解就可以熟能生巧。希望广大读者能熟练掌握 Andes SAG 这样一把利器,在软件开发中发挥四两拨千斤的作用。

参考文档:
 1: BSP321 programming guide link generator
 2: The GNU Linker Manual