ELFヘッダとセクションテーブル
Linuxの実行ファイル (ELF形式) は簡単なものでは次のような構造になっています。普通はリンカ (ld) がオブジェクトファイルをもとに構成してくれますが、rvtlc では自分で設定する必要があります。ここでは rvtlc がELF形式の実行ファイルを作成する部分を解説します。
+---------------------------------+ | ELF ヘッダ | +---------------------------------+ | プログラムヘッダテーブル | +---------------------------------+ | .text セクション | | | +---------------------------------+ | .data セクション | | | +---------------------------------+ | .bss セクション (サイズ 0) | +---------------------------------+ | .shstrtabセクション (オプション)| +---------------------------------+ | セクションテーブル (オプション) | +---------------------------------+
rvtlcが出力するファイルは .bss セクションを固定アドレスに配置するために .data セクションはありません。
ELFセクションテーブルの設定
ELFのセクションデータとセクションテーブルを設定します。ELF実行ファイルでは使われないため、省略可能ですが、一応設定しています。
10770 :--------------------- 10780 : ELFの作成 10790 :--------------------- 10800 H['Z']=P : section size 10810 !=^DataSection 10820 !=^SectionStr 10830 !=^SectionHeader 10840 Obj[17]=H['Z']+H['P'] : p_filesz 10850 Obj[18]=H['Z']+H['P'] : p_memsz
.dataセクション
初期化済みデータをおきますが、rvtlc では .dataセクションは使っていません。サイズを 0 にしています。
28660 :------------------------------------------------- 28670 : .data 28680 :------------------------------------------------- 28690 ^DataSection 28700 :P=(P+$FF)/$100*$100 28710 H['M']=P 28720 :@ 28730 : Obj(P)=0 : initialize 28740 : P=P+1 28750 :@=(P=(H['M']+H['L'])) 28760 H['Q']=P 28770 ] 28780 :
.shstrtabセクション
セクション名を示す文字列を設定します。
28790 :------------------------------------------------- 28800 : セクション文字列テーブルの設定 28810 :------------------------------------------------- 28820 ^SectionStr 28830 +q 28840 H['S']=P 28850 q=Obj+P 28860 q(0)=0 q=q+1 28870 H['T']=q-Obj-P 28880 q*=".text" q=q+%+1 28890 H['D']=q-Obj-P 28900 q*=".data" q=q+%+1 28910 H['E']=q-Obj-P 28920 q*=".bss" q=q+%+1 28930 H['H']=q-Obj-P 28940 q*=".shstrtab" q=q+%+1 28950 P=q-Obj 28960 H['Y']=P-H['S'] : 28970 ;=D>2 / $*=Obj+H['S']+H['T'] / 28980 ;=D>2 $*=Obj+H['S']+H['D'] / 28990 ;=D>2 $*=Obj+H['S']+H['E'] / 29000 ;=D>2 $*=Obj+H['S']+H['H'] / 29010 -q 29020 ] 29030 :
セクションテーブル
.text、.data、.bss、.shstrtabの各セクションの情報を設定します。
29040 :------------------------------------------------- 29050 : セクションテーブルの設定 29060 :------------------------------------------------- 29070 ^SectionHeader 29080 Obj[08]=P : e_shoff 29090 Obj{23}=40 : e_shentsize 29100 Obj{24}=5 : e_shnum 29110 : NULL 29120 E=Obj+P 29130 E[0]=0 : sh_name 29140 E[1]=0 : sh_type 29150 E[2]=0 : sh_flags 29160 E[3]=0 : sh_addr 29170 E[4]=0 : sh_offset 29180 E[5]=0 : sh_size 29190 E[6]=0 : sh_link 29200 E[7]=0 : sh_info 29210 E[8]=0 : sh_addralign 29220 E[9]=0 : sh_entsize 29230 P=P+40 29240 : .text 29250 E=Obj+P 29260 E[0]=H['T'] : sh_name 29270 E[1]=1 : sh_type SHT_PROGBITS<1> 29280 E[2]=6 : sh_flags SHF_ALLOC<2> | SHF_EXECINSTR<4> 29290 E[3]=H['A'] : sh_addr 29300 E[4]=H['P'] : sh_offset 29310 E[5]=H['Z'] : sh_size 29320 E[6]=0 : sh_link 29330 E[7]=0 : sh_info 29340 E[8]=0 : sh_addralign 29350 E[9]=0 : sh_entsize 29360 P=P+40 29370 : .data 29380 E=Obj+P 29390 E[0]=H['D'] : sh_name 29400 E[1]=1 : sh_type SHT_PROGBITS<1> 29410 E[2]=3 : sh_flags SHF_ALLOC<2> | SHF_WRITE<1> 29420 E[3]=H['K'] : sh_addr $080A0000 29430 E[4]=H['M'] : sh_offset 29440 E[5]=H['L'] : sh_size 0 29450 E[6]=0 : sh_link 29460 E[7]=0 : sh_info 29470 E[8]=$1000 : sh_addralign 29480 E[9]=0 : sh_entsize 29490 P=P+40 29500 : .bss 29510 E=Obj+P 29520 E[0]=H['E'] : sh_name 29530 E[1]=8 : sh_type SHT_NOBITS<8> 29540 E[2]=3 : sh_flags SHF_ALLOC<2> | SHF_WRITE<1> 29550 E[3]=H['K']+H['L'] : sh_addr $080A0000 29560 E[4]=H['M']+H['L'] : sh_offset 29570 E[5]=H['U']+H['O'] : sh_size $4000+$40000 29580 E[6]=0 : sh_link 29590 E[7]=0 : sh_info 29600 E[8]=$1000 : sh_addralign 29610 E[9]=0 : sh_entsize 29620 P=P+40 29630 : .shstrtab 29640 E=Obj+P 29650 E[0]=H['H'] : sh_name 29660 E[1]=3 : sh_type SHT_STRTAB<3> 29670 E[2]=0 : sh_flags 29680 E[3]=0 : sh_addr 29690 E[4]=H['S'] : sh_offset 29700 E[5]=H['Y'] : sh_size 29710 E[6]=0 : sh_link 29720 E[7]=0 : sh_info 29730 E[8]=16 : sh_addralign 29740 E[9]=0 : sh_entsize 29750 P=P+40 29760 ] 29770 :
ELFヘッダ
ELF形式の実行ファイルの先頭部分にはELFヘッダと呼ぶデータが必要です。ELFの型(オブジェクト、実行ファイル)、CPUの種類、エントリーポイント、プログラムヘッダテーブルの位置、セクションヘッダテーブルの位置などの情報を設定します。実行ファイルのイメージ(配列Obj)の先頭部分にELFヘッダとELFプログラムヘッダテーブルを書き込んだ後、ランタイムライブラリのコード部分をコピーします。
29780 :------------------------------------------------- 29790 : Setup ELF Header and Runtime Library 29800 :------------------------------------------------- 29810 ^SetUpLib 29820 : Elf32_Header 29830 Obj[00]=$464c457f 29840 Obj[01]=$00010101 29850 Obj[02]=0 29860 Obj[03]=0 29870 Obj{08}=2 : e_type ET_EXEC<2> 29880 Obj{09}=3 : e_machine EM_386<3> 29890 Obj[05]=1 : e_version EV_CURRENT<1> 29900 Obj[06]=H['A'] : e_entry 29910 Obj[07]=13*4 : e_phoff 29920 Obj[08]=0 : e_shoff 29930 Obj[09]=0 : e_flags 29940 Obj{20}=52 : e_ehsize 29950 Obj{21}=32 : e_phentsize 29960 Obj{22}=2 : e_phnum 29970 Obj{23}=0 : e_shentsize 29980 Obj{24}=0 : e_shnum 29990 Obj{25}=4 : e_shstrndx
プログラムヘッダテーブル
プログラムヘッダテーブルは.text用と.bss用の2つを登録します。今回は初期化済みデータを格納する .data は使用せず、.bss用には初期化のためのデータは不要なため、ファイル中のデータサイズを指定する p_filesz は 0 でも問題ないはずですが、カーネル中で mmap が失敗するため Obj[25]=$100の部分で適当に256バイトを指定しています。
30000 : Elf32_ProgramHeader .text 30010 Obj[13]=1 : p_type PT_LOAD<1> 30020 Obj[14]=0 : p_offset 30030 Obj[15]=H['B'] : p_vaddr 30040 Obj[16]=H['B'] : p_paddr 30050 Obj[17]=100 : p_filesz 30060 Obj[18]=100 : p_memsz 30070 Obj[19]=5 : p_flags PF_X<1> + PF_R<4> 30080 Obj[20]=$100 : p_align 30090 : Elf32_ProgramHeader .data .bss 30100 Obj[21]=1 : p_type PT_LOAD<1> 30110 Obj[22]=0 : p_offset 30120 Obj[23]=H['K'] : p_vaddr 30130 Obj[24]=H['K'] : p_paddr 30140 Obj[25]=$100 : p_filesz 30150 Obj[26]=H['L']+H['U']+H['O'] : p_memsz 30160 Obj[27]=6 : p_flags PF_W<2> + PF_R<4> 30170 Obj[28]=$100 : p_align 30180 : _start jump main 30190 Obj[029]=$90909090 30200 Obj[030]=$90909090 30210 Obj[031]=$90909090
ランタイムライブラリのコピー
ランタイムライブラリを Obj 配列に書き込みます。ランタイムライブラリのバイナリファイル (rt.bin) は次の形式になっています。
+------------------------------------+ F[0] | ELFヘッダ | +------------------------------------+ | プログラムヘッダテーブル | +------------------------------------+ F[32] | プログラム本体へのジャンプ命令 | +------------------------------------+ F[34] | ライブラリのサイズ(dword単位) | +------------------------------------+ | ライブラリルーチン0の先頭アドレス | +------------------------------------+ | ライブラリルーチン1の先頭アドレス | +------------------------------------+ : : : +------------------------------------+ | ライブラリ本体 | : : +------------------------------------+
ランタイムライブラリのバイナリファイル (rt.bin) を読み込んでいる配列 F の必要な部分、F[32]からライブラリ本体の最終までを Obj 配列にコピーしています。
30220 Obj[032]=$0013EFE9 : ここ以降はrt.binに上書きされる 30230 Obj[033]=$90909000 30240 : ?=F[034] / : ライブラリサイズ(word) 30250 : Jump Table lib# 30260 : Library 30270 i=32 30280 @ 30290 Obj[i]=F[i] 30300 i=i+1 30310 @=(i>=F[34]) 30320 : 30330 P=F[34]*4 30340 ] 30350 :
[前] [目次] [次]