Microsoft Macro Assembler(以降、MASMと略)でアプリケーションを開発する際のメモ書きです。
この記事では、MASM, Visual C++等のMicrosoftの開発環境(16bit, 32bit)におけるメモリーモデルの指定方法を解説します。
※64bitのコードにおいては、メモリモデルは無く、以下の3つのディレクティブは非対応です。
メモリーモデルとは
Intel 8086のCPUシリーズ(及び286以降のリアルモード)における、セグメントを用いたメモリアクセスを行うアーキテクチャに対応するためのモデル。
これらのアーキテクチャでは、アドレス空間は20bit(1 MBytes)となるが、アドレスを示すレジスタや、各命令コードが持つアドレス幅は16bit(64 kByte)という制約がある。
これらのIntel 8086、及び286以降のリアルモード(16 bit)のプログラムコードでは、セグメントレジスタ(CS
, DS
, ES
, SS
, 386以降よりFS
, GS
)に格納される16bitのセグメントアドレス、並びに16bitのオフセットアドレスによって、20bit幅のアドレスが決まる(そのため、1つのセグメントは、64 kByteの制約がある)。
※20bitのアドレス空間は、セグメントアドレス(16bit) × 16 + オフセットアドレス(16bit)となる。
メモリーモデルの種類
※64bit(x86-64)の実行ファイルには、メモリモデルは無い。
TINY
実行コードと、データが同じセグメントに存在するメモリーモデル。
したがって、両方合わせて、64 kByte以内となる。
MS-DOS, Windows以外のアプリケーション(例えば、ワンダースワンのゲーム)を開発する場合等は、このメモリーモデルを使う。
- 実行ファイルの形式:バイナリ形式(MS-DOSの実行ファイル
.COM
を含む) - セグメントグループ:
DGROUP
=_TEXT
,_DATA
,CONST
,_BSS
(,STACK
)
<MS-DOS の .COM
形式について>
.COM
形式のファイルは、0x0100番地から始まるプレーンなバイナリであり、プログラム開始時は以下の様に初期化される。
- セグメントレジスタ:
CS
=DS
=ES
=SS
- スタックポインタ:
SP
=0000h (※十分な空きメモリがある場合) - 命令ポインタ:
IP
=0100h
従い、以下のような注意点がある。
- コード(
_TEXT
セグメント)の先頭には、ORG 0100h
、もしくは.startup
ディレクティブが必要となる。 -
.COM
形式の実行時、COMMAND.COMは空きメモリ領域を全て割り当て、この時64 kByte以上割り当てることが出来た場合、SP
レジスタを0に設定する。そのため、多くの場合、ファンクションコール(INT 21h, AH=4Ah
)により割り当てられたメモリサイズを変更する必要があり、それに伴いスタックポインタ(SP
レジスタ)も設定し直す必要がある。
例:
.186
.model tiny, stdcall
.dosseg
.stack 1000h
;プロトタイプ宣言
Memory_Small_Com proto near, sizeCOM:WORD
.code
.startup ;スタートアップコードの生成
MOV SP, offset DGROUP:STACK ; SP を.stackディレクティブで設定したスタック領域の末尾に設定。
INVOKE Memory_Small_Com, SP ;メモリの最小化
CALL _main ;mainルーチンの呼出
.exit 0 ;終了コードの生成
.186
.model tiny,stdcall
.code
;メモリーの最小化
Memory_Small_Com proc near uses ax bx es,
sizeCOM:WORD
PUSH CS ;
POP ES ;ES ← CS
MOV BX, sizeCOM
SHR BX, 4
INC BX ;BX ← (sizeCOM >> 4) + 1
MOV AH, 04AH ;
INT 21H ;割り当てられたメモリの最小化
.if (carry?)
; to do: Error 処理をここに書く
.endif
RET
Memory_Small_Com endp
end
※.COM
は、元々CP/M-80で使われていた拡張子であり、コード・データのサイズは、64kByte-256Byte(オフセットアドレス0x0100~0xFFFFの範囲)となる。
SMALL
実行コードに1つのセグメント(_TEXT
)、データに1つのセグメント(DGROUP
)を使用するメモリーモデル。
実行コード、データ共に64 kByte(合計128 kByte)までの実行ファイルを作れる。
一般的なMS-DOS用の16bitアプリケーションは、このモデルを用いて開発する。
- 実行ファイルの形式:
.EXE
(16 bit) - セグメントグループ:
DGROUP
=_DATA
,CONST
,_BSS
(,STACK
)
COMPACT
実行コードに1つのセグメント(_TEXT
)、データには複数のセグメントを使用することができるメモリーモデル。
- 実行ファイルの形式:
.EXE
(16 bit) - セグメントグループ:
DGROUP
=_DATA
,CONST
,_BSS
(,STACK
)
MEDIUM
実行コードに複数のセグメント、データに1つのセグメント(DGROUP
)を使用することができるメモリーモデル。
- 実行ファイルの形式:
.EXE
(16 bit) - セグメントグループ:
DGROUP
=_DATA
,CONST
,_BSS
(,STACK
)
LARGE
実行コード、データ共に複数のセグメント使用することができるメモリーモデル。
配列変数等のサイズは64 kByteに制限される。
- 実行ファイルの形式:
.EXE
(16 bit) - セグメントグループ:
DGROUP
=_DATA
,CONST
,_BSS
(,STACK
)
HUGE
実行コード、データ共に複数のセグメント使用することができるメモリーモデル。
配列変数等のサイズは64 kByteに制限されない。
- 実行ファイルの形式:
.EXE
(16 bit) - セグメントグループ:
DGROUP
=_DATA
,CONST
,_BSS
(,STACK
)
FLAT
プロテクトモード(32bit)用のメモリモデル。
実行コード、データ共に同一のセグメントを使用する。
Windows用の32bitアプリケーションを開発する場合は、このメモリモデルを使う。
- 実行ファイルの形式:
.EXE
(32 bit) - セグメントグループ:
FLAT
=_TEXT
,_DATA
,CONST
,_BSS
,STACK
Intel 8086、及びリアルモード(16bitコード)におけるポインタについて
near ポインタ
オフセットアドレス(16bit)のみで構成されるポインタ。
far ポインタ
セグメントアドレス(16bit)と、オフセットアドレス(16bit)で構成されるポインタ。
.model
書式
.model memorymodel (,langtype) (,stackoption)
説明
当該アセンブリ言語ファイルをアセンブルする時のモデルを設定する。
通常、CPU指定(例: .586
)の次に記述する。
パラメータ
memorymodel
メモリーモデルを指定する。
メモリーモデルについては、上述のメモリーモデルの種類を参照
- 32bit版のWindows用アプリケーションの実行ファイル(.exe)のメモリモデルは
FLAT
であり、Visual C++等でコンパイルされた.objファイルとリンクする場合は、FLAT
を指定する。 - 64bit版のWindows用アプリケーションの実行ファイル(*.exe)にはメモリモデルは無く、
.model
ディレクティブは不要となる。
langtype
デフォルトの関数の言語タイプを設定する。
関数呼出規約についての詳細は、別途、MASM, Visual C++における関数呼出規約を参照。
langtype | Visual C++ における関数呼出規約 |
---|---|
C | __cdecl |
SYSCALL | __syscall (廃止) |
STDCALL | __stdcall |
BASIC | |
FORTRAN | __fortran (廃止) |
PASCAL | __pascal (廃止) |
※BASIC , FORTRAN , PASCAL は、全く同じ関数呼出規約です。 |
|
※16bit版Windows(Windows 3.x以前)のWINAPIの関数呼び出し規約はPASCAL です。 |
|
※32bit版Windows(Windows NT及びWindows 95以降)のWINAPIの関数呼び出し規約はSTDCALL です。 |
stackoption
スタック領域の場所を示す。
stack option | スタックの場所 |
---|---|
NEARSTACK | SS = DS |
FARSTACK | SS ≠ DS |
※i8086、及びリアルモード用のメモリモデルにおいて、stackoptionにてFARSTACK
を指定した場合、セグメントグループDGROUP
からセグメントSTACK
は外される。
尚、FLAT
モデルでは、stackoptionは不要。
.startup
書式
.startup
説明
MS-DOS用の、スタートアップのコードを生成する。
modelの指定内容によって、生成コードが異なる。
32bit, 64bitのスタートアップコードの生成は非対応。
memorymodel=TINY
の場合。
org 0100h
@Startup:
memorymodel≠TINY
, FLAT
以外で、且つstackoption=NEARSTACK
(SS=DS)の場合
SS=DS(DGROUP)として、SPレジスタを調整するコードを生成する。
@Startup:
mov ax, DGROUP
mov ds, ax
mov bx, ss
sub bx, ax
shl bx, 1 ; If .186 or higher, this is
shl bx, 1 ; shortened to shl bx, 4
shl bx, 1
shl bx, 1
cli ; Not necessary in .286 or higher
mov ss, ax
add sp, bx
sti ; Not necessary in .286 or higher
; statements
END @Startup
memorymodel≠TINY
, FLAT
以外で、且つstackoption=FARSTACK
(SS≠DS)の場合
@Startup:
mov dx, DGROUP
mov ds, dx
; statements
END @Startup
.exit
書式
.exit expression
説明
MS-DOS用の、シェル(command.com等)に戻るコードを生成する。
32bit, 64bitのスタートアップコードの生成は非対応。
mov ah, 04Ch
int 21h
パラメータ
expression
シェールに返すコードを0~255で指定する。
主に、エラーコードとして用いられ、指定した場合は以下のコードを生成する。
mov ax, 04C00h + expression
int 21h