2012-01-21 15 views
7

GCCを使用してARMでベアメタルプログラミングを行い、QEMUでテストしようとしています。 CからARMラベルを呼び出すたびに、プログラムがハングします。 https://gist.github.com/1654392の問題を示す簡単なコード例があります。そのコードでactivate()を呼び出すと、ハングします。C、GCC(ベアメタル)からARMアセンブリを呼び出す

私はアセンブリからbコードを(_startのように)行うと、親指の指示に切り替わる小さなラッパーを生成していることをobjdumpで観察しました。サムコードでCコードが生成されているようですが、すべてのアセンブリがARM(32ビット)命令で生成されています。私はこれがなぜであるか、それをどう修正するかを理解できません。

+0

このコンパイラから提示されましたか? –

+0

kernel.o :(。ARM.exidx + 0x0):未定義の参照__aeabi_unwind_cpp_pr1 make:*** [kernel.elf]エラー1 –

+0

あなたはアームのLinuxアプリケーションを構築しようとしていますか?または組み込み型(オペレーティングシステムなし)のアプリケーションですか? Linuxアプリケーションの場合は、スタートアップコードを必要としないので、toolchainはすべてのことを行う必要があります。main()についてはエントリーポイントとして心配してください。 –

答えて

5

Cで定義されたTHUMBモード関数からアセンブリーで定義されたARMモード関数を呼び出すには、アセンブリー内のシンボルを関数として定義する必要があり、ツール(Linaro gcc)はblxbl

例:

@ Here, we suppose that this part of code is inside of .code 32 

.type fn, %function 

fn: 
    mov pc, lr 
+0

ありがとう!これは完全に動作するように見え、ライブラリコードでリンクすることができます! – singpolyma

3

qemuディレクトリを参照してください。あなたは、命令セット・リファレンスを見れば、あなたはARMおよびThumb状態の間で切り替えるようにBXまたはBLXを使用する必要があることがわかります

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 

ここ

が腕から腕や親指を呼び出すの例のカップルです。 BLXはBXほど広くサポートされていません。

定義の観点からは、プログラムカウンタpcは、命令実行中の2命令先です。アーム8バイトの場合は4バイトのサムについて。いずれの場合も2つの命令。状態を変更するのに使用できないblをシミュレートするには、リンクレジスタに戻りアドレスをロードし、bxを使用してアドレスのlsbitに応じて関数変更状態に分岐する必要があります。そう

mov lr,pc 
bx r1 
here: 

MOV LRが、PCは上記ここのアドレスロード:私達のリターンアドレスで、状態に依存しない方法でBX r1が関数を呼び出します。コンパイラは関数を呼び出すためのBL命令を割り当てLRアドレスの最下位ビットがに戻るにはモードを示し、あなたは常に

pre_thumb: 
ldr pc,lr 

thumb_capable: 
bx lr 

を返すためにBXを使用する必要があり、それはあまりにもあれば、リンカは、後の残りの部分を埋め遠いところにはリンカーが追加しているトランポリン機能が必要です。同様に、モードを変更する必要がある場合、blはトランポリン機能を呼び出します。私は上記のうちの1つを模倣して、それは少し無駄であることがわかります。blのスペースを割り当てるだけのコンパイラについての私の説明は、より明確で無駄なことは常にモード変更を計画することですコードの大部分の関数呼び出しにnopを挿入する必要があります。

コードもアセンブラで親指から腕への呼び出しが含まれています

.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に開くことができますが、私はそれがモードを切り替え思ういけません、あなたはそれを使用することはできませんので、再び予備のレジスタが必要です。もちろん、あなたが使用することができます登録するかを知るために呼び出し規則を知っておく必要があります。また、プッシュの別のセットをラップすることができますし、親指またはあなただけのBLを使う武装させるアーム親指

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 

LR以外のすべてを維持するためにポップあなたが達することができるならば。 ldr pc、あなたが傾けていない場合のアドレス。

0

asmコードをThumbとしてアセンブルする場合は、その関数をThumb関数としてマークする必要があります。そのため、リンカーは分岐時に正しい命令(BLXやBXなどのビットがセットされているアドレス)を使用します。これはthe。thumb_funcディレクティブ:

.global activate 
.thumb_func 
activate: 
    b test 

別のオプションは、明示的にARMコードを生成するようにアセンブラに依頼することです。ただし、現在のプロセッサはARMv4のに必要であった多くの回避策を必要としないことを覚えておいてください、あまりにも

.code 32 
.global activate 
activate: 
    b test 

チェックthis articleをあなたは恐らくそれを盲目的に続けるべきではないでしょう。混乱を排除するために

0

問題は、ARM用のUbuntuのGCCクロスコンパイラは、デフォルトでは、親指(16ビット)命令を生成ということでした。他の答えが示されているように、2つの間の呼び出しが可能ですが、GNUアセンブラがCコードがサム命令を生成していることを検出しているので、 Cに呼び出すためにbxを使用してshimを正しく生成すると、 GCC自体が関数を呼び出すために生成するものを上回っており、アセンブリコードがARM命令(32ビット)でなければならないため、blで呼び出していました。

解決方法(文書化されていない)は、少なくともすべてのコードを同じタイプにするgcc -marmを送信することです。

関数のbx呼び出しを生成するgccを取得するスイッチがある場合は、おそらく同様に動作します。

+0

gcc -marmは私にとってはうまくいきません。私はarm-v4t-linux-gnueabiのアセンブリコードが必要です –

関連する問題