2011-11-05 28 views
1

ARMアセンブリ言語ルーチンからprintfを呼び出す必要があります。私は同じ操作(printf("%d.%d",1,2))を行うcプログラムを書いています。私はコンパイラの出力を逆アセンブルしましたが、フォーマット文字列がどのように渡されるかは明白ではありません。これを行うコードの例はありますか?ARMアセンブリ言語からc関数printfを呼び出す

ここで私がprintfを呼び出す方法を見てきたテストCのルーチンです。

#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
     printf("%d.%d\n",1,2); 
     return EXIT_SUCCESS; 
} 

次のようなメインルーチンルックスのための私の解体:

000081c4 <main>: 
81c4:  e1a0c00d  mov  ip, sp 
81c8:  e92dd800  stmdb sp!, {fp, ip, lr, pc} 
81cc:  e24cb004  sub  fp, ip, #4  ; 0x4 
81d0:  e59f0014  ldr  r0, [pc, #20] ; 81ec <.text+0x11c> 
81d4:  e3a01001  mov  r1, #1 ; 0x1 
81d8:  e3a02002  mov  r2, #2 ; 0x2 
81dc:  eb000212  bl  8a2c <_IO_printf> 
81e0:  e3a03000  mov  r3, #0 ; 0x0 
81e4:  e1a00003  mov  r0, r3 
81e8:  e89da800  ldmia sp, {fp, sp, pc} 
81ec:  00060120  andeq r0, r6, r0, lsr #2 

を私は_IO_printfルーチンへの分岐を参照してください、私はそれに書式文字列を渡す方法が表示されません。

+0

解体の関連部分を添付しておけば説明しやすくなります(また同じ言語の方言を使用することもできます)。 – user786653

+0

最新の質問をご覧ください。 – ziggle314

+0

フォーマット文字列が '00060120'にあるようです。最後にデコードされた命令は、実際に命令として解釈されることを意味しないことに留意されたい。 – user786653

答えて

0

Cでは、文字列は一連のバイトとして格納されます。文字列を関数に渡すと、実際には文字列の最初の文字のアドレスが渡されます。

printf()(コンパイラの最適化なし)を呼び出すと、引数は逆順、つまり右から左にスタックにプッシュされます。その後、printf()は、フォーマット文字列(のポインタ)である最初の引数をポップします。書式文字列を解析して、連続した各引数についてポップ・オフするバイト数と、それらが表すデータ型(int、stringなど)に基づいてそれらを解釈する方法を決定します。

アップデート:ARMプロセッサでは、別の呼び出し規約が使用されているとの指摘もあります。スタックを使用するのではなく、最初のパラメータをレジスタに渡します。しかし、それらのパラメータの内容はスタックに渡された場合と同じです。 R0には書式文字列へのポインタが含まれており、下の同等のコードは依然として正確です。

訂正を申し出た方に感謝します。

だから、少なくとも限りprintf()が懸念しているとして、あなたのコードは、これに相当します

const char formatString[] = "%d.%d"; 
printf(&formatString[0], 1, 2); 
+0

私と一緒にお泊りください!私はあなたが私が知る必要があることを知っていると思います。更新された質問を参照してください。 – ziggle314

+3

4を超える場合を除き、ARMの呼び出し規約では引数のスタックは使用されません。 –

+0

dwelchの答えをご覧ください。あなたに+1! –

0

私は_IO_printfルーチンへの分岐を参照してください、私は渡す方法が表示されませんそれはフォーマット文字列です。

メガネをきれいにします。レジスタR0は文字列のアドレスであり、R1は "1"であり、R2は "2"である。 Adam Lissは間違っていますが、ARMではR0〜R4を最初の4つの関数パラメータとして使用します。

ライン

81d0: e59f0014 ldr r0, [pc, #20] ; 81ec <.text+0x11c>

負荷R0に復帰背後機能の「尾」で保存され、このアドレス。

2
#include <stdio.h> 
#include <stdlib.h> 

int main(void) { 
     printf("%d.%d\n",1,2); 
     return EXIT_SUCCESS; 
} 

コンパイル及びアセンブル:

0000842c <main>: 
    842c: e92d4008 push {r3, lr} 
    8430: e3a01001 mov r1, #1 
    8434: e3a02002 mov r2, #2 
    8438: e59f0008 ldr r0, [pc, #8] ; 8448 <main+0x1c> 
    843c: ebffffcc bl 8374 <_init+0x44> 
    8440: e3a00000 mov r0, #0 
    8444: e8bd8008 pop {r3, pc} 
    8448: 00008524 andeq r8, r0, r4, lsr #10 

をR0は最初のパラメータ、フォーマット文字列であり、R1は、二番目のパラメータ1、2形式の文字列は、文字列であり、第三のパラメータR2バイト配列へのポインタr0にはそのポインタがロードされます。アドレスはバイト列にロードされます。この場合のアドレスは0x8524です。

あなたは0x8524を見て、あなたの文字列を見に行くことができます興味があるならば、

8524: 252e6425 strcs r6, [lr, #-1061]! ; 0xfffffbdb 
8528: 00000a64 andeq r0, r0, r4, ror #20 

0x25、0x64、0x2e、0x25、0x64、0x0Aを、あなたの解体アドレスで同様に0x00を

あなたがあなたの文字列が表示されます0x60120番地のためのあなたの解体を見れば、あなたの文字列が

81d0:  e59f0014  ldr  r0, [pc, #20] ; 81ec <.text+0x11c> 
... 
81ec:  00060120  andeq r0, r6, r0, lsr #2 

です。

関連する問題