Tatara

第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つのファイルがあります。

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に示します。

PIC

図 28.1: BUILD.BATがTWOMOD.COMを作る流れ。

例のディレクトリで実行してください。/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)。

PIC

図 28.2: メモリの中のTWOMOD.COM。MAINの 2つの呼び出しは、どちらも0147hのputstrに行きます。

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.