天天看點

arm跳轉指令

編寫了一段彙編,理論上是拷貝到sdram上面運作的,移植在思考這樣的一個問題,闆子的外接ram在沒有初始化之前是不能使用的,jlink是不能幫我們拷貝程式到sdram的,同時自己寫的隻是一個小小的程式,沒有必要大動幹戈用uboot,這樣的引導程式拷貝我們的小程式到sdram上面去,因而自己實作的拷貝,因為我的闆子外部ram的位址是0x30000000,這個位址必須要初始化之後才能使用。

大概的思路是這樣的,寫一個小程式,包含了拷貝動作的代碼,和需要拷貝的程式,一起燒寫到我們的nand flash(nand flash)啟動,注意要小于4K,然後我們的把需要執行的小程式拷貝到sdram上面去。

代碼如下。

.equ MEM_CTL_BASE,0x48000000

.equ SDRAM_BASE,0x30000000

.text

.global _start

_start:

    bl disable_watch_dog   @關閉watchdog

    bl memsetup            @設定儲存控制器

    bl copy_steppingstone_to_sdrame @複制代碼到sdram

    ldr pc,=on_sdram

on_sdram:

    ldr sp,=0x34000000   @設定棧

    bl main

halt_loop:

    b halt_loop

……………………(後面的省略)

注意我們的拷貝是拷貝從0x00開始的4k的片内ram,就是自己把自己拷貝到SDRAM上面去,然後跳轉到SDRAM上面運作。

也就是說,同樣的程式,放在4k ram執行了一次,然後放在0x30000000又執行了一次,我對執行的正确度表示懷疑,因為,最起碼,放的地方不同,跳轉的地方也不同,程式還能正常運作嗎?

注意,在ARM指令中,一般的子函數的調用都是相對的跳轉,也就是說,我們的所有的代碼就是一大塊,這一塊無論你放在什麼地方,隻要你的PC隻想程式的開始地方,他就會一條一條的執行,碰到跳轉的時候,自動的找到目前位置的子函數的位置,這是怎麼實作的呢?——相對跳轉。

例如:

bl disable_watch_dog

在編譯的時候

錯誤的了解:首先編譯器計算出disable_watch_dog的位址,然後跳轉到上面運作,這樣顯然,我的程式編譯之後就不會再去編譯,當時程式放在不同的位址上面就不能運作了。

正确的了解:bl disable_watch_dog,編譯器計算目前的PC值,然後計算處目前的PC值和disable_watch_dog之間的距離,然後跳轉的位置是pc+offset,這個offset偏移量,不管你的程式放在哪裡都是不會變的,因而程式可以到處搬運。隻是要注意,這個offset隻是在正負32M範圍之内的。

是以說,即使我的程式最開始是準備到0x30000000上運作的,隻要裡面使用相對跳轉的指令,我把程式拷貝到0x0000照樣能夠運作。

然後在看一下絕對的跳轉,絕對的跳轉就是直接給pc指派,例如:

ldr pc,=0x34000000

也許,如果考慮的比較深入,有的人會問,既然這樣我們編譯之後連接配接還要指明一個-Ttext有什麼用,反正放在什麼地方執行都是一樣的,真的要用到絕對跳轉,注意一下就可以了。

使用-T,就是給每一條指令添加一個屬性,就是運作的位址,這個可以在elf檔案中看出來,這個運作的位址在相對跳轉的時候沒有什麼大用,但是在絕對跳轉的時候,你不可能記住或者運算某一個函數的位址,必須要借助lable,然後

ldr pc,=on_sdram

說的簡單一點,相對跳轉,要使用lable,然後計算lable與目前pc的差距,就可跳轉。

絕對跳轉的時候,首先可以直接指明一個值,其次,我如果想用lable呢,這個lable不是想放在什麼地方都可以的,于是就必須知道程式運作的地方,程式運作的地方并不是程式隻能在那裡運作,而是程式最終還是要到那裡去的,添加這個位址,便于我們的編譯器知道絕對跳轉的時候該如何跳轉。

不知道說的清楚不,個人了解,僅供參考。

繼續閱讀