由于Thumb指令在某些特殊情況下可能比ARM指令更有效,所以它在很多方面得到了廣泛的應用。但是Thumb知識ARM指令集的一個子集,它不能獨立組成一個應用系統(tǒng),所以在很多情況下應用程序需要二者的混合編程,這就必然存在ARM與Thumb狀態(tài)之間函數(shù)調用的問題。下面將分別詳細介紹。
? ? ? 狀態(tài)切換的實現(xiàn)
ARM/Thumb之間的狀態(tài)切換是通過一條專用的轉移交換指令BX來實現(xiàn)的。BX指令以通用寄存器位操作數(shù),通過拷貝Rn到PC來實現(xiàn)4GB空間范圍內的一個絕對跳轉。BX利用Rn寄存器中目的地址值的最后一位來判斷跳轉后的狀態(tài)。當最后一位為0時,表示轉移到ARM狀態(tài);當最后一位為1時,表示轉移到Thumb狀態(tài)。如圖所示
無論是ARM還是Thumb,其指令在存儲器中都是邊界對齊的。(2字節(jié)或者4字節(jié)對齊,最低位不起作用?。┮虼?,在執(zhí)行跳轉過程中,PC寄存器中的最低位被舍棄,不起作用。在BX指令的執(zhí)行過程中,最低位正好被用作狀態(tài)判斷的標志,不會造成存儲器訪問不對齊的錯誤。
下面是一段直接進入狀態(tài)切換的例程:
?????????????????????????????????????????????????????????????????????;從ARM狀態(tài)開始 CODE32?????????????????????????????????????????????????????????;表明一下是ARM指令 ???????ADR???????R0,Into_Thumb+1????????????????????;得到目標地址,末位置1,表示轉移到Thumb ???????BX?????????R0?????????????????????????????????????????????;轉向Thumb ??????????????… CODE16?????????????????????????????????????????????????????????;表明以下是Thumb指令Into_Thumb ???????… ???????ADR???????R5,Back_to_ARM???????????????????????;得到目標地址,末位缺省為0?,轉移到ARM ???????BX?????????R5?????????????????????????????????????????????;轉向ARM ???????… CODE32 ???????Back_to_ARM??????????????????????????????????????????;ARM代碼段起始地址
舉例:從ARM態(tài)進入thumb態(tài)
① 將在Makefile中將.c文件編譯指定為thumb態(tài)
%.o:%.c arm-linux-gcc?-mthumb?-c?-o?$@?$^?-fno-builtin %.o:%.S arm-linux-gcc?-c?-o?$@?$^
.S文件直接在文件中修改來實現(xiàn)態(tài)的轉化
② 修改.S文件從arm轉化到thumb態(tài)
.text .global?_start .code?32 _start: /*?怎樣從arm_state?->?thumb_state?*/ adr?r0,thumb_func add?r0,r0,#1 bx?r0 .code?16 thumb_func: bl?sdram_init //bl?sdram_init2?//用到有初始值的數(shù)組,不是位置無關碼 bl?copy2sdram bl?clean_bss //bl?main?//使用BL命令相對跳轉,程序仍然在Nor/sram執(zhí)行 ldr?r0,=main?//絕對跳轉,跳到SDRAM mov?pc,r0 halt: b?halt
-----------------------------------------------------------------------------------------------------------------------------------------------------
問題:
①:
start.S: Assembler messages:
start.S:60: Error: lo register required -- `ldr pc,=main'
Makefile:11: recipe for target 'start.o' failed
thumb不像arm態(tài)那樣,不能直接將標號賦值給pc,需要通過寄存器轉化:
ldr r0,=main
mov pc,r0
②:
init.o(.text+0x58): In function `sdram_init2':
: undefined reference to `memcpy'
thumb中自動給我們將數(shù)組中的值通過memcpy復制到了數(shù)組,我們可以通過static來解決這個問題:
參考Getting GCC to compile without inserting call to memcpy:
https://stackoverflow.com/questions/6410595/getting-gcc-to-compile-without-inserting-call-to-memcpy
unsigned?int?arr[]??=?{ 0x02000000,?????//BWSCON 0x00000700,?????//BANKCON0 0x00000700,?????//BANKCON1 0x00000700,?????//BANKCON2 0x00000700,?????//BANKCON3?? 0x00000700,?????//BANKCON4 0x00000700,?????//BANKCON5 0x00018001,?????//BANKCON6 0x00018005,?????//BANKCON7 0x008404f5,?????//REFRESH ?0x000000b1,?????//BANKSIZE 0x00000020,?????//MRSRB6 0x00000020,?????//MRSRB7 };//把那些值全部放在數(shù)組里面 ->>>>>> const?static?unsigned?int?arr[]??=?{ 0x02000000,?????//BWSCON 0x00000700,?????//BANKCON0 0x00000700,?????//BANKCON1 0x00000700,?????//BANKCON2 0x00000700,?????//BANKCON3?? 0x00000700,?????//BANKCON4 0x00000700,?????//BANKCON5 0x00018001,?????//BANKCON6 0x00018005,?????//BANKCON7 0x008404f5,?????//REFRESH ?0x000000b1,?????//BANKSIZE 0x00000020,?????//MRSRB6 0x00000020,?????//MRSRB7 };//把那些值全部放在數(shù)組里面
③:
warning: conflicting types for built-in function
解決:在編譯的時候加上-fno-builtin不使用內建函數(shù)
arm-linux-gcc -mthumb -c -o $@ $^ -fno-builtin