CPU実験室

誰も見向きもしない古いCPUをいじって動かしてみようというプロジェクトです

GCCプログラミング(2)

動作しない原因をビルド時の中間ファイルを見ながら調査しました

1.まずはTEST.Cのコンパイル結果です。
 単に文字列のアドレスをスタックに積んで文字列出力関数putstr()に渡すだけです
	.file	"test.c"
gcc2_compiled.:
___gnu_compiled_c:
.text
LC0:
	.ascii "Hello, C world.\12\15\0"
	.p2align 2
.globl _main
_main:
	pushl %ebp
	movl %esp,%ebp
	.align 2,0x90
L4:
	pushl $LC0
	call _putstr
	addl $4,%esp
	jmp L4
	.align 2,0x90

2.次にリンク時のメモリマップです。
 指定どおりコードが0x2000、データが0x10000から割り付けられています
 またmain関数のロケーションは0x201cであることがわかります

Linker script and memory map

Address of section .text set to 0x2000
Address of section .bss set to 0x10000
LOAD start.o
LOAD test.o
LOAD 386lib.o
LOAD c:\usr\asm\djgpp\lib/libc.a

.text           0x00002000      0x800
 *(.text)
 .text          0x00002000        0x8 start.o
                0x00002000                start
 .text          0x00002008       0x28 test.o
                0x0000201c                main
 .text          0x00002030      0x5f4 386lib.o
                0x00002230                _matherr
                0x00002518                lcdini
                0x00002130                cnv_tbl_in
                0x00002498                getstr
                0x0000253c                lcdctr
                0x000024d0                lcdcset
                0x00002564                lcdstr
                0x000023b0                sioled
                0x00002474                putstr
                0x000023f8                wait
         :
         :

3.次に出来上がったバイナリを仮にDOS上に展開してsymdebで逆アセンブルしたものです

-u2000
_start:
0000:2000 E81700         CALL	201A 
0000:2003 0000           ADD	[BX+SI],AL 
0000:2005 F4             HLT	 
_end:

_main:
0000:201C 55             PUSH	BP 
0000:201D 89E5           MOV	BP,SP 
0000:201F 90             NOP	 
L4:
0000:2020 680820         PUSH	2008 
0000:2023 0000           ADD	[BX+SI],AL 
0000:2025 E84A04         CALL	2472 
0000:2028 0000           ADD	[BX+SI],AL 
0000:202A 83C404         ADD	SP,+04 
0000:202D EBF1           JMP	2020 
0000:202F 90             NOP	 

この逆アセンブルリストをじーっと見ているとおかしい点に気づきました

①コール先アドレスが違う
  main関数は0x201c番地、putstr関数0x2474番地にリロケートされているのに
  それぞれ呼んでいるほうは CALL 201A, CALL 2472 と2番地手前

②CALL命令の後に「00」が2バイト挿入されている
  結果的にこれが「ADD [BX+SI],AL」という意味不明なコードが挿入されたことになっている

アセンブルソースは32ビットレジスタを使用しているのに出来上がったバイナリは
 16ビットレジスタを使用している

大体からして、コール先アドレスがずれている以上暴走するのは当然です
何故なんでしょう・・