gcc の 32kB の壁

※ 注意: このページの情報は、 Palmprc-tools-2.0 を出したことで obsolete になりました。 一応、昔を偲ぶ資料として残しておきますが...

Contents:

1. 問題

Palm OS 用の gcc (prc-tools 0.5.0) では、32kB を越える code リソース
(以下、単に code と書きます。) の生成に問題があります。

具体的には、

a. prc-tools 0.5.0 のリンカでは、code のサイズを 32kB に制限して
   いた。(ld: region coderes is full などと怒られます。)

b. ふつーに gcc で Palm OS アプリケーションをリンクすると、code の
   先頭に crt0.o が来るが、こいつはいくつかの hook を参照していて、
   それが code の最後に来てしまう。このため、c. の制約に引っかかる。
   (crt0.c:141: relocation truncated to fit: DISP16 bhook_start
    のようなエラーがいくつか出ます。)

c. 関数呼び出しに 16bit pc 相対アドレッシングが使われているので、
   32kB 以上離れたところにある関数を呼び出すことができない。
   (relocation truncated to fit: DISP16 foo などと怒られます。)

d. Palm OS 2.0 までは、storage heap が 64kB ごとのセグメントに分割
   されていたので、64kB 以上のリソースは格納できなかった。また、
   メモリ管理が貧弱で heap の分断化が起こりやすく、code が大きく
   なるにつれて HotSync に失敗する確率が高まるという報告があった。
   (この制限は、Palm OS 3.0 では解消されています。)

e. global 変数のアクセスには、16bit a5 レジスタ相対アドレッシング
   が使われるため、global 変数の合計サイズにも 32kB の制約がある。
   (ここでいう global 変数には、static 変数なども含みます。)

てなとこです。

2. 対処法

a. リンカの制限

# 詳しくは、
#     http://www.geocities.com/SiliconValley/Lab/9981/gcctech.htm
# をどーぞ。

Windoze 用の gcc 0.5.0 バイナリパッケージなど、prc-tools 0.5.0 を
そのままコンパイルしたものの場合、pilot.ld というファイルの先頭に

    MEMORY 
            {
            coderes   : ORIGIN = 0x10000, LENGTH = 32767
            datares   : ORIGIN = 0x0, LENGTH = 32767
            }

と書かれています。この coderes の行を

            coderes   : ORIGIN = 0x10000, LENGTH = 65535
                                                   ~~~~~
などと書き換えれば code のサイズを大きくできます。なお、Windoze の
場合、このファイルは (インストール時の指定にもよりますが)

    c:\Program Files\tshg\GNU PalmPilot Developer Tools\lib\gcc-lib\m68k-palmos-coff\2.7.2.2-kgpd-071097\pilot.ld

あたりにある筈です。(うにっくすな人は自分で探してね。;-p)

# よくは知らないけど、修正済みのパッケージも存在するのかも...

b. crt0.o

# これも、詳しくは、
#     http://www.geocities.com/SiliconValley/Lab/9981/gcctech.htm
# をどーぞ。

簡単に手順を説明すると、

・myStart.c というファイルに、次のように書きます。

    extern unsigned long start();
    unsigned long myStart()
    {
        return start();
    }

  または、myStart.S というファイルに、次のように書きます。

            .text
            .even

            .globl  entry
    myStart:
            bra.w   start

・myStart.c (または myStart.S) をコンパイルします。

    m68k-palmos-coff-gcc -c myStart.c (または myStart.S)

・リンク時には、通常、

    m68k-palmos-coff-gcc $(OBJS) $(LIBS) -o $(PROGRAM)

  とするところを、$(OBJS) を $(OBJS1) と $(OBJS2) に分割し、
  (この際、ソースが 1 ファイルだと破綻します。;-p)

    m68k-palmos-coff-gcc -nostartfiles myStart.o $(OBJS1) $(CRT0) $(OBJS2) $(LIBS) -o $(PROGRAM)

  のようにします。なお、$(CRT0) は crt0.o のフルパス名です。

てな感じです。もちろん、ふつーはちゃんと Makefile を書くんですよ!

c. 遠くの関数の呼び出し

こいつの回避策は、
・関数の並び順や *.o のリンク順を変える。
・中継関数 (jump island ともいう...) を用意する。
・global または static 変数なポインタ経由で呼び出す。
などがあります。

前の二つは、試行錯誤が必要になりますし、ソースを変更するたびに
あちこちでエラーが発生する可能性があるので、美しくないですね。

で、ポインタ経由の呼び出しですが、単に、

    void someFunc()
    {
        foo();
    }

を、

    void someFunc()
    {
        void (*pFoo)();

        pFoo = foo;
        (*pFoo)();
    }

としても意味はありません。

pFoo を global または static な変数として、定義と同時に初期化を
行なう必要があります。つまり、

    void (*pFoo)() = foo;

    void someFunc()
    {
        (*pFoo)();
    }

または、

    void someFunc()
    {
        static void (*pFoo)() = foo;

        (*pFoo)();
    }

などとする必要があります。

foo() の呼び出しをひとつひとつ (*pFoo)(...) に直すのが面倒ならば、
pFoo の定義の直後に #define foo (*pFoo) とするのも良いでしょうが、
foo() の定義の前には #undef foo するのを忘れずに。

pFoo の初期化を忘れると fatal error になりますのでご注意ください。
また、どういうわけか foo() が存在しなくてもリンカではエラーにならず、
m68k-palmos-coff-obj-res が Abort しますが、どの関数が見つからない
のかは分からないので、困ったものです。

なお、ソースを一つのファイルにまとめる必要はまったくありません。
ソースを分割すると数バイト大きくなるような気がしないでもありません
が、メリットの方が断然大きいと思います。

d. リソースサイズ

省略。

e. global 変数のサイズ

global 変数は dynamic heap に取られますが、Palm OS の dynamic heap
は貴重な資源なので、そもそも使い過ぎてはいけません。

const なデータはリソースに追い出し、const でないデータは DB を利用し、
大きな配列などは MemPtrNew()/MemHandleNew() で動的に取得するように
しましょう。

3. 他のコンパイラへの乗り換え

CW for Palm OS の場合、e 以外の問題は multi-segment にすることで
回避できます。

gcc でも multi-segment を可能にしようという試みはあります。が、
・Windoze 用のバイナリパッケージは (たぶん) 用意されていない。
・バグが残っている可能性がある。
  (以前、これで App/DA Launcher をコンパイルした時には原因不明の
   fatal error に悩まされた。Hack だからかな?)
・最近、update されたって話しは聞かないけど、どうなってるんだろ?
ので、腕に憶えのある方はどーぞ。
(バグを取ってあげたらさぞ喜ばれることでしょう。;-p)

url は、
    http://homepages.enterprise.net/jmarshall/palmos/
    http://homepages.enterprise.net/jmarshall/palmos/build-prct.html
です。また、
    http://idefix.rp-online.de/pilot/devel.html
    http://idefix.rp-online.de/pilot/m68k-palmos-tools.tar.bz2
に Linux 用のバイナリがあるようです。

※ 注意: 最近、 Palm から prc-tools-2.0 ってのが出てますので、そちらをどーぞ。


Hoshi Takanori, Last update: $Date: 1999/07/06 08:07:03 $