连接脚本相关

上传人:206****923 文档编号:37518262 上传时间:2018-04-17 格式:DOC 页数:4 大小:33.50KB
返回 下载 相关 举报
连接脚本相关_第1页
第1页 / 共4页
连接脚本相关_第2页
第2页 / 共4页
连接脚本相关_第3页
第3页 / 共4页
连接脚本相关_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

《连接脚本相关》由会员分享,可在线阅读,更多相关《连接脚本相关(4页珍藏版)》请在金锄头文库上搜索。

1、连接脚本相关知识连接脚本相关知识一个程序本质上都是由 bss 段、data 段、text 段三个组成的。这样的概念,不知道最初来源于哪里的规定, 但在当前的计算机程序设计中是很重要的一个基本概念。而且在嵌入式系统的设计中也非常重要,牵涉到嵌入 式系统运行时的内存大小分配,存储单元占用空间大小的问题。 BSS 段:BSS 段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS 是英 文 Block Started by Symbol 的简称。BSS 段属于静态内存分配。用于存放没有被初始化的或者初始化为 0 的全 局变量和静态变量。 数据段:数据段(data

2、segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属 于静态内存分配。用于存放已经初始化过的(且初始化值不为 0)的全局变量和静态变量。 代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区 域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改 程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。 堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程 调用 malloc 等函数分配内存时,新

3、分配的内存就被动态添加到堆上(堆被扩张) ;当利用 free 等函数释放内存 时,被释放的内存从堆中被剔除(堆被缩减) 栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“”中定义的变量 (但不包括 static 声明的变量,static 意味着在数据段中存放变量) 。除此以外,在函数被调用时,其参数也会被 压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点, 所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内 存区。 SECTIONS /该链接脚本,就是用来对 bs

4、s 段、data 段、text 段进行有效的排版的! . = 0x00000000; .text : *(.text) /冒号:两边一定要有空格! . = 0x32000000; .data : *(.data) _bss_start = .; .bss : *(.bss) _end = .; 注意:1.若为 nor flash 启动,为什么. = 0x32000000 不能够改成. = 0x1000 呢?那是因为 nor flash 的只读不写的 特 性决定了的,当程序再次初始化 bss 中的全局变量的时候,是不可能完成的!2.一般 bss 段是紧跟在 data 段后面的! 问:怎么理解一个

5、连接地址? 答:以一个没有被初始化的变量 i 为例子(在编译的时候,它会被归为 BSS 段的): a. 当连接地址指定为 0x00000000 时,那么编译的时候,编译器给 i 分配的地址可能是 0x00000000 后一小 段的的某个地址(查看反汇编可以得知); b. 当连接地址指定为 0x30000000 时,那么编译的时候,编译器给 i 分配的地址可能是 0x30000000 后一小 段的的某个地址(查看反汇编可以得知); c. 所以,可以感悟出,如果我们的连接地址是 0x300000000,而我们在没有重定位之前,想去访问这个 i 变量,那绝对会失败的。总结: 1.程序运行时, “应该

6、”位于它的连接地址; 2.但是由于硬件的特性决定,程序最开始执行时,是从 0x0 地址开始的,所以,再最开始的几段代码里面,需 要实现重定位,这几段代码实现把程序拷贝到连接地址去,然后执行,如果不拷贝到连接地址去,那么将得不 到理想的上述的 i 变量;3.既然程序应该从连接地址开始运行,那么为什么,上述的最前面的代码却可以运行呢?因为最前面的代码都 是使用的是位置无关码。 位置无关码 -相对寻址和绝对寻址 相对寻址: 用到的指令:bl,b,adr 指令 bl,b 的反汇编:add r0, pc, #num 解释:pc 等于相对与当前 pc+一个 num 数的偏移地址,相对与当前 pc 的一个跳

7、转,这就是相对跳转。 adr 的反汇编:sub,r0,pc,#num 解释:r0 等于相对与当前 pc 减去一个 num 数的偏移地址,就得到程序真正从哪里开始执行的地址了,那 个 num 的值,是由编译器决定的。 注意:因为 bl, b,adr 只能跳转+-32MB,所以他不能够完成大的跳转(从 0x04 跳转到 0x30000000)!所以 一般使用相对寻址指令时,使用的地址,任然是 ram 中的地址;绝对寻址: 用到的指令:ldr pc, =main 它的反汇编:ldr pc, pc, #num 解释:pc 等于(当前 pc 的地址加上一个偏移 num 地址后得到的相对地址)中取取到的地

8、址数据。这个数据会 是由(-Ttext 连接地址)指定的连接地址后边的地址!这时候便实现了大跳转(如从 0x04 跳转到 0x30000000)! !因此在内存没有初始化好,或者还没有重定位之前,就执行这样的绝对寻址,那么将得不到想要的数据, 那么程序就会因此而死掉!问:什么是位置无关码? 答: 问:位置无关码,到底是用来实现相对寻址,还是绝对寻址的呢? 答:位置无关码,是用来实现相对寻址的! 问:怎么使用位置无关码? 答:a. 使用相对寻址的指令; b. C 语言中不使用全局变量,静态变量 问:为什么不能够使用全局变量,静态变量? 答:不能使用全局变量的原因是这样的: 我们的裸编程序在链接(

9、arm-linux-ld)的时候,会进行重定位,建立符号规则,为变量,函数分配运行地址, 也就是我们在链接脚本里定义的0x30000000这个地址。 但问题就来了,如果我们在初始化这个阶段(也就是还没重定位到 sdram 之前)使用了全局变量,那么这个全 局变量的运行地址会被映射到 SRAM 中,这个不好的地方就是,即便以后 ldr pc,=main 之后跳到0x30000000 地址上去了,但在这个地址上如果要访问这个全局变量,这个变量就要在映射表中查询,发现这个变量还在 SRAM 中,那么程序就会跳回到 SRAM 中,这个不是我们希望的。 所谓的映射是:在编译的时候,会有个映射表,里边存的

10、是变量,函数的地址。这样当程序运行的时候,cpu 方 便在表中查询相应的变量,函数地址。 注意:局部变量是在栈里的,而不是在这个映射表里面,所以初始化的程序里有 ldr sp, =4096,是为了设置 sram 的栈空间,用于保存局部变量等。 结论: 所以我们不要在重定位之前在映射表中留有变量的痕迹,也就是说不要使用全局变量例如:(注意对比!) 例1: lowlevel_init: /* memory control configuration */* make r0 relative the current location so that it */ /* reads SMRDATA ou

11、t of FLASH rather than memory ! */ ldr r0, =SMRDATA /注意:用的是绝对寻址! ldrr1, _TEXT_BASE sub r0, r0, r1 /因为用的是绝对寻址,所以这里要做这样的操作! ldrr1, =BWSCON/* Bus Width Status Controller */ add r2, r0, #13*4 0: ldr r3, r0, #4 str r3, r1, #4 cmp r2, r0 bne 0b/* everything is fine now */ mov pc, lr.ltorg /* the literal p

12、ools origin */SMRDATA:.word (0+(B1_BWSCON4)+(B2_BWSCON8)+(B3_BWSCON12)+(B4_BWSCON16)+(B5_BWSCON20)+(B6 _BWSCON24)+(B7_BWSCON28) .word (B0_Tacs13)+(B0_Tcos11)+(B0_Tacc8)+(B0_Tcoh6)+(B0_Tah4)+(B0_Tacp2)+(B0_PMC).word (B1_Tacs13)+(B1_Tcos11)+(B1_Tacc8)+(B1_Tcoh6)+(B1_Tah4)+(B1_Tacp2)+(B1_PMC).word (B2_

13、Tacs13)+(B2_Tcos11)+(B2_Tacc8)+(B2_Tcoh6)+(B2_Tah4)+(B2_Tacp2)+(B2_PMC).word (B3_Tacs13)+(B3_Tcos11)+(B3_Tacc8)+(B3_Tcoh6)+(B3_Tah4)+(B3_Tacp2)+(B3_PMC).word (B4_Tacs13)+(B4_Tcos11)+(B4_Tacc8)+(B4_Tcoh6)+(B4_Tah4)+(B4_Tacp2)+(B4_PMC).word (B5_Tacs13)+(B5_Tcos11)+(B5_Tacc8)+(B5_Tcoh6)+(B5_Tah4)+(B5_T

14、acp2)+(B5_PMC).word (B6_MT15)+(B6_Trcd2)+(B6_SCAN).word (B7_MT15)+(B7_Trcd2)+(B7_SCAN).word (REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT).word 0xb1.word 0x30 .word 0x30例2: memsetup: 设置存储控制器以便使用 SDRAM 等外设mov r1, #MEM_CTL_BASE 存储控制器的13个寄存器的开始地址adrl r2, mem_cfg_val 这13个值的起始存储地址 (注意:用的是相对寻址!)add

15、 r3, r1, #52 13*4 = 54 1: ldr r4, r2, #4 读取设置值,并让 r2加4str r4, r1, #4 将此值写入寄存器,并让 r1加4cmp r1, r3 判断是否设置完所有13个寄存器bne 1b 若没有写成,继续mov pc, lr 返回.align 4 mem_cfg_val: 存储控制器13个寄存器的设置值.long 0x22011110 BWSCON.long 0x00000700 BANKCON0.long 0x00000700 BANKCON1.long 0x00000700 BANKCON2.long 0x00000700 BANKCON3 .long 0x00000700 BANKCON4.long 0x00000700 BAN

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号