第25章
モジュール間のシンボル
モジュールは、PUBLICでほかのモジュールに名前を提供し、EXTRNでほかのモジュールの名前を使います(12.5節)。TATARAは外部の名前をすべて未完成のまま残し、TANRENがそれを、ほかのモジュールが与えた値で仕上げます。この章では、TANRENが名前をどのように対応させるか、どのモジュールも定義していない名前や2つのモジュールが定義している名前をどう扱うか、そして/Mが何を表示するかを説明します。
25.1 名前の対応のさせかた
21章のプログラムでは、MAIN.ASがgreetをEXTRNで宣言して呼び出し、SUB.ASがそれをPUBLICで宣言して定義しています。
; MAIN.AS - calls greet, in another module, and ends the program. include msxdos.inc extrn greet cseg start: call greet system _TERM0 end start
; SUB.AS - greet prints a line. include msxdos.inc include ascii.inc public greet cseg greet: ld de,msg system _STROUT ret dseg msg: db 'Hello from TANREN.',CHR_CR,CHR_LF,'$' end
TANRENは、リンク全体で1つの名前の表を持ち、モジュールを2回読みます。
- 1回目のパスでは、すべてのモジュールのパブリックな名前と外部の名前を表に読み込みます。パブリックな名前は、値とともに定義されます。greetはSUBのコードの最初のバイトで、SUBのコードはMAINの8バイトのあとに来るので、greetは0108hです。外部の名前は参照されます。つまり、どこかのモジュールがその値を必要としています。パスの終わりには、参照されている名前がすべて定義されていなければなりません。
- 2回目のパスでは、各モジュールのバイトを書き出し、外部の名前が使われている場所すべてに、表の値を入れます。
図25.1は、2つのパスでのgreetの流れを示しています。TATARAはcall greetをCD 00 00として書き出し、TANRENがそれを0108hを呼ぶCD 08 01に変えます。
どのバイトを書き出す前にも、すべての名前が表に入っているので、名前についてはモジュールの順番は関係ありません。モジュールは、自分より前に指定したモジュールの名前も、あとに指定したモジュールの名前も使えます。順番が関係するのは、各モジュールがメモリのどこに置かれるかだけです(24章)。
/Mは、ほかの情報とともにこの表を表示します。このプログラムでは名前は1つです。
A:\>tanren /m main sub ... Symbols: DR 0108 greet 2 modules, 16 records, ends at EOF. Wrote MAIN.COM, 0100-0125 (38 bytes), entry 0100.
Dはgreetが定義されていること、Rは参照されていることを示し、0108がその値です。/Mのそのほかの表示は25.7節で説明します。
25.2 外部の名前の値
外部の名前には、数を加えることも引くこともできます(8.6節)。TATARAはその数を値が入る場所に書いておき、TANRENがそれに名前の値を加えます。次の2つのモジュールは、コードとデータの中で名前を使っています。
; USE.AS - uses two names from VALS.AS, with and without an addend. extrn table,count cseg start: ld hl,table+2 ld bc,count ld de,count+1 ret dseg ptrs: dw table,table+4 end start
; VALS.AS - a table in the data segment, and an absolute value. public table,count count equ 10 dseg table: db 1,2,3,4,5,6 end
A:\>tanren /m use vals ... Symbols: DR 000A count DR 010E table 2 modules, 17 records, ends at EOF. Wrote USE.COM, 0100-0113 (20 bytes), entry 0100.
tableはUSEのデータのあとの010Ehにあるので、USE.COMの中ではld hl,table+2は21 10 01に、dw table,table+4は0E 01 12 01になります。
countはEQUで定義されているので、セグメントの中のアドレスではなくアブソリュートな値です(8.6節)。TANRENはこれを動かしません。モジュールがどこに置かれても000Ahで、ld de,count+1は11 0B 00になります。
25.3 どのモジュールも定義していない名前
参照されているのに定義されていない名前があると、TANRENは1回目のパスの終わりで止まり、出力ファイルは書き出されません。MAINだけをリンクすると、greetを定義するモジュールがありません。
A:\>tanren main ... Never defined: greet ERROR: the symbols above were never defined.
TANRENは、最初の1つだけでなく、足りない名前をすべて表示するので、1回の実行ですべてがわかります。次のモジュールは3つの名前を使い、そのうちbetaだけがBETA.ASで定義されています。
; MISS.AS - three externals; nobody defines alpha or gamma. extrn alpha,beta,gamma cseg ld hl,alpha ld de,beta ld bc,gamma ret end
; BETA.AS - defines beta. public beta cseg beta: ret end
A:\>tanren miss beta ... Never defined: gamma alpha ERROR: the symbols above were never defined.
名前は、特に決まっていない順で表示されます。
警告. EXTRNで宣言した名前は、モジュールがそれを一度も使わなくても参照されていることになり、TANRENはやはりその定義を求めます。
; UNUSED.AS - declares an external and never uses it. extrn nothere cseg start: ret end startA:\>tanren unused ... Never defined: nothere ERROR: the symbols above were never defined.
25.4 2回定義された名前
1つの名前を定義できるのは1つのモジュールだけです。2つ目の定義があると、TANRENはモジュールを読んでいる途中で止まり、エラーの前の行に、その名前と、2つ目の定義が見つかったモジュールを表示します。次の例では、DUP2.ASが2つ目のgreetを定義していて、OTHER.TROにアセンブルされています。
; DUP2.AS - a second greet. public greet cseg greet: ret end
A:\>tatara /q dup2.as other.tro A:\>tanren main sub other /o:dup.com ... greet is defined again in module dup2 ERROR: that public symbol is already defined.
モジュールには、オブジェクト・ファイルではなく、アセンブルしたソースの名前が付くので、メッセージにはotherではなくdup2と表示されます。
1つのオブジェクト・ファイルを2回指定したときも、たとえばコマンド・ラインとリンク・ファイルの両方に書いたときも(22章)、同じことが起きます。
A:\>tanren main sub sub /o:dup.com ... greet is defined again in module sub ERROR: that public symbol is already defined.
TANRENは、2回定義された最初の名前で止まり、そのあとで足りない名前を探すことはしません。1つのリンクに両方の誤りがあるときは、まず2回定義された名前を直してから、もう一度リンクしてください。
25.5 大文字と小文字
/Cを付けないと、TATARAは名前の大文字と小文字を区別せず(7.3節)、TANRENも区別しません。次のモジュールは、大文字でGREETを呼びます。
; UPPER.AS - calls GREET, in capitals. include msxdos.inc extrn GREET cseg start: call GREET system _TERM0 end start
このモジュールは、名前がgreetであるSUBとリンクできます。/Mは、TANRENが最初に見た形で名前を表示します。
A:\>tanren /m upper sub ... Symbols: DR 0108 GREET 2 modules, 16 records, ends at EOF. Wrote UPPER.COM, 0100-0125 (38 bytes), entry 0100.
/Cを付けてアセンブルすると、2つのモジュールの名前は別の名前になり、一方は定義されているだけ、もう一方は参照されているだけなので、リンクは失敗します。
A:\>tatara /q /c upper.as upperc.tro A:\>tatara /q /c sub.as subc.tro A:\>tanren /m upperc subc ... Symbols: D- 0108 greet -R ---- GREET Never defined: GREET ERROR: the symbols above were never defined.
/Cを付けてアセンブルしたモジュールと付けずにアセンブルしたモジュールは、一緒にリンクできません(7.3節)。
A:\>tanren upperc sub /o:mix.com ... ERROR: one module was assembled /C and another was not.
25.6 すべてのモジュールがリンクされる
TANRENは、渡されたモジュールをそのままリンクします。ほかのどのモジュールからも参照されないモジュールもリンクされ、そのバイトは出力ファイルに入ります。EXTRA.ASのspareは、どこからも参照されていません。
; EXTRA.AS - a module nobody refers to. public spare cseg spare: ld a,1 ret end
A:\>tanren /m main sub extra /o:ex.com ... Symbols: D- 0111 spare DR 0108 greet 3 modules, 22 records, ends at EOF. Wrote EX.COM, 0100-0128 (41 bytes), entry 0100.
spareは定義されていて参照されておらず、その3バイトの分だけ、EX.COMはMAIN.COMより3バイト長くなります。TANRENは、プログラムに必要なモジュールをライブラリから探すことはしません。コマンド・ラインやリンク・ファイルで指定したモジュールは、使われるかどうかにかかわらず、すべてリンクされます。
25.7 /Mの表示のすべて
/Mは、バナーのあと、要約行の前に、4つの部分を表示します。tanren /m main subでは次のようになります。
A:\>tanren /m main sub Tatara MSX Linker v1.2.0 Copyright (C) 2026 Javier Lavandeira https://tatara.tools Modules: 2 Groups: Segments: flags 00 group FF base 0100 size 0011 end 0110 C flags 01 group FF base 0111 size 0015 end 0125 D Symbols: DR 0108 greet 2 modules, 16 records, ends at EOF. Wrote MAIN.COM, 0100-0125 (38 bytes), entry 0100.
- Modulesは、TANRENが読んだオブジェクト・ファイルの数です。
- Groupsは、トランジェント・セグメントのグループを1行に 1つずつ表示します。グループには、表示された順に00から番号が付きます(24.4節)。このプログラムにはグループはありません。
- Segmentsは、すべてのセグメントについて、置かれた場所と大きさを表示します(24.1節)。
- Symbolsは、すべてのパブリックな名前と外部の名前を、1行に 1つずつ、特に決まっていない順で表示します。最初の欄は2文字で、どこかのモジュールが名前を定義していればD、どこかのモジュールが外部として宣言していればRで、当てはまらない文字の代わりに-が入ります。次が値で、どのモジュールも定義していない名前では––になります。最後が名前です。
/Mは、足りない名前があるときも、その一覧の前に表を表示します。足りない名前は-R ––と表示されます。
A:\>tanren /m main /o:m1.com ... Modules: 1 Groups: Segments: flags 00 group FF base 0100 size 0008 end 0107 C flags 01 group FF base 0108 size 0000 end ----- D Symbols: -R ---- greet Never defined: greet ERROR: the symbols above were never defined.
大きさが0000のセグメントには最後のアドレスがないので、endは––-と表示されます。
25.8 メッセージ
名前に関するメッセージを表25.1に示します。TANRENのすべてのメッセージは27章にあります。
メッセージ |
意味 |
ERROR: the symbols above were never defined. |
Never defined:の下に表示された名前は、どこかのモジュールが外部として宣言していますが、どのモジュールも定義していません。 |
ERROR: that public symbol is already defined. |
その前の行のNAME is defined again in module MODが示すパブリックな名前を、2つ目のモジュールも定義しています。 |
ERROR: one module was assembled /C and another was not. |