運行地址和加載地址


http://blog.csdn.net/ce123_zhouwei/article/details/6990100

運行地址和加載地址
在連接目標代碼時,會提到運行地址和加載地址。這兩者有什麼區別呢?
加載時地址就是程序放置的地址,運行地址就是程序定位的絕對地址,也即在編譯連接時定位的地址。
如果程序是在flash裏運行,則運行地址和加載地址是相同的。
如果程序是在ram裏運行,但程序是存儲在flash裏,則運行地址指向ram,而加載地址是指向flash。

代碼一般是燒寫在NAND裏面,比如S3C2440 如果開機從NAND啓動 其開始的4K代碼會被COPY到2440內部的4KRAM 用於對關鍵硬件的初始化 這時候內部RAM被映射爲0x0地址。
如果從NOR啓動,因爲NOR支持片上運行,代碼可以直接在NOR上運行 此時NOR便被映射成0x0,S3C2440 內部的4KRAM便被映射到了0x40000000處。


下面我們看看鏈接文件。           
    對於.lds文件,它定義了整個程序編譯之後的連接過程,決定了一個可執行程序的各個段的存儲位置。先看一下GNU官方網站上對.lds文件形式的完整描述:

複製代碼
    SECTIONS {  
    ...  
    secname start BLOCK(align) (NOLOAD) : AT ( ldadr )  
      { contents } >region :phdr =fill  
    ...  
    } 
複製代碼

secname和contents是必須的,其他的都是可選的。下面看看幾個常用的:
1、secname:段名
2、contents:決定哪些內容放在本段,可以是整個目標文件,也可以是目標文件中的某段(代碼段、數據段等)
3、start:本段連接(運行)的地址,如果沒有使用AT(ldadr),本段存儲的地址也是start。GNU網站上說start可以用任意一種描述地址的符號來描述。
4、AT(ldadr):定義本段存儲(加載)的地址。

看一個簡單的例子:

/* nand.lds */  
SECTIONS {   
   firtst 0x00000000 : { head.o init.o }   
   second 0x30000000 : AT(4096) { main.o }   
}

以上,head.o放在0x00000000地址開始處,init.o放在head.o後面,他們的運行地址也是0x00000000,即連接和存儲地址相同(沒有AT指定);
main.o放在4096(0x1000,是AT指定的,存儲地址)開始處,但是它的運行地址在0x30000000,運行之前需要從0x1000(加載處)複製到0x30000000(運行處),
此過程也就用到了讀取Nand flash。這就是存儲地址和連接(運行)地址的不同,稱爲加載時域和運行時域,可以在.lds連接腳本文件中分別指定。
編寫好的.lds文件,在用arm-linux-ld連接命令時帶-Tfilename來調用執行,如arm-linux-ld –Tnand.lds x.o y.o –o xy.o。也用-Ttext參數直接指定連接地址,
arm-linux-ld –Ttext 0x30000000 x.o y.o –o xy.o

總之:
         連接地址<==>運行地址
         存儲地址<==>加載地址

既然程序有了兩種地址,就涉及到一些跳轉指令的區別,下面就來具體看看這些跳轉指令。
ARM彙編中,常有兩種跳轉方法:b跳轉指令、ldr指令向PC賦值。
(1)b step1 :b跳轉指令是相對跳轉,依賴當前PC的值,偏移量是通過該指令本身的bit[23:0]算出來的,這使得使用b指令的程序不依賴於要跳到的代碼的位置,只看指令本身。
(2)ldr pc, =step1 :該指令是從內存中的某個位置(step1)讀出數據並賦給PC,同樣依賴當前PC的值,但是偏移量是那個位置(step1)的連接地址(運行時的地址),
       所以可以用它實現從Flash到RAM的程序跳轉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章