自己學驅動6——uboot程式碼閱讀一(start.S)
阿新 • • 發佈:2019-02-09
uboot中的start.S檔案開頭的這段程式碼:
00000000 [0xea000012] b 0x50
00000004 [0xe59ff014] ldr pc,0x00000020 ; = #0x33f80140
00000008 [0xe59ff014] ldr pc,0x00000024 ; = #0x33f801a0
0000000c [0xe59ff014] ldr pc,0x00000028 ; = #0x33f80200
00000010 [0xe59ff014] ldr pc,0x0000002c ; = #0x33f80260
00000014 [0xe59ff014] ldr pc,0x00000030 ; = #0x33f802c0
00000018 [0xe59ff014] ldr pc,0x00000034 ; = #0x33f80320
0000001c [0xe59ff014] ldr pc,0x00000038 ; = #0x33f80380
00000020 [0x33f80140] mvnccs r0,#0x10 ; ? rn = 0x8
00000024 [0x33f801a0] mvnccs r0,#0x28 ; ? rn = 0x8
00000028 [0x33f80200] mvnccs r0,#0, 4 ; ? rn = 0x8
0000002c [0x33f80260] mvnccs r0,#6 ; ? rn = 0x8
00000030 [0x33f802c0] mvnccs r0,#0xc ; ? rn = 0x8
00000034 [0x33f80320] mvnccs r0,#0x80000000 ; ? rn = 0x8
00000038 [0x33f80380] mvnccs r0,#2 ; ? rn = 0x8
0000003c [0xdeadbeef] cdple p14,0xa,c11,c13,c15,7
現在來簡單的分析一下這一段程式碼,程式碼中的七個ldr指令就是使程式進入到不同的模式中,因為ARM對應有7個不同的模式。一直很讓人弄不明白的就是經過這樣的程式碼,比如現在要FIQ中斷產生了,pc會被強制賦值為ldr pc, _fiq這條指定的地址,這個時候pc的值會指向_fiq標號處,最終pc裡面將會被賦為fiq標號的值。首先補充一下ARM的中斷向量表:ARM要求中斷向量表必須放置在從0地址開始,連續8×4位元組的空間內(ARM720T和ARM9、ARM10也支援從0xFFFF0000開始的高地址向量表)。具體如下圖所示:
我理解到這裡的時候心裡面一直有兩個問題想不明白:
1.為什麼pc的值被賦值為_fiq: .word fiq指令的地址後,fiq的值就會被賦到pc中?
2.為什麼要做這樣兩次的跳轉?為什麼不直接使用一次跳轉就跳轉到fiq的位置,比如使用b指令跳轉或者ldr pc,=_fiq這種方式呢?
這兩個問題查了很久也沒有找到確切的答案,但是以下的意見可以提供參考:
.word fiq這是.word偽指令的使用方法,偽指令的處理並不是由處理器來執行,處理器也沒有與之相對應的指令碼。這個.word偽指令的作用就是將fiq的執行地址的值取出來,存放到當前的記憶體單元中,從反彙編程式碼可以看出來這個地址佔了4個位元組,其值為0x33f80380,雖然反彙編程式碼將這個值解釋出來了一個指令,但是這個指令是沒有意義的!這裡需要使用的是0x33f80380而並非需要把它當做一個操作碼。所以整個7個.word構成的可以看做是跳轉的第二級的表格,當pc被賦值為這個表格中的一個地址時,由於什麼機制(可能硬體預設第二次就是取跳轉的值,並不會將取到的資料當做指令來解釋,這個當然是一種猜測)就直接會將這個記憶體單元中的值賦值給pc。
當時看ldr偽指令的操作的時候,如果使用ldr pc,=_fiq這種使用方法,當跳轉範圍不能夠使用一個立即數來表示的時候,編譯器將會藉助於記憶體來完成跳轉的賦值操作,這裡相當於就把這個功能直接寫出來,而並不是讓編譯器去做。因為從反彙編指令可以看出,ldr pc, _undefined_instruction,給pc賦的值為0x00000020。要這樣兩級跳轉的目的是不是防止跳轉範圍過大超出立即數的表示範圍呢?這個問題先這樣假設,如果有了新的證據再來修改這裡的文章。
.balign是意思是:以當前地址為開始開始,找到第一次出現的以第一個引數為整數倍的地址,並將其作為結束地址,在這個結束地址前面儲存一個位元組長度的資料,儲存內容正是第二個引數。如果當前地址正好是第一個引數的倍數,則沒有資料被寫入到記憶體。
ldr r1,label ;把label這個地址裡面的內容賦給r1
ldr偽指令
ldr r1,=0x2000014 ;將0x2000014付給r1.
ldr r1,=label ;把label這個地址值賦給r1
對應的反彙編的結果:.globl _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq .balignl 16,0xdeadbeef
00000000 [0xea000012] b 0x50
00000004 [0xe59ff014] ldr pc,0x00000020 ; = #0x33f80140
00000008 [0xe59ff014] ldr pc,0x00000024 ; = #0x33f801a0
0000000c [0xe59ff014] ldr pc,0x00000028 ; = #0x33f80200
00000010 [0xe59ff014] ldr pc,0x0000002c ; = #0x33f80260
00000014 [0xe59ff014] ldr pc,0x00000030 ; = #0x33f802c0
00000018 [0xe59ff014] ldr pc,0x00000034 ; = #0x33f80320
0000001c [0xe59ff014] ldr pc,0x00000038 ; = #0x33f80380
00000020 [0x33f80140] mvnccs r0,#0x10 ; ? rn = 0x8
00000024 [0x33f801a0] mvnccs r0,#0x28 ; ? rn = 0x8
00000028 [0x33f80200] mvnccs r0,#0, 4 ; ? rn = 0x8
0000002c [0x33f80260] mvnccs r0,#6 ; ? rn = 0x8
00000030 [0x33f802c0] mvnccs r0,#0xc ; ? rn = 0x8
00000034 [0x33f80320] mvnccs r0,#0x80000000 ; ? rn = 0x8
00000038 [0x33f80380] mvnccs r0,#2 ; ? rn = 0x8
0000003c [0xdeadbeef] cdple p14,0xa,c11,c13,c15,7
現在來簡單的分析一下這一段程式碼,程式碼中的七個ldr指令就是使程式進入到不同的模式中,因為ARM對應有7個不同的模式。一直很讓人弄不明白的就是經過這樣的程式碼,比如現在要FIQ中斷產生了,pc會被強制賦值為ldr pc, _fiq這條指定的地址,這個時候pc的值會指向_fiq標號處,最終pc裡面將會被賦為fiq標號的值。首先補充一下ARM的中斷向量表:ARM要求中斷向量表必須放置在從0地址開始,連續8×4位元組的空間內(ARM720T和ARM9、ARM10也支援從0xFFFF0000開始的高地址向量表)。具體如下圖所示:
我理解到這裡的時候心裡面一直有兩個問題想不明白:
1.為什麼pc的值被賦值為_fiq: .word fiq指令的地址後,fiq的值就會被賦到pc中?
2.為什麼要做這樣兩次的跳轉?為什麼不直接使用一次跳轉就跳轉到fiq的位置,比如使用b指令跳轉或者ldr pc,=_fiq這種方式呢?
這兩個問題查了很久也沒有找到確切的答案,但是以下的意見可以提供參考:
.word fiq這是.word偽指令的使用方法,偽指令的處理並不是由處理器來執行,處理器也沒有與之相對應的指令碼。這個.word偽指令的作用就是將fiq的執行地址的值取出來,存放到當前的記憶體單元中,從反彙編程式碼可以看出來這個地址佔了4個位元組,其值為0x33f80380,雖然反彙編程式碼將這個值解釋出來了一個指令,但是這個指令是沒有意義的!這裡需要使用的是0x33f80380而並非需要把它當做一個操作碼。所以整個7個.word構成的可以看做是跳轉的第二級的表格,當pc被賦值為這個表格中的一個地址時,由於什麼機制(可能硬體預設第二次就是取跳轉的值,並不會將取到的資料當做指令來解釋,這個當然是一種猜測)就直接會將這個記憶體單元中的值賦值給pc。
當時看ldr偽指令的操作的時候,如果使用ldr pc,=_fiq這種使用方法,當跳轉範圍不能夠使用一個立即數來表示的時候,編譯器將會藉助於記憶體來完成跳轉的賦值操作,這裡相當於就把這個功能直接寫出來,而並不是讓編譯器去做。因為從反彙編指令可以看出,ldr pc, _undefined_instruction,給pc賦的值為0x00000020。要這樣兩級跳轉的目的是不是防止跳轉範圍過大超出立即數的表示範圍呢?這個問題先這樣假設,如果有了新的證據再來修改這裡的文章。
.balign是意思是:以當前地址為開始開始,找到第一次出現的以第一個引數為整數倍的地址,並將其作為結束地址,在這個結束地址前面儲存一個位元組長度的資料,儲存內容正是第二個引數。如果當前地址正好是第一個引數的倍數,則沒有資料被寫入到記憶體。
補充:上面的困惑終於有點眉目了,感謝chinaunix上的網友幫助,補充內容如下:
ldr偽指令
ldr r1,=0x2000014 ;將0x2000014付給r1.
ldr r1,=label ;把label這個地址值賦給r1