書籍の補足情報

書籍の内容について,出版後に気がついた点などをその都度追記していきます.

■ 誤記など

■ cross-gcc494-v1.0 でのAArch64のスタックポインタ設定の不備について (2018/02/08)

シミュレータ動作のためのサンプルプログラムで, AArch64のスタックポインタ設定に不備があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-aarch64-elf.S
cross2-gcc494/exec/lib-aarch64-elf.S
cross2-gcc494/printf/lib-aarch64-elf.S

上記3つのファイル中にスタートアップがあり,スタックポインタを初期化している 部分があります(以下).ここで _estack の値は .long で定義されており, 32ビット値になっています.しかしAArch64は64ビット・アーキテクチャで スタックポインタも64ビットのため,ここから値をロードしようとしたときに, 後続の4バイトも含めた64ビット値としてロードしてしまい,スタックポインタの 上位32ビット値が不定になってしまうようです.(スタックポインタがとんでもなく 大きな値となり,スタック操作している箇所で動作がおかしくなったりします)

        .globl  _start
        .type   _start, %function
_start:
        ldr     x0, _stack_addr
...
        .align 4
_stack_addr:
        .long   _estack
配布している cross-gcc494-v1.0 のコンパイル済みモジュール(aarch64-elf.x)では, 上記対象となる3つとも,たまたま後続の4バイトがオールゼロになっているため 実害は起きませんが,モジュールを再生成したりすると構成が変化して問題が起きる かもしれません.

正しくは,以下のようにして .quad を使って8バイト値として定義するようにします. (アラインメントも8バイトにします)

        .align 8
_stack_addr:
        .quad   _estack

■ cross-gcc494-v1.0 でのMSP430のgccビルドエラーの不備について (2018/11/29)

gcc-4.9.4のビルドで,MSP430に不備があることが判明しました.

環境によって,ビルド時に以下のエラーが発生します.

../../../../toolchain/gcc-4.9.4/gcc/config/msp430/msp430.c:1632:24: error: unable to find string literal operator 'operator""N' with 'const char [10]', 'unsigned int' arguments
 #define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }

上記箇所の #define の定義で,文字列の連結のために文字列リテラルと変数Nが 密着している点がまずいようです.

以下の修正をすることで,ビルド時のエラーを回避できます.

--- gcc/config/msp430/msp430.c.orig	2014-05-21 01:49:40.000000000 +0900
+++ gcc/config/msp430/msp430.c	2018-11-29 00:07:02.843725000 +0900
@@ -1629,7 +1629,11 @@
 }
   const_shift_helpers[] =
 {
+#if 0
 #define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }
+#else
+#define CSH(N,C,X,G) { "__mspabi_" N, C, X, gen_##G }
+#endif
 
   CSH ("slli", 1, 1, slli_1),
   CSH ("slll", 1, 1, slll_1),

■ cross-gcc494-v1.0 でのMSP430のスタックポインタ設定の不備について (2018/12/24)

シミュレータ動作のためのサンプルプログラムで, MSP430のスタックポインタ設定に不備があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-msp430-elf.S
cross2-gcc494/exec/lib-msp430-elf.S
cross2-gcc494/printf/lib-msp430-elf.S

実行開始時にスタックポインタ設定が初期化されておらずゼロとなってしまうため, その後のスタックフレームの獲得によるスタックポインタの減算でゼロで折り返され 0xFFF.. のような値になり,その後にスタックフレームより後のアドレスに アクセスできません.(アドレスの折り返しが起きるため)

以下の修正をすることで,正常に設定されます.

@@ -16,7 +16,7 @@
        .globl  _start
        .type   _start, @function
 _start:
-       mov     _estack, r1
+       mova    #_estack, r1
        calla   #main

■ cross-gcc494-v1.0 でのPowerPCのgdbビルドエラーの不備について (2020/05/26)

gdb-7.12.1のビルドで,PowerPCに不備があることが判明しました.

環境によって,ビルド時にエラーが発生します.

error()が未定義の場合があり,リンクエラーとなるようです.

以下の修正をすることで,ビルド時のエラーを回避できます.

--- sim/ppc/gen-idecode.c.orig	2016-08-02 00:50:21.000000000 +0900
+++ sim/ppc/gen-idecode.c	2018-12-02 20:51:40.370107000 +0900
@@ -1521,6 +1521,19 @@
   lf_printf(file, "\n");
   lf_printf(file, "\n");
 
+#if 1
+  lf_printf(file, "__attribute__((weak)) void error (const char *msg, ...)\n");
+  lf_printf(file, "{\n");
+  lf_printf(file, "  va_list ap;\n");
+  lf_printf(file, "  va_start(ap, msg);\n");
+  lf_printf(file, "  vprintf(msg, ap);\n");
+  lf_printf(file, "  printf(\"\\n\");\n");
+  lf_printf(file, "  va_end(ap);\n");
+  lf_printf(file, "  exit (1);\n");
+  lf_printf(file, "}\n");
+  lf_printf(file, "\n");
+#endif
+
   if ((code & generate_calls)) {
 
     print_idecode_lookups(file, table, cache_rules);

■ cross-gcc494-v1.0 でのARM/Thumbのread/writeの戻り値の不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,ARM/Thumbのread/writeシステムコールの 戻り値処理に問題があることが判明しました.

対象となるのは,以下の6つのファイルです.

cross-gcc494/exec/lib-arm-elf.S
cross2-gcc494/exec/lib-arm-elf.S
cross2-gcc494/printf/lib-arm-elf.S
cross-gcc494/exec/lib-arm16-elf.S
cross2-gcc494/exec/lib-arm16-elf.S
cross2-gcc494/printf/lib-arm16-elf.S

GDBシミュレータのread/writeシステムコールの処理で,戻り値が反転されており, 通常は読み込み/書き込みサイズが返るところで,残りサイズが返されています.

システムコール・ラッパーに以下の反転処理を追加することで, 戻り値として読み込み/書き込みサイズ期待を得ることができます.

(lib-arm-elf.S)

        SWI(SWI_XXXX)
+       cmp     r0, #0
+       subge   r0, r2, r0
        mov     pc, lr

(lib-arm16-elf.S)

        SWI(SWI_XXXX)
-       bx      lr
+       cmp     r0, #0
+       blt     1f
+       subs    r0, r2, r0
+1:     bx      lr

■ cross-gcc494-v1.0 でのM32Cのシステムコール呼び出し処理の不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,M32Cのシステムコール処理に問題がある ことが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-m32c-elf.S
cross2-gcc494/exec/lib-m32c-elf.S
cross2-gcc494/printf/lib-m32c-elf.S

GDBシミュレータのシステムコール処理に合わせて,システムコール呼び出しで0x400 というアドレスに書き込みしていますが,ワードアクセスのために後続の0x401にも 書き込みを行ってしまい,さらに0x401への書き込みは1文字出力として扱われるため, 不正な文字が出力されていました.

システムコール・ラッパーを以下のように修正することで,バイトアクセスとなり 改善されます.

-       mov.w:g r0, SYSCALL_ADDR
+       mov.b:g r0l, SYSCALL_ADDR

■ cross-gcc494-v1.0 でのMN10300のシステムコールの戻り値の不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,MN10300のシステムコール呼び出し処理の 戻り値の扱いに問題があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-mn10300-elf.S
cross2-gcc494/exec/lib-mn10300-elf.S
cross2-gcc494/printf/lib-mn10300-elf.S

GDBシミュレータでは戻り値はd1レジスタ,エラーコードはd0レジスタで返されますが, 関数の返り値はd0レジスタで返されるため,システムコールの戻り値として エラーコードが返っていました.

以下のようにしてd1→d0へのコピーを追加することで,戻り値が返るようになります.

        syscall
+       mov     d1, d0
        rets

■ cross-gcc494-v1.0 でのMoxieのレジスタコピーの不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,Moxieのシステムコール処理に問題がある ことが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-moxie-elf.S
cross2-gcc494/exec/lib-moxie-elf.S
cross2-gcc494/printf/lib-moxie-elf.S

GDBシミュレータのシステムコール処理で引数を受け取るレジスタが,関数呼び出しで 引数を渡すレジスタとは異なると判断してレジスタコピーを行っていましたが, GDBシミュレータのシステムコール処理の読み違いで,レジスタコピーは不要で, システムコールの引数が正常に渡されていませんでした.

以下のようにしてレジスタコピーを廃止することで,システムコールの引数が 期待通りに渡されるようになります.

-       mov     $r4, $r2
-       mov     $r3, $r1
-       mov     $r2, $r0
        swi     SYS_xxxx
-       mov     $r0, $r2
        ret

■ cross-gcc494-v1.0 でのMoxieのopenシステムコール処理のバグ対応について (2020/05/26)

シミュレータ動作のサンプルプログラムで,Moxieのopenシステムコールの処理に 問題があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-moxie-elf.S
cross2-gcc494/exec/lib-moxie-elf.S
cross2-gcc494/printf/lib-moxie-elf.S

GDB付属のMoxieシミュレータのopenシステムコールの(おそらく)バグで,ファイル名の コピーとopen()の呼び出しが逆転していて,ファイル名が設定されずにopen()が呼び 出されることで,open()が不定のファイル名で実行されてエラーとなっていました.

苦肉の策として,以下のようにしてopenシステムコールを2回呼び出すことで, 1回目の呼び出しでファイル名が設定され,2回目の呼び出しではスタック上にある ファイル名がそのまま残っているため,open()が期待通りに行われるようになります.

        .globl  __open
        .type   __open, @function
__open:
        mov     $r3, $r0
        swi     SYS_open
        mov     $r0, $r3
        swi     SYS_open
        ret

■ cross-gcc494-v1.0 でのRXのopenシステムコールの引数の不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,RXのopenシステムコール処理に問題があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-rx-elf.S
cross2-gcc494/exec/lib-rx-elf.S
cross2-gcc494/printf/lib-rx-elf.S

GDB付属のRXシミュレータのopenシステムコール処理で,openシステムコールは引数を スタック経由で渡されていたため,引数が正常に受け取れていませんでした.

以下のようにしてopenシステムコールの呼び出し時にスタックに引数を積むことで,open()の引数が期待通りに渡されるようになります.

        .globl  ___open
        .type   ___open, @function
___open:
        sub     #16, r0
        mov.l   r2, 4[r0]
        mov.l   r3, 8[r0]
        mov     #SYS_open, r5
        int     #255
        add     #16, r0
        rts

■ cross-gcc494-v1.0 でのCR16のスタックポインタの設定の不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,CR16のスタックポインタの設定処理に 問題があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/exec/lib-cr16-elf.S
cross2-gcc494/exec/lib-cr16-elf.S
cross2-gcc494/printf/lib-cr16-elf.S

スタックポインタの設定を16ビットとして行っているため,実行コードのサイズが 拡大してスタックのアドレスが16ビット範囲(64KB)を越えたときにオーバーフロー してしまい,リンク時にアドレス補填できずリンクエラーとなっていました.

以下のようにしてスタックポインタの設定を32ビットで行うことで回避できます.

        .globl  _start
        .type   _start, @function
 _start:
-       movw    $_estack:l, sp
+       movd    $_estack:l, (sp)
        bal     (ra),_main

■ cross-gcc494-v1.0 でのSPARCのスライディング・ウィンドウのオーバーフローの不備について (2020/05/26)

シミュレータ動作のサンプルプログラムで,SPARCの関数呼び出しに問題があることが 判明しました.

対象となるのは,以下の1つのファイルです.

cross2-gcc494/printf/Makefile

レジスタウィンドウの利用のために,関数呼び出し時にsave/restore命令が利用されて いますが,libcのライブラリを利用すると関数呼び出しが深くなり, レジスタウィンドウの上限を越えてループしてしまうことで戻り先アドレスが破壊 され,関数呼び出しの呼び元まで戻った際に不正なアドレスにジャンプしていました. (gdb-7.12.1/sim/erc32のPSR_CWPを利用している部分を参照)

Makefileに以下を追加してコンパイル時に -mflat オプションを付加することで, save/restore命令を利用せずにスタック上にレジスタを退避する実行コードが生成 され,回避できます.

CFLAGS-sparc-elf += -mflat

■ cross-gcc494-v1.0 でのAArch64のアセンブリ出力が環境によって異なる問題について (2020/06/08)

Aarch64で,環境によってアセンブリ出力が異なる問題があることが判明しました.

対象となるのは,以下の3つのファイルです.

cross-gcc494/sample/Makefile
cross-gcc494/exec/Makefile
cross2-gcc494/sample/Makefile
cross2-gcc494/exec/Makefile
cross2-gcc494/printf/Makefile

gccのビルド環境によって,sample/sample.c:get_static_value_addr()等で アドレス設定にadrp/add命令が使われることがあります (v1.0版に付属するアセンブリ出力では,ldr命令により直後のメモリから ロードしています)

AArch64のコンパイルオプションに,以下のようにして -mcmodel=large を設定する ことでv1.0版に付属する出力相当のコードが生成されます (gcc-4.9.4/gcc/config/aarch64/aarch64-protos.h の SYMBOL_SMALL_ABSOLUTE に 関するコメントと,gcc-4.9.4/gcc/config/aarch64/aarch64.c の SYMBOL_SMALL_ABSOLUTE に関する処理を参照. なお -mcmodel=small で,adrp/add命令を利用するアセンブリが出力されます)

なお未確認ですが,手元で試したところだと, ビルド環境のgccのバージョンがgcc-4.8.x以前とgcc-4.9.x以降で, アセンブリの出力が異なるようです. (gcc-4.8.x以前だと -mcmodel=large 相当, gcc-4.9.x以降だと -mcmodel=small 相当になるようです)

CFLAGS-aarch64-elf += -mcmodel=large

メールは kozos(アットマーク)kozos.jp まで