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 :
[前] [目次] [次]