8

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

objdumpを使用して、アセンブリからCコードに(_startからのように)blを実行すると、thumb命令に切り替わる小さなラッパーが生成されることを確認しました。Cコードはすべてthumb命令で生成されているようですが、私のアセンブリはすべてARM(32ビット)命令で生成されています。これがなぜなのか、どうやって修正するのかわかりません。

4

4 に答える 4

7

Cで定義されたTHUMBモード関数からアセンブリで定義されたARMモード関数を呼び出すには、アセンブリでシンボルを関数として定義する必要があります。ツール(Linaro gcc)は。blxの代わりに命令を生成しblます。

例:

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

.type fn, %function

fn:
   mov  pc, lr
于 2013-04-20T07:13:38.773 に答える
3

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、できない場合はアドレス。

于 2012-01-22T15:43:54.500 に答える
0

asmコードをThumbとしてアセンブルする場合は、関数をThumb関数としてマークする必要があります。これにより、リンカーは分岐時に正しい命令を使用します(たとえば、下位ビットが設定されたアドレスへのBLXまたはBX)。これは、.thumb_funcディレクティブを使用して行われます。

.global activate
.thumb_func
activate:
    b test

もう1つのオプションは、ARMコードを生成するようにアセンブラに明示的に要求することです。

.code 32
.global activate
activate:
    b test

この記事も確認してください。ただし、現在のプロセッサはARMv4で必要だった多くの回避策を必要としないため、盲目的に従わないでください。

于 2012-01-23T11:30:43.903 に答える
0

混乱をなくすには:

問題は、UbuntuのARM用GCCクロスコンパイラがデフォルトでthumb(16ビット)命令を生成することでした。ここでの他の回答が示すように、2つの間での呼び出しは可能ですが、GNUアセンブラは、Cコードがサム命令を生成していることを検出し、bxを使用してCを呼び出すためのモードを正しく設定するためにシムを生成しましたが、私は何を制御できませんGCC自体は関数を呼び出すために生成し、blだけでそれらを呼び出していましたが、アセンブリコードはARM命令(32ビット)である必要があるため、これは壊れていました。

解決策(文書化が不十分です)は、gcc -marmを送信することです。これにより、少なくともすべてのコードが同じタイプになります。

gccに関数のbx呼び出しを生成させるスイッチがある場合、それもおそらく機能します。

于 2012-01-31T16:28:32.253 に答える