兩年前開始接觸MIPS,那時(shí)候覺得好多問題不是很理解,當(dāng)然有些問題至今還是一知半解的。在后來的學(xué)習(xí)中經(jīng);剡^頭來看之前碰到的那些問題,每次看都會(huì)有新的心得,也許這正應(yīng)了那句古語“溫故而知新”。唉,古人很早就明白了這個(gè)道理,不禁感慨自己落后了不是一點(diǎn)半點(diǎn)!
下面回顧一下MIPS中RELOC的這段描述。首次接觸RELOC是在vxWorks中的一段MIPS匯編,RELOC是一個(gè)宏定義,具體如下:
- #define RELOC(toreg,address) \
- bal 9f; \
- 9:; \
- la toreg,address; \
- addu toreg,ra; \
- la ra,9b; \
- subu toreg,ra
當(dāng)時(shí)覺得這段的意思是在進(jìn)行地址的轉(zhuǎn)換,也許你會(huì)說我從RELOC這個(gè)字面上就可以理解到這個(gè)意思了。呵呵,如果這樣的話那么你是個(gè)高手了,小弟自嘆不如!
那么這一段究竟講什么意思呢?在具體講解之前,我們還是來看看這個(gè)宏具體是如何使用的。我們學(xué)一個(gè)東西往往是從模仿開始的,實(shí)踐證明這是學(xué)習(xí)的最最有效的途徑。RELOC的使用大致是這樣的:
- RELOC(t0, romStart)
- jal t0
- nop
這樣我們就可以具體來了解這一段的具體意思了:romStart的連接地址是在ram所在的地址,而實(shí)際運(yùn)行是在flash上(這是一段bootloader啟動(dòng)代碼,上電運(yùn)行是在flash中運(yùn)行的),我們需要將romStart的地址換成在flash中的位置,所以該段代碼先加上當(dāng)前運(yùn)行位置的地址,然后減去鏈接時(shí)生成的當(dāng)前位置的地址,這樣就得到實(shí)際運(yùn)行時(shí)romStart的相對(duì)地址,這樣就可以直接跳轉(zhuǎn)過去了。
為什么是這樣子的一個(gè)功能呢?我記得當(dāng)時(shí)上網(wǎng)搜到了這樣一段描述:
- RELOC(t0,romStart) \
- 0Xbfc01004: bal 9f; \
- 9: ;\
- 0Xbfc01008:la t0, romStart; \
- 0Xbfc01010:addu t0, ra; \
- 0Xbfc01014:la ra, 9b; \
- 0Xbfc0101c:subu t0, ra \
- jal t0
- nop
1. 執(zhí)行bal之后,ra寄存器的值為0Xbfc0100c;
2. 執(zhí)行l(wèi)a之后,t0寄存器存放的是romStart的鏈接地址。
3. 執(zhí)行addu之后,t0寄存器存放的是0Xbfc0100c+romStart的鏈接地址。
4. 執(zhí)行l(wèi)a之后,ra寄存器存放的是0xbfc01008的地址對(duì)應(yīng)的鏈接地址。
5. 執(zhí)行subu之后,t0寄存器存放的是0xbfc01008的地址對(duì)應(yīng)的鏈接地址-(0Xbfc0100c+romStart),此時(shí)t0寄存器存放的即是romStart對(duì)應(yīng)的ROM地址。
看了上面這段解釋,總感覺有那么點(diǎn)的奇怪。難道最終計(jì)算出來的romStart在flash中的地址沒有偏移4字節(jié)嗎?
后來,我有幸接觸到了Broadcom的CFE。它里面關(guān)于reloc的做法比較合理,很清晰,新手很容易就看明白。
- /* Check if we booted from SDRAM */
- bal 1f
- nop
- 1: li t0,PHYSADDR_MASK
- and t0,t0,ra
- li t1,SI_FLASH1
- blt t0,t1,2f
- move s5,zero
- /* If we are in flashcompute reloc for text addresses */
- la t0,1b
- sub s5,ra,t0 # s5: Relocation factor
- 2:
- /* jyh 2009.12 led_out=1 */
- li a0,1
- la t2,led_out
- add t2,t2,s5
- jalr t2
- nop
參照上面的發(fā)法試著分析一下,是不是很容易?沒有一點(diǎn)歧義吧?
對(duì)于vxWorks中存在的歧義,至今仍未參透,期待個(gè)中高手的指點(diǎn)了!
附:
何謂鏈接地址?凡是標(biāo)號(hào)的值都是標(biāo)號(hào)所在指令的鏈接地址(即RAM地址)。在分支指令中的標(biāo)號(hào)所表示的值是一個(gè)相對(duì)于本分支指令地址的16bit的偏移量。匯編器會(huì)將標(biāo)號(hào)所表示的有效地址(目標(biāo)地址)轉(zhuǎn)換成合適的偏移值放入指令中。在跳轉(zhuǎn)指令中的標(biāo)號(hào)所表示的值也是由匯編器將標(biāo)號(hào)所在的有效地址(目標(biāo)地址)轉(zhuǎn)換成合適的偏移值,轉(zhuǎn)換規(guī)則詳見指令說明。
本文是在學(xué)習(xí)網(wǎng)絡(luò)上一位博友的日志之后,有感所寫,在此感謝一下他。
http://blog.sina.com.cn/s/blog_3f7cc7420100p62j.html |