運行地址和加載地址


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的程序跳轉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM