---
title: はりぼて OS で ELF なアプリを起動してみた
tags:  #elf #ld #loader #linker #はりぼてos #osdev_moku2  
author: [内田公太](https://convert.docswell.com/user/uchan_nos)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/G7W3ZG6M72.jpg?width=480
description: はりぼて OS を改造して ELF バイナリを起動します。 ELF の内部構造や、好きな ELF 構造を生成するためのリンカスクリプトの書き方を説明し、はりぼて OS のどこを改造すればよいか示します。
published: November 26, 16
canonical: https://convert.docswell.com/s/uchan_nos/Z6YE1E-run-elf-app-on-haribote-os
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/G7W3ZG6M72.jpg)

はりぼて OS で ELF な
アプリを起動してみた
@uchan_nos
2016/11/26 第4回自作OSもくもく会


# Page. 2

![Page Image](https://bcdn.docswell.com/page/4JZV1LYM73.jpg)

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


# Page. 3

![Page Image](https://bcdn.docswell.com/page/YE65LWD5JV.jpg)

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


# Page. 4

![Page Image](https://bcdn.docswell.com/page/GE5Y1M3GE4.jpg)

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


# Page. 5

![Page Image](https://bcdn.docswell.com/page/972G19ZD7R.jpg)

ロード後のメモリ配置
stack
ヘッダ
.text
.hrbファイル
そのまま
.data
.bss
.data
Segm 1
heap
Segm 2
ESP初期値


# Page. 6

![Page Image](https://bcdn.docswell.com/page/DJYVZ4RMJM.jpg)

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


# Page. 7

![Page Image](https://bcdn.docswell.com/page/V7NM3YD3E8.jpg)

実行可能形式いろいろ
• COM
• 実行時のメモリイメージそのままの形式
• PE
• Windowsの標準
• a.out
• Unix最初期の形式。TEXT, DATA, BSSだけをもつ
• COFF
• オブジェクトファイル形式として有名
• ELF
• Executable and Linking Format


# Page. 8

![Page Image](https://bcdn.docswell.com/page/YJ9N9PGPJ3.jpg)

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


# Page. 9

![Page Image](https://bcdn.docswell.com/page/GJ8K9DVXED.jpg)

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


# Page. 10

![Page Image](https://bcdn.docswell.com/page/LJLZWM5N7R.jpg)

ELF32ヘッダフォーマット
ELFヘッダ
PHT
セクション
SHT
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 セクション名格納用セクションの番号


# Page. 11

![Page Image](https://bcdn.docswell.com/page/47MV9Y3Q7W.jpg)

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


# Page. 12

![Page Image](https://bcdn.docswell.com/page/P7R2G9QKJ9.jpg)

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


# Page. 13

![Page Image](https://bcdn.docswell.com/page/PJXDXQ55EX.jpg)

ロードの仕様を考える
• はりぼてOSでは、スタッ
ク領域は.dataの前に置く
• メモリ上では .text, .stack
の先頭アドレスが両方と
も 0 になって欲しい
• .stack, .bss, .malloc
はファイル上は0バイト
欲しい
ELFファイル
ELFヘッダ
PHT
.text
.stack
.data
.bss
.malloc
SHT
欲しい
メモリ配置
0番地
EXEC
.text
RW
.stack
.data
.bss
.malloc
0番地


# Page. 14

![Page Image](https://bcdn.docswell.com/page/3JKXW96RED.jpg)

ELF用リンカ
スクリプト
EXECセグメントに
ロードされる部分
ENTRY(_HariMain)
INCLUDE ld_variables.lds
SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) }
&quot;file offset of data&quot; = .;
. = 0;
.stack : AT(&quot;file offset of data&quot;) {
. = STACK;
}
.data : { *(.rodata*) *(.data) }
.bss : { *(.bss) }
.malloc : { . += MALLOC; }
RWセグメントに
ロードされる部分
}


# Page. 15

![Page Image](https://bcdn.docswell.com/page/LE351W6GJ5.jpg)

生成されるヘッダ構造
セクション
.text
.stack
.data
タイプ
PROGBITS
NOBITS
PROGBITS
ロード先
00000094
00000000
00000400
Offset
000094
00021c
00021c
Size
000188
000400
000088
.bss
.malloc
NOBITS
NOBITS
00000488
00000588
0002a4
0002a4
000100
00c000
セグメント
LOAD
LOAD
LOAD
Offset
000094
00021c
00021c
仮想アドレス
00000094
00000000
00000400
File Size
000188
000000
000088
※これらは readelf -a hoge.elf で表示できるよ！
Mem Size
000188
000400
00c188
Flag
R E
RW
RW


# Page. 16

![Page Image](https://bcdn.docswell.com/page/8EDDXKVNEG.jpg)

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


# Page. 17

![Page Image](https://bcdn.docswell.com/page/V7PXPKVNE8.jpg)

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


# Page. 18

![Page Image](https://bcdn.docswell.com/page/2JVL2VZY7Q.jpg)

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


# Page. 19

![Page Image](https://bcdn.docswell.com/page/5EGXRL4WJL.jpg)

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


# Page. 20

![Page Image](https://bcdn.docswell.com/page/4JQ8VYGQ7P.jpg)

ローダの改造4
.dataのコピーとアプリ起動
p
appsiz
ELF
EXEC ファイル
0*8+4
全体
q
esp
segsiz
RW
1*8+4
.stack
.data
.bss
.malloc


# Page. 21

![Page Image](https://bcdn.docswell.com/page/K742MW5YJ1.jpg)

calc_elf_datasize


# Page. 22

![Page Image](https://bcdn.docswell.com/page/LJ1M8YWNEG.jpg)

copy_elf_data


# Page. 23

![Page Image](https://bcdn.docswell.com/page/GJW3ZGRMJ2.jpg)

ELFアプリ起動 デモ


# Page. 24

![Page Image](https://bcdn.docswell.com/page/4EZV1LRMJ3.jpg)

リンカスクリプト豆知識
location counter
と
virtual memory address (VMA)
load memory address (LMA)
の関係
参考：https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html


# Page. 25

![Page Image](https://bcdn.docswell.com/page/Y765LWR5EV.jpg)

Location counter is . (dot)
SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) }
&quot;file offset of data&quot; = .;
• VMA, LMA の現在値を保持するもの
• 値が加算されていくので「カウンタ」
• &quot;file offset of data&quot; はシンボル


# Page. 26

![Page Image](https://bcdn.docswell.com/page/G75Y1M8G74.jpg)

Virtual memory address (VMA)
SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) }
&quot;file offset of data&quot; = .;
SIZEOF_HEADERS
ファイルのヘッダの
バイト数を返す
リンカの組み込み変数
• VMAはそのセクションが配置されるメモリの仮想アドレス
• 上記の例では “.text” の VMA は SIZEOF_HEADERS


# Page. 27

![Page Image](https://bcdn.docswell.com/page/9J2G19KDJR.jpg)

Virtual memory address (VMA)
ヘッダ
SIZEOF_HEADERS
(= ELFヘッダ+PHT) バイト
.text
.data
SHT
&quot;file offset of data&quot;


# Page. 28

![Page Image](https://bcdn.docswell.com/page/DEYVZ4NMEM.jpg)

Load memory address (LMA)
. = 0;
.stack : AT(&quot;file offset of data&quot;) {
. = STACK;
}
• VMA はファイル実行時のアドレス
• 対して、LMA はファイルが読み込まれるアドレス
• 今回、これを「ファイル内のオフセット」として使っている
• 上記の例では “.stack” の VMA は 0、LMA は “.text” の直後


# Page. 29

![Page Image](https://bcdn.docswell.com/page/VJNM3YX378.jpg)

. = 0;
.stack : AT(&quot;file offset of data&quot;) {
. = STACK;
}
.data : { *(.rodata*) *(.data) }
.bss : { *(.bss) }
Sect
.stack
.data
.bss
VMA
0
STACK
STACK+sizeof(.data)
LMA
“file offset of data”
“file offset of data”
“file offset of data”+sizeof(.data)
ATを指定しなければ、LMAに関して直前のATの効果が続く


# Page. 30

![Page Image](https://bcdn.docswell.com/page/YE9N9P8PE3.jpg)

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


