http://github.com/dwelch67/yagbatqemuディレクトリを参照してください。
腕または腕から親指を呼び出す例をいくつか示します。
start_vector:
mov sp,#0x20000
;@ call an arm function from arm
bl notmain
;@ call a thumb function frm arm
ldr r0,=0xAABBAABB
bl hexstring_trampoline
;@ call a thumb function frm arm
ldr r0,=0x12341234
ldr r1,hexstring_addr
mov lr,pc
bx r1
;@ call a thumb function frm arm
ldr r0,=0x12312344
bl hexstring_trampoline
hang:
b hang
hexstring_trampoline:
ldr r1,hexstring_addr
bx r1
hexstring_addr: .word hexstring
命令セットリファレンスを見ると、腕と親指の状態を切り替えるためにBXまたはBLXを使用する必要があることがわかります。BLXはBXほど広くサポートされていません。
定義の観点から、プログラムカウンターでは、pcは命令の実行中に2命令先にあります。親指の場合は4バイト、腕の場合は8バイト。どちらの場合も2つの指示。状態の変更に使用できないblをシミュレートするには、リンクレジスタにリターンアドレスをロードし、bxを使用して、アドレスのlsbitに応じて状態を変更する関数に分岐する必要があります。だから
mov lr,pc
bx r1
here:
上記のmovlr、pcは、ここのアドレスをロードします。これは、リターンアドレスであり、状態に依存しない方法でbxr1が関数を呼び出します。lrアドレスのlsbitは戻るモードを示しており、戻るには常にbxを使用する必要があります
pre_thumb:
ldr pc,lr
thumb_capable:
bx lr
コンパイラは関数を呼び出すためにbl命令を割り当て、リンカは後で残りを埋めます。それが到達範囲から遠すぎる場合は、リンカがそれ自体を追加しているトランポリン関数が必要です。同様に、モードを変更する必要がある場合、blはそれを行うトランポリン関数を呼び出します。私はそれを模倣するために上記の1つでそれをモデル化しました、あなたはそれが少し無駄であることがわかります、うまくいけば、blにスペースを割り当てるだけのコンパイラの私の説明はそれをより明確にし、無駄は常にモード変更を計画することであり、コード内の関数呼び出しの大部分にnopsを挿入する必要があります。
このコードには、アセンブラーのサムからアームへの呼び出しも含まれています。
.thumb
.thumb_func
.globl XPUT32
XPUT32:
push {lr}
;@ call an arm function from thumb asm
ldr r2,=PUT32
mov lr,pc
bx r2
pop {r2}
bx r2
サムモードでlrにポップできないこと、pcにポップできることを除いて、ほとんど同じですが、モードを切り替えるとは思わないので、使用できません。予備のレジスタが必要です。もちろん、使用できるレジスタを知るために呼び出し規約を知る必要があります。または、lrを除くすべてを保持するために、プッシュとポップの別のセットをラップすることができます。
push {r2,lr}
;@ call an arm function from thumb asm
ldr r2,=PUT32
mov lr,pc
bx r2
pop {r2}
mov lr,r2
pop {r2}
bx lr
親指から親指または腕から腕に到達できる場合は、blを使用します。ldr pc、できない場合はアドレス。