第24章
プログラムの配置
TATARAは、すべてのラベルに、セグメントの中で0から数えたアドレスを与えます(10章)。TANRENは、各モジュールの各セグメントをメモリのどこに置くかを決め、それによってすべてのラベルの最終的なアドレスを決めます。この章では、TANRENが従う規則、それを変えるオプション、そして出力ファイルに何が書き出されるかを説明します。
24.1 コードが先、データがあと
TANRENは、すべてのコードを先に置き、すべてのデータをそのあとに置きます。
- コード・セグメントは、MSX-DOSが.COMのプログラムを読み込むメモリ・アドレス0100hから始まります。
- データ・セグメントは、コードの最後のバイトのすぐあとから始まります。
複数のモジュールが使うセグメントは1つにまとめられ、その中に各モジュールの部分が、コマンド・ラインで指定した順に並びます。
次の2つのモジュールには、それぞれコードとデータがあります。A.ASには、名前付きコード・セグメントextraもあります。
; A.AS - code, data, and a named code segment. public astart,aextra,adata cseg astart: ld hl,adata ret cseg extra aextra: nop dseg adata: ds 4 end astart
; B.AS - code and data. public bcode,bdata cseg bcode: ld hl,bdata ret dseg bdata: db 1,2 end
/Mを付けると、TANRENはほかの情報とともに、プログラムのセグメントと、それぞれに与えたアドレスを表示します。
A:\>tanren /m a b ... Modules: 2 Groups: Segments: flags 00 group FF base 0100 size 0008 end 0107 C flags 00 group FF base 0108 size 0001 end 0108 extra flags 01 group FF base 0109 size 0006 end 010E D Symbols: D- 0100 astart D- 0108 aextra D- 0104 bcode D- 0109 adata D- 010D bdata 2 modules, 21 records, ends at EOF. Wrote A.COM, 0100-010E (15 bytes), entry 0100.
Segments:の下の各行が1つのセグメントで、TANRENが置いた順に並んでいます。最後の言葉はセグメントの名前で、Cは標準のコード・セグメント、Dは標準のデータ・セグメント、それ以外は名前付きセグメントです。baseは最初のアドレス、sizeはバイト数、endは最後のアドレスです。flagsはコードなら00、データなら01です。グループとシンボル、そのほかの/Mの表示については、25章で説明します。
同じプログラムのメモリを図24.1に示します。コード・セグメントにはAの4バイト、続いてBの4バイトが0100hから 0107hまで入り、そのあとの0108hにextraがあります。データ・セグメントは0109hから始まり、Aの4バイト、続いてBの 2バイトが入ります。
モジュールを逆の順に指定したtanren b aでは、各セグメントの中でBの部分が先になります。bcodeは0100hに、astartは 0104hに移り、エントリー・アドレスも一緒に移ります。
24.1.1 ファイルに書き出されるもの
出力ファイルには、内容を持つ最初のバイトから最後のバイトまでのメモリが書き出されます。DSはメモリを確保しますが内容を与えないので(11章)、プログラムの最後にあるDSは、ファイルにまったく書き出されません。tanren b aではAのds 4が最後になるので、ファイルはBの2バイトのあとの010Ahで終わります。
A:\>tanren /m b a /o:ba.com ... WARNING: BA.COM is entered at 0100, not at 0104. 2 modules, 21 records, ends at EOF. Wrote BA.COM, 0100-010A (11 bytes), entry 0104.
最初のバイトについても同じです。DSのためにファイルから除かれたメモリは、0にもされません。プログラムが始まったとき、そこにはそれまでにあった値が残っています。値0から始まる必要がある変数は、プログラム自身で0にするか、DBやDWで定義してください。
24.2 名前付きセグメント
プログラムには、それぞれの種類のセグメントを複数持たせることができます(10.5節)。TANRENは、種類ごとに、まず標準のセグメントを置き、次に名前付きセグメントを、コマンド・ラインの順に並べたモジュールの中で最初に現れた順に置きます。次のモジュールは、名前付きセグメントを標準のセグメントより先に選んでいます。
; ORDER.AS - named segments written before the default ones. public zfirst,cmain,zdata,dmain cseg zcode zfirst: nop cseg cmain: ret dseg zvars zdata: db 1 dseg dmain: db 2 end cmain
A:\>tanren /m order ... Segments: flags 00 group FF base 0100 size 0001 end 0100 C flags 00 group FF base 0101 size 0001 end 0101 zcode flags 01 group FF base 0102 size 0001 end 0102 D flags 01 group FF base 0103 size 0001 end 0103 zvars
それでも、標準のコード・セグメントは0100hから始まります。MSX-DOSは.COMのプログラムを必ず0100hから始めるので、これは重要です。最初に実行するコードは、最初のモジュールの標準のコード・セグメントに入れてください。
24.3 コードとデータを動かす:/P:と/D:
/P:はコードを別のアドレスから始め、データはこれまでと同じようにそのあとに続きます。
A:\>tanren /m /p:8000 a b /o:p8000.bin ... Segments: flags 00 group FF base 8000 size 0008 end 8007 C flags 00 group FF base 8008 size 0001 end 8008 extra flags 01 group FF base 8009 size 0006 end 800E D ... Wrote P8000.BIN, 8000-800E (15 bytes), entry 8000.
MSX-DOSは.COMのプログラムを0100hに読み込むので、ほかのアドレス用にリンクしたプログラムは.COMのプログラムではありません。たとえばMSX-BASICのBLOADのような、別の方法で読み込みます(26章)。
/D:は、データをコードのすぐあとではなく、指定したアドレスから始めます。データはコードより上にも下にも置けます。/p:c000 /d:8000では、コードがC000hに、データがその下の8000hに置かれます。
A:\>tanren /m /p:c000 /d:8000 a b /o:high.bin ... Segments: flags 00 group FF base C000 size 0008 end C007 C flags 00 group FF base C008 size 0001 end C008 extra flags 01 group FF base 8000 size 0006 end 8005 D ... Wrote HIGH.BIN, 8004-C008 (16389 bytes), entry C000.
ファイルが8000hではなく8004hから始まっているのは、データの最初の 4バイトが内容を持たないAのds 4だからです(24.1.1節)。
データをコードの中から始めることはできません。0100hから0108hまでがコードのとき、/d:0102を指定すると、TANRENは/D: would put the data on top of the code.と表示して止まります。
警告. コードとデータの間にあるものはすべて、0としてファイルに書き出されます。/d:c000を指定すると、コードとデータが合わせて15バイトの.COMのプログラムが、48,902バイトのファイルになります。
A:\>tanren /m /d:c000 a b /o:dc000.com ... Wrote DC000.COM, 0100-C005 (48902 bytes), entry 0100.
24.4 モジュールをまたぐトランジェント・セグメント
トランジェント・データ・セグメントのグループは同じメモリを共有し(10.6節)、TANRENはこれをモジュールをまたいで適用します。トランジェント・セグメントのグループは、どのモジュールにあっても、すべて同じアドレスから始まり、セグメントの大きさはいちばん大きいグループの大きさになります。次の2つのモジュールは、それぞれセグメントscratchにグループを1つずつ加えます。
; T1.AS - the group reading of the transient segment scratch. public inbuf dseg scratch,transient group reading inbuf: ds 64 end
; T2.AS - the group writing of the same segment. public outbuf dseg scratch,transient group writing outbuf: ds 32 end
A:\>tanren /m a b t1 t2 /o:tr.com ... Groups: reading writing Segments: flags 00 group FF base 0100 size 0008 end 0107 C flags 00 group FF base 0108 size 0001 end 0108 extra flags 01 group FF base 0109 size 0006 end 010E D flags 03 group 00 base 010F size 0040 end 014E scratch flags 03 group 01 base 010F size 0020 end 012E scratch ... Wrote TR.COM, 0100-010E (15 bytes), entry 0100.
トランジェント・セグメントには、グループごとにflagsが03の行が1つずつあり、Groups:の中でのグループの番号が 00から数えて表示されます。どちらのグループも010Fhから始まるので(図24.2)、inbufとoutbufは同じアドレスになり、scratchはreadingの大きさである64バイトを占めます。scratchにはDSしかないので、ファイルは 15バイトのままです。
24.5 アブソリュート・セグメント
アブソリュート・セグメント(10章)は動かされません。そのバイトは、ソースに書いたアドレスに置かれます。次のモジュールは、4000hに2バイトを置きます。
; ABS.AS - two bytes at 4000h. public romhdr aseg org 4000h romhdr: db 'AB' end
これをA、Bと一緒にリンクすると、プログラムは0100hから 4001hまでになり、データの最後のバイトから4000hまでの間はすべて0として書き出されます(図24.3)。
A:\>tanren /m a b abs /o:gap.com ... Wrote GAP.COM, 0100-4001 (16130 bytes), entry 0100.
アブソリュート・セグメントは、ROMイメージのように、決まったアドレスにバイトを置かなければならないプログラムのためのものです(26章)。.COMのプログラムでは、コードよりずっと上にあるバイトはファイルを大きくします。
24.6 メッセージ
配置についてのメッセージを、表24.1に示します。