久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

UBoot中關(guān)于TEXT_BASE,,代碼重定位,,鏈接地址相關(guān)說(shuō)明

 chengong510 2013-11-07

都知道U-BOOT分為兩個(gè)階段,,第一階段是(~/cpu/arm920t/start.S中)在FLASH上運(yùn)行(一般情況下),完成對(duì)硬件的初始化,,包括看門狗,,中斷緩存等,并且負(fù)責(zé)把代碼搬移到SDRAM中(在搬移的時(shí)候檢查自身代碼是否在SDRAM中),,然后完成C程序運(yùn)行所需要環(huán)境的建立,,包括堆棧的初始化等,最后執(zhí)行一句跳轉(zhuǎn)指令:

        ldr pc, _start_armboot

        _start_armboot: .word start_armboot,

進(jìn)入到/lib_arm/board.c中的函數(shù)void start_armboot (void),從此就進(jìn)入了第二階段,。這是在很多資料上都有講述的,,所以勿需多言了。

    現(xiàn)在對(duì)于第一階段有幾個(gè)問(wèn)題,,以前我一直是沒有搞明白的,,既然在FLASH中的代碼是把自己拷貝到SDRAM中,那么在S3C2410的內(nèi)存地址空間,,就有兩份的啟動(dòng)代碼,,第一份就是在FLASH中,第二份就是在SDRAM中,。根據(jù)鏈接腳本文件(~/board/smdk2410/u-boot.lds)

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
 . = 0x00000000;   

 . = ALIGN(4);
 .text      :
 {
   cpu/arm920t/start.o (.text)
   *(.text)
 }

 . = ALIGN(4);
 .rodata : { *(.rodata) }

 . = ALIGN(4);
 .data : { *(.data) }

 . = ALIGN(4);
 .got : { *(.got) }

 . = .;
 __u_boot_cmd_start = .;
 .u_boot_cmd : { *(.u_boot_cmd) }
 __u_boot_cmd_end = .;

 . = ALIGN(4);
 __bss_start = .;
 .bss : { *(.bss) }
 _end = .;

}
    其中的鏈接命令 . = 0x00000000;表示地址計(jì)數(shù)器從0地址開始計(jì)數(shù),,而且_start 是程序代碼段的入口,那么*.text中的所有地址標(biāo)號(hào)(cpu/arm920t/start.S中定義的)就應(yīng)該從0地址開始計(jì)數(shù),,那么標(biāo)號(hào) start_armboot(就是void start_armboot (void)函數(shù)的入口地址)應(yīng)該在FLASH中才對(duì)啊,,所以按照上邊的分析,

        ldr pc, _start_armboot

        _start_armboot: .word start_armboot

此條語(yǔ)句后,,并沒有跳轉(zhuǎn)到SDRAM中的void start_armboot (void),,而是跳轉(zhuǎn)到了FLASH中的void start_armboot (void)中。

所以就出現(xiàn)了這樣的矛盾,,在FLASH中有一段代碼把自己拷貝到SDRAM中,,產(chǎn)生了兩份UBOOT可執(zhí)行的指令流,但是最后卻沒有跳轉(zhuǎn)到SDRAM中去運(yùn)行以提高指令執(zhí)行的速度,。

產(chǎn)生以上的認(rèn)識(shí)是基于以下幾個(gè)認(rèn)識(shí)(肯定是錯(cuò)誤的):

1.*.text中的所有地址標(biāo)號(hào)(在鏈接時(shí)確定)是從0地址開始生成的。

      實(shí)際上在arm-linux-ld 執(zhí)行時(shí),,原來(lái)定義的0x0地址被更新為TEXT_BASE定義的地址,。

2.relocate:   
   adr r0, _start 
   ldr r1, _TEXT_BASE 
   cmp     r0, r1                 
   beq     stack_setup

   ldr r2, _armboot_start
   ldr r3, _bss_start
   sub r2, r3, r2 
   add r2, r0, r2 

如果不是出于調(diào)試階段,這段搬移代碼中的r0和r1肯定不相等的,,r0=#0,r1=#TEXT_BASE: 0x33F80000(在./board/smdk2410/config.mk中),,所以執(zhí)行代碼的自身拷貝與搬移。

注意:在GNU中:adr r0, _start 作用是獲得 _start 的實(shí)際運(yùn)行所在的地址值,,而ldr r1, _TEXT_BASE 為獲得地址_TEXT_BASE中所存放的數(shù)據(jù),,其中adr r0, _start翻譯成 add r0,(PC+#offset),,offset 就是 adr r0, _start 指令到_start 的偏移量,在鏈接時(shí)確定,,這個(gè)偏移量是地址無(wú)關(guān)的,。而 ldr r1, _TEXT_BASE 指令表示以程序相對(duì)偏移的方式加載數(shù)據(jù),是索引偏移加載的另外一種形式,,等同于ldr r1,[PC+#offset],,offset 是 ldr r1, _TEXT_BASE 到 _TEXT_BASE 的偏移量。注意這種用法并不是偽指令,,偽指令的特征是 ldr r1, =expr/lable_expr,。對(duì)于LDR偽指令,ADS的情況有些不一樣(細(xì)微差別),,在ADS中的情況可以參考杜春雷<ARM體系結(jié)構(gòu)與編程>144頁(yè),。


比較一下:

add r0,(PC+#offset):(PC+#offset)是相對(duì)地址,表示把本指令上溯或下溯offset處的地址加載到 r0,;

ldr r1,[PC+#offset]:[PC+#offset]也是相對(duì)地址,,表示把偏移offset處的地址上的數(shù)據(jù)加載到 r1;

現(xiàn)在繼續(xù):

    剛才分析所得到的矛盾,,肯定是在認(rèn)識(shí)上存在的偏差,,經(jīng)過(guò)把U-BOOT進(jìn)行make后,從所生成的兩個(gè).map文件來(lái)看(~/u-boot.map和 Systen.map),,所有的地址標(biāo)號(hào)都是從0x33f80000開始的,,就是從SDRAM的高地址開始,等于TEXT_BASE的值,,也就是說(shuō),,鏈接器是從0x33F80000開始來(lái)鏈接所編譯生成的目標(biāo)文件的,而不是從0地址開始,,經(jīng)過(guò)查看,,start_armboot=0x33f80d9c,就是說(shuō)void start_armboot (void)函數(shù)的入口地址在SDRAM中(鏈接器決定),,所以執(zhí)行

        ldr pc, _start_armboot

        _start_armboot: .word start_armboot,

PC指針肯定就指向了SDRAM中,,換句話就是說(shuō)進(jìn)入到SDRAM中了,對(duì)于ldr pc, _start_armboot,,其仍然是GNU中使用程序相對(duì)偏移的方式加載數(shù)據(jù),,翻譯一下就是ldr pc, [pc+pc到_start_armboot的偏移值],結(jié)果就把_start_armboot地址中的數(shù)start_armboot放入pc中完成了跳轉(zhuǎn),,而 start_armboot 的值(函數(shù)地址)是在鏈接時(shí)就確定了,,是相對(duì)于 TEXT_BASE 的。因?yàn)樵谡麄€(gè)UBOOT的階段1中所有的尋址都是相對(duì)位置的尋址(雖然鏈接器認(rèn)為是階段1的代碼是從地址0x3ff80000中開始鏈接的),,把階段1 的代碼放在0地址開始的FLASH中也是可以正確的運(yùn)行的,,如果ARM的復(fù)位向量是在0x00000001(假設(shè)),,那么把代碼燒寫到從 0x00000004處開始的地方,上電時(shí)也可以正確的運(yùn)行(假設(shè)ARM的復(fù)位向量是在0x00000004成立),,當(dāng)然ARM的復(fù)位向量不在這里,,只是以此假設(shè)來(lái)說(shuō)明以上的對(duì)于階段1的分析。

    現(xiàn)在最后一個(gè)矛盾就是鏈接腳本(~/board/smdk2410/u-boot.lds)所描述的鏈接地址與實(shí)際的鏈接地址不相同的問(wèn)題,,因?yàn)楦鶕?jù)鏈接腳本,,所有的地址標(biāo)號(hào)應(yīng)該從0地址開始計(jì)數(shù)的,然而不是,。經(jīng)過(guò)查找Makefile文件,,在頂層的Makefile文件中,在166行中鏈接是的鏈接命令:

$(LD) $(LDFLAGS) $$UNDEF_SYM $(OBJS) \,

其中的LDFLAGS在定義在頂層的config.mk中的145行:LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS),

最關(guān)鍵的就是 -Ttext $(TEXT_BASE)命令了,他的含義就是說(shuō),起始地址在TEXT_BASE,而TEXT_BASE在~/board/smdk2410/config.mk中TEXT_BASE = 0x33F80000;

到此就弄清楚為什么鏈接從0x3ff80000開始的了,,至于鏈接腳本,,其主要作用是用來(lái)指明各個(gè)*.o文件的順序,如入口地址標(biāo)號(hào)(_start)等,,以及使兩個(gè)地址標(biāo)號(hào)得到當(dāng)前的地址

    __u_boot_cmd_start = .;    *.u_boot_cmd段的起始地址

    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;       *.u_boot_cmd段的結(jié)束地址

以供C程序使用,。 __u_boot_cmd_start和__u_boot_cmd_end可以作為全局的一個(gè)常數(shù)使用。

總結(jié):

    因?yàn)?Ttext $(TEXT_BASE)命令的使用,鏈接器把UBOOT從地址0x3ff80000開始連接,,在第一階段中,,所有使用的目標(biāo)地址尋址都是使用當(dāng)前PC值加減偏移量的方法,所以把UBOOT燒寫到0地址開始的FLASH中,,不影響第一階段的正確執(zhí)行

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多