第28章
複数のモジュールからなる
プログラム
この章では、A:\TATARA\EXAMPLES\TWOMODにある例、TWOMODを作ります。2つのモジュールからなり、リンク・ファイルでリンクするプログラムです。ファイルを1つずつ見ていき、プログラムを作り、TANRENが作ったものを確かめ、最後に3通りに変えて、何がうまくいかないのか、なぜなのかを見ます。それぞれの部分のくわしい説明は、途中で示す参照の章にあります。
28.1 この例
TWOMODは、2行を表示して終わります。
A:\TATARA\EXAMPLES\TWOMOD>twomod Two modules, one program. The linker joined them.
表示は、独立したモジュールにあるputstrというルーチンが行います。この例には、4つのファイルがあります。
- MAIN.AS:プログラムが始まるモジュール
- PUTSTR.AS:putstrのあるモジュール
- TWOMOD.LNK:2つのモジュールを指定するリンク・ファイル
- BUILD.BAT:それらをアセンブルしてリンクするバッチ・ファイル
28.2 2つのモジュール
MAIN.ASは、1行ごとにputstrを呼び、2回呼んだあとでプログラムを終えます。
; MAIN.AS - one of two modules. ; ; It knows that putstr exists. It does not know where putstr is, and ; it does not need to: EXTRN says the name is somebody else's, and the ; linker fills the address in. extrn putstr ; defined in PUTSTR.AS include msxdos.inc ; _TERM0 and "system" include ascii.inc ; CHR_CR and CHR_LF cseg start: ld hl,msg1 call putstr ld hl,msg2 call putstr system _TERM0 msg1: db "Two modules, one program.",CHR_CR,CHR_LF,0 msg2: db "The linker joined them.",CHR_CR,CHR_LF,0 end start
extrn putstrは、putstrがほかのどこかのモジュールで定義されていることをTATARAに伝えます(12.5節)。TATARAにはそれがどこかわからないので、それぞれのcall putstrのアドレスは、TANRENが入れるように空けておきます。ENDの行は、最初の命令であるstartを示しています。
PUTSTR.ASはputstrを定義しています。これは、0のバイトに達するまで、文字列の文字を1つずつ表示します。
; PUTSTR.AS - the other module. ; ; PUBLIC is what makes the name visible outside this file. Without it ; the name would still assemble here and the link of MAIN.AS would ; stop with an undefined symbol - which is worth trying once. public putstr include msxdos.inc ; BDOS, _CONOUT and "system" cseg ; putstr - print a string. ; ; HL is pushed around the BDOS call because MSX-DOS promises nothing ; about the registers it hands back. ; ; Input: HL -> the string, ending in a zero byte ; Output: it is printed ; Modifies: AF, BC, DE, HL putstr: ld a,(hl) or a ret z push hl ld e,a system _CONOUT pop hl inc hl jr putstr end
public putstrは、この名前をほかのモジュールに提供します。どちらのモジュールも、相手についてそれ以上のことは知りません。MAIN.ASが知っているのはputstrという名前だけで、PUTSTR.ASは誰が自分を呼ぶかを知りません。それぞれが別々にアセンブルされ、それぞれのオブジェクト・ファイルになります。
28.3 リンク・ファイル
リンクのそれ以外の部分は、TWOMOD.LNKにあります(22章)。
; TWOMOD.LNK - the link, in a file instead of on the command line. ; ; TANREN reads this when it is given @TWOMOD, and the words in it are ; the words it would have read from the command line. A ; starts a ; comment and the rest of the line is ignored. ; ; MSX-DOS gives a command line 127 characters and cuts a longer one ; without saying so. That is the whole reason this exists: the ; assembler is itself linked from a file of nineteen module names. /o:twomod.com main.tro putstr.tro
コメントのあとに、言葉の行が2つあります。出力ファイルの名前を示す/o:twomod.comと、2つのオブジェクト・ファイルです。MAIN.TROを先に書いているのは、MSX-DOSが.COMのプログラムを0100hから実行し、TANRENが最初のモジュールのコードをそこに置くからです(21.1節)。
28.4 作って実行する
BUILD.BATがプログラムを作ります。
rem BUILD.BAT - EXAMPLE: TWOMOD rem rem Two modules, one program. MAIN.AS declares putstr EXTRN and rem PUTSTR.AS declares it PUBLIC; the linker matches the two. rem rem The link itself is in TWOMOD.LNK rather than on this line. @NAME rem reads a file of words, and .LNK is assumed when the name has no rem extension. Everything in it could have been typed here instead. rem The headers are in A:\TATARA\INCLUDE and are not copied here. rem TATARA is rule 3 of the include search - see the DIRS example. rem CHANGE THE PATH BELOW if you put the tree somewhere else. set TATARA=a:\tatara\include echo === Assembling both modules tatara /q main.as main.tro tatara /q putstr.as putstr.tro echo === Linking from TWOMOD.LNK tanren /q @twomod echo === Done. Type TWOMOD to run it. set TATARA=
このバッチ・ファイルは、TATARAがMSXDOS.INCとASCII.INCを見つけられるようにTATARAを設定し(13.3節)、それぞれのモジュールをオブジェクト・ファイルにアセンブルし、@twomodでリンクしてから、TATARAを元に戻します。読むファイルと作るファイルを図28.1に示します。
例のディレクトリで実行してください。/QでTATARAとTANRENは何も表示しないので、バッチ・ファイル自身の行だけが表示されます。
A:\TATARA\EXAMPLES\TWOMOD>build === Assembling both modules === Linking from TWOMOD.LNK === Done. Type TWOMOD to run it. A:\TATARA\EXAMPLES\TWOMOD>twomod Two modules, one program. The linker joined them.
同じリンクを/Qなしで行うと、TANRENの要約が表示されます。TATARAが必要なのはアセンブルのときだけなので、このリンクはそのまま入力できます。
A:\TATARA\EXAMPLES\TWOMOD>tanren @twomod Tatara MSX Linker v1.2.0 Copyright (C) 2026 Javier Lavandeira https://tatara.tools 2 modules, 14 records, ends at EOF. Wrote TWOMOD.COM, 0100-0154 (85 bytes), entry 0100.
28.5 TANRENがしたこと
/Mを付けると、TANRENがそれぞれをどこに置いたかがわかります(25.7節)。
A:\TATARA\EXAMPLES\TWOMOD>tanren /m @twomod /o:tm.com ... Modules: 2 Groups: Segments: flags 00 group FF base 0100 size 0055 end 0154 C flags 01 group FF base 0155 size 0000 end ----- D Symbols: DR 0147 putstr 2 modules, 14 records, ends at EOF. Wrote TM.COM, 0100-0154 (85 bytes), entry 0100.
どちらのモジュールもすべてを標準のコード・セグメントに置いているので、プログラムは0100hから0154hまでの55hバイトのコード・セグメント1つになります。最初にMAINの71バイト、続いてPUTSTRの14バイトです。データ・セグメントは空です。putstrはPUTSTRが定義し(D)、MAINが参照していて(R)、MAINのすぐあとの0147hにあります。TANRENは、2つのcall putstrの命令の両方に0147hを書き込みました(図28.2)。
28.6 試してみること
次のそれぞれの変更は、TANRENが見つける誤りを1つずつ示します。使うファイルは例には含まれていないので、例のファイルをコピーして、同じディレクトリに作ってください。アセンブルには、BUILD.BATと同じようにTATARAが必要です。
set tatara=a:\tatara\include
28.6.1 PUBLICを外す
NOPUB.ASは、PUTSTR.ASからpublic putstrの行を除いたものです。これはアセンブルできます。putstrは、その中ではふつうのラベルです。しかし、どのモジュールもこの名前を提供しなくなるので、リンクは失敗します(25.3節)。
A:\TATARA\EXAMPLES\TWOMOD>tatara /q nopub.as nopub.tro A:\TATARA\EXAMPLES\TWOMOD>tanren main nopub /o:np.com ... Never defined: putstr ERROR: the symbols above were never defined.
28.6.2 モジュールの順番を逆にする
SWAP.LNKは、TWOMOD.LNKの出力ファイルを/o:swap.comにし、最後の行をputstr.tro main.troにしたものです。これはエラーなしでリンクできますが、警告が出ます。
A:\TATARA\EXAMPLES\TWOMOD>tanren /m @swap ... Symbols: DR 0100 putstr WARNING: SWAP.COM is entered at 0100, not at 010E. 2 modules, 14 records, ends at EOF. Wrote SWAP.COM, 0100-0154 (85 bytes), entry 010E.
しかし、putstrは0100hに、startは010Ehに置かれます。MSX-DOSはSWAP.COMを0100hから実行するので、HLにたまたま入っている値でputstrを実行し、MAINのコードには決してたどり着きません。実行しないでください。エントリー・アドレスの010Ehは正しいのですが、.COMのプログラムはそこからは始まらず、TANRENは警告でそのことを伝えます(26.5節)。
28.6.3 1つのモジュールだけを/Cでアセンブルする
/Cを付けてアセンブルしたMAIN.ASと、付けずにアセンブルしたPUTSTR.ASは、一緒にリンクできません(25.5節)。
A:\TATARA\EXAMPLES\TWOMOD>tatara /q /c main.as mainc.tro A:\TATARA\EXAMPLES\TWOMOD>tanren mainc putstr /o:mix.com ... ERROR: one module was assembled /C and another was not.