30
はははは OS は ELF は はははははははははは @uchan_nos 2016/11/26 は 4 ははは OS ははははは

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

Embed Size (px)

Citation preview

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

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

2016/11/26 第 4 回自作 OS もくもく会

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

はりぼて OS によるアプリ起動• デモ

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

はりぼて OS によるアプリ起動• コンソールにコマンドを打ち込むと起動する• 裏では:• カーネルが .hrb ファイルをメモリに配置• アプリ用のデータ領域確保や ESP 設定• エントリポイントにジャンプ

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

hrb ファイルフォーマット( p.460 )off 意味0x00 stack+.data+heap の大きさ0x04 “Hari”0x08 mmarea の大きさ0x0C ESP の初期値( = .data の転送先)0x10 .data のサイズ0x14 .data の初期値のファイル内オフセット0x18 0xE90000000x1C エントリアドレス -0x200x20 heap 領域開始アドレス

ヘッダ.text

.data

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

Segm 1Segm 2

ロード後のメモリ配置stack

.data.bss

heap

.text

.data

ヘッダ.hrb ファイルそのまま

ESP 初期値

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

はりぼて OS のプログラムローダ( ELF 化前)console.c

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

実行可能形式いろいろ• COM• 実行時のメモリイメージそのままの形式

• PE• Windows の標準

• a.out• Unix 最初期の形式。 TEXT, DATA, BSS だけをもつ

• COFF• オブジェクトファイル形式として有名

• ELF• Executable and Linking Format

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

ELF : Executable and Linking Format• 現在の Unix, Linux での標準• オブジェクトファイル、実行可能ファイルどちらも OK• ツールチェーンで良くサポートされている• a.out や COFF に比べ柔軟。新しい言語にも対応できる• → これは ELF に対応するしかないでしょ!

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

ELF ファイルフォーマット• ELF ヘッダ、 SHT 、 PHT 、セクション群からなる• SHT :セクション・ヘッダ・テーブル• PHT :プログラム・ヘッダ・テーブル• セクション群: .text, .data, .bss, .shstrtab など• 詳しくは『リンカ・ローダ実践開発テクニック』坂井弘亮 , 2010

ELF ヘッダPHT

SHT

セクション

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

ELF32 ヘッダフォーマットoff field 意味0x00 e_ident 先頭 4 バイトは 0x7f, ‘E’, ‘L’, ‘F’0x10 e_type ファイルタイプ ET_EXEC, ET_REL など0x12 e_machin

eEM_386 など

0x14 e_version ファイルバージョン0x18 e_entry エントリポイントのアドレス0x1C e_phoff プログラムヘッダテーブルのファイル位置0x20 e_shoff セクションヘッダテーブルのファイル位置0x24 e_flags 未使用0x28 e_ehsize ELF ヘッダサイズ0x2A …0x32 e_shstrnd

xセクション名格納用セクションの番号

ELF ヘッダPHT

SHT

セクション

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

セクション・ヘッダ• .text 、 .data 、 .bss などのセクションを管理するヘッダ• コンパイラが出力したセクションをリンカがまとめる• セクション名• セクションの属性(書き込み、実行)• セクションのロード先仮想アドレス• セクションデータのファイル位置とサイズ

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

プログラム・ヘッダ• ローダが利用するセグメントを記述する• PHT は実行可能ファイルにしかない• セグメントのタイプ• セグメントのロード先仮想アドレス• セグメントデータのファイル位置とサイズ• セグメントのメモリ上のサイズ• セグメント属性(読み書き実行)

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

ロードの仕様を考える• はりぼて 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

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

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 セグメントにロードされる部分

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

生成されるヘッダ構造セクション タイプ ロード先 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 ELOAD 00021c 00000000 000000 000400 RWLOAD 00021c 00000400 000088 00c188 RW※ これらは readelf -a hoge.elf で表示できるよ!

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

ローダの改造 1.elf ファイルを探す console.c

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

ローダの改造 2ELF のマジックナンバーを確認する

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

ローダの改造 3esp の初期値を計算する

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

calc_elf_esp

.stack セクションがあれば、そのサイズを返す→.stack セクションが 0 番地から配置されることを暗に仮定している

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

ローダの改造 4.data のコピーとアプリ起動

EXEC0*8+4

RW1*8+

4

ELFファイル全体

.data.bss

.stack

p

q

appsiz

segsiz

.malloc

esp

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

calc_elf_datasize

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

copy_elf_data

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

ELF アプリ起動 デモ

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

リンカスクリプト豆知識location counterとvirtual memory address (VMA)load memory address (LMA)の関係

参考: https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html

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

Location counter is . (dot)SECTIONS{ . = SIZEOF_HEADERS; .text : { *(.text) } "file offset of data" = .;

• VMA, LMA の現在値を保持するもの• 値が加算されていくので「カウンタ」• "file offset of data" はシンボル

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

Virtual memory address (VMA)

• VMA はそのセクションが配置されるメモリの仮想アドレス• 上記の例では “ .text” の VMA は SIZEOF_HEADERS

SECTIONS{ . = SIZEOF_HEADERS; .text : { *(.text) } "file offset of data" = .;

SIZEOF_HEADERSファイルのヘッダのバイト数を返すリンカの組み込み変数

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

Virtual memory address (VMA)

ヘッダ.text

SIZEOF_HEADERS(= ELF ヘッダ +PHT) バイト

"file offset of data" .dataSHT

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

Load memory address (LMA)

• VMA はファイル実行時のアドレス• 対して、 LMA はファイルが読み込まれるアドレス• 今回、これを「ファイル内のオフセット」として使っている

• 上記の例では “ .stack” の VMA は 0 、 LMA は “ .text” の直後

. = 0;

.stack : AT("file offset of data") { . = STACK;}

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

. = 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 の効果が続く

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

参考文献など• 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