Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
リンカを作ってみた
Search
hotaru
April 17, 2026
210
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
リンカを作ってみた
hotaru
April 17, 2026
More Decks by hotaru
See All by hotaru
Raspberry Pi 5の起動プロセスについて
hotaru_jp
1
1.2k
デバッグ支援ハイパーバイザとRaspberry pi 5でのAMP
hotaru_jp
0
110
Featured
See All Featured
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
280
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
620
The agentic SEO stack - context over prompts
schlessera
0
830
BBQ
matthewcrist
89
10k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Documentation Writing (for coders)
carmenintech
77
5.4k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.7k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
How to Ace a Technical Interview
jacobian
281
24k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
210
Transcript
リンカを 2 週間で作ってみた 2026/4/17 コンパイラのコンパの部分 第2回 LT ほたるいか 1 1
ほたるいか 詳細なプロフィール 東京科学大学 学士3年 サイボウズ・ラボユース ‘25 SecHack365 '25 坂井ゼミ セキュリティキャンプ
2024 全国大会 ハイパーバイザゼミ 2 ハイパーバイザやCコンパイラを作成しています
モチベーション 3 去年の2月ぐらいからコンパイラを作っているが、IR対応/multi arch 対応したら 2万行以上になってセルフホストせずに放置してる、、、 + 最近実行バイナリをそのまま吐くコンパイラ?を作ったが案外簡単 ↓ リンカをつくれるのでは?
つくってみた
今回の目標 (簡単な)リンカを作ってみよう 4
できたもの 5 入力されたobject fileをまとめて静的リンクをするリンカ newlibによる標準ライブラリもリンクできるようにしている ここでデモ GitHub
リンカの仕組み (簡単な)リンカの仕組み 6
リンカの仕組み 7 elfリンカの役割は、複数のオブジェクトファイルを統合して実行可能な ファイルにすること。 Cコード アセンブリ オブジェクト ファイル 実行可能 elf
コンパイラ アセンブラ リンカ
オブジェクトファイルの中身 8 オブジェクトファイルとは、linkableな方のelf fileである。 elf は executable and linkable formatの略であり、実行可能fileとリンク可能fileの
2つの形態がある。 executable elf そのままローダに通して、‘./a.out’等で実行可能なelf linkable elf (オブジェクトファイル) Cコードやアセンブリと1対1で対応する型式 Cコードやアセンブリでexternとして外部定義するシンボル(関数/変数)は アドレスを決められずに残ったまま
オブジェクトファイルをlinkする方法 9 基本はすごい簡単な2 step 1.すべてのオブジェクトファイルを読んで、シンボルをすべてリストアップ 2.そのシンボルを使って未解決なまま残っている外部定義シンボルを解決する これさえやれば標準ライブラリを使わないプログラムは動く
外部シンボルの解決方法 10 ※静的リンクの場合 object file object/archive file を読む object fileのセクションのうち
必要なものをまとめる シンボルをまとめて 未解決シンボルを解決 .textセクション等に relocationを適用 executable elfを 出力する executable elf
object/archive fileを読む 11 標準ライブラリへの対応には、object fileだけでなく、archive fileも読めなければなら ない。 archive fileはUnixのar型式で、object fileをまとめたもの。
このarchive file内部にobject fileが複数並んでいるので、それを必要に応じて入れる。 archive fileにはどのobject fileになんのシンボルが定義されているか/未定義のまま残さ れているかが書かれている。 このmain.cをコンパイルしたmain.oには printfが未定義 ↓ 標準ライブラリのarchive fileからprintf が定義されているobject fileを探して一緒にリンク
object fileのセクションのうち 必要なものをまとめる 12 object fileには色々なセクションがある .textセクション: プログラムが入る .dataセクション: グローバル変数が入る
.rodataセクション: read onlyなグローバル変数が入る .bssセクション: 0埋めのグローバル変数が入る .noteセクション: gccのメモ書き等で使われたりする .debugセクション: DWARFが入ってたりする ※より正確にはSHF_ALLOCであるもののみ持って、SHT_NOBITSなら.bss、SHF_EXECINSTRなら.text、 SHF_WRITEなら.data、それ以外を.rodataに入れている 今回は最低限の.text .data .rodata .bss以外すべて捨てる! デバッグ用等で実際にはメモリに乗らないものも多いので、 、 、
シンボルをまとめて 未解決シンボルを解決 13 シンボルとは、関数やグローバル変数のことである。 別の関数で定義されているシンボルはobject fileの時点では読めないため、 Undefinedなシンボルとして扱われる。 ここでは、definedなシンボルをまず集めて、Undefinedなシンボルを解決しようとしている Undefinedなシンボルが解決できなかったらarchive fileを見て、それにもなければエラー
__attribute__((weak))等のweak symbolもここで衝突したら無視するなどの処理を入れる
.textセクション等にrelocationを適用 14 .textセクションでは機械語が実際に書かれている その際に、関数呼び出し等があるが、object fileの時点で未解決なシンボルに相当する 機械語部分は0埋め(RELA)または情報が置かれている(REL) ここに実際のシンボルのアドレスを入れる シンボルが関数の場合 関数アドレスを入れる シンボルが変数の場合
変数のアドレスを入れる 絶対アドレスによる呼び出し、PC相対呼び出し等によって入れるべき値が違うため、 object fileのrelocation情報の書かれたセクションからどういう計算をすればいいかを知る .e.g.: R_X86_64_PC32であれば相対32bitなので、 symbol_addr + addend /* offsetのようなもの */ - place_addr で計算される ※今回はRELA対応のみ
executable elfを出力する 15 最後、executableなelfとして出力する elfには最初に実行されるべきentry pointを必要とするが、これは_startシンボルのアドレス とする また、.text .data .rodata
.bssはそれぞれpage size alignされている必要がある これをしてなかったせいで、.dataと.rodataが一緒のページに配置されてセグフォした
TODO 16 Thread Local Storageへの対応 グローバル変数はプロセスごとにわかれているのみであり、同じプロセス のスレッドは変数を共有してしまう ライブラリではerrno等、スレッドごとに記憶領域を別にしたいものは Thread Local
Storage(TLS)に入れられている。 CではTLSは通常の変数へのアクセスのように扱われるが、linuxではTLSへ のアクセスはFS セグメントからの相対アドレスで扱われる このため、executable elfでも.dataセクション等とは別の扱いが必要であ り、.tdataセクション等にまとめる必要がある。
TODO 17 glibcへの対応を行う そもそも今回はnewlibへの対応しかしなかった newlibとした利点は、TLS無しにできたり、よくわからないセクションを吐 かないため .text/.data/.rodata/.bssに帰着できないセクションを吐かれるとリンク不能/ セグフォする 外部リンクへの対応 どうやればいいかあまりわかってないから調べるところから
pltやgotなどセクションが更に増えてややこしそう
おまけ 18 weak undefined symbolの話 __attribute__((weak))で定義されていて、かつundefinedな場合 つまり、‘__attribute__((weak)) extern foo’等のとき、 未定義シンボルが解決されなかった場合には、そのシンボルはNULLとなる
このため、 if (foo) foo(); のようにする必要がある。