STM32裸机开发(9) — 使用链接脚本链接代码

STM32裸机开发(9) — 使用链接脚本链接代码

一、链接脚本的作用

链接脚本的作用就是用来指定程序的链接方式的,一个程序中包含各种文件,例如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);
    }
}

编译烧录运行,并于反汇编文件做对比,可以看到,其地址完全符合:
在这里插入图片描述

五、附录

上一篇:STM32裸机开发(8) — 在gcc环境下编写uart串口打印程序
下一篇:STM32裸机开发(10) — 复制data段和清除BSS段

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值