はりぼて OS で ELF な
アプリを起動してみた
@uchan_nos
2016/11/26 第4回自作OSもくもく会
はりぼてOSによるアプリ起動
• デモ
はりぼてOSによるアプリ起動
• コンソールにコマンドを打ち込むと起動する
• 裏では:
• カーネルが.hrbファイルをメモリに配置
• アプリ用のデータ領域確保やESP設定
• エントリポイントにジャンプ
hrb ファイルフォーマット(p.460)
off 意味
0x00 stack+.data+heap の大きさ
0x04 “Hari”
0x08 mmarea の大きさ
0x0C ESPの初期値(= .data の転送先)
0x10 .data のサイズ
0x14 .data の初期値のファイル内オフセット
0x18 0xE9000000
0x1C エントリアドレス-0x20
0x20 heap 領域開始アドレス
ヘッダ
.text
.data
Segm 1
Segm 2
ロード後のメモリ配置
stack
.data
.bss
heap
.text
.data
ヘッダ
.hrbファイル
そのまま
ESP初期値
はりぼてOSのプログラムローダ(ELF化前)
console.c
実行可能形式いろいろ
• COM
• 実行時のメモリイメージそのままの形式
• PE
• Windowsの標準
• a.out
• Unix最初期の形式。TEXT, DATA, BSSだけをもつ
• COFF
• オブジェクトファイル形式として有名
• ELF
• Executable and Linking Format
ELF : Executable and Linking Format
• 現在の Unix, Linux での標準
• オブジェクトファイル、実行可能ファイルどちらもOK
• ツールチェーンで良くサポートされている
• a.out や COFF に比べ柔軟。新しい言語にも対応できる
• →これは ELF に対応するしかないでしょ!
ELF ファイルフォーマット
• ELFヘッダ、SHT 、PHT 、セクション群からなる
• SHT:セクション・ヘッダ・テーブル
• PHT:プログラム・ヘッダ・テーブル
• セクション群:.text, .data, .bss, .shstrtab など
• 詳しくは
『リンカ・ローダ実践開発テクニック』坂井弘亮, 2010
ELFヘッダ
PHT
SHT
セクション
ELF32ヘッダフォーマット
off field 意味
0x00 e_ident 先頭4バイトは 0x7f, ‘E’, ‘L’, ‘F’
0x10 e_type ファイルタイプ ET_EXEC, ET_REL など
0x12 e_machine EM_386 など
0x14 e_version ファイルバージョン
0x18 e_entry エントリポイントのアドレス
0x1C e_phoff プログラムヘッダテーブルのファイル位置
0x20 e_shoff セクションヘッダテーブルのファイル位置
0x24 e_flags 未使用
0x28 e_ehsize ELF ヘッダサイズ
0x2A …
0x32 e_shstrndx セクション名格納用セクションの番号
ELFヘッダ
PHT
SHT
セクション
セクション・ヘッダ
• .text、.data、.bss などのセクションを管理するヘッダ
• コンパイラが出力したセクションをリンカがまとめる
• セクション名
• セクションの属性(書き込み、実行)
• セクションのロード先仮想アドレス
• セクションデータのファイル位置とサイズ
プログラム・ヘッダ
• ローダが利用するセグメントを記述する
• PHTは実行可能ファイルにしかない
• セグメントのタイプ
• セグメントのロード先仮想アドレス
• セグメントデータのファイル位置とサイズ
• セグメントのメモリ上のサイズ
• セグメント属性(読み書き実行)
ロードの仕様を考える
• はりぼてOSでは、スタッ
ク領域は.dataの前に置く
• メモリ上では .text, .stack
の先頭アドレスが両方と
も 0 になって欲しい
• .stack, .bss, .malloc
はファイル上は0バイト
.text
.stack
.malloc
欲しい
ELFファイル
EXEC
RW
.text
.data
.bss
ELFヘッダ
PHT
SHT
欲しい
メモリ配置
.stack
.data
0番地
0番地
.bss
.malloc
ELF用リンカ
スクリプト
ENTRY(_HariMain)
INCLUDE ld_variables.lds
SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) }
"file offset of data" = .;
. = 0;
.stack : AT("file offset of data") {
. = STACK;
}
.data : { *(.rodata*) *(.data) }
.bss : { *(.bss) }
.malloc : { . += MALLOC; }
}
EXECセグメントに
ロードされる部分
RWセグメントに
ロードされる部分
生成されるヘッダ構造
セクション タイプ ロード先 Offset Size
.text PROGBITS 00000094 000094 000188
.stack NOBITS 00000000 00021c 000400
.data PROGBITS 00000400 00021c 000088
.bss NOBITS 00000488 0002a4 000100
.malloc NOBITS 00000588 0002a4 00c000
セグメント Offset 仮想アドレス File Size Mem Size Flag
LOAD 000094 00000094 000188 000188 R E
LOAD 00021c 00000000 000000 000400 RW
LOAD 00021c 00000400 000088 00c188 RW
※これらは readelf -a hoge.elf で表示できるよ!
ローダの改造1
.elfファイルを探す console.c
ローダの改造2
ELFのマジックナンバーを確認する
…
ローダの改造3
espの初期値を計算する
calc_elf_esp
.stackセクションがあれば、そのサイズを返す
→.stackセクションが0番地から配置されることを暗に仮定している
ローダの改造4
.dataのコピーとアプリ起動
EXEC
0*8+4
RW
1*8+4
ELF
ファイル
全体
.data
.bss
.stack
p
q
appsiz
segsiz
.malloc
esp
calc_elf_datasize
copy_elf_data
ELFアプリ起動 デモ
リンカスクリプト豆知識
location counter
と
virtual memory address (VMA)
load memory address (LMA)
の関係
参考:https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html
Location counter is . (dot)
SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) }
"file offset of data" = .;
• VMA, LMA の現在値を保持するもの
• 値が加算されていくので「カウンタ」
• "file offset of data" はシンボル
Virtual memory address (VMA)
• VMAはそのセクションが配置されるメモリの仮想アドレス
• 上記の例では “.text” の VMA は SIZEOF_HEADERS
SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) }
"file offset of data" = .;
SIZEOF_HEADERS
ファイルのヘッダの
バイト数を返す
リンカの組み込み変数
Virtual memory address (VMA)
ヘッダ
.text
SIZEOF_HEADERS
(= ELFヘッダ+PHT) バイト
"file offset of data"
.data
SHT
Load memory address (LMA)
• VMA はファイル実行時のアドレス
• 対して、LMA はファイルが読み込まれるアドレス
• 今回、これを「ファイル内のオフセット」として使っている
• 上記の例では “.stack” の VMA は 0、LMA は “.text” の直後
. = 0;
.stack : AT("file offset of data") {
. = STACK;
}
. = 0;
.stack : AT("file offset of data") {
. = STACK;
}
.data : { *(.rodata*) *(.data) }
.bss : { *(.bss) }
Sect VMA LMA
.stack 0 “file offset of data”
.data STACK “file offset of data”
.bss STACK+sizeof(.data) “file offset of data”+sizeof(.data)
ATを指定しなければ、LMAに関して直前のATの効果が続く
参考文献など
• ELF化したはりぼてOSのソースコード
https://github.com/osdev-jp/elf_haribote
• 『リンカ・ローダ実践開発テクニック』坂井 弘亮, 2010
• ELFの仕様書
http://www.skyfree.org/linux/references/ELF_Format.pdf
• LDのドキュメント
https://sourceware.org/binutils/docs/ld/
• 3.1 Basic Linker Script Concepts
• 3.6.8.2 Output Section LMA
• はりぼてOSサポートページ内 “tools/obj2bim”
http://hrb.osask.jp/wiki/?tools/obj2bim

はりぼて OS で ELF なアプリを起動してみた