一、链接脚本的作用
链接脚本的作用就是用来指定程序的链接方式的,一个程序中包含各种文件,例如start.o、main.o、led.o等,每个文件有包含如代码段、数据段等各种段,而链接脚本的作用就是用来指定各种文件各种段的链接方式。前面我们都没有使用链接文件,只使用了-Ttext参数来指明代码段的链接地址,其他都是按照默认链接的,使用之前曾强调要将start.o文件放在最前面。
二、编写链接文件
将Makefile中的链接命令改为如下所示
- $(LD) -g $(OBJECTS) -T stm32f103zet6.ld -o $@
复制代码
接着编写一个最简单的链接文件stm32f103zet6.ld如下所示,其实这个和之前的-Ttext 0x80100000参数效果是一样的。首先SECTIONS {}是链接文件的语法,表示程序的所有段都在其中;然后. = 0x80100000表示当前地址设置为0x80100000,亦即链接的起始地址为0x80100000;. = ALIGN(4)表示当前地址按4字节对齐;.text表示段名,*(.text)表示将所有文件的代码段都存放在此。
- SECTIONS {
- . = 0X8000000;
- . = ALIGN(4);
- .text :
- {
- *(.text)
- }
- }
复制代码
我们打开反汇编文件,可以看到段名为.text的段,同时其链接地址也是从0X8000000开始的
三、指定内存区域
因为对于在STM32F103这类资源紧缺的单片机芯片中:
代码段保存在Flash上,直接在Flash上运行(当然也可以重定位到内存里)
数据段暂时先保存在Flash上,然后在使用前被复制到内存里(只读数据段不复制)
所以我们要给予代码段和数据段不同的保存地址,在链接文件中添加如下内存区域指定说明,分别定义RAM和FLASH两个内存区域,分别对应stm32芯片上的ram和flash区域,其中Flash区域可读可执行,开始地址为0x08000000,长度为512K,Ram区域可读可写可执行,开始地址为0x20000000,长度为 64K
- MEMORY
- {
- RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
- FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K
- }
复制代码
然后添加只读数据段、数据段、BSS段并指定其内存区域,修改完的链接文件如下
- /* 指定内存区域 */
- MEMORY
- {
- FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
- RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
- }
- SECTIONS {
- .text :
- {
- . = ALIGN(4);
- *start.o (.text)
- *main.o (.text)
- *(.text)
- } > FLASH
- .rodata :
- {
- . = ALIGN(4);
- *(.rodata) /* .rodata sections (constants, strings, etc.) */
- *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
- . = ALIGN(4);
- } >FLASH
- .data :
- {
- . = ALIGN(4);
- _sdata = .; /* create a global symbol at data start */
- *(.data) /* .data sections */
- *(.data*) /* .data* sections */
- . = ALIGN(4);
- _edata = .; /* define a global symbol at data end */
- } >RAM
- . = ALIGN(4);
- .bss :
- {
- /* This is used by the startup in order to initialize the .bss secion */
- _sbss = .; /* define a global symbol at bss start */
- __bss_start__ = _sbss;
- *(.bss)
- *(.bss*)
- *(COMMON)
- . = ALIGN(4);
- _ebss = .; /* define a global symbol at bss end */
- __bss_end__ = _ebss;
- } >RAM
- }
复制代码
然后修改main程序添加如下全局变量
使用make编译,打开反汇编文件,找到如下所示,可以看到这三个段分别存放着刚刚定义的C语言中的全局变量。
首先,只读数据段.rodata中放置加const修饰的变量myconst,其存放在Flash区域;
然后,数据段data中已初始化的全局变量mydata,其存放在Ram区域;
最后,bss段放置未初始化或初始化为零的全局变量,同样也存放在Ram区域。
四、验证
修改mian.c如下所示,添加各个变量地址的打印
- #include "uart.h"
- #include "led.h"
- int mydata = 0x12315;
- const int myconst = 0x22315;
- int myzero = 0;
- int my;
- int main(void)
- {
- uart_init();
- led_init();
- putstring("stm32f103zet6\r\n");
- putstring("mydata\t:");
- puthex((unsigned int)&mydata);
- putstring("\r\nmyconst\t:");
- puthex((unsigned int)&myconst);
- putstring("\r\nmyzero\t:");
- puthex((unsigned int)&myzero);
- putstring("\r\nmy\t:");
- puthex((unsigned int)&my);
- putstring("\r\n");
- while(1)
- {
- putstring("led on\r\n");
- led_on();
- delay(1000000);
- putstring("led off\r\n");
- led_off();
- delay(1000000);
- }
- }
复制代码
编译烧录运行,并于反汇编文件做对比,可以看到,其地址完全符合:
————————————————
Willliam_william
|