アセンブリ言語に精通している:(a)の再学習C言語

序文

この記事では、研究ノートの著者です。運命ならば、批判のサプリメントを歓迎します。

以下の場合:

  • 各ステップの非常に明確な内容をプログラムのコンパイルプロセスを暗示が、そうではありません
  • デバッガに精通していません
  • 何が起こったかの背後にあるプログラムとプログラミング言語の詳細については、
  • 何もの人々が技術的な記事を見て、無料ではありません

この記事は含まれていません。

  • プログラムの最適化プログラム
  • ファッションデザインプログラム
  • 便利なソフトウェアのスキルを書きます

基本:

  • C言語のスキルで書かれた「ノーマル」をマスターしています
  • 私は、コンピュータ用語とその意味では、いくつかの「共通」を知っています
  • 文書を照会することにより、(人間  の未知を使用してAPIの概要を説明し、グーグル)

コード

本明細書で使用する場合、次のコード(のhello.c)。

1の#include <stdio.hの>
 2  
3  int型のmain(int型 ARGC、チャー *のARGV []){
 4  
5      ASM 揮発性" #のprintf開始" )。
6  
7      のprintf(" こんにちは、世界%D%sの\ nは!"、のargc、argvの[ 0 ]);
8  
9      ASM 揮発性" #のprintf端" )。
10  
11      戻り 0 ;
12 }

読み取りアセンブリコードの生成を容易にするために、我々は、これらの文字列のルックスから生成されたアセンブリコードを配置することができるので、ちょうど前後で、関数呼び出しに加えて、特定のIDの後に見てみたいです。

次のように加えて、GCCを使用してコンパイルされ、コマンドは次のとおりです。

$ gccの hello.cの-Wall -g -O0 -S - O hello.s
$ gccの hello.s - O hello.outの
$ objdumpの -d hello.outの> hello.asm

ここでhello.asmの作者で一部の最後の生成環境の主な機能です。
もちろん、あなたが.Sファイルを読み取ることができますが、CPUの命令実行の一部のみが、その後、両方の内容は同じです。

000000000000064a <メイン>:
 64     55                        プッシュ   %のRBP
 64 B:    48  89 E5                  のMOV     %のRSPは、%RBP
 64 E:    48  83、EC 10               、サブ    $ 0x10の、%RSP
  65289 7D FC                  MOV     %EDI、-0x4(%のRBP)
  65548  89  75 F0の               MOVの    %のRSI、-0x10(%のRBP)
  65948 8B 45 F0               MOV     -0x10(%のRBP)、%のRAX
 65 D:    48 8B 10                  MOV     (%のRAX)、%RDX
  660:8B 45 FCの                  MOVの    -0x4(%のRBP)、%EAX
  66389 C6の                     MOVの    %のEAX、%ESI
  66548 8D 3D 98  00  00  00      LEA     0×98 (%のRIP)、%RDI#704 <_IO_stdin_used + 0x4の>
 66個のC:     B8 00  00  00  00            のmov     $ 0x0の、%eaxに
  671:E8 AA FE FF FF callq   520 <printfのPLT @>
  676:B8 00  00  00  00            のmov     $ 0x0の、%eaxに
 67 B:    C9 leaveq
 67 C:    C3 retq   
 67 D:    0F 1F 00                  nopl(%のRAX)

解決

公式ドキュメント

:インテルは、インテル64およびIA-32アーキテクチャーマニュアルは、このサイトで見つけることができ開示さ
https://software.intel.com/en-us/articles/intel-sdm

公式サイトでは、パフォーマンスを最適化するために、文書、文書などの拡張命令セットを発表しました。

登録

x86アーキテクチャでは、Eの先頭に64ビットレジスタrで始まる、32ビットのレジスタです。
GPR(汎用レジスタ)登場属し上記のアセンブリ・コード・レジスタ、それはプログラムが自由にこれらのレジスタを操作し、そのメモリの使用と違いがないことができると言うことです。

上記のコンパイルコマンドで、一緒に(例えば、括弧内のレジスタマーク付き  )RAXの%(  )、値を保持するメモリアドレスにこのレジスタ・ポイントの代表値。
単語を説明するためのC言語です  (* INT *)RAX  。
括弧の前の値があれば、その後、値を保持するメモリアドレスの減算値レジスタ後の値を表します。
例えば  -0x10(%のRBP)  メモリことを意味  RBP  16(注16進数)だけ減分値が、位置を記憶します。
単語を説明するためにC言語と同じである  *(INT *)((CHAR *)RBP - が0x10  。

C言語の解釈とトップは正確ではないかもしれません。
具体的には、  MOV  とデータサイズが指定されていない、つまり、ソース・データ・レジスタのサイズであり、最初のパラメータに依存するデータの特定の32ビットまたは64ビットのコピーで言うことです。
著者は、652枚の分析と考えて  MOVの  コピーは、32ビットのデータ、及び655は、  MOVの  コピー64ビットのデータ。

注意すべき事は、そのようなことであります  RAX  と  EAXが  実際には2つの別々のレジスタではありません。 EAX  参照  RAX  32以下です。
だけでなく、  AX  、  AH  、  アル  。

スタック

コンパイラ  RSP  (32ビットレジスタである  ESP  スタックポインタ(SP、スタックポインタ)として専用)。
SPは、より小さい、すなわち低下に向かう方向に延びるのx86である  RSPの  スタック空間のこの部分を得るに等しい値を。

さらに、  RSPは  (すなわち、16バイトに整列されなければならない  RSPの  値が16の倍数でなければなりません)。
しかし、メインで同様のコマンドがありませんでした。
私は次のようにコマンドを整列スタートは、部分的に、コンパイルがあるが見つかりました:

0000000000000540 <_start>:
  54031編の                     XORの    場合%ebp、%のEBP
  54249  89 D1                  のmov     %のRDX、%R9
  545:5Eの                        ポップ    %のRSI
  54648  89 E2                  のmov     %のRSP、%のRDX
  54948の 83 E4のF0                   $ 0xfffffffffffffff0、%のRSP
 54 D:    50                        プッシュ   %のRAX
 54 E:    54                        プッシュ   %のRSP
 54 F:     4C部8d 05 9A 01  00  00      LEAの    0x19a(%のRIP)、%R8#1 6f0 <__ libc_csu_fini>
  55648 8D 0D  23  01  00  00      LEA     0x123(%のRIP)、%RCX#680 <__ libc_csu_init>
 55 D:    48 8D 3D E6 00  00  00      LEAの    0xe6(%のRIP)、%RDI位部64a <メイン>
  564:FF 15  76  0A  20  00         callq * 0x200a76(%RIP)#2 00fe0 <__ libc_start_mainする@ GLIBC_2。25 >
 56      F4                        HLT     
 56 B:    0F 1F 44  00  00            noplの0x0の(%のRAX、%のRAX、1

コマンド564は、この命令がメインの前に実行する必要がありますね観察することができます。
そしてコマンド549は、整列される  のRSP  (のコマンド  RSP  すなわち、16の倍数4が0になる最後に、)。

関数呼出し

32ビットアーキテクチャでは、パラメータが(レジスタの拡張子を持っていると思われる)空間をスタックする関数呼び出しである場合。
64ビットアーキテクチャでは、レジスタの数が増加する(以降  R8  〜  R15  )、多くの場合、パラメータレジスタに直接であってもよいです。

元のアセンブリコードブックは、32ビットアーキテクチャを使用して、著者は、アセンブラコードを解析し64であるので、段差関数呼び出しの小さな差はありません。
それらのほとんどは、以下の私の個人的な分析です。

「レジスタ内のパラメータは、」この条件は、主な機能にも同様に適用されるべきです。
メイン関数のパラメータは、(二つがある)に別々に格納する必要があり  、EDI  及び  RSI  それらを。最初のものはある  のint  型の、ここでは32、それらが置かれた  EDIを  内部。64ビットの64ビットアーキテクチャでポインタの配列(ポインタである)間違い、それに格納されている  RSI  これら。

次のステップでは、原因が呼び出される  のprintf  関数を、私たちは最初に必要な  EDI  と  RSI  スタックに格納された値。これらのレジスタの値を変更するように。したがって、16のプログラム最初のSP値は、それが16バイトスタック空間を拡大、縮小されます。
次に、プログラムがスタックに格納されている2つのパラメータを置きます。

そしてその後、コマンドの次のシリーズ、最初の店舗  のargv [ 0 ]  に  RDX  再び、  ARGC  に格納された  ESI  それら、および最後に再びフォーマットされた文字列(アドレス)に格納されている  RDI  それら。
内部で書かれたプログラムの実行とフォーマット文字列は、アドレスからの時間取るために使用することができます  リップ  これは推測される(PCは64ビットのレジスタを保存するために使用される)レジスタを。実装でこの文字列を変更することができない理由です。

次に、コマンドの関数呼び出しがあります。そして返します。

 NOPは  何も(無操作)を行わないことを意図しています。ここで埋める  NOP  (67D後方番号3は、16バイトにアラインされ680、であることを起こる)が背面位置合わせの機能16のバイトを可能にすることです。

私は破壊と信じ  EDI  と  RSIは  、これらの値ために使用されていないスタックのバックから回復しませんでした。この推測は、より深い検査をしませんでした。

概要

このセクションでは、私は基本的な汎用レジスタと呼ばれる機能モードを学びました。
洗礼の日の後、それは今ええ、サブCPUを理解するのに約10億5におけるプログラムの割合ですることができます。

おすすめ

転載: www.cnblogs.com/kko-liu/p/11069274.html