国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

嵌入式u-boot中標號_start的值的問題

發布時間:2013-12-2 17:28    發布者:edu118gct
關鍵詞: u-boot , _start
關于u-boot中標號_start的值的問題

為什么編譯后_start標號的值0x33f80000,而不是0x00000000?下面來詳細分析一下。
大家都知道U-BOOT分為兩個階段,第一階段是(~/cpu/arm920t/start.S)FLASH上運行(一般情況下),完成對硬件的初始化,包括看門狗,中斷緩存等,并且負責把代碼搬移到SDRAM(在搬移的時候檢查自身代碼是否在SDRAM),然后完成C程序運行所需要環境的建立,包括堆棧的初始化等,最后執行一句跳轉指令:

  ldr pc, _start_armboot

  _start_armboot: .word start_armboot,

進入到/lib_arm/board.c中的函數void start_armboot (void),從此就進入了第二階段。這是在很多資料上都有講述的,所以勿需多言了。
現在對于第一階段有幾個問題,以前我一直是沒有搞明白的,既然在FLASH中的代碼是把自己拷貝到SDRAM中,那么在S3C2410的內存地址空間,就有兩份的啟動代碼,第一份就是在FLASH中,第二份就是在SDRAM中。根據鏈接腳本文件(~/board/smdk2410/u-boot.lds)

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;    /* 后記:這個鏈接起始地址實際上被-Ttest $(TEST_BASE)更新了*/

. = 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 = .;

}
我們通常會這樣認為:
*.text中的所有地址標號(在鏈接時確定)是從0地址開始生成的。
其中的鏈接命令 . = 0x00000000;表示地址計數器從0地址開始計數,而且_start 是程序代碼段的入口,那么*.text中的所有地址標號(cpu/arm920t/start.S中定義的)就應該從0地址開始計數,那么標號start_armboot(就是void start_armboot (void)函數的入口地址)應該在FLASH中才對啊,所以按照上邊的分析,

ldr pc, _start_armboot

_start_armboot: .word start_armboot

此條語句后,并沒有跳轉到SDRAM中的void start_armboot (void),而是跳轉到了FLASH中的void start_armboot (void)中。
所以當我們這樣認為時,就出現了這樣的矛盾,在FLASH中有一段代碼把自己拷貝到SDRAM中,產生了兩份UBOOT可執行的指令流,但是最后卻沒有跳轉到SDRAM中去運行以提高指令執行的速度。
這個看法是錯的,因為實際上在arm-linux-ld 執行時,原來定義的0x0地址被更新為TEXT_BASE定義的地址。

對于以下代碼:
   relocate:    /* relocate U-Boot to RAM     */
   adr r0, _start /* r0 <- current position of code   */
   ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
   cmp     r0, r1                  /* don't reloc during debug         */
   beq     stack_setup

   ldr r2, _armboot_start
   ldr r3, _bss_start
   sub r2, r3, r2 /* r2 <- size of armboot            */
   add r2, r0, r2 /* r2 <- source end address         */

注意:GNU:adr r0, _start 作用是獲得 _start 的實際運行所在的地址值,而ldr r1, _TEXT_BASE 為獲得地址_TEXT_BASE中所存放的數據,其中adr r0, _start翻譯成 add r0,(PC+#offset)offset 就是 adr r0, _start 指令到_start 的偏移量,在鏈接時確定,這個偏移量是地址無關的。而 ldr r1, _TEXT_BASE 指令表示以程序相對偏移的方式加載數據,是索引偏移加載的另外一種形式,等同于ldr r1,[PC+#offset]offset ldr r1, _TEXT_BASE _TEXT_BASE 的偏移量。注意這種用法并不是偽指令,偽指令的特征是 ldr r1, =expr/lable_expr。也就是ldr后面形式的不同,會影響它是指令還是偽指令。
比較一下:
add r0,(PC+#offset)(PC+#offset)是相對地址,表示把本指令上溯或下溯offset處的地址加載到 r0
ldr r1,[PC+#offset][PC+#offset]也是相對地址,表示把偏移offset處的地址上的數據加載到 r1

現在繼續:
剛才分析所得到的矛盾,肯定是在認識上存在的偏差,經過把U-BOOT進行make后,從所生成的兩個.map文件來看(~/u-boot.mapSysten.map),所有的地址標號都是從0x33f80000開始的,就是從SDRAM的高地址開始,等于TEXT_BASE的值,也就是說,鏈接器是從0x33F80000開始來鏈接所編譯生成的目標文件的,而不是從0地址開始,經過查看,start_armboot= 0x33f80b40,這個地址肯定在SDRAM中了,就是說void start_armboot (void)函數的入口地址在SDRAM(鏈接器決定),所以執行

ldr pc, _start_armboot
_start_armboot: .word start_armboot,

PC指針肯定就指向了SDRAM中,換句話就是說進入到SDRAM中了,對于ldr pc, _start_armboot,其仍然是GNU中使用程序相對偏移的方式加載數據,翻譯一下就是ldr pc, [pc+pc_start_armboot的偏移值,結果就把_start_armboot地址中的數start_armboot放入pc中完成了跳轉,而 start_armboot 的值(函數地址)是在鏈接時就確定了,是相對于 TEXT_BASE 的。因為在整個UBOOT的階段1中所有的尋址都是相對位置的尋址(雖然鏈接器認為是階段1的代碼是從地址0x3ff80000中開始鏈接的),把階段1的代碼放在0地址開始的FLASH中也是可以正確的運行的,如果ARM的復位向量是在0x00000001(假設),那么把代碼燒寫到從0x00000004處開始的地方,上電時也可以正確的運行(假設ARM的復位向量是在0x00000004成立),當然ARM的復位向量不在這里,只是以此假設來說明以上的對于階段1的分析。
現在最后一個矛盾就是鏈接腳本(~/board/smdk2410/u-boot.lds)所描述的鏈接地址與實際的鏈接地址不相同的問題,因為根據鏈接腳本,所有的地址標號應該從0地址開始計數的,然而不是。經過查找Makefile文件,在頂層的Makefile文件中,在166行中鏈接是的鏈接命令:
$(LD) $(LDFLAGS) $$UNDEF_SYM $(OBJS) \,
其中的LDFLAGS在定義在頂層的config.mk中的145DFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS),

最關鍵的就是 -Ttext $(TEXT_BASE)命令了,他的含義就是說,起始地址在TEXT_BASE,TEXT_BASE~/board/smdk2410/config.mk中規定了:TEXT_BASE = 0x3FF80000;

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

    __u_boot_cmd_start = .;    *.u_boot_cmd段的起始地址
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;       *.u_boot_cmd段的結束地址

以供C程序使用。 __u_boot_cmd_start__u_boot_cmd_end可以作為全局的一個常數使用。
總結:
因為-Ttext $(TEXT_BASE)命令的使用,鏈接器把UBOOT從地址0x3ff80000開始連接,在第一階段中,所有使用的目標地址尋址都是使用當前PC值加減偏移量的方法,所以把UBOOT燒寫到0地址開始的FLASH中,不影響第一階段的正確執行。第一階段是與代碼位置無關的代碼,第二階段才是與代碼位置有關的代碼。專業嵌入式技術實訓咨詢Q754634522      


本文地址:http://www.qingdxww.cn/thread-124111-1-1.html     【打印本頁】

本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
您需要登錄后才可以發表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區
  • 了解一下Microchip強大的PIC18-Q24 MCU系列
  • 5分鐘詳解定時器/計數器E和波形擴展!
  • 基于CEC1712實現的處理器SPI FLASH固件安全彈性方案培訓教程
  • PIC18-Q71系列MCU概述
  • 貿澤電子(Mouser)專區

相關視頻

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 星空影院手机免费观看下载 | 四虎影永久在线高清免费 | 国产好片无限资源 | 亚欧色视频在线观看免费 | 婷婷丁香色综合狠狠色 | 禁天堂a在线观看 | 男女激情视频国产免费观看 | 青青草原国产在线观看 | 日本午夜精品 | 亚洲精品成人久久 | 日本免费观看视频 | 亚洲系列中文字幕一区二区 | 在线天堂中文有限公司 | 成人福利在线视频 | 欧美一区二区三区日韩免费播 | 国产亚洲日本 | 好吊爽在线播放视频 | 国产高清精品一级毛片 | 欧美精品v日韩精品v国产精品 | 毛片一区 | 曰本亚洲欧洲色a在线 | 久久夜色精品国产欧美 | 色网站视频 | 三级视频网站 | 久久青青草原精品国产不卡 | 国产精品免费久久久免费 | 国产欧美一区二区成人影院 | 美国大片免费看 | 欧美日韩在线精品一区二区三区 | 97视频精品全国在线观看 | 国产无限制自拍 | 日韩高清专区 | 日韩欧美高清在线 | 日韩亚洲欧洲在线rrrr片 | 2019国内自拍| 色综合久久久久久久久五月性色 | 岛国大片在线播放高清 | 国产高清a毛片在线看 | 国产免费131美女视频 | 狠狠色婷婷丁香六月 | 九九亚洲视频 |