MASM Version 5、及び6におけるセグメント

Microsoft Macro Assembler（以降、MASMと略）Version 6以降でアプリケーションを開発する際のメモ書きです。
この記事では、セグメントの指定方法について記します。

- [セグメント定義（MASM Version 5までの方法）](#セグメント定義masm-version-5までの方法)
  - [`SEGMENT` ~ `ENDS`](#segment--ends)
  - [`GROUP`](#group)
  - [`ASSUME`](#assume)
- [簡略化セグメント（MASM Version 6以降の方法）](#簡略化セグメントmasm-version-6以降の方法)
  - [`.dosseg`](#dosseg)
  - [`.code`](#code)
  - [`.const`](#const)
  - [`.data`](#data)
  - [`.data?`](#data-1)
  - [`.fardata`](#fardata)
  - [`.fardata?`](#fardata-1)
  - [`.stack`](#stack)

# セグメント定義（MASM Version 5までの方法）

## `SEGMENT` ~ `ENDS`

### 書式

```asm
name    SEGMENT (align) (READONLY) (combine) (use) ('class')

        (statements)

name    ENDS
```

### 説明

セグメントの名前、区間、属性等を設定する。

### パラメータ

#### name

セグメントの名前

#### align

このセグメントのアライメントを指定する。

| align  | 開始アドレス |
|--------|--------------|
|  BYTE  |   1 Byte単位で配置する。 |
|  WORD  |   2 Byte単位で配置する(偶数アドレスに配置)。 |
| DWORD  |   4 Byte単位で配置する。 |
|  PARA  |  16 Byte単位で配置する(16進数で末尾1桁が0のアドレスに配置)。省略時のデフォルト |
|  PAGE  | 256 Byte単位で配置する(16進数で末尾2桁が00のアドレスに配置)。 |
| ALIGN(n) | (n) Byte単位で配置する(nは1～8192の範囲の2のべき乗を指定する)。 |

#### READONLY

これを指定した場合、当該セグメントは読み込み専用とする。
当該セグメントに書き込みを行う命令を記述した場合は、アセンブラーはエラーを出力する。

#### combine

`*.obj`ファイルのリンク時の動作を指定する。
※16bit, 32bitのみ（64bit版MASMでは非対応）

| combine | リンカーの動作 |
|---------|---------------|
| PRIVATE | 他の *.obj ファイルから、このセグメントのアクセスを許可しない。 |
| PUBLIC  | 他の *.obj ファイルから、このセグメントのアクセスを許可する。 |
| STACK   | スタック用のセグメント。この属性のセグメントは全て連結し、OSは`SS:0000`を下位アドレスに、`SS:SP`を上位アドレスに設定する。初期化済データの配置は不可。 |
| COMMON  | この属性のセグメントは結合する。初期化済データの配置は不可。 |
| MEMORY  | PUBLICと同義 |
| AT (address) | セグメントアドレスを直接指定する。このセグメントには、コード及び、初期化済データを配置できない。当該セグメントにVRAM等の構造体を定義する事で、直接アクセスするコードを書くことが出来る。（16bitコード）|

#### use

オフセットアドレスの扱い
※32bitのみ（16bit、及び64bitでは非対応）

| use | オフセットアドレスの扱い |
|-----|-----|
| USE16 | オフセットアドレスを16bitとして扱う。 |
| USE32 | オフセットアドレスを32bitとして扱う。Visual C++で書かれた32bitコードとリンクする場合、だいたいこれを指定する。 |
| FLAT  |      |

#### 'class'

クラス名を指定する。
リンカはメモリ内で自動的に同じクラスの区分を分類する。

| class     |      |
|-----------|-----|
|'CODE'     | コード領域である事を示す。 |
|'FAR_DATA' | 初期化データ領域である事を示す。 |
|'FAR_BSS'  | 未初期化データ領域である事を示す。 |
|'DATA'     | 初期化データ領域である事を示す。 |
|'CONST'    | 初期化データ領域である事を示す（書込み禁止）。 |
|'BSS'      | 未初期化データ領域である事を示す。 |
|'STACK'    | スタック領域領域である事を示す。 |

## `GROUP`

### 書式

```asm
group_name     GROUP   [name]...
```

### 説明

指定したセグメントを、同一のセグメントにまとめる。

### パラメータ

#### group_name

セグメントグループの名前。

#### name

セグメント名。

## `ASSUME`

### 書式

```asm
ASSUME  [segregister:name]...
ASSUME  [dataregister:type]...
ASSUME  [register:ERROR]...
```

### 説明

セグメントレジスタの値、レジスタの型を仮定する。

### パラメータ

#### segregister

セグメントレジスタ（`CS`, `DS`, `ES`, `SS`）。

#### name

セグメント名、若しくは、セグメントグループ名。

#### dataregister

レジスタ

#### type

`BYTE`, `WORD`, `DWORD`, `PTR`, 等の他、`PTR STRUC`といった構造体のポインタも仮定可能

### 例

`ASSUME`ディレクティブにて`DS`レジスタを`name`に仮定する事で省略することができる。

```ex1.asm
        ASSUME  DS:DGROUP               ;DSレジスタには DGROUP が設定されているものと仮定する。
        MOV     EAX, label              ;上記仮定の元、アセンブルする（labelの実体はセグメントDGROUPに存在する）。
```

`ASSUME`ディレクティブにて、レジスタの型を構造体に仮定する事で、構造体名を省略することができる。

```ex2.asm
        ASSUME  EDI:PTR STRUCT          ;EDIレジスタは、構造体STRUCTのポインタが設定されているものと仮定する。
        MOV     EAX, [EDI].member       ;上記仮定の元、アセンブルする。
```

# 簡略化セグメント（MASM Version 6以降の方法）

MASM Version 6から導入された簡易的なセグメントの指定方法。
上記のディレクティブを用いずに、セグメントの指定が行える（`ASSUME  DS:DGROUP`も必要ない）。
Visual C++で書かれたコードとリンクする場合、これらのディレクティブを用いてコードを記述すれば、開発しやすい。

## `.dosseg`

### 書式

```asm
.dosseg
```

### 説明

セグメントの並び方を、MS-DOSの仕様にする。
MS-DOS仕様のＣ言語等でコンパイルした*.objファイルとリンクする場合等に記述する。
(32bit、64bitのコードでは、不要)

| Segment | 配置順番 |
|---------|----------|
| heap    | ヒープ領域（残りメモリ） |
| STACK   | スタックエリア |
| BSS     | 未初期化データ |
| CONST   | 初期化済みデータ（書き換え禁止） |
| DATA    | 初期化済みデータ |
| FAR_BSS | far 領域の未初期化データ |
| FAR_DATA | far 領域の初期化済みデータ |
| _TEXT   | コード領域 |

## `.code`

### 書式

```asm
.code   (name)
```

### 説明

次の行以降を、コード用のセグメントに設定する。

### パラメータ

#### name

セグメントの名前を指定する。
省略した場合、[メモリモデル](https://qiita.com/sha_w/items/8c703fefa76741cfebaa#model)が`TINY`, `SMALL`, `COMPACT`, `FLAT`の時は`_TEXT`、
[メモリモデル](https://qiita.com/sha_w/items/8c703fefa76741cfebaa#model)が`MEDIUM`, `LARGE`, `HUGE`の時は、`module_TEXT`と設定される。

## `.const`

### 書式

```asm
.const
```

### 説明

セグメント名は、`CONST`が設定され、
次の行以降を、書き換え不可のデータ用のセグメントに設定する。
多くのＣ言語における、nearがつく変数領域と同一のセグメント。

## `.data`

### 書式

```asm
.data
```

### 説明

セグメント名は、`DATA`が設定され、
次の行以降を、書き換え可の、初期化済みデータセグメントに設定する。
多くのＣ言語における、nearがつく変数領域と同一のセグメント。

## `.data?`

### 書式

```asm
.data?
```

### 説明

セグメント名は、`BSS`が設定され、
次の行以降を、書き換え可の、未初期化データセグメントに設定する。
多くのＣ言語における、nearがつく変数領域と同一のセグメント。

## `.fardata`

### 書式

```asm
.fardata (name)
```

### 説明

次の行以降を、書き換え可の、初期化済みデータセグメントに設定する。

### パラメータ

#### name

セグメントの名前を指定する。
省略した場合、セグメント名は`FAR_DATA`と設定される。

## `.fardata?`

### 書式

```asm
.fardata? (name)
```

### 説明

次の行以降を、書き換え可の、未初期化データセグメントに設定する。

### パラメータ

#### name

セグメントの名前を指定する。
省略した場合、セグメント名は`FAR_BSS`と設定される。

## `.stack`

### 書式

```asm
.stack (size)
```

### 説明

セグメント名を`STACK`で、スタック領域を確保する。
[メモリモデル](https://qiita.com/sha_w/items/8c703fefa76741cfebaa#model)が`TINY`の場合は、確保されないので注意。

Visual C++で書かれたコードとリンクする時は、指定の必要はない。
（おそらく、ランタイムの方で確保されている。）

### パラメータ

#### size

スタック領域のサイズ[byte]を設定する。
省略した場合は、1024[byte]となる。