JZ2440裸ボード開発エクササイズ#2 - LED照明プログラムのコンパイル、分析

プラットフォーム: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    
公開された19元の記事 ウォン称賛7 ビュー6928

おすすめ

転載: blog.csdn.net/G_METHOD/article/details/104156501