さて前回はTurbo Pascalを現代によみがえらせるFree Pascalコンパイラで自前Unitを作製。無事に分割コンパイルできました。今回はFree Pascalのインラインアセンブラを使ってみます。過去回でやったOpenWatcomのつもりで書いたらダメダメ。ビルド環境と実行環境をよく見ろと。
※実機動作確認には以下を使用しております。
-
- Windows 11 PC (i5-1235U)
- Ubuntu 24.04 LTS on WSL2
- QEMU 8.2.2
- FreeDOS 1.3
- Free Pascal Compiler 3.2.2
Free Pascalのインライン・アセンブラ
以下の過去回で OpenWatcom C のインラインアセンブラを使ってみてます。
ソフトな忘却力(52) FreeDOS、OpenWatcom C、インラインアセンブラ
FreeDOS上のOpenWatcom環境のツールチェーンの各プログラムはDOSイクステンダ DOS4GW 上で動くプログラムどもでしたが、
-
- コンパイラスイッチでMS-DOS用の「ピュア16ビット」オブジェクトも生成可能
- アセンブルはOpenWatcom内部ツール(MASM風?)、インテル式のニーモニックOKね
ということで、アセンブリ言語部分はインテル8086式に書けばOKでした。
ところが、今回のFree Pascalコンパイラは、MS-DOS互換のFreeDOS上で運用しており、DOSイクステンダ GO32v2 上で動作しているところはOpenWatcom環境と似ているとは言え
-
- 基本GO32v2 上で動作する「32ビット」のオブジェクトを生成する
- アセンブルはGnuツール、as に依存している
のであります。つまり、
-
- アセンブラは80386の32ビットモードで動作しているつもりで書かねばならない
- アセンブルは「素の」as が担当する。インテル式でなく、AT&T式で書かねばならない
端的に言えば、「右から左」のインテル式ではなく、「左から右」のAT&T式で書く上に、デフォルトは32ビット(16ビットを使う場合にはプリフィックスなどがついて長くなってしまう)のモードなので、%eax とか32ビットレジスタ中心で書くのが身のため、ということであります。
今回作成のサンプルプログラム
今回作成のFree Pascalのソースが以下に。
(* inline assembler test *) program asm0; var srcW : integer; srcB : byte; tempW : integer; tempB : byte; begin srcW := 333; srcB := 22; tempW := 257; tempB := 127; asm nop mov word(srcW), %ax mov %ax, word(tempW) mov byte(srcB), %al mov %al, byte(tempB) nop end ['ax']; writeln('tempW=',tempW); writeln('tempB=',tempB) end.
上記のソース中、asmに始まり、end [‘ax’]; までのブロックがインライン・アセンブラ部分であります。endの後の部分は、コンパイラ様にインライン・アセンブラ内で破壊したレジスタをお教えするための記述です。なお後で逆アセンブルしたときにこの部分を見つけやすいように殊更に nop で挟んであります。
やってることは簡単、Pascal 上で定義されているワード(x86の場合は16ビット)型の srcW変数の内容をtempWへコピー、同様にバイト型のsrcB変数の内容をtempBへコピーするだけです。このプログラムの動作後は最初に代入されてあった tempW、tempBの値は333および22に上書きされるハズ。
ビルドして実行
赤枠内が実行結果です。予定どおりね。
生成されたオブジェクトコードを逆アセンブル
上記で使われたオブジェクトコードをディスアセンブルし、該当部分を取り出したものが以下に。
16ビットと8ビットの転送の割にコードが長くないかい?というのはごもっともです。
まずワード幅(16bit)のAXを介してロードしてストアの2命令のところ、ミドリ色の燦然と輝くコード0x66こそは、オペランド・サイズ・プリフィックスです。386の32ビットモードではデフォルトで使えるのはバイトかダブルワード(32bit)の2択なので、16ビット使うときにはこいつのお世話になる必要があります。
また黄色の部分はオフセット・アドレスです。ここではダイレクト・アドレシングを使ってメモリ上の変数にアクセスしているのですが、32ビット空間で動作している前提なのでオフセット・アドレスは32ビット幅になってます。
まあ、インライン・アセンブラも使えそう。でも、インテル式とAT&T式が頭の中で混じるとヤバいよ。。。昔やったな、そんなこと。