Z80のC言語クロスコンパイル(SDCC)(3)

  • 投稿日:
  • 更新日:2015/03/08
  • by
  • カテゴリ:
前へ 第1回 第2回 第3回 第4回 第5回 次へ

リンクについて

sdccでは他のCコンパイラと同様、ライブラリを作って、それをリンクすることができます。ここでは、通常のスタティックリンクと、外部プログラムとリンクするテクニックについて説明します。

ライブラリの作成とリンク

ライブラリはsdcclibというコマンドで作ります。

% sdcc a mylib.lib prog1.o prog2.o

このようにして作ったライブラリをリンクするときに、

% sdcc -mz80 --out-fmt-ihx --no-std-crt0 -o myobj.ihx crt0.o -lmylib.lib

のようにします。ここでcrt0.oは初回に説明したcrt0モジュールです。 sdcclibコマンドはオブジェクトファイル(上記ならprog1.oとprog2.o)の中身をライブラリファイル内にインポートするので、作成後はオブジェクトファイルを消しても大丈夫です。

オブジェクトファイルを消さないなら、sdcclibを使わなくてもライブラリファイルは作れます。そのときのライブラリファイルの中身は、単にファイル名を並べるだけです。

  • mylib.lib
  • prog1.o
  • prog2.o

このファイルを用意して、同じように

% sdcc -mz80 --out-fmt-ihx --no-std-crt0 -o myobj.ihx crt0.o -lmylib.lib

でリンクできます。mylib.libファイルと同じディレクトリにprog1.oとprog2.oが必要です。

外部プログラムとのリンク

既 に作成されたプログラムがメモリ上に存在して、それを利用したい場合は、わざわざ同じルーチンをリンクするのはメモリのムダですね。ここでは、そのような 外部プログラムをライブラリとしてリンクするという小技を紹介します。出力にすべてのライブラリコードを入れなくて済むので、コード量が小さくなります。

拙作のSDOSのアプリケーションを作る際は、この方法をとることができるようにしてあります。また、BIOSルーチン(BASICインタプリタなど)などがある場合にも活用できます(ただし、前回説明したsdccの関数呼び出し規約に注意)。

準備

外部プログラムをライブラリとしてリンクできるようにするため、リンク対象となるプログラムはヘッダファイルをきちんと準備しておきます。 ここではSDOSのヘッダ(の一部)を例として挙げます。

conio.h
--------
void libputc(unsigned char ch);
void libputs(char* str);

もちろん、conio.hの実装も作成します(ここでは省略)。

symファイルからアセンブリファイルの作成

上記の実装プログラムがコンパイル、リンクされると、symファイルというものが生成されます。このファイルは、リンクによって生成されたシンボルがどのアドレスに配置されたかの情報が入っています。

sdos.sym
(一例)
--------
01:5000 _libputc
01:5010 _libputs

この情報をもとに、アセンブリファイル(.Sファイル)を作ります。

sdos.S
------
.area _SDOSLIB (ABS) .org 0x5000 _libputc:: .org 0x5010 _libputs::

アプリケーションの作成 先ほどのconio.hを利用したアプリケーションを作ります。

main.c
------ #include "conio.h" void main() { libputc("Hello World"); libputc('\n'); }

main.cとsdos.S(とcrt0.S)をコンパイル、アセンブルすると、関数libputc、libputsの実装は存在しなくてもリンクすることができます。

ここでのポイントは、sdos.Sでのエリア定義(_SDOSLIB)が絶対アドレス指定(ABS)になっていることです。これにより、main.cをリン クするときに定義されているアドレスが利用されます。 当たり前ですが、リンク対象のプログラムを変更するとアドレスが変わってしまい、アプリケーション側もsdos.Sの再アセンブルと再リンクが必要となる ので注意してください。

symファイルからアセンブリファイル作成の自動化

symファイルからアセンブリファイルを作るのはperlで簡単にできます。以下に実例を示します。

mklib.pl
--------
#!/usr/bin/perl
print ".area _CODE2 (ABS)\n";
while (<>) {
  if (/^\d\d:([0-9A-F]{4})\s(\w+)/) {
    if ($2 =~ /^s__/ || $2 eq "_main" || $2 eq "gsinit" || $2 eq "_datastart" || $2 eq "_dataend") {
    } else {
      print ".org 0x$1\n"; print "$2::\n";
    }
  }
}

上記を使い、

% perl mklib.pl sdos.sym > sdos.S

とすることにより、sdos.Sを生成することができます。なお、このperlスクリプトでは、リンクされるプログラムにあるシンボルのうち、以下を除外しています。

  • _main
  • gsinit
  • _datastart
  • _dataend
  • s__で始まるシンボル(各エリアのスタート位置を示す)

これらは、すべてのプログラムに存在する可能性があるため、sdos.Sに存在すると二重定義になってしまいます。また、アプリケーション作成時にリンクする意味もないでしょう。

前へ 第1回 第2回 第3回 第4回 第5回 次へ

こちらもよく読まれています