S3C2440 lds链接脚本解析
1. ?SECTIONS到底意味著什么
? ? 在一個(gè)裸版程序里面含有*.lds文件,而lds文件意味著如果你的程序燒錄在nandflash,那在nandflash的內(nèi)存將根據(jù)lds文件指定偏移來分布,下面從不同場景來解釋SECTIONS的內(nèi)容。
2. ?小于4K程序
? ? 若程序小于4K,那程序的整個(gè)重定位地址設(shè)置為0,可以沒有拷貝到sdram的處理。
????uart.lds
SECTIONS {. = 0x00000000;.text : { *(.text) }.rodata ALIGN(4) : {*(.rodata)} .data ALIGN(4) : { *(.data) }.bss ALIGN(4) : { *(.bss) *(COMMON) } }????head.S
.text .global _start _start:ldr ? ? r0, =0x53000000 ? ? @ WATCHDOG寄存器地址mov ? ? r1, #0x0 ? ? ? ? ? ? ? ? ? ??str ? r1, [r0] ? ? ? ? ? ? ?@ 寫入0,禁止WATCHDOG,否則CPU會(huì)不斷重啟ldr ? ? sp, =1024*4 ? ? ? ? @ 設(shè)置堆棧,注意:不能大于4k, 因?yàn)楝F(xiàn)在可用的內(nèi)存只有4K@ nand flash中的代碼在復(fù)位后會(huì)移到內(nèi)部ram中,此ram只有4Kbl ? ? ?main ? ? ? ? ? ? ? ?@ 調(diào)用C程序中的main函數(shù) halt_loop:b ? ? ? halt_loop????Nandflash其內(nèi)存結(jié)構(gòu)如下:
????一開始運(yùn)行之前,默認(rèn)會(huì)從NandFlash拷貝4K大小的程序代碼到芯片片內(nèi)內(nèi)存上面并且從0開始執(zhí)行,由于片內(nèi)內(nèi)存只有4K,所以鏈接腳本只適用于程序運(yùn)行空間小于4K的情況。
3. 大于4K程序
????若要支持程序大于4K,就需要考慮將程序拷貝到sdram中運(yùn)行,修改head.s文件,添加從片內(nèi)內(nèi)存拷貝到Sdram的操作,同時(shí)鏈接腳本設(shè)置重定位地址為0x30000000。
???uart.lds
SECTIONS {. = 0x30000000;.text : { *(.text) }.rodata ALIGN(4) : {*(.rodata)} .data ALIGN(4) : { *(.data) }.bss ALIGN(4) : { *(.bss) *(COMMON) } }????head.S
.extern main .text .global _start _start: Reset: ldr sp, =4096 bl disable_watch_dog bl clock_init bl memsetup bl nand_initldr r0, =0x30000000 mov r1, #0 mov r2, #(1024*10) bl nand_read ldr pc, =on_sdram onsdram:ldr sp, =0x34000000 ldr lr, =halt_loop ldr pc, =main halt_loop:b halt_loop? ? 此時(shí)NanFlash和Sdram內(nèi)存分布如下:
? ? 當(dāng)重定位0x30000000后,其內(nèi)存的指令碼后會(huì)發(fā)生什么變化呢?以main函數(shù)里面,獲取全局變量值為例,
? ? 重定位0x00的時(shí)候:
690: e59f2224 ldr r2, [pc, #548] ; 8bc <main+0x234> 8bc: 000009d4 ldrdeq r0, [r0], -r4 9d4: 00000000 andeq r0, r0, r0? ? 重定位0x30000000的時(shí)候:
30000690: e59f2224 ldr r2, [pc, #548] ; 300008bc <main+0x234> 300008bc: 300009d4 ldrdcc r0, [r0], -r4 300009d4: 00000000 andeq r0, r0, r0? ? 三句匯編代碼其作用是獲取全局變量的值,將其放入寄存器r2中??梢钥吹降谝粭l匯編指令碼和第三條匯編指令碼沒有變化,重點(diǎn)分析第二條匯編指令碼,第二條匯編指令碼實(shí)際上是第一條匯編寄存器尋址偏移, [pc, #548]的值需要找8bc或300008bc偏移的匯編指令,而其匯編指令又指向0x9d4或0x300009d4偏移,最終獲取在其偏移的內(nèi)容。由此推想若重定位到0x00,當(dāng)執(zhí)行到main函數(shù)時(shí),會(huì)導(dǎo)致執(zhí)行地址還在片內(nèi)范圍,假設(shè)9d4大于4K,則尋址大于片內(nèi)內(nèi)存4K,程序就會(huì)溢出。所以鏈接腳本需要設(shè)置重定位地址為0x30000000。
5. 大于4K程序并支持中斷
? ? 當(dāng)需要支持中斷時(shí),head.S需要加上中斷向量表,如下:
? 此時(shí)需要修改鏈接腳本,若延續(xù)上述寫法,如下:
SECTIONS {. = 0x30000000;.text : { *(.text) }.rodata ALIGN(4) : {*(.rodata)} .data ALIGN(4) : { *(.data) }.bss ALIGN(4) : { *(.bss) *(COMMON) } }? ?則會(huì)有嚴(yán)重的問題,這時(shí)看head.S生成的匯編指令
Disassembly of section .text:30000000 <_start>: 30000000: ea000006 b 30000020 <Reset>? ? 第一條指令碼,直接程序跑飛,因?yàn)檫@條指令碼ea000006表示跳轉(zhuǎn)到30000020執(zhí)行,而30000020位于Sdram,還并沒有初始化,所以鏈接腳本應(yīng)該這樣寫:
SECTIONS {. = 0x00000000;.init : AT(0){ head.o init.o nand.o} . = 0x30000000;.text ALIGN(4) : AT(4096) { *(.text) } .rodata ALIGN(4) : {*(.rodata)}.data ALIGN(4) : { *(.data) }__bss_start = .;.bss ALIGN(4) : { *(.bss) *(COMMON) }__bss_end = .; }? ? 可以看到main函數(shù)的重定位也以0x30000000為基準(zhǔn)。當(dāng)執(zhí)行到main函數(shù)時(shí),此時(shí)能保證在sdram里執(zhí)行,并且也能保證取數(shù)據(jù)段的時(shí)候,能得到偏移哪怕大于4K也能正確的重定位到,看如下main匯編指令碼:
300025a4 <main>: 300025a4: e92d4080 push {r7, lr} 300025a8: e24dd080 sub sp, sp, #128 ; 0x80 300025ac: e3a0207d mov r2, #125 ; 0x7d? ? 此時(shí)看nandflash和sdram的內(nèi)存分布如下:
????
????
? ??
總結(jié)
以上是生活随笔為你收集整理的S3C2440 lds链接脚本解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java程序员常用查询和学习的网站
- 下一篇: 风机桨叶故障诊断(六) 利用自编码器进行