mdk keil 指定变量、函数存储位置,使用 Scatter-Loading Description File, __attribute__(("section“))

0. 数据类型说明

主要包括4类:

  1. Code (inc. data) ,属于RO,也就是写的函数代码(包括代码中的变量)
  2. RO Data , 属于RO,使用const修饰的变量。
  3. RW Data, 属于RW,变量。
  4. ZI Data,   属于RW,没有初始化的变量。

1. mdk 设置Scatter 文件

默认情况下,片内会有两大存储块IROM(只读存储器RO,用来存常量、代码等),IRAM(读写存储器RW,用来存变量,包括被默认初始化为0的变量),如下图 "Target"选项卡。

来看“Linker”选项卡,下面介绍操作:

1. 默认的选项是使用的“Target”的内存分区,需要把这个勾去掉。

2. 去掉勾后会出现一个“.sct"文件,点击Edit就可以修改了,对文件做了注释说明如下:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_region, 装载区域
                                    ; LR_IROM1, 这是一个名字,随便起。可以理解为一块存储器的名字。
                                    ; 0x08000000,这是起始地址。
                                    ; 0x00080000,代表size,也就是存储器的最大空间。

  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address, 执行区域
   *.o (RESET, +First)        ; *.o, 是说对于任意的".o"文件
                            ; RESET 是说含有“RESET”的section名称的
                            ; +First 是说最先匹配
                            ; 合起来就是在所有的“.o”文件中找到含有“RESET”字段的内容放到“ER_IROM1"这块存储区域内
   *(InRoot$$Sections)
   .ANY (+RO)                ; ‘.ANY‘ 可以理解成 ‘*‘ ,是说把剩下的RO类型的数据(常量和代码)放到这里。
  }
  RW_IRAM1 0x20000000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)            ; 是说把剩下的RW,ZI类型的数据(常量和代码)放到这里。
  }
}

从上面可以看到这里只做了两个区分,大体上就是RO和RW的区别,下面说明自定义区域。

3. 这里我们定义两个区域,一个用来存放函数,一个用来存放数据:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }

  MY_FUN 0x20000000 0x00000080  {     ; 自定义函数存储位置,地址及大小仅作说明。
   .ANY (pg_fun)
  }

  MY_DATA 0x20000080 0x00000080 {    ; 自定义数据存储位置,地址及大小仅作说明。
    .ANY (pg_data)
  }

  RW_IRAM2 0x20000100 0x0000FF00  {
   .ANY (+RW +ZI)     ; RW data
  }
}

4. 在“inc.h"头文件中:

#define PG_FUN_ATTRIBUTES  __attribute__ ((section("pg_fun")))
#define PG_DATA_ATTRIBUTES __attribute__ ((section("pg_data")))

void test1 (void);

5. 在”test.c"文件中:

#include "inc.h"

typedef struct tt{    // 自定义结构体
    int a;
    double b;
}tt_t;

// 变量定义,分配到定义的数据区域内
static tt_t t0 PG_DATA_ATTRIBUTES = {
    .a = 1,
    .b = 2,
};
static char t1[10] PG_DATA_ATTRIBUTES;

// 函数定义,分配到定义的函数区域内
void test1 PG_FUN_ATTRIBUTES()
{
    t0.a = 1;
}

6. 在“main.c"文件中:

#include "stm32f10x.h"
#include <stdint.h>
#include "inc.h"
#include <stdio.h>

static char tc2[5] PG_DATA_ATTRIBUTES;
void foo PG_FUN_ATTRIBUTES()
{
    tc2[0] = 2;
}

int main()
{
    foo();
    test1();
    return 0;
}

7. 文件“test.map" 查看结果:

    Execution Region MY_FUN (Base: 0x20000000, Size: 0x00000018, Max: 0x00000080, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x20000000   0x0000000c   Code   RO            5    pg_fun              main.o
    0x2000000c   0x0000000c   Code   RO          150    pg_fun              test.o

    Execution Region MY_DATA (Base: 0x20000080, Size: 0x0000002c, Max: 0x00000080, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x20000080   0x00000005   Data   RW            6    pg_data             main.o
    0x20000085   0x00000003   PAD
    0x20000088   0x00000022   Data   RW          151    pg_data             test.o

可以看到,函数和代码都以如愿以偿。

结构体编译出错,参考这篇文章:MDK KEIL 机构体初始化

原文地址:https://www.cnblogs.com/qiyuexin/p/9026365.html

时间: 2024-10-25 01:59:15

mdk keil 指定变量、函数存储位置,使用 Scatter-Loading Description File, __attribute__(("section“))的相关文章

u-boot-2014.10移植(7)修改环境变量的存储位置

原来环境变量存储在nor flash里, 前面mtdparts分区第二个分区就是params 现在修改环境变量到nand里, 搜索default environment 在Env_common.c函数里面: default_environment结构体default_environment结构体定义在env_common.c里面 其中有: #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif 这

java中变量的存储位置

1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中.) 3. 堆:存放所有new出来的对象. 4. 静态域:存放静态成员(static定义的) 5. 常量池:存放字符串常量和基本类型常量(public static final). 6. 非RAM存储:硬盘等永久存储空间 这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象

Python3基础 使用id() 查询变量的存储位置

镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.------------------------------------------ code: dict1={'子':'鼠','丑':'牛','寅':'虎','卯':'兔','辰':'龙','巳':'蛇','午':'马','未':'羊','申':'猴','酉':'鸡','戌':'狗','亥':'猪'} print(id(dict1)) a=1 print(id(a)) r

JAVA变量的存放位置

JAVA变量(包括常量)可以存放在 栈.堆.方法区三块内存区域,除去方法区的常量池中存放的常量之外主要的变量都存放在栈和堆中. 其中栈中的变量会受线程的影响(线程私有),当线程结束时变量销毁 堆中的变量则是线程共享的,由 gc 处理. 变量的存储位置跟变量的类型和变量的作用域有关,如下:   局部变量 全局变量 基本数据类型 变量名和值都存放在栈中 变量名和值都存在在堆中 引用数据类型 变量名存放在栈中,值存放在堆中 原文地址:https://www.cnblogs.com/guofz/p/93

堆和栈 各种变量存储位置

c++内存到底分几个区?一: 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由os回收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵. 3.全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域. - 程序结束后有

c 变量的存储类型auto等(基础知识)和c函数变量

总结 1).在c语言中每一个变量和函数有两个属性:数据类型和数据的存储类别. 2). 对数据型(如整型.字符型等).存储类别指的是数据在内存中存储的方式. 存储方式分为两大类: 静态存储类和动态存储类 具体包括四种:{自动的(auto), 静态的(static), 寄存器(register), 外部的(extern)}. 根据变量的存储类别, 可以知道变量的作用域和生存期. 例如: 局部变量: 自动变量: int main(void){int a, b, c; 自动变量} 静态局部变量: int

js判断是否存在指定变量或函数

//是否存在指定变量 function isExitsVariable(variableName) { try { if (typeof(eval(variableName)) == "undefined") { console.log("已声明变量,但未初始化"); return false; } else { console.log("已声明变量,且已经初始化"); return true; } } catch(e) { console.lo

C++基础知识——变量存储位置

1.栈区(stack):程序运行时由编译器自动分配 存放:函数的参数值,局部变量的值. 存储连续,其操作方式类似于数据结构中的栈. 栈区处于相对较高的地址以地址的增长方向为上的话,栈地址是向下增长的,所以空间有限,windows下大多1-2M. 2.堆区(heap): 在内存开辟另一块存储区域.一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 . 存放:程序员申请的内存空间. 存储不连续,数据结构中的堆是两回事,类似于链表,受限于虚拟内存,32bit系统可达到4G. 堆区是向上增

程序通过定义学生结构体变量,存储学生的学号、姓名和3门课的成绩。函数fun的功能是:对形参b所指结构体变量中的数据进行修改,并在主函数中输出修改后的数据。

程序通过定义学生结构体变量,存储学生的学号.姓名和3门课的成绩.函数fun的功能是:对形参b所指结构体变量中的数据进行修改,并在主函数中输出修改后的数据.例如,若b所指变量t中的学号.姓名和三门课的成绩一次是:10002."ZhangQi".93.85.87,修改后输出t中的数据应为:10004."Lijie".93.85.87. #include <stdio.h>#include <string.h>struct student { lo