プラットフォーム:JZ2440開発ボード--cpu:S3C2440(ARM920)
序文
前の演習では、C言語プログラムLEDライトを使用して、この演習は、分解したファイルプログラムの解析を行い、それらの知識をタップします。
予備
ARMレジスタ
ATPCS(アーム親指プロシージャコール標準)
目的
C言語とアセンブラ指定コールルールの順序に限り言語規格に準拠するために使用されるように、それらはお互いを呼び出して実行することができ、互いを呼び出すことができます。
コンテンツ
1.登録の使用規則
レジスタR0-R15として16 ARMモードの合計で使用することができます。
渡すパラメータR0-R3は、使用後の機能は、元の値を復元することはできません。
R4-R11ローカル変数、必要の元の値が保存して、戻り値で元の値を復元する場合。
MOVのIP、SPの操作で説明したように他のレジスタを格納するために使用されるIPエイリアススクラッチ・レジスタとしてR12サブルーチンは、スタックなど、省エネありません
R13は、スタックポインタ、SPとして、これはARMを含むすべてのアーキテクチャであり、IA-32はあなたもバランスを維持するために、スタックとして知られ、それ以外の場合は、通常の動作に影響を与える、保存して正確な復元する必要があり、レジスタ内に存在しています。
R14は、リターンアドレス、LRを保存し、BL命令がアドレス格納されている値に戻ります、一般的な使用法は次のとおりです。関数の終了は、リターンアドレスの目的を達成するためにPCレジスタ、実行に割り当てられたLRときに、保存、および、スタック上のアドレス保存LR。
住所R15、アドレスのPC、プログラムカウンタ、レジスタのプログラムは、ARMパイプラインのメカニズムに基づいて、実行されるためには、3段パイプラインの場合の下で、PCは現在実行中の命令アドレス+8のアドレスを指します。他のレジスタは、オーバーフロー、キャリー、0等のプログラムステータスビットを保存するために使用されます。PCは、説明した機能上記に加えて使用することができない、レジスタは直接割り当てが、間接的にのみJMP命令でIA-32等を変更することができるという違いを持つIA-32アーキテクチャー。
2.データスタックの使用規則
良好なスタックの成長方向の規定は、これは通常、降順スタックです。例えば、ときスタックスタックを、降順で、spはデシベル(減少前)またはダ(後の減少)を必要とする、spはIA(後に増加)またはIB(増加の前に)必要があり、これらは、スタックのスタックをできるように団結の必要性あり通常の使用。
3.パラメータの受け渡しのルール
関数呼び出し、残りのスタックによって渡されたパラメータ、および戻り値が返され、パラメータの数が4を超えると、パラメータR0-R3を通過すると、R0-R3を使用することです。
4.保存と復元ルール
これは、レジスタまたは他の関数呼び出し、関数が戻った後、通常の動作に機能するためには、サイトの保護の必要性に格納された値の一部を破壊します。私たちは、関数が終了し、対応する合意されたルールに従ってサイトを復元する必要があります。スタックは、次に順番に脱積層することができる場合に機能現在使用されるレジスタは、スタック(例えばR15として、スタックの上位レジスタ)順序に従ってレジスタを使用する必要があります。
分析
led.elf: file format elf32-littlearm
Disassembly of section .text:
00008074 <_start>:
8074: e3a00000 mov r0, #0 ; 0x0
8078: e5901000 ldr r1, [r0]
807c: e5800000 str r0, [r0]
8080: e5902000 ldr r2, [r0]
8084: e1520000 cmp r2, r0
8088: e59fd00c ldr sp, [pc, #12] ; 809c <.text+0x28>
808c: 03a0da01 moveq sp, #4096 ; 0x1000
8090: 05801000 streq r1, [r0]
8094: eb000001 bl 80a0 <main> //bl跳转main,返回地址lr=8098
00008098 <halt>:
8098: eafffffe b 8098 <halt>
809c: 40001000 andmi r1, r0, r0
000080a0 <main>:
80a0: e1a0c00d mov ip, sp
80a4: e92dd800 stmdb sp!, {fp, ip, lr, pc}
80a8: e24cb004 sub fp, ip, #4 ; 0x4
80ac: e24dd008 sub sp, sp, #8 ; 0x8
80b0: e3a03456 mov r3, #1442840576 ; 0x56000000
80b4: e2833050 add r3, r3, #80 ; 0x50
80b8: e50b3010 str r3, [fp, #-16]
80bc: e3a03456 mov r3, #1442840576 ; 0x56000000
80c0: e2833054 add r3, r3, #84 ; 0x54
80c4: e50b3014 str r3, [fp, #-20]
80c8: e51b2010 ldr r2, [fp, #-16]
80cc: e51b3010 ldr r3, [fp, #-16]
80d0: e5933000 ldr r3, [r3]
80d4: e3c33c3f bic r3, r3, #16128 ; 0x3f00
80d8: e5823000 str r3, [r2]
80dc: e51b2010 ldr r2, [fp, #-16]
80e0: e51b3010 ldr r3, [fp, #-16]
80e4: e5933000 ldr r3, [r3]
80e8: e1e03003 mvn r3, r3
80ec: e2033c15 and r3, r3, #5376 ; 0x1500
80f0: e1e03003 mvn r3, r3
80f4: e5823000 str r3, [r2]
80f8: e51b2014 ldr r2, [fp, #-20]
80fc: e51b3014 ldr r3, [fp, #-20]
8100: e5933000 ldr r3, [r3]
8104: e3c33070 bic r3, r3, #112 ; 0x70
8108: e5823000 str r3, [r2]
810c: e3a03000 mov r3, #0 ; 0x0
8110: e1a00003 mov r0, r3
8114: e24bd00c sub sp, fp, #12 ; 0xc
8118: e89da800 ldmia sp, {fp, sp, pc}
Disassembly of section .comment:
00000000 <.comment>:
0: 43434700 cmpmi r3, #0 ; 0x0
4: 4728203a undefined
8: 2029554e eorcs r5, r9, lr, asr #10
c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
10: Address 0x10 is out of bounds.
分解上、それは活性化この実施例nandflashで想定され、SPは4096に設定されています。Cプログラムのメインブートファイル主な機能にBLのジャンプ、レジスタLR今回は、8098が返されたアドレスが含まれています。
メインを入力した後、最初のサイトを維持するために必要なセーブ、あなたは保存レジスタ・スタックを使用する必要があります
80a0: e1a0c00d mov ip, sp //fp=? ip=4096 sp=4096 lr=8098 pc=80A8
80a4: e92dd800 stmdb sp!, {fp, ip, lr, pc}
スタックアドレス | 値 | コメント | ||
4092 | 0x80A8 | パーソナルコンピュータ | ||
4088 | 0x8098 | LR | ||
4084 | 4096 | IP =古いSP | ||
4080 | unknowvalue | FP | <-sp |
FPは、その後、バックFP、FPレジスタの使用に基づいて、格納された第1のアドレスフィールドに調整し、Iは、に基づいてオフセット値を加算し、その基準スタックフレームとしてIA-32 EBPレジスタアーキテクチャ同様の効果があると思われています任意の変数スタックフレームをアドレス指定します。その後、SP - 8は、Cプログラムに対応する同一のIA-32アーキテクチャは、我々の2個のレジスタがポインタをポイントは、その時点で、それはローカル変数である共有メモリのコンパイルです。
80a8: e24cb004 sub fp, ip, #4 ; 0x4 //fp = ip - 4 =4096-4 =4092
80ac: e24dd008 sub sp, sp, #8 ; 0x8 //sp =sp -8 = 4072 //两个int 局部变量
スタックアドレス | 値 | コメント | ||
4092 | 0x80A8 | パーソナルコンピュータ | ||
4088 | 0x8098 | LR | ||
4084 | 4096 | IP =古いSP | ||
4080 | unknowvalue | FP | ||
4076 | ||||
4072 | <-sp |
FP参照にメモリは、メモリのアドレスに宛てた後、それだけ割り当てレジスタの値
80b0: e3a03456 mov r3, #1442840576 ; 0x56000000//r3=0x56000000
80b4: e2833050 add r3, r3, #80 ; 0x50 //r3=0x56000050
80b8: e50b3010 str r3, [fp, #-16] //fp - 16 = 4092 - 16 = 4076
80bc: e3a03456 mov r3, #1442840576 ; 0x56000000
80c0: e2833054 add r3, r3, #84 ; 0x54
80c4: e50b3014 str r3, [fp, #-20]
スタックアドレス | 値 | コメント | ||
4092 | 0x80A8 | パーソナルコンピュータ | ||
4088 | 0x8098 | LR | ||
4084 | 4096 | IP =古いSP | ||
4080 | unknowvalue | FP | ||
4076 | 0x56000050 | |||
4072 | 0x56000054 | <-sp |
Cプログラムの処理に相当するが、明確に理解することができ、ローカル変数、無知識に位置するプログラムが続くので、説明を省略する。
//*pGPFCON &= ~((3<<8) | (3<<10) | (3<<12));
80c8: e51b2010 ldr r2, [fp, #-16]
80cc: e51b3010 ldr r3, [fp, #-16]
80d0: e5933000 ldr r3, [r3]
80d4: e3c33c3f bic r3, r3, #16128 ; 0x3f00
80d8: e5823000 str r3, [r2]
//*pGPFCON |= ~((1<<8) | (1<<10) | (1<<12));
80dc: e51b2010 ldr r2, [fp, #-16]
80e0: e51b3010 ldr r3, [fp, #-16]
80e4: e5933000 ldr r3, [r3]
80e8: e1e03003 mvn r3, r3
80ec: e2033c15 and r3, r3, #5376 ; 0x1500
80f0: e1e03003 mvn r3, r3
80f4: e5823000 str r3, [r2]
//*pGPFDAT &=~((1<<4) | (1<<5) | (1<<6));
80f8: e51b2014 ldr r2, [fp, #-20]
80fc: e51b3014 ldr r3, [fp, #-20]
8100: e5933000 ldr r3, [r3]
8104: e3c33070 bic r3, r3, #112 ; 0x70
8108: e5823000 str r3, [r2]
コンパイラは、スマート点でなければならない場合は、最後には、分解特別の媒体としてR3を介していない意味R0レジスタは、レジスタに格納された戻り値としてここで使用され、戻り値が0であることをATPCS番組によれば、割り当ての戻り値でありますここで離れて最適化されました。
810c: e3a03000 mov r3, #0 ; 0x0
8110: e1a00003 mov r0, r3
このように、メイン関数の端部は、SPを回復しながら、スタック内のレジスタに保存された値を復元する場合に必要ポイントに戻りアドレスLRの準備ができ、実行されます。まず、ローカル変数のスタック領域の回復、回復ポイントSPのローカル変数に割り当てられたアドレスの上端部のみに割り当てられ、なぜならバインド次のメモリアドレスを使用する必要性、ヒープ適切でない回復操作を行いますそれはカバーされますので、追加の処理を必要としません。
8114: e24bd00c sub sp, fp, #12 ; 0xc //局部变量退栈
スタックアドレス | 値 | コメント | ||
4092 | 0x80A8 | パーソナルコンピュータ | ||
4088 | 0x8098 | LR | ||
4084 | 4096 | IP =古いSP | ||
4080 | unknowvalue | FP | <-sp | |
4076 | 0x56000050 | |||
4072 | 0x56000054 |
最後LDMIAのSTMDBの先頭に対応する、スタックに格納されたデータがレジスタに戻されます{}。比較表はスタック上で見ることができ、保存されたスタックfpがレジスタに復元されますfpを、最後のLRがリターンアドレスに格納されたセーブだけで、メイン呼び出し前に戻り、それによって、SP、SPの古いSPの値を保持するIP次の命令は、戻り値は、関数のメインの正常終了にPCアドレスポイントを実行するので、PCは、登録して復元します。(SPへの割り当てを含むLDMIA、それでも動作指令IaがtmpのSPであるため、操作の詳細を行うを参照して、通常のIA SPを実行し続けます https://blog.csdn.net/G_METHOD/article/詳細/ 104126283 LDMについて記述)
8118: e89da800 ldmia sp, {fp, sp, pc}
スタックアドレス | 値 | コメント | ||
4092 | 0x80A8 | パーソナルコンピュータ | <-sp | |
4088 | 0x8098 | LR ======「PC | ||
4084 | 4096 | IP =古いSP ===「SP | ||
4080 | unknowvalue | FP =======「FP | ||
4076 | 0x56000050 | |||
4072 | 0x56000054 |