Windows用のFASMプログラムのファイル形式

Windowsからアセンブラープログラム(たとえば、FASMが表示されます)を作成する場合、選択するファイル形式に関して疑問が生じます。

作成された実行可能ファイルの形式を決定するために、「format」ディレクティブとそれに続く形式識別子が使用されます。

カットの下には、プログラムテンプレートを使用したMZおよびPE形式のCOMプログラムとEXEプログラムの簡単な説明があります(従来の「Hello World!」の形式)。



デフォルトの形式は単純なバイナリファイルですが、.formatなどのプログラムを形成する「バイナリ形式」ディレクティブを使用して選択することもできます。

「Use16」および「use32」は、選択された出力形式のデフォルト設定を無視して、16ビットまたは32ビットのコードを生成するようにアセンブラに指示します。 「Use64」は、ロングモードx86プロセッサのコード生成を有効にします。

それらに固有のディレクティブを含むさまざまな出力形式を以下に説明します。



.Comプログラム


.comのようなプログラムは、メモリに読み込まれた後、ディスク上の機械語によるプログラムの変更されていない表現です。 .com形式は、最も単純なx86実行可能ファイル形式の1つです。 .comファイルのサイズは1セグメントのサイズに制限されており、64 KBに等しいため、すべてのデータは同じコードセグメントで定義する必要があります。 COMプログラムが動作を開始すると、すべてのセグメントレジスタにはプログラムセグメントプレフィックス(PSP)のアドレスが含まれます。これは、メモリ内のCOMまたはEXEプログラムの直前にDOSオペレーティングシステムによって予約されている256バイト(100h)ブロックです。 アドレス指定はPSPの先頭からオフセット100hで始まるため、ORGディレクティブ100hはプログラムにエンコードされます。 このディレクティブは、プログラムを開始するための相対アドレスを設定します。 ブートローダーは、このアドレスをコマンドポインターに使用します。



.COM形式の単純なプログラムの例:



use16 ; 16-  org 100h ;    100h mov dx,hello ; DX  . mov ah,9 ;  DOS. int 21h ;   DOS. mov ax,4C00h ;  AH  4Ch,  AL – 00h. int 21h ;  ;------------------------------------------------------- hello db 'Hello, world!$'
      
      





「use 16」ディレクティブは、16ビットコードの生成を示します。 「Org 100h」は、256バイトのパス(アドレス0000h-00FFh)を宣言します。 これらのアドレスは、サービスデータ(PSP)用に予約されています。

以下はコマンドです。 文字列helloのアドレスは、DXレジスタに配置されます。 次に、割り込み21hの関数番号9が呼び出され、画面に文字列が表示されます。

プログラムは、同じ割り込みパラメーター21hで関数4Cを呼び出すことにより終了します。

hello行は「$」文字で終了します。DOSでは、これは行の終わりを示します。



COMなどのプログラムは、64ビットWindowsではサポートされていないことに注意してください。 これらのオペレーティングシステムでこのようなプログラムを実行するには、DOSBoxプログラムを使用するか、以下で説明するPE形式を使用する必要があります。



MZ形式


MZは、DOS用の.EXE拡張子を持つ16ビット実行可能ファイルの標準形式です。 これは、署名に基づいて名前が付けられます-最初の2バイトのASCII文字MZ(4D 5A)。



MZ形式を使用した簡単なプログラムの例:



 format MZ ;  DOS EXE (MZ EXE) entry code_seg:start ;    stack 200h ;  ;-------------------------------------------------------------------- segment data_seg ;C  hello db 'Hello, asmworld!$' ; ;-------------------------------------------------------------------- segment code_seg ;  start: ;    mov ax,data_seg ;  DS mov ds,ax mov ah,09h mov dx,hello ;  int 21h mov ax,4C00h int 21h ; 
      
      







作成するには、「format MZ」ディレクティブを使用する必要があります。 デフォルトでは、この形式のコードは16ビットです。

「セグメント」は、新しいセグメントを定義し、その後に値が決定されるセグメントの番号であるラベルが続きます。 オプションで、このディレクティブの後に「use16」または「use32」を続けて、セグメント内のコードのビット深度を示すことができます。 セグメントの先頭は段落(16バイト)に揃えられます。 以下で定義されるすべてのラベルには、このセグメントの開始に関連する値があります。 上記の例では、「data_seg」と「code_seg」の2つのセグメントが宣言されています。

「エントリ」は、MZ形式のエントリポイントを設定し、その後に目的のエントリポイントの遠隔アドレス(セグメント名、コロン、およびセグメント内のオフセット)を設定します。 この例では、ラベル「start」が宣言されています。

「スタック」は、MZのスタックを設定します。 ディレクティブの後には、自動作成用のスタックのサイズを示す数値式、またはスタックを手動で設定する場合の初期スタックフレームの遠いアドレスを指定できます。 スタックが定義されていない場合、4096バイトのデフォルトサイズで作成されます。

後続の値を持つ「ヒープ」は、段落内の追加スペースの最大サイズを決定します(この場所は、スタックに加えて、未定義データ用です)。 ヒープ0を使用して、プログラムが本当に必要とするメモリのみを常に割り当てるようにします。



MZ形式は、COMプログラムと同様、64ビットWindowsではサポートされていません。



PEフォーマット


PEはPortable Executableの略です。 ポータブル(ユニバーサル)実行可能ファイル。 この形式はWindows 3.11の後半に登場しましたが、Windows 95の全盛期に広く普及しました。Windows9x / 2K / XP / Vista / 7 95%のコンピューターでは実行可能(exe、dll、ドライバー(sys) )ファイルはPEファイルです。



PE形式を選択するには、「format PE」ディレクティブを使用する必要があります。その後に追加の形式設定を続けることができます。「console」、「GUI」、または「native」演算子でターゲットサブシステムを選択します(サブシステムのバージョンを示す浮動小数点値が従うことができます) )、「DLL」は出力ファイルをダイナミックリンクライブラリとしてマークします。 次に、「at」演算子とPEイメージのベースを示す数値式が続き、オプションでファイル名を含む引用符で囲まれた次の行に「on」演算子があり、PEプログラムのMZスタブを選択します(指定されたファイルがMZ形式でない場合、単純なバイナリ実行可能ファイルとして扱われ、MZ形式に変換されます)。 デフォルトでは、この形式のコードは32ビットです。



すべてのプロパティを持つPE形式宣言の例:

'stub.exe'で7000000hにPE GUI 4.0 DLLをフォーマットする

「セクション」は新しいセクションを定義し、その後にセクションの名前を指定する引用符付き文字列が続きます。その後に1つ以上のセクションフラグが続きます。 可能なフラグは、「コード」、「データ」、「読み取り可能」、「書き込み可能」、「実行可能」、「共有可能」、「破棄可能」、「ページング不可」です。 セクションの先頭はページ上で揃えられます(4096バイト)。



PEセクションを宣言する例:

セクション「.text」コード読み取り可能実行可能ファイル

フラグとともに、特別なPEデータ識別子の1つを定義して、セクション全体を特別なデータ、可能な識別子としてマークすることもできます:「エクスポート」、「インポート」、「リソース」、「フィックスアップ」。 アドレス設定の内容のセクションがマークされている場合、それらは自動的に生成され、データを決定する必要はありません。 また、リソースデータはリソースファイルから自動的に生成できます。これは、識別子「resourse」と引用符で囲んだファイル名の後に「from」演算子を記述することで実現できます。



以下に、いくつかの特別なデータを含むセクションの例を見ることができます。

セクション「.reloc」データ破棄可能フィックスアップ

「my.res」からのセクション「.rsrc」データ読み取り可能リソース

「エントリ」はPEのエントリポイントを作成し、その後にエントリポイントの値が続きます。

「スタック」はPEのスタックサイズを設定し、予約済みスタックサイズの値が続きます。オプションで、スタックの先頭のコンマ区切り値を続けることができます。 スタックが定義されていない場合、4096バイトのデフォルトサイズが割り当てられます。

「ヒープ」は、PEの追加スペースのサイズを選択し、予約されているスペースの値が続きます。オプションで、コンマで区切られた先頭の値が存在する場合もあります。 余分なスペースが定義されていない場合、デフォルトで65536バイトに設定され、先頭が指定されていない場合は0に設定されます。

「データ」は特別なPEデータの定義を開始します。ディレクティブの後には、データ識別子(「export」、「import」、「resource」、または「fixups」)の1つ、またはPEヘッダーのデータレコードの番号が続きます。 データは次の行で定義し、「end data」ディレクティブで終了する必要があります。 アドレス設定定義を選択すると、それらが自動的に生成され、データを決定する必要がなくなります。 「from」ステートメントが識別子「resourse」と引用符で囲まれたファイル名の後に続く場合、同じことがリソースに適用されます。この場合、データはこのリソースファイルから取得されます。



PE形式を使用した単純なプログラムの例:



 format PE console ;  Windows EXE entry start ;    include 'win32a.inc' section '.text' code executable start: push hello call [printf] push 0 ccall [getchar] call [ExitProcess] section '.rdata' data readable hello db 'Hello World!', 0 section '.idata' data readable import library kernel32, 'kernel32.dll', \ msvcrt, 'msvcrt.dll' import kernel32, ExitProcess, 'ExitProcess' import msvcrt, printf, 'printf', getchar,'_fgetchar'
      
      





この例では、WinAPI関数を使用してコンソールを操作します。



PEおよびMZ形式の使用に関する短い(誰かにとって有益な)レビューを以下に示します。 この記事の冒頭にはELFとCOFFがありました。これらについてはあまり判断しないようお願いします。



All Articles