加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 11.10  ARM和Thumb的混合編程
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

Thumb指令集之: ARM和Thumb的混合編程

2013/09/30
3
閱讀需 38 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

 

11.10  ARM和Thumb的混合編程

11.10.1  互交工作基礎(chǔ)

Thumb以其較高的代碼密度和在窄存儲(chǔ)器上的性能,使得它在很多系統(tǒng)中得到廣泛應(yīng)用。但在很多情況下,還是不得不使用ARM指令,這是因?yàn)椋?/p>

① ARM代碼比Thumb代碼有更快的執(zhí)行速度;

② ARM處理器的一些特定功能必須由ARM指令實(shí)現(xiàn),其中包括PSR指令、協(xié)處理器指令;

③ 異常發(fā)生時(shí),處理器自動(dòng)進(jìn)入ARM狀態(tài),如果異常處理程序需要使用Thumb指令也必須通用一個(gè)ARM程序頭(ARM assembler header)。

基于以上原因,即使程序需要由Thumb代碼實(shí)現(xiàn),也必須通過ARM-Thumb互交(ARM-Thumb interworking)進(jìn)入Thumb狀態(tài)。

ARM-Thumb互交是指對(duì)匯編語言和C/C++語言的ARM和Thumb代碼進(jìn)行連接的方法,它進(jìn)行兩種狀態(tài)(ARM和Thumb狀態(tài))間的切換。在進(jìn)行這種切換時(shí),有時(shí)需使用額外的代碼,這些代碼被稱為Veneer。AAPCS定義了ARM和Thumb過程調(diào)用的標(biāo)準(zhǔn)。

從一個(gè)ARM例程調(diào)用一個(gè)Thumb例程,內(nèi)核必須進(jìn)行狀態(tài)切換。狀態(tài)的變化由CPSR的T位來顯示。在跳轉(zhuǎn)到一個(gè)例程時(shí)BX指令可用于ARM和Thumb狀態(tài)切換,具體用法如下。

在Thumb狀態(tài)調(diào)用ARM例程時(shí),采用:

BX  Rn;

在ARM狀態(tài)調(diào)用Thumb例程時(shí),采用:

BX{cond}  Rn;

其中,Rn可以是r0~r15中的任意寄存器。

這種帶狀態(tài)切換的跳轉(zhuǎn)指令BX,將寄存器Rn的內(nèi)容拷貝到程序計(jì)數(shù)器寄存器PC,因此可以實(shí)現(xiàn)4G空間的跳轉(zhuǎn)。指令根據(jù)寄存器Rn的bit[0]來決定處理器是否進(jìn)行狀態(tài)切換,詳細(xì)內(nèi)容參見ARM指令一節(jié)。

下面是一段ARM程序,該程序調(diào)用虛擬的SWI_writeC子程序從存儲(chǔ)器的固定地址取出字符串“hello world”并輸出。

        AREA    Hello,CODE,READONLY

SWI_WriteC        EQU        &0 ;軟中斷調(diào)用參數(shù)

SWI_Exit           EQU        &11 ;程序退出軟中斷調(diào)用參數(shù)

        ENTRY

START    ADR    r1,TEXT ;取字符串地址

LOOP    LDRB    r0,[r1],#1 ;取下一字節(jié)內(nèi)容

         CMP  r0,#0 ;判斷是否為字符串尾

         SWINE  SWI_WriteC ;軟中斷調(diào)用打印字符

         BEN  LOOP ;循環(huán)

         SWI  SWI_Exit ;軟中斷調(diào)用退出程序執(zhí)行

TEXT      =      “Hello World”,&0a,&0d,0

         END

下面的代碼將上面的ARM代碼轉(zhuǎn)換成等價(jià)的Thumb代碼。

          AREA  HelloW_Thumb,CODE,READONLY 

SWI_WriteC  EQU    &0 ;軟中斷調(diào)用參數(shù)

SWI_Exit  EQU    &11 ;程序退出軟中斷調(diào)用參數(shù)

          ENTRY ;程序入口點(diǎn)

          CODE32  進(jìn)入ARM狀態(tài)

          ADR r0, START+1 ;取得Thumb代碼入口地址 

          BX r0 ;進(jìn)入Thumb代碼 

          CODE16 ;Thumb代碼入口點(diǎn)

START    ADR  r1, TEXT ;r1 -> "Hello World" 

LOOP     LDRB  r0, [r1] ;取下一字節(jié)內(nèi)容 

          ADD  r1, r1, #1 ;地址指針加1  **T 

          CMP r0, #0 ;判斷是否為字符串尾

          BEQ DONE ;完成? **T 

          SWI SWI_WriteC ;如果不是字符串尾

          B LOOP ;繼續(xù)循環(huán) 

DONE     SWI  SWI_Exit ;程序退出 

          ALIGN ;字對(duì)齊 

TEXT     DATA 

                "Hello World",&0a,&0d,&00 

          END

上例中,ARM代碼到Thumb代碼轉(zhuǎn)換過程中新增加的指令用“**T”標(biāo)注。

 

在實(shí)現(xiàn)ARM代碼和Thumb代碼轉(zhuǎn)換時(shí),大部分的ARM指令有等價(jià)的Thumb指令,只有少數(shù)指令沒有。如加載字節(jié)指令(LDR)不支持自動(dòng)變址,軟中斷指令不能條件執(zhí)行。

在編寫Thumb代碼時(shí)要注意以下幾點(diǎn)。

① 匯編器需要知道什么時(shí)候產(chǎn)生ARM代碼、什么時(shí)候產(chǎn)生Thumb代碼,程序中使用CODE32和CODE16偽操作提供給編譯器這些信息。

② 由于處理器上電執(zhí)行是在ARM狀態(tài)下完成的,所以要使用Thumb指令必須由ARM指令調(diào)用Thumb指令,這一過程是通過“BX  LR”指令來實(shí)現(xiàn)的。需要注意的是,在使用“BX  LR”指令前,要對(duì)寄存器LR做正確的初始化。

③ 在ARM和Thumb混合編程時(shí),常使用ALIGN偽操作保證內(nèi)存地址對(duì)齊。

11.10.2  互交子程序

編寫ARM/Thumb互交代碼時(shí),下面兩點(diǎn)需要注意。

① 對(duì)于C/C++子程序而言,只要在編譯時(shí)指定--apcs/interwork選項(xiàng),匯編器會(huì)生成合適的返回代碼,使得程序返回到和調(diào)用程序相同的狀態(tài)。

② 在匯編語言子程序中,用戶必須自己編寫相應(yīng)的返回代碼,使得程序返回到和調(diào)用程序相同的狀態(tài)。

如果目標(biāo)代碼包含以下內(nèi)容,應(yīng)該在編譯或匯編時(shí)使用--apcs/interwork選項(xiàng)使處理器能夠在ARM和Thumb代碼間進(jìn)行正確的切換,這種情況包含以下4種。

① 需要返回到ARM狀態(tài)的Thumb子程序。

② 需要返回到Thumb狀態(tài)的ARM子程序。

③ 間接調(diào)用ARM子程序的Thumb子程序。

④ 間接調(diào)用Thumb子程序的ARM子程序。

如果在程序連接階段,連接器發(fā)現(xiàn)ARM子程序和Thumb子程序間存在相互調(diào)用,而源文件在編譯時(shí)沒有使用--apcs/interwork選項(xiàng),則連接器將報(bào)告以下錯(cuò)誤。

Error: L6239E: Cannot call ARM symbol 'arm_function' in non-interworking object

armsub.o from THUMB code in thumbmain.o(.text)

其中,“arm_function”為需要進(jìn)行狀態(tài)切換的子程序名。

在這種情況下,用戶必須使用--apcs/interwork選項(xiàng)重新對(duì)源文件進(jìn)行編譯。

但在下面兩種情況下,不必指定--apcs/interwork選項(xiàng)。

① 在Thumb狀態(tài)下,發(fā)生異常中斷時(shí),處理器自動(dòng)切換到ARM狀態(tài),這時(shí)不需要添加狀態(tài)切換代碼。

② 當(dāng)異常發(fā)生在Thumb狀態(tài)時(shí),從異常返回不需要添加狀態(tài)切換的Veneer代碼。

1.使用匯編語言實(shí)現(xiàn)互交

對(duì)于匯編程序來說,可以有兩種方法來實(shí)現(xiàn)程序狀態(tài)的切換。第一種方法是利用連接器提供的交互子程序Veneer來實(shí)現(xiàn)程序狀態(tài)的切換,這時(shí)用戶可以使用指令BL來調(diào)用子程序;另一種方法是用戶自己編寫狀態(tài)切換的程序。

在ARMv4版本及其以前的版本中,可以使用BX指令實(shí)現(xiàn)程序狀態(tài)的切換。

從ARMv5版本開始,下面的指令也可以用來實(shí)現(xiàn)程序的狀態(tài)切換。

·  BX(Branch and eXchange)

·  BLX、LDR、LDM和POP

下面的兩個(gè)偽操作用來區(qū)分源程序中的ARM代碼和Thumb代碼。

·  CODE16

·  CODE32

下面簡單介紹用于狀態(tài)切換的指令和偽操作,更詳細(xì)的信息請(qǐng)分別參見相關(guān)章節(jié)。

(1)BX指令

ARM狀態(tài)下的BX指令,使程序跳轉(zhuǎn)到指令中指定的參數(shù)Rm指定的地址執(zhí)行程序,Rm的第0位拷貝到CPSR中T位,位[31∶1]移入PC。若Rm的bit[0]為1,則跳轉(zhuǎn)時(shí)自動(dòng)將CPSR中的標(biāo)志位T置位,即把目標(biāo)地址的代碼解釋為Thumb代碼;若Rm的位bit[0]為0,則跳轉(zhuǎn)時(shí)自動(dòng)將CPSR中的標(biāo)志位T復(fù)位,即把目標(biāo)地址代碼解釋為ARM代碼。指令的語法格式如下。

BX{<cond>}  <Rm>

① <cond>

為指令編碼中的條件域。它指示指令在什么條件下執(zhí)行。當(dāng)<cond>忽略時(shí),指令為無條件執(zhí)行(cond=AL(Alway))。

② <Rm>

包含跳轉(zhuǎn)指令的目標(biāo)地址。如果Rm的bit[0]=0,目標(biāo)地址處指令為ARM指令;如果Rm的bit[0]=1,目標(biāo)地址處指令為Thumb指令。

指令操作的偽代碼。

指令操作的偽代碼如下面程序段所示。

If  conditionPassed{cond}  then

     T  Flag=Rm[0]

     PC = Rm AND 0xfffffffe

Thumb狀態(tài)下的BX指令,用于ARM和Thumb代碼間的相互調(diào)用。

指令的語法格式。

BX  <Rm>

其中<Rm>為目標(biāo)地址寄存器,包含程序的跳轉(zhuǎn)地址。BX指令的目標(biāo)地址寄存器可以是r0~r15中的任意寄存器。

注意

如果Rm[1:0]=0b10,不滿足ARM指令的內(nèi)存對(duì)齊方式。指令的執(zhí)行結(jié)果不可預(yù)知。如果該指令使用r15作為目標(biāo)寄存器,其操作方式和使用其他寄存器相同。

 

指令操作的偽代碼如下所示。

T  Flag=Rm[0]

PC=Rm[31:1]<<1

ARM指令集中的BX指令和Thumb指令集中的BX指令相差較大,它們分別為不同方向的跳轉(zhuǎn)。當(dāng)r15作為目的寄存器使用時(shí),要特別注意該指令在兩個(gè)指令集中的區(qū)別。

(2)BLX指令

ARM狀態(tài)下的BLX指令使用一個(gè)寄存器中的絕對(duì)地址或標(biāo)號(hào),用于使程序跳轉(zhuǎn)到Thumb狀態(tài)或從Thumb狀態(tài)返回,該指令用分支寄存器的最低位來更新CPSR中的T位,并將返回地址寫入到連接寄存器LR中。

指令的語法格式如下所示:

① BLX  <target_addr>

② BLX{<cond>}  <Rm>

第一種格式中,轉(zhuǎn)移目標(biāo)按下述方法計(jì)算。將指令中指定的24位偏移量進(jìn)行符號(hào)擴(kuò)展,左移兩位形成字偏移量,然后將其累加進(jìn)程序計(jì)數(shù)器PC中。這時(shí),程序計(jì)數(shù)器的內(nèi)容為BX指令地址加8字節(jié)。位H(bit[24])也加到結(jié)果地址的第一位(bit[1]),使目標(biāo)地址為半字地址,以執(zhí)行接下來的Thumb指令。計(jì)算偏移量的工作一般由ARM匯編器來完成。這種形式的跳轉(zhuǎn)指令只能實(shí)現(xiàn)±32MB空間的跳轉(zhuǎn)。

第二種格式中,寄存器Rm指定轉(zhuǎn)移目標(biāo),Rm的第0位拷貝到CPSR中的T位,bit[31:0]移入PC。

·  如果Rm的bit[0]=1,則跳轉(zhuǎn)時(shí)自動(dòng)將CPSR中的標(biāo)志位T置位,即把目標(biāo)地址的代碼解釋為Thumb代碼。

·  如果Rm的bit[0]=0,則跳轉(zhuǎn)時(shí)自動(dòng)將CPSR中的標(biāo)志位T復(fù)位,即把目標(biāo)地址的代碼解釋為ARM代碼。

指令操作的偽代碼如下面程序段所示。

第一種格式BLX指令。

LR=address of the instruction after the BLX instruction

T Flag=1

PC=PC + PC = PC + (SignExtend(signed_immed_24)<<2) + (H<<1)

第二種格式BLX指令。

If  ConditionPass{cond}  then

       LR = address of the instruction after the branch instruftion

       T Flag=Rm[0]

       PC=Rm AND 0xfffffffe

Thumb狀態(tài)下帶返回鏈接的跳轉(zhuǎn)指令BLX(1)提供了一種在Thumb狀態(tài)下無條件調(diào)用ARM子程序的方法,當(dāng)從子程序返回時(shí),通常使用下面的方式之一:

·  BX  LR

·  加載PC的LDR或LDM指令。

BLX指令不可條件執(zhí)行,可以實(shí)現(xiàn)在大約±4MB的地址空間范圍內(nèi)跳轉(zhuǎn),實(shí)現(xiàn)方法是將一條BLX指令編譯成兩條16位的Thumb指令,從而實(shí)現(xiàn)上述跳轉(zhuǎn)。對(duì)編譯后的兩條指令說明如下。

① H=10的跳轉(zhuǎn)指令。該跳轉(zhuǎn)包含跳轉(zhuǎn)偏移量的高位部分。

② H=01的跳轉(zhuǎn)指令。該跳轉(zhuǎn)包含跳轉(zhuǎn)偏移量的低位部分。

指令的語法格式

BL  <target_address>

<target_address>

指定程序跳轉(zhuǎn)的目標(biāo)地址。指令通過下面的方法計(jì)算目標(biāo)地址。

·  將H=10的BL指令的offset_11域左移12位。

·  將結(jié)果符號(hào)擴(kuò)展為32位。

·  將得到的值加到PC寄存器中。

·  與H=11的BL指令的offset_11域相加。

因此BL指令可以實(shí)現(xiàn)在大約±4MB的地址空間范圍內(nèi)跳轉(zhuǎn)。

指令操作的偽代碼為:

if  H==10  then

     LR=PC+(SignExtend(offset_11)<<12)

Else  if  H==11  then

     PC=LR+(offset_11<<11)

     LR=(address  of  next  instruction)|1

Else  if  H==01  then

     PC=(LR+(offset_11<<1)) AND 0xFFFFFFFC

     LR=(address of next instruction)|1

Else  if  H==01  then

     PC=(LR+(offset_11<<1)) AND 0Xfffffffc

     LR=(address of next instruction)|1

     T Flag=0

另外Thumb狀態(tài)下包含另一種格式的BLX指令,該BLX(2)指令用于ARM和Thumb子程序間的相互調(diào)用。程序狀態(tài)字的T標(biāo)志位根據(jù)目的寄存器的bit[0]位而改變。

 

指令的語法格式為:

BLX  <Rm>

其中<Rm>為目標(biāo)地址寄存器,r0~r14寄存器均可以作為目標(biāo)地址寄存器。

注意

如果在此指令中使用r15作為目的寄存器,指令的執(zhí)行結(jié)果不可預(yù)知。

此指令只在ARMv5版本以上指令集中被支持。

指令操作的偽代碼為:

LR = (address of the instruction after this BLX)|1

T Flag = Rm[0]

PC = Rm[31:1]<<1

(3)匯編偽指令

匯編編譯器可以產(chǎn)生ARM代碼也可以產(chǎn)生Thumb代碼。使用--thumb或--16選項(xiàng)指示編譯器產(chǎn)生Thumb代碼。由于所有支持Thumb代碼的ARM處理器都從ARM狀態(tài)開始執(zhí)行,所以必須人為地使用BX或BLX指令,使處理器狀態(tài)切換到Thumb狀態(tài)并使用下面的偽操作使編譯器產(chǎn)生Thumb代碼。

·  CODE16

·  CODE32

CODE32偽操作指示匯編器后面的指令為32位的ARM指令。

ARM和CODE32偽操作的意義相同。

當(dāng)匯編器對(duì)源程序進(jìn)行編譯時(shí),如果需要,將會(huì)在程序中插入空指令,以保證內(nèi)存單元字對(duì)齊。

語法格式如下。

ARM

CODE32

使用在同時(shí)包含ARM指令和Thumb指令的源文件中。當(dāng)需要從ARM指令序列切換到Thumb指令序列時(shí),使用偽操作ARM(或CODE32);當(dāng)需要從Thumb指令序列切換到ARM指令序列時(shí)使用Thumb偽操作。ARM(或CODE32)偽操作只是指示匯編器后面的指令類型是ARM指令。該偽操作本身并不進(jìn)行程序狀態(tài)的切換,要進(jìn)行狀態(tài)切換,可以使用BX指令操作。

CODE16偽指令通知編譯器,其后的指令序列為16位的Thumb指令。

語法格式如下。

CODE16

若在匯編源程序中同時(shí)包含ARM指令和Thumb指令時(shí),可用CODE16偽指令通知編譯器其后的指令序列為16位的Thumb指令。

(4)編程實(shí)例

      PRESERVE8

      AREA     AddReg,CODE,READONLY ;段名為AddReg,屬性為READONLY

      ENTRY ;程序入口

; SECTION 1

main

      ADR r0, ThumbProg + 1 ;確定跳轉(zhuǎn)地址

;并將bit[0]置1

;使程序切換到thumb狀態(tài)

      BX  r0 ;程序跳轉(zhuǎn)并執(zhí)行狀態(tài)切換

; SECTION 2

      CODE16 ;Thumb代碼指示偽操作

ThumbProg

      MOV r2, #2 ;r2 = 2

      MOV r3, #3 ;r2 = 3

      ADD r2, r2, r3 ;r2 = r2 + r3

      ADR r0, ARMProg

      BX  r0 ;程序跳轉(zhuǎn)并執(zhí)行狀態(tài)切換

; SECTION 3

      CODE32 ;ARM代碼指示偽操作

ARMProg

     MOV r4, #4

     MOV r5, #5

     ADD r4, r4, r5

; SECTION 4

stop MOV r0, #0x18 ;設(shè)置semihosting軟中斷號(hào)

      LDR r1, =0x20026 ;ADP_Stopped_ApplicationExit

      SWI 0x123456 ;ARM semihosting SWI軟中斷調(diào)用

      END ;文件結(jié)束

 

上面的例子分為4部分,通過下面的步驟編譯和運(yùn)行。

① 使用文本編輯器,如notepad,輸入上面的代碼,并保存成文件addreg.s;

② 在命令行中鍵入?yún)R編命令 armasm –g addreg.s;

③ 在命令行中鍵入鏈接命令 armlink addreg.o -o addreg;

④ 使用調(diào)試器(Debugger)(如,RealView Debuggeror AXD)運(yùn)行映像文件??梢允褂脝尾綀?zhí)行,觀察代碼在Thumb狀態(tài)下的執(zhí)行。

注意

Thumb代碼的地址標(biāo)號(hào)如果用偽操作export聲明為“外部的”,則連接器會(huì)自動(dòng)調(diào)整該地址標(biāo)號(hào)使其bit[0]等于1;如果該地址標(biāo)號(hào)沒有被聲明為“外部的”,則使用者必須手動(dòng)地對(duì)標(biāo)號(hào)進(jìn)行調(diào)整,如上例中的ThumProg+1。

(5)ARMv5架構(gòu)下的狀態(tài)切換

在ARMv5體系結(jié)構(gòu)的指令集中,增加了下面兩條指令用于ARM和Thumb代碼互交。

·  BLX  address

該指令跳轉(zhuǎn)到指令中指定的地址處執(zhí)行程序并進(jìn)行程序狀態(tài)切換,該地址是“PC相關(guān)的”,地址范圍為±32MB(ARM狀態(tài))或±4MB(Thumb狀態(tài))。

·  BLX  register

在該中格式的跳轉(zhuǎn)指令中寄存器Rm指定轉(zhuǎn)移目標(biāo),Rm的第0位拷貝到CPSR中的T位,bit[31:0]移入PC。

使用上面兩條指令,在執(zhí)行程序跳轉(zhuǎn)之前,處理器自動(dòng)將返回連接寄存器LR的bit[0]位更新為CPSR寄存器的T位,所以無論處理器狀態(tài)是否發(fā)生變化,程序都能正確返回。

當(dāng)使用LDR、LDM及POP指令向PC寄存器中賦值時(shí),寄存器CPSR中的Thumb位將被設(shè)置成PC寄存器的bit[0],這時(shí)就實(shí)現(xiàn)了程序狀態(tài)的切換。這種方法在子程序的返回時(shí)非常有效,同樣的指令可以根據(jù)需要返回到ARM狀態(tài)或Thumb狀態(tài)。

連接器在對(duì)目標(biāo)代碼進(jìn)行連續(xù)時(shí),將代碼中的地址標(biāo)號(hào)分為3類。

·  ARM指令地址標(biāo)號(hào)。

·  Thumb指令地址標(biāo)號(hào)。

·  數(shù)據(jù)(Data)地址標(biāo)號(hào)。

當(dāng)連接器重定位Thumb代碼中的地址標(biāo)號(hào)時(shí),地址標(biāo)號(hào)的bit[0]位將被自動(dòng)設(shè)置為1。這就意味著跳轉(zhuǎn)指令(這些指令包括BX、BLX和LDR)可以根據(jù)目標(biāo)地址正確的進(jìn)行狀態(tài)切換。

注意

上面提到的連接器自動(dòng)設(shè)置目的地址的行為,只有在ARMv5及其以上版本中支持。

 

2.使用C和C++語言實(shí)現(xiàn)互交

對(duì)于不同的C和C++源程序,可以有些程序中包含ARM指令,有些程序中包含Thumb指令,這些程序可以相互調(diào)用,只是在編譯這些程序時(shí)指定--apcs/interwork選項(xiàng)。當(dāng)使用了--apcs/interwork選項(xiàng),編譯器會(huì)自動(dòng)進(jìn)行一些相應(yīng)處理;連接器在檢測(cè)到程序中存在互交工作時(shí),會(huì)生成一些用于程序狀態(tài)切換的代碼。

(1)代碼編譯

可以使用下面的指令,將C或C++程序編譯為可以執(zhí)行互交的目標(biāo)代碼。

armcc --c90 --thumb --apcs /interwork

armcc --c90 --arm --apcs /interwork

armcc --cpp --thumb --apcs /interwork

armcc --cpp --arm --apcs /interwork

注意

--cpp是C++文件(文件后綴為.cpp)默認(rèn)的編譯選項(xiàng)。

使用--apcs/interwork選項(xiàng)對(duì)文件進(jìn)行編譯時(shí),編譯器會(huì)進(jìn)行如下處理。

·  對(duì)于葉子程序(leaf function,即程序中沒有其他子程序調(diào)用的程序),編譯器將程序中的“MOV  PC,LR”指令替換成“BX  LR”指令,因?yàn)?ldquo;MOV  PC”指令不能進(jìn)行狀態(tài)切換。

·  對(duì)于非葉子程序,要進(jìn)行一系列的指令替換,如:

POP  {r4,r5,pc}

替換為:

  POP  {r4,r5}

  POP  {r3}

  BX   r3

下面的例子顯示了一段帶子程序調(diào)用的C語言程序,使用--apcs/interwork選項(xiàng)進(jìn)行編譯時(shí),對(duì)代碼產(chǎn)生的影響。

C語言源程序。

Void  func(void)

{

….

Sub()

..

}

使用armcc  --apcs/interwork選項(xiàng)進(jìn)行編譯產(chǎn)生結(jié)果如下。

Func

STMFD  sp!,{r4-r7,lr}

….

BL  sub

….

LDMFD  sp!, {r4-r7,lr}

BX  lr

使用tcc  --apcs/interwork選項(xiàng)進(jìn)行編譯產(chǎn)生結(jié)果如下。

PUSH  {r4-r7,lr}

….

BL  sub

….

POP  {r4-r7}

POP  {r3}

BX

 

(2)C語言的互交實(shí)例

下面的例子顯示了一個(gè)Thumb狀態(tài)下的代碼通過互交調(diào)用ARM子程序;而后又在ARM子程序中調(diào)用Thumb指令集的庫函數(shù)printf()。

   /*********************

   *       thumbmain.c  *

   **********************/

   #include <stdio.h>

   extern void arm_function(void);

   int main(void)

   {

          printf("Hello from Thumb Worldn");

          arm_function();

          printf("And goodbye from Thumb Worldn");

          return (0);

   }

   /*********************

   *            armsub.c    *

   **********************/

   #include <stdio.h>

   void arm_function(void)

   {

          printf("Hello and Goodbye from ARM worldn");

   }

使用下面的命令對(duì)程序進(jìn)行編譯連接。

① 編譯生成帶互交的Thumb代碼。

armcc --thumb -c -g --apcs /interwork -o thumbmain.o thumbmain.c

② 編譯生成帶互交的ARM代碼。

armcc -c -g --apcs /interwork -o armsub.o armsub.c

③ 連接目標(biāo)文件。

armlink thumbmain.o armsub.o -o thumbtoarm.axf

另外,可以使用--info選項(xiàng)使連接器輸出由于互交所增加的代碼大小。

armlink armsub.o thumbmain.o -o thumbtoarm.axf --info veneers

輸出信息如下所示。

Adding Veneers to the image

     Adding TA veneer(4 bytes, Inline) for call to'arm_function'from thumbmain.o(.text).

     Adding AT veneer (8 bytes, Inline) for call to '__0printf' from armsub.o(.text).

     Adding AT veneer (8 bytes, Inline) for call to '__rt_lib_init' from kernel.o(.text).

     Adding AT veneer (12 bytes,Long) for call to'__rt_lib_shutdown'from kernel.o(.text).

     Adding TA veneer (4 bytes, Inline) for call to '__rt_memclr_w' from stdio.o(.text).

     Adding TA veneer (4 bytes, Inline) for call to '__rt_raise' from stdio.o(.text).

     Adding TA veneer (8 bytes, Short) for call to '__rt_exit' from exit.o(.text).

     Adding TA veneer (4 bytes, Inline) for call to '__user_libspace' from free.o(.text).

     Adding TA veneer (4 bytes, Inline) for call to '_fp_init' from lib_init.o(.text).

     Adding TA veneer (4 bytes, Inline) for call to '__heap_extend' from malloc.o(.text).

     Adding AT veneer (8 bytes, Inline) for call to '__raise' from rt_raise.o(.text).

     Adding TA veneer (4 bytes, Inline) for call to '__rt_errno_addr' from ftell.o(.text).

12 Veneer(s) (total 72 bytes) added to the image.

(3)Thumb狀態(tài)下的功能指針

任何指向Thumb函數(shù)(由Thumb指令完成的功能函數(shù)并且其返回狀態(tài)也為Thumb狀態(tài))的指針,其最低有效位(LSB)必為1。

當(dāng)重定位Thumb代碼中的地址標(biāo)號(hào)時(shí),連接器將自動(dòng)設(shè)置地址的最低有效位。如果在程序中使用絕對(duì)地址,連接器將無法完成該設(shè)置。因此,如果在Thumb代碼中使用絕對(duì)地址時(shí),必須手工設(shè)置為其地址加1。

下面的例子顯示了Thumb代碼的功能指針的使用。

typedef int (*FN)();

myfunc() {

     FN fnptrs[] = {

          (FN)(0x8084 + 1), // 有效的Thumb地址

          (FN)(0x8074) // 無效的Thumb地址

     };

     FN* myfunctions = fnptrs;

     myfunctions[0](); // 調(diào)用成功

     myfunctions[1](); // 調(diào)用失敗

}

Arm

Arm

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(www.farsight.com.cn)是國內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊(cè)于中國北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營分公司。華清遠(yuǎn)見除提供嵌入式相關(guān)的長期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實(shí)驗(yàn)平臺(tái)的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開出版70余本嵌入式/移動(dòng)開發(fā)/物聯(lián)網(wǎng)相關(guān)圖書。企業(yè)理念:專業(yè)始于專注 卓識(shí)源于遠(yuǎn)見。企業(yè)價(jià)值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。