Skip to content

Commit 3e37e02

Browse files
committed
doc: Add demo about how to use OVERLAY in linker scripts
Signed-off-by: qiujiandong <qiujiandong@nucleisys.com>
1 parent 776aaa8 commit 3e37e02

File tree

4 files changed

+169
-1
lines changed

4 files changed

+169
-1
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# 在链接脚本中使用`OVERLAY`命令
2+
3+
## 问题说明
4+
5+
CPU Core内的SRAM具有速度快,容量小,面积大的特点。在嵌入式系统中,这部分Core内的RAM很可能无法放下所有的函数。
6+
为了解决这个问题,有一种方案是在链接脚本中使用`OVERLAY` 命令。
7+
GNU `ld` 提供的`OVERLAY`命令,可以在同一块内存区域上“叠放”多个段(Section)。若干个段可以共享运行时的
8+
VMA(Virtual Memory Address),只是在运行时需要手动管理这些Overlay的段的加载和卸载。
9+
10+
那么如何在Nuclei Studio IDE中使用`OVERLAY`命令呢?本文将提供一个示例程序演示如何使用`OVERLAY`命令。
11+
12+
## 解决方案
13+
14+
### 示例程序
15+
16+
[demo_overlay](https://drive.weixin.qq.com/s?k=ABcAKgdSAFcp7C3O2T)是基于
17+
[Nuclei Stuido IDE 2025.02](https://www.nucleisys.com/download.php)
18+
创建的示例工程,支持Linux和Windows两种平台,演示了如何在链接脚本中使用`OVERLAY`命令。
19+
20+
示例工程中的代码与[Overlay Sample Program](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Overlay-Sample-Program.html)
21+
中提供的代码基本一致,主要区别是在main函数中增加了测试结果的打印,另外根据evalsoc的地址映射关系
22+
对链接脚本做了修改。
23+
24+
``` txt
25+
├── bar.c
26+
├── baz.c
27+
├── foo.c
28+
├── grbx.c
29+
├── overlays.c
30+
├── ovlymgr.c
31+
└── ovlymgr.h
32+
```
33+
34+
原始代码可以从[bminor/binutils-gdb/gdb/testsuite/gdb.base](https://github.com/bminor/binutils-gdb/tree/master/gdb/testsuite/gdb.base)获取。
35+
36+
### Overlay布局
37+
38+
![ovly](asserts/images/29/overlay.png)
39+
40+
在我们的evalsoc上,如果程序无法完全放在Core内的ILM/DLM上,就可以采取上图中的方法
41+
将部分Section以Overlay的形式动态加载到ILM/DLM中运行。
42+
`.ovlyx``.data0x` 共8个Section的LMA(Load Memory Address)都位于Core外的SRAM上,
43+
但它们的VMA都在Core内,并且有部分重叠。
44+
45+
### 编写链接脚本
46+
47+
`MEMORY`命令中先划分出需要用到的Memory区域,比如这里4个Core内的区域`ovrom0`, `ovrom1`,
48+
`ovram0`, `ovram1`和Core外的`ovstorage`区域。这些Memory区域的大小都可以根据实际的代码和数据的大小进行调整。
49+
50+
``` ld
51+
MEMORY
52+
{
53+
rom (rxa!w) : ORIGIN = SRAM_MEMORY_BASE, LENGTH = SRAM_MEMORY_ROM_SIZE
54+
ovstorage (rwa) : ORIGIN = SRAM_MEMORY_BASE + SRAM_MEMORY_ROM_SIZE, LENGTH = SRAM_OVLY_STORAGE_SIZE
55+
ram (wxa!r) : ORIGIN = SRAM_MEMORY_BASE + SRAM_MEMORY_ROM_SIZE + SRAM_OVLY_STORAGE_SIZE, LENGTH = SRAM_MEMORY_SIZE - SRAM_MEMORY_ROM_SIZE - SRAM_OVLY_STORAGE_SIZE
56+
ovrom0 (rwx) : ORIGIN = ILM_MEMORY_BASE, LENGTH = ILM_OVLY_SIZE0
57+
ovrom1 (rwx) : ORIGIN = ILM_MEMORY_BASE + ILM_OVLY_SIZE0, LENGTH = ILM_OVLY_SIZE1
58+
ovram0 (rwx) : ORIGIN = DLM_MEMORY_BASE, LENGTH = DLM_OVLY_SIZE0
59+
ovram1 (rwx) : ORIGIN = DLM_MEMORY_BASE + DLM_OVLY_SIZE0, LENGTH = DLM_OVLY_SIZE1
60+
}
61+
```
62+
63+
`OVERLAY`需要放在`SECTION`命令中实现。例如下方的代码就是将`.ovly0``.ovly1`两个段放到`ovrom0`
64+
表示的同一个VMA地址区间中,同时它们的LMA则是连续地位于`ovstorage`所表示的地址区间中。
65+
66+
``` ld
67+
OVERLAY :
68+
{
69+
.ovly0 { *foo.o(.text .text.*) }
70+
.ovly1 { *bar.o(.text .text.*) }
71+
} >ovrom0 AT>ovstorage
72+
```
73+
74+
参考[Automatic Overlay Debugging](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Automatic-Overlay-Debugging.html#Automatic-Overlay-Debugging)
75+
链接脚本中的以下代码则是将Overlay的段的VMA, LMA和数量以`_ovly_table``_novlys`变量的形式供C代码访问;
76+
`ovlymgr.c`中进一步实现动态加载和卸载Section的功能。
77+
78+
``` ld
79+
/* _ovly_tabel used for gdb debug overlay sections */
80+
_ovly_table = .;
81+
_ovly0_entry = .;
82+
LONG(ABSOLUTE(ADDR(.ovly0)));
83+
LONG(SIZEOF(.ovly0));
84+
LONG(LOADADDR(.ovly0));
85+
LONG(0);
86+
...
87+
_novlys = .;
88+
LONG((_novlys - _ovly_table) / 16);
89+
```
90+
91+
### 测试结果
92+
93+
观察编译后生成的map文件,可以看到相应的代码段和数据段都按照预期的VMA和LMA进行了分配。
94+
例如`.ovly0``.ovly1`具有相同的VMA `0x80000000`,同时它们的LMA分别为`0xa0008000``0xa0008028`
95+
96+
```txt
97+
.ovly0 0x80000000 0x28 load address 0xa0008000
98+
*foo.o(.text .text.*)
99+
.text.foo 0x80000000 0x28 ./application/foo.o
100+
0x80000000 foo
101+
[!provide] PROVIDE (__load_start_ovly0 = LOADADDR (.ovly0))
102+
[!provide] PROVIDE (__load_stop_ovly0 = (LOADADDR (.ovly0) + SIZEOF (.ovly0)))
103+
104+
.ovly1 0x80000000 0x28 load address 0xa0008028
105+
*bar.o(.text .text.*)
106+
.text.bar 0x80000000 0x28 ./application/bar.o
107+
0x80000000 bar
108+
[!provide] PROVIDE (__load_start_ovly1 = LOADADDR (.ovly1))
109+
[!provide] PROVIDE (__load_stop_ovly1 = (LOADADDR (.ovly1) + SIZEOF (.ovly1)))
110+
```
111+
112+
`main`函数中通过`OverlayLoad`切换调用不同的函数,并在最后将每个函数的返回值累加,校验累加后的结果。
113+
114+
```c
115+
/* load .text and .data for `foo` */
116+
OverlayLoad (0);
117+
OverlayLoad (4);
118+
a = foo (1);
119+
/* load .text and .data for `bar` */
120+
OverlayLoad (1);
121+
OverlayLoad (5);
122+
b = bar (1);
123+
/* load .text and .data for `baz` */
124+
OverlayLoad (2);
125+
OverlayLoad (6);
126+
c = baz (1);
127+
/* load .text and .data for `grbx` */
128+
OverlayLoad (3);
129+
OverlayLoad (7);
130+
d = grbx (1);
131+
132+
e = a + b + c + d;
133+
if (e != ('f' + 'o' +'o'
134+
+ 'b' + 'a' + 'r'
135+
+ 'b' + 'a' + 'z'
136+
+ 'g' + 'r' + 'b' + 'x')) {
137+
printf ("Overlay Test FAIL\r\n");
138+
} else {
139+
printf ("Overlay Test PASS\r\n");
140+
}
141+
```
142+
143+
通过QEMU仿真或者利用FPGA开发板进行测试,可以看到如下的结果。其中`Overlay Test PASS`表明结果符合预期。
144+
145+
```txt
146+
Nuclei SDK Build Time: Sep 25 2025, 17:02:19
147+
Download Mode: SRAM
148+
CPU Frequency 16003235 Hz
149+
CPU HartID: 0
150+
Overlay Test PASS
151+
```
152+
153+
### 注意事项
154+
155+
1. 数据段Overlay在要替换Section时,需要保存数据,也就是需要“卸载”的操作,将数据保存到外部SRAM中;而
156+
代码段是只读的,所以不需要Unload。
157+
2. 在示例工程中,ILM/DLM都不会经过Cache,所以不需要考虑Cache一致性的问题。但如果Overlay的Section所在
158+
的VMA是Cachebale的区域,则一般都需要考虑Cache一致性的问题,除非ICache和DCache之间有硬件支持的Snoop。
159+
更多细节可以参考示例工程中`ovlymgr.c`的实现。
160+
161+
## 参考资料
162+
163+
- [How Overlays Work](https://sourceware.org/gdb/current/onlinedocs/gdb.html/How-Overlays-Work.html#How-Overlays-Work)
164+
- [Overlay Commands](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Overlay-Commands.html#Overlay-Commands)
165+
- [Automatic Overlay Debugging](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Automatic-Overlay-Debugging.html#Automatic-Overlay-Debugging)
166+
- [Overlay Sample Program](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Overlay-Sample-Program.html)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Click [this link](https://doc.nucleisys.com/nuclei_studio_supply/) to see online
3030
3131
## Documents
3232

33-
> Generated by `python3 update.py` @ 2025-05-22 18:05:37
33+
> Generated by `python3 update.py` @ 2025-09-26 09:48:46
3434
3535
- [1. 因内存不足,导致在Nuclei Studio中启动qemu失败](1-cannot-setup-guestmemory.md)
3636
- [2. windows 11下使用Nuclei Studio进行qemu调试程序时报错](2-qemu-glib-gio-unexpectedly.md)
@@ -60,4 +60,5 @@ Click [this link](https://doc.nucleisys.com/nuclei_studio_supply/) to see online
6060
- [26. OpenOCD对FreeRTOS的调试支持使用指南](26-debugging_support_for_freertos_by_openocd.md)
6161
- [27. 如何同时使用多个蜂鸟调试器进行调试](27-debug_with_multiple_ftdi_devices.md)
6262
- [28. Nuclei SDK基于evalsoc快速适配customsoc](28-quick_porting_from_evalsoc_to_customsoc_based_on_Nuclei_SDK.md)
63+
- [29. 在链接脚本中使用`OVERLAY`命令](29-using_overlay_command_in_linker_scripts.md)
6364

asserts/images/29/overlay.png

50.1 KB
Loading

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ nav:
3333
- 26-debugging_support_for_freertos_by_openocd.md
3434
- 27-debug_with_multiple_ftdi_devices.md
3535
- 28-quick_porting_from_evalsoc_to_customsoc_based_on_Nuclei_SDK.md
36+
- 29-using_overlay_command_in_linker_scripts.md
3637
exclude_docs: |
3738
0-*.md
3839
theme:

0 commit comments

Comments
 (0)