当前位置: 首页 > news >正文

网站css文件百度云网页版登录入口

网站css文件,百度云网页版登录入口,国内优秀网页网站,固原市住房和城乡建设局网站文章目录 一、段的概念以及重定位的引入1.1 问题的引入1.2 段的概念1.3 重定位 二、如何实现重定位2.1 程序中含有什么?2.2 谁来做重定位?2.3 怎么做重定位和清除BSS段?2.4 加载地址和链接地址的区别 三、散列文件使用与分析3.1 重定位的实质…

文章目录

  • 一、段的概念以及重定位的引入
    • 1.1 问题的引入
    • 1.2 段的概念
    • 1.3 重定位
  • 二、如何实现重定位
    • 2.1 程序中含有什么?
    • 2.2 谁来做重定位?
    • 2.3 怎么做重定位和清除BSS段?
    • 2.4 加载地址和链接地址的区别
  • 三、散列文件使用与分析
    • 3.1 重定位的实质: 移动数据
    • 3.2 散列文件示例
      • 3.2.1 示例代码
      • 3.2.2 散列文件语法
    • 3.3 散列文件解析
    • 3.4 怎么获得region的信息
      • 3.4.1 可执行域的信息
      • 3.4.2 加载域的信息
      • 3.4.3 汇编代码里怎么使用这些信息
      • 3.4.4 C语言里怎么使用这些信息
        • 1.方法1
        • 2.方法2
  • 四、清除BSS段(ZI段)
    • 4.1 C语言中的BSS段
    • 4.2 清除BSS段
      • 4.2.1 BSS段的位置和大小
      • 4.2.2 怎么清除BSS段
        • 1.汇编码
        • 2.C语言
  • 五、代码段重定位
    • 5.1 加载地址等于链接地址
    • 5.2 加载地址不等于链接地址
    • 5.3 代码段不重定位的后果
    • 5.4 代码段重定位
      • 5.4.1 代码段的位置和大小
      • 5.4.2 怎么重定位
        • 1.汇编代码
        • 2.C语言代码
    • 5.5 为什么重定位之前的代码也可以正常运行?
  • 五、重定位的纯C函数实现
    • 5.1 难点
    • 5.2 怎么理解上述代码

一、段的概念以及重定位的引入

1.1 问题的引入

复制之前的串口程序,修改为:”01_uart_question“,添加全局变量,把它打印出来,看看会发生什么事。

#include "uart.h"char g_char1 = 'A';
const char g_char2 = 'B';void delay(int d)
{while(d--);
}int main()
{char c;uart_init();putchar('l');putchar('j');putchar('g');putchar('6');putchar('6');putchar('6');putchar('\n');putchar('\r');putchar(g_char1);putchar(g_char2);while (1){c = getchar();putchar(c);putchar('\n');putchar('\r');putchar(c+1);	putchar('\n');putchar('\r');		}return 0;
}

在这里插入图片描述
可以看见,我们在定义了g_char1和g_char2(定义为常量)后,分别打印时g_char1显示的是乱码,而g_char2显示正常。

为了研究该问题,我们写了一个string.c和string.h,里面是打印函数,我们将该文件包含进该工程中,查看g_char1和g_char2的地址。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由图可见,g_char2指向ROM,且表现为只读,所以能被成功打印,而g_char1指向内存RAM,该区域是可读可写的,而我们对于内存未进行赋值,所以当访问到g_char1指向的地址时,就会打印乱码(该内存中的任意值)。

1.2 段的概念

代码段、只读数据段、可读可写的数据段、BSS段。

char g_Char = 'A';           // 可读可写,不能放在ROM上,应该放在RAM里
const char g_Char2 = 'B';    // 只读变量,可以放在ROM上
int g_A = 0;   // 初始值为0,干嘛浪费空间保存在ROM上?没必要
int g_B;       // 没有初始化,干嘛浪费空间保存在ROM上?没必要

所以,程序分为这几个段:

  • 代码段(RO-CODE):就是程序本身,不会被修改
  • 可读可写的数据段(RW-DATA):有初始值的全局变量、静态变量,需要从ROM上复制到内存
  • 只读的数据段(RO-DATA):可以放在ROM上,不需要复制到内存
  • BSS段或ZI段:
    • 初始值为0的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以
    • 未初始化的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以
  • 局部变量:保存在栈中,运行时生成
  • 堆:一块空闲空间,使用malloc函数来管理它,malloc函数可以自己写

1.3 重定位

保存在ROM上的全局变量的值,在使用前要复制到内存,这就是数据段重定位。

想把代码移动到其他位置,这就是代码重定位。

二、如何实现重定位

2.1 程序中含有什么?

  • 代码段:如果它不在链接地址上,就需要重定位
  • 只读数据段:如果它不在链接地址上,就需要重定位
  • 可读可写的数据段:如果它不在链接地址上,就需要重定位
  • BSS段:不需要重定位,因为程序里根本不保存BSS段,使用前把BSS段对应的空间清零即可

2.2 谁来做重定位?

  • 程序本身:它把自己复制到链接地址去
  • 一开始,程序可能并不位于它的链接地址上,为什么它可以执行重定位的操作?
    • 因为重定位的代码是使用“位置无关码”写的
  • 什么叫位置无关码:这段代码扔在任何位置都可以运行,跟它所在的位置无关
  • 怎么写出位置无关码:
    • 跳转:使用相对跳转指令,不能使用绝对跳转指令
      • 只能使用branch指令(比如bl main),不能给PC直接复制,比如ldr pc, =main
    • 不要访问全局变量、静态变量
    • 不使用字符串

2.3 怎么做重定位和清除BSS段?

  • 核心:复制
  • 复制的三要素:源、目的、长度
    • 怎么知道代码段/数据段保存在哪?(加载地址)
    • 怎么知道代码段/数据段要被复制到哪?(链接地址)
    • 怎么知道代码段/数据段的长度?
  • 怎么知道BSS段的地址范围:起始地址、长度?
  • 这一切
    • 在keil中使用散列文件(Scatter File)来描述
    • 在GCC中使用链接脚本(Link Script)来描述

2.4 加载地址和链接地址的区别

程序运行时,应该位于它的链接地址处,因为:

  • 使用函数地址时用的是"函数的链接地址",所以代码段应该位于链接地址处
  • 去访问全局变量、静态变量时,用的是"变量的链接地址",所以数据段应该位于链接地址处

但是: 程序一开始时可能并没有位于它的"链接地址":

  • 比如对于STM32F103,程序被烧录器烧写在Flash上,这个地址称为"加载地址"
  • 比如对于IMX6ULL/STM32MP157,片内ROM根据头部信息把程序读入内存,这个地址称为“加载地址”

加载地址 != 链接地址时,就需要重定位。

三、散列文件使用与分析

3.1 重定位的实质: 移动数据

把代码段、只读数据段、数据段,移动到它的链接地址处(mcmcpy)。
也就是复制
数据复制的三要素:源、目的、长度。

  • 数据保存在哪里?加载地址

  • 数据要复制到哪里?链接地址

  • 长度

这3要素怎么得到?
在keil中,使用散列文件来描述。
散列?分散排列?
是的,在STM32F103这类资源紧缺的单片机芯片中,

  • 代码段保存在Flash上,直接在Flash上运行(当然也可以重定位到内存里)
  • 数据段保存在Flash上,使用前被复制到内存里

3.2 散列文件示例

3.2.1 示例代码

复制”01_uart_question“,改名为”02_uart_sct“。

在 Keil 中进行如下配置:
在这里插入图片描述
会生成一个.sct结尾的文件,使用Nope++打开:
在这里插入图片描述

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************LR_IROM1 0x08000000 0x00080000  {    ; load region size_regionER_IROM1 0x08000000 0x00080000  {  ; load address = execution address*.o (RESET, +First).ANY (+RO).ANY (+XO)}RW_IRAM1 0x20000000 0x00010000  {  ; RW data.ANY (+RW +ZI)}
}

3.2.2 散列文件语法

一个散列文件由一个或多个Load region(加载域)组成:

load_region_description ::=load_region_name (base_address | ("+" offset)) [attribute_list] [max_size]"{"execution_region_description+"}

Load region中含有一个或多个Execution region(可执行域)
在这里插入图片描述

Execution region语法如下:

execution_region_description ::=exec_region_name (base_address | "+" offset) [attribute_list] [max_size | length]"{"input_section_description*"}

Execution region中含有一个或多个Input section
Input section语法如下:

input_section_description ::=
module_select_pattern [ "(" input_section_selector ( ","
input_section_selector )* ")" ]
input_section_selector ::=
"+" input_section_attr |
input_section_pattern |
input_section_type |
input_symbol_pattern |
section_properties

3.3 散列文件解析

在这里插入图片描述
*.o :所有objects文件

*:所有objects文件和库,在一个散列文件中只能使用一个*

.ANY:等同于*,优先级比*低;在一个散列文件的多个可执行域中可以有多个.ANY

.ANY (+RO):所有.o文件、库文件的只读数据段

.ANY (+XO):所有.o文件、库文件的可执行数据段

.ANY (+RW +ZI):所有.o文件、库文件的可读可写段和BSS段

3.4 怎么获得region的信息

3.4.1 可执行域的信息

在这里插入图片描述

3.4.2 加载域的信息

在这里插入图片描述

3.4.3 汇编代码里怎么使用这些信息

Load$$region_name$$Base	//下面修改时候要注意region_name(区域名)

在这里插入图片描述
在这里插入图片描述
通过上图可知,可执行域1的源地址和目的地址一致,所以能够正常执行,不需要重定位;而可执行域2的源地址紧随1后,但其目的地址与源地址不同,所以需要对可执行域进行重定位。所以需要将区域名字修改成 RW_IRAM1

示例代码如下:
string.c中的memcpy函数:

void mcmcpy(void *dest, void *src, unsigned int len)
{unsigned char *pcDest;unsigned char *pcSrc;while (len--){*pcDest = *pcSrc;	//让目的地与源地址相等,后面两者长度++,知道len=0,完成复制pcSrc++;pcDest++;}
}
IMPORT |Image$$RW_IRAM1$$Base|
IMPORT |Image$$RW_IRAM1$$Length|
IMPORT |Load$$RW_IRAM1$$Base|
IMPORT memcpyLDR R0, = |Image$$RW_IRAM1$$Base|    ; DEST
LDR R1, = |Load$$RW_IRAM1$$Base|     ; SORUCE
LDR R2, = |Image$$RW_IRAM1$$Length|  ; LENGTH
BL memcpy

在这里插入图片描述

修改start.s,让目的地址与源地址一样后,编译烧录,可以发现A被成功打印。

在这里插入图片描述

3.4.4 C语言里怎么使用这些信息

1.方法1

声明为外部变量。
注意:使用时需要使用取址符:

extern int Image$$RW_IRAM1$$Base;
extern int Load$$RW_IRAM1$$Base;
extern int Image$$RW_IRAM1$$Length;memcpy(&Image$$RW_IRAM1$$Base, &Image$$RW_IRAM1$$Length, &Load$$RW_IRAM1$$Base);
2.方法2

声明为外部数组。
注意:使用时不需要使用取址符:

extern char Image$$RW_IRAM1$$Base[];
extern char Load$$RW_IRAM1$$Base[];
extern int Image$$RW_IRAM1$$Length;memcpy(Image$$RW_IRAM1$$Base, Image$$RW_IRAM1$$Length, &Load$$RW_IRAM1$$Base);

四、清除BSS段(ZI段)

4.1 C语言中的BSS段

程序里的全局变量,如果它的初始值为0,或者没有设置初始值,这些变量被放在BSS段里,也叫ZI段。

char g_Char = 'A';
const char g_Char2 = 'B';
int g_A = 0;  // 放在BSS段
int g_B;      // 放在BSS段

BSS段并不会放入bin文件中,否则也太浪费空间了。
在使用BSS段里的变量之前,把BSS段所占据的内存清零就可以了。

  • 注意:对于keil来说,一个本该放到BSS段的变量,如果它所占据的空间小于等于8字节自己,keil仍然会把它放在data段里。只有当它所占据的空间大于8字节时,才会放到BSS段。

    int g_A[3] = {0, 0};   // 放在BSS段
    char g_B[9];           // 放在BSS段int g_A[2] = {0, 0};   // 放在data段
    char g_B[8];           // 放在data段
    

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.2 清除BSS段

4.2.1 BSS段的位置和大小

在散列文件中,BSS段(ZI段)在可执行域RW_IRAM1中描述:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_regionER_IROM1 0x08000000 0x00080000  {  ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO).ANY (+XO)}RW_IRAM1 0x20000000 0x00010000  {  ; RW data.ANY (+RW +ZI)}
}

BSS段(ZI段)的链接地址(基地址)、长度,使用下面的符号获得:
在这里插入图片描述

4.2.2 怎么清除BSS段

1.汇编码

string.c中的memset函数:

void memset(void *dest, unsigned char val, unsigned int len)
{unsigned char *pcDest = dest;while (len --){*pcDest = val;pcDest++;}
}
IMPORT |Image$$RW_IRAM1$$ZI$$Base|			;IMPORT在这里相当于定义
IMPORT |Image$$RW_IRAM1$$ZI$$Length|
IMPORT memsetLDR R0, = |Image$$RW_IRAM1$$ZI$$Base|       ; DEST
MOV R1, #0   								; VAL:VAL为0 并赋给dest 完成清零操作
LDR R1, = |Image$$RW_IRAM1$$ZI$$Length|     ; Length
BL memset

在这里插入图片描述

调用memset函数后,可见放入BSS段成功被清除为0:

在这里插入图片描述

2.C语言
  • 方法1
    声明为外部变量,使用时需要使用取址符:
extern int Image$$RW_IRAM1$$ZI$$Base;
extern int Image$$RW_IRAM1$$ZI$$Length;memset(&Image$$RW_IRAM1$$ZI$$Base, 0, &Image$$RW_IRAM1$$ZI$$Length);
  • 方法2
    声明为外部数组,使用时不需要使用取址符:
extern char Image$$RW_IRAM1$$ZI$$Base[];
extern int Image$$RW_IRAM1$$ZI$$Length[];memset(Image$$RW_IRAM1$$ZI$$Base[], 0, Image$$RW_IRAM1$$ZI$$Length);

五、代码段重定位

5.1 加载地址等于链接地址

在默认散列文件中,代码段的load address = execution address
也就是加载地址和执行地址(链接地址)一致,所以无需重定位:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_regionER_IROM1 0x08000000 0x00080000  {  ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO).ANY (+XO)}RW_IRAM1 0x20000000 0x00010000  {  ; RW data.ANY (+RW +ZI)}
}

5.2 加载地址不等于链接地址

有时候,我们需要把程序复制到内存里运行,比如:

  • 想让程序执行得更快:需要把代码段复制到内存里
  • 程序很大,保存在片外SPI Flash中,SPI Flash上的代码无法直接执行,需要复制到内存里

这时候,需要修改散列文件,把代码段的可执行域放在内存里。
那么程序运行时,需要尽快把代码段重定位到内存。
散列文件示例:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_regionER_IROM1 0x20000000   {  ; load address != execution address*.o (RESET, +First).ANY (+RO).ANY (+XO)}RW_IRAM1 +0   {  ; RW data.ANY (+RW +ZI)}
}

在这里插入图片描述

上面的散列文件中:

  • 可执行域ER_IROM1
    • 加载地址为0x08000000,可执行地址为0x20000000,两者不相等
    • 板子上电后,从0x08000000处开始运行,需要尽快把代码段复制到0x20000000
  • 可执行域RW_IRAM1
    • 加载地址:紧跟着ER_IROM1的加载地址(+0)
    • 可执行地址:紧跟着ER_IROM1的可执行地址(+0)
    • 需要尽快把数据段复制到可执行地址处

数据段的重定位我们做过实验,
如果代码段不重定位的话,会发生什么事?
修改完上面的散列文件,发现程序编译烧录后在Mobe软件上毫无反应,说明程序发生崩溃。我们进行解析:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们程序运行时,在start.s中,第一条指令是从不是从Reset_Handler开始执行,而是从__Vectors,对于__Vectors的第一个数据DCD是用来设置栈,但是我们并不需要第一个数据,我们自己手动设置了栈(LDR SP, =(0x20000000+0x10000)),对于第二个数据,CPU会在DCD中取出Reset_Handler这个值,并将其作为函数地址跳转过去。为了了解函数地址,我们打开反汇编代码,可以看见其对应的地址为20000009,而我们的代码烧写在Flash上时,在开始是0,CPU一上电会用第一个值设置栈,但我们没有使用,我们后面自己去设置栈,在第二个位置取出该值,将其作为函数地址跳过去执行(注意:这里的20000009中的bit0并不使用,bit0只是用来表示跳过去后的指令为Tumb指令集),会跳到Reset Handler对应的20000008,但在20000008上,我们并未对该内存进行任何操作,此时如果PC跳到位置则会崩溃,由第三张图可见Reset_Handler对应的是08000008,所以我们需要在20000009的位置放入08000009(设置成09是因为bit(0)等于1表示后面执行的是Tumb指令集)。修改完毕后程序得以正常执行,成功清除ss段:

在这里插入图片描述

5.3 代码段不重定位的后果

不能使用链接地址来调用函数

  • 汇编中

    ldr  pc, =main   ; 这样调用函数时,用到main函数的链接地址,如果代码段没有重定位,则跳转失败
    
  • C语言中

    void (*funcptr)(const char *s, unsigned int val);
    funcptr = put_s_hex;
    funcptr("hello, test function ptr", 123);
    

5.4 代码段重定位

5.4.1 代码段的位置和大小

在散列文件中,代码段在可执行域ER_IROM1中描述:

LR_IROM1 0x08000000 0x00080000  {    ; load region size_regionER_IROM1 0x08000000 0x00080000  {  ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO).ANY (+XO)}RW_IRAM1 0x20000000 0x00010000  {  ; RW data.ANY (+RW +ZI)}
}

代码段的链接地址(基地址)、长度,使用下面的符号获得:

在这里插入图片描述

代码段的加载地址,使用下面的符号获得:

在这里插入图片描述

5.4.2 怎么重定位

1.汇编代码

把代码段从Flash复制到内存中:

IMPORT |Image$$ER_IROM1$$Base|		;IMPORT在这里相当于定义
IMPORT |Image$$ER_IROM1$$Length|
IMPORT |Load$$ER_IROM1$$Base|LDR R0, = |Image$$ER_IROM1$$Base|    ; DEST
LDR R1, = |Load$$ER_IROM1$$Base|     ; SORUCE
LDR R2, = |Image$$ER_IROM1$$Length|  ; LENGTH
BL memcpy

在这里插入图片描述

在这里插入图片描述

注意:第二段代码已经进行重定位,而第一段代码还位于Flash上,为什么该段代码还没位于他的链接地址上却可以正常执行,因为该段代码使用的是位置无关码。所谓位置无关就是放在任何地方都能得以执行,跟他的位置没有任何关系。关键在于跳转,他使用的是相对跳转指令,而第二段代码使用的是链接地址跳转指令。

2.C语言代码
  • 方法1

声明为外部变量,使用时需要使用取址符:

extern int Image$$ER_IROM1$$Base;
extern int Load$$ER_IROM1$$Base;
extern int Image$$ER_IROM1$$Length;memcpy(&Image$$ER_IROM1$$Base, &Image$$ER_IROM1$$Length, &Load$$ER_IROM1$$Base);
  • 方法2

声明为外部数组,使用时不需要使用取址符:

extern char Image$$ER_IROM1$$Base[];
extern char Load$$ER_IROM1$$Base[];
extern int Image$$ER_IROM1$$Length;memcpy(Image$$ER_IROM1$$Base, Image$$ER_IROM1$$Length, &Load$$ER_IROM1$$Base);

5.5 为什么重定位之前的代码也可以正常运行?

因为重定位之前的代码是使用位置无关码写的:

  • 只使用相对跳转指令:B、BL

  • 不只用绝对跳转指令:

    LDR R0, =main
    BLX R0
    
  • 不访问全局变量、静态变量、字符串、数组

  • 重定位完后,使用绝对跳转指令跳转到XXX函数的链接地址去

    BL main         ; bl相对跳转,程序仍在Flash上运行LDR R0, =main   ; 绝对跳转,跳到链接地址去,就是跳去内存里执行
    BLX R0
    

在这里插入图片描述

五、重定位的纯C函数实现

5.1 难点

难点在于,怎么得到各个域的加载地址、链接地址、长度。

  • 方法1

声明为外部变量,使用时需要使用取址符:

extern int Image$$ER_IROM1$$Base;
extern int Load$$ER_IROM1$$Base;
extern int Image$$ER_IROM1$$Length;memcpy(&Image$$ER_IROM1$$Base, &Image$$ER_IROM1$$Length, &Load$$ER_IROM1$$Base);
  • 方法2

声明为外部数组,使用时不需要使用取址符:

extern char Image$$ER_IROM1$$Base[];
extern char Load$$ER_IROM1$$Base[];
extern int Image$$ER_IROM1$$Length;memcpy(Image$$ER_IROM1$$Base, Image$$ER_IROM1$$Length, &Load$$ER_IROM1$$Base);

5.2 怎么理解上述代码

对于这样的C变量:

int g_a;

编译的时候会有一个符号表(symbol table),如下:

NameAddress
g_axxxxxxxx

对于散列文件中的各类Symbol,有2中声明方式:

extern int Image$$ER_IROM1$$Base;     // 声明为一般变量(包括int、char还有指针)
extern char Image$$ER_IROM1$$Base[];  // 声明为数组

不管是哪种方式,它们都会保存在符号表里,比如:

NameAddress
g_axxxxxxxx
Image E R I R O M 1 ER_IROM1 ERIROM1Baseyyyyyyyy
  • 对于int g_a变量
    • 使用&g_a得到符号表里的地址。
  • 对于extern int Image$$ER_IROM1$$Base变量
    • 要得到符号表中的地址,也是使用&Image$$ER_IROM1$$Base
  • 对于extern char Image$$ER_IROM1$$Base[]变量
    • 要得到符号表中的地址,直接使用Image$$ER_IROM1$$Base,不需要加&
    • 为什么?mage$$ER_IROM1$$Base本身就表示地址啊

示例代码:
在start.s中定义SystemInt,并调用跳转:

PRESERVE8THUMB; Vector Table Mapped to Address 0 at ResetAREA    RESET, DATA, READONLYEXPORT  __Vectors__Vectors       DCD     0                  DCD     0x08000009              ; Reset HandlerAREA    |.text|, CODE, READONLY; Reset handler
Reset_Handler   PROCEXPORT  Reset_Handler             [WEAK]IMPORT  mymainIMPORT	SystemInit				;定义SystemInitLDR SP, =(0x20000000+0x10000)BL SystemInit					;跳转SystemInit;BL mymainLDR R0, =mymainBLX R0ENDPEND

创建一个init.c,在其中写入c函数的重定位(包括int、char和指针):

#include "string.h"#if 0
void SystemInit()
{               extern int Image$$ER_IROM1$$Base;extern int Image$$ER_IROM1$$Length;extern int Load$$ER_IROM1$$Base;extern int Image$$RW_IRAM1$$Base;extern int Image$$RW_IRAM1$$Length;extern int Load$$RW_IRAM1$$Base;extern int Image$$RW_IRAM1$$ZI$$Base;extern int Image$$RW_IRAM1$$ZI$$Length;/* 代码段重定位 */memcpy(&Image$$ER_IROM1$$Base, &Load$$ER_IROM1$$Base, &Image$$ER_IROM1$$Length); //目的地址、源地址、长度/* 数据段重定位 */memcpy(&Image$$RW_IRAM1$$Base, &Load$$RW_IRAM1$$Base, &Image$$RW_IRAM1$$Length); //目的地址、源地址、长度/* 清除BSS段 */memset(&Image$$RW_IRAM1$$ZI$$Base, 0, &Image$$RW_IRAM1$$ZI$$Length);			 //源地址、清除为0、长度
}
#endif#if 0
void SystemInit()
{               extern int Image$$ER_IROM1$$Base[];extern int Image$$ER_IROM1$$Length[];extern int Load$$ER_IROM1$$Base[];extern int Image$$RW_IRAM1$$Base[];extern int Image$$RW_IRAM1$$Length[];extern int Load$$RW_IRAM1$$Base[];extern int Image$$RW_IRAM1$$ZI$$Base[];extern int Image$$RW_IRAM1$$ZI$$Length[];/* 代码段重定位 */memcpy(Image$$ER_IROM1$$Base, Load$$ER_IROM1$$Base, Image$$ER_IROM1$$Length); //目的地址、源地址、长度/* 数据段重定位 */memcpy(Image$$RW_IRAM1$$Base, Load$$RW_IRAM1$$Base, &Image$$RW_IRAM1$$Length); //目的地址、源地址、长度/* 清除BSS段 */memset(Image$$RW_IRAM1$$ZI$$Base, 0, Image$$RW_IRAM1$$ZI$$Length);			 //源地址、清除为0、长度
}
#endifvoid SystemInit()
{               extern int *Image$$ER_IROM1$$Base;extern int *Image$$ER_IROM1$$Length;extern int *Load$$ER_IROM1$$Base;extern int *Image$$RW_IRAM1$$Base;extern int *Image$$RW_IRAM1$$Length;extern int *Load$$RW_IRAM1$$Base;extern int *Image$$RW_IRAM1$$ZI$$Base;extern int *Image$$RW_IRAM1$$ZI$$Length;/* 代码段重定位 */memcpy(&Image$$ER_IROM1$$Base, &Load$$ER_IROM1$$Base, &Image$$ER_IROM1$$Length); //目的地址、源地址、长度/* 数据段重定位 */memcpy(&Image$$RW_IRAM1$$Base, &Load$$RW_IRAM1$$Base, &Image$$RW_IRAM1$$Length); //目的地址、源地址、长度/* 清除BSS段 */memset(&Image$$RW_IRAM1$$ZI$$Base, 0, &Image$$RW_IRAM1$$ZI$$Length);			 //源地址、清除为0、长度
}

三者结果一致:

在这里插入图片描述

http://www.khdw.cn/news/37412.html

相关文章:

  • 百度云虚拟主机做网站网站优化包括对什么优化
  • 服务器 网站建设 过程seo网络优化是什么意思
  • 国外购物网站排行榜百度医生
  • 湖南网站制作公司seo搜索引擎优化步骤
  • 遨游网站建设有限公司网络营销推广方式包括
  • 网络营销推广的策略百度地图优化排名方法
  • 什么是网站的用户体验武汉网站建设优化
  • 番禺区移动端网站制作广州网站营销seo费用
  • 做网站需求方案定制网站多少钱
  • 农药放行单在哪个网站做semikron
  • 临沂企业建站效果好微信朋友圈广告投放价格表
  • 建网页服务公司seopeixun
  • 网站导航css代码矿泉水软文广告500字
  • ubuntu服务器上wordpressseo整站优化费用
  • 原则网站设计版式怎么下载app到手机上
  • 微信上微网站怎么做的吗长春seo顾问
  • 做外贸可以用哪些网站seo研究所
  • 个性化wordpress网络优化培训骗局
  • 表白网页制作网站百度优化点击软件
  • 网站建设技术规范关键词优化难度分析
  • 网站编辑做app重庆网站建设维护
  • 广州天河区做网站网站seo分析案例
  • 网站建设设计公司哪家好今天国内新闻
  • 做亚马逊和淘宝网站seo搜索引擎优化人才
  • 手机如做网站b站推广网站入口202
  • 免费淘宝客网站模板下载市场营销网站
  • 学做日本蛋糕网站关键词免费网站
  • win7下如何建设网站信阳seo公司
  • 网站模板制作与安装教程视频杭州网站优化多少钱
  • 网站代做多长时间直播发布会