ELFとDWARF勉強会 に参加しました。

以下、今回のメモです。

資料は後日公開されるようなので、公開されたらリンクする予定です。

会場

昨日と同じ場所なので、迷わずたどり着けましたが、なぜか1階からはタワーAに入れなくて2階から入る必要がありました。

参加者自己紹介

一言ずつぐらい参加者の自己紹介がありました。 大阪以外からきている人も多く、遠くからきている人もいて驚きました。 組み込み系などで普段から関連するようなことをしていそうな人が多そうな感じでした。

遠くから参加といえば Binary 2.0 カンファレンス2005 の時はイベントのためだけにわざわざ東京に行ったような覚えがあるので、レアなイベントだと遠くからの参加もよくあることなのかもしれません。

ドキュメントを読まずに知るELF入門

  • http://kozos.jp/
  • 本日の内容はリンカ・ローダ実践開発テクニック という本にかいてある内容のさわり
  • Linkers and Loaders は概要だけで実装するには他の資料に当たる必要がある
  • リンカ・ローダについて詳しくかいてある本は他にはないのではないか
  • 発表者が主に使っているのが FreeBSD なので FreeBSD の話が中心
  • Executable and Linking Format なので本来は ELF フォーマットというのはおかしい (が、RPG などのエルフと紛らわしいので ELF フォーマットといってしまうことも多い)
  • 実行ファイルやオブジェクトファイル、共有ライブラリだけではなくコアダンプも表現可能
  • 「リンク」のための領域情報と「ロード」のための領域情報を別々に持つというのは珍しい
  • リンクとロードの説明
  • バイナリエディタを入れるのがおすすめ
  • hexedit というのを使っている
  • 最初の方は 00 が多い部分、次に ASCII データっぽい部分、配列データっぽい部分、機械語コードっぽい部分のように領域ごとに特徴が分かれている
  • xpm に変換して眺める
  • 英語のドキュメントを探すのではなく /usr/include/**/*elf* などを探すことが多い
  • /usr/include/elf.h/usr/include/sys/elf32.h をみてみる
  • hdr は header など、略語などを知っているとソースコードを読むのがはやくなる
  • ELF ヘッダ - ファイルの先頭に1個
  • プログラムヘッダ - ロード用 - セグメントをさしている
  • セクションヘッダ - リンク用 - セクションをさしている
  • セグメントとセクションは独立した領域だが、セグメントの中に複数セクションがあったりする
  • Elf32_Half は 2 バイト
  • Elf32_Word は 4 バイト
  • Elf32_Addr は 4 バイト (32ビット環境をみているので)
  • readelf -a 実行ファイル で情報表示できる
  • elf_common.hEM_386 として 3 が定義されている
  • e_machine のところを書き換えて readelf -a で変わったのを確認して、実行してみて実行できないのを確認 (間違ったアーキテクチャです と出てきた)
  • 2,3 種類以上の情報を見比べて確認すると良い
  • ロードしてエラーにしている部分を探す
  • FreeBSD は /usr/src/sys にカーネルソースがある
  • 重要なものはそんなに深いところにはないので find . -name "*elf*" ではなく ls */*elf* ぐらいで探せば良い
  • ちょっと見つからなかったのでパス
  • セグメントをロードしている部分をみてみる
  • 実際のロード処理は load_section という名前になっているっぽい (load_segment の方が良いのではないかという指摘)
  • セクションという単語は割と適当に使う人もいるらしいので注意が必要
  • プログラムヘッダの情報をみていくのは簡単に作れる (e_phoff から e_phentsize バイト を e_phnum 個みていけば良い)
  • 実際にライブコーディングで作ってみる
  • OS を作っているとフラグをちょっと変えたいとかいうことがある
  • objcopy などでできることもあるが、対応できない場合に自作のコードがあると応用できるので、 readelf でできるようなことでも自作できると良いことがある
  • Debian などでは bintuils にある (ビンユーティリティと読んでいた)
  • kozos のブートローダをみる (本質的にはプログラムヘッダをループでコピーしているだけ)
  • リンクはセグメントではなくセクションを見ていく
  • readelf -a 実行ファイルの .text セクションのオフセット部分を実際にバイナリエディタで見てみると確かに機械語っぽい
  • オブジェクトファイルの .text をみてみる
  • デフォルトのリンカスクリプトは ld -verbose でみえる
  • リンカスクリプトの自作例 (-Wl,Tld.scr で指定)
  • objdump -d hello.oobjdump -d hello をみてみる
  • 関数呼び出しのアドレスがオブジェクトファイルだと 0 (空欄) になっているのが実行ファイルだと埋められている
  • .rela.text セクションに埋める必要のある位置が書かれている
  • リンカがやっているのはセクションを寄せ集めるのと再配置情報を埋めること
  • 書籍では簡易リンカを作るサンプルコードがある
  • コアダンプをみてみる
  • prstatus というキーワードでカーネルのソースコードをみてみる
  • 質疑応答
  • 各セクションが何なのかの説明はまとまったものはなさそう
  • 調べるときは FreeBSD と Linux 両方のソースコードをみることが多い
  • リンカスクリプトで .text セクションのアドレスを指定しなかったらアボートしていたが指定したアドレスの意味は?
  • 他で使っていたアドレスをそのまま使っているだけで詳細は不明
  • CPU などで決まっているアーキテクチャの場合はそのアドレスを使う
  • リンカスクリプトの文法は info ld の Scripts が一番詳しい (だいたいは書籍にもかいてある)

休憩

DWARFとデバッガのからくり

  • 自己紹介
  • https://github.com/takubo
  • UNIX 文化 (ハッカー文化) と、組み込み文化を結びつけたい
  • 関西でも、勉強する勉強する勉強会をしたい
  • 「〜の使い方」じゃなくて50年戦える「技術」と「知識」を
  • AWK, sed
  • 今回は AWK ではなく DWARF の話
  • 基礎情報
  • デバッグ情報フォーマット (の規格)
  • Debug With Attributed Record Format の略
  • デバッガでできること、わかること (ユーザ視点): 実行制御 (ブレークポイント、ステップ実行、〜まで実行)、スタックトレース、変数の値を表示
  • デバッガに課せられた任務: 実際は機械語が実行されているが、ソースコードがそのまま実行されているかのような錯覚を与える
  • デバッガが知るべきこと: ソースの各行に対応する機械語、関数の先頭・末尾に対応する機械語、変数のありか、変数のビット幅・表現形式(文字列、整数、浮動小数)、文字列や配列の境界、コールスタックを巻き戻す方法
  • コールスタックの例: スタックに return アドレスを持つ、レジスタウィンドウ、リンクリスト
  • ブレークポイントの仕組みの例: デバッグレジスタにアドレスを設定、メモリアクセスを監視、MMU などでメモリ番地の rwx を落として例外を発生させる、命令を書き換えて例外を発生させる
  • どの方法でもブレークポイントを設定するアドレスを知る必要がある
  • デバッグ情報とは: 「デバッガが知るべきこと」が保存されている情報が「デバッグ情報」
  • デバッグ情報を生成するのはコンパイラやリンカの役目
  • ソースの情報を直接知れるのはコンパイラのみ
  • リンカは再配置に伴う処理や重複情報の削除
  • デバッグ情報の課題、あるいは、デバッガにとっての難問
  • 最適化:
  • ソースの原型をとどめない機械語: 対応がめちゃくちゃ、ソースと機械語の対応は1対1ではない、インライン展開
  • 不要な変数は消される
  • 消されなかった変数もどこへ行った
  • メモリ上になかったりレジスタも関数呼び出しを挟んで同じ変数が別のレジスタになっているかもしれない
  • RISC の台頭: デバッグ中でも最適化を切れない
  • アセンブラさえも命令の並べ替えを行うことがある (例: 遅延スロット)
  • デバッガがソースを再現するための全ての情報は、通常は非常に巨大になる: ディスクを圧迫する、メモリにはとても乗らない
  • これをなんとかして小さくしないといけない
  • DWARF の特徴: オープンかつフリー、デバッグフォーマットとして優秀、実際に広く使われている
  • http://www.dwarfstd.org/
  • GFDL
  • DWARF の歴史
  • 1992 に Version 1
  • 現在は 2017.2 リリースの Version 5
  • 他のデバッグ形式: STABS, *COFF, PDB, IEEE695
  • DWARF の精神: 何にも依存しない、暗黙ではなく明示、ゆるい標準、ベンダー拡張対応、より小さなデータ表現、効率的に処理できる
  • DWARF の目標
  • DWARF はなぜ難しいのか?: 日本語の情報も英語の情報も少ない、より小さなデータ表現
  • 圧縮について確認
  • DWARF フォーマット解説
  • 重要な用語
  • LEB128 (Little Endian Base 128)
  • uLEB128 (unsigned LEB128、符号なし)
  • sLEB128 (signed LEB128、符号付き)
  • CU (Compilation Unit)
  • 翻訳単位

休憩

時間がおしているので短めに

バイナリかるた体験

  • http://kozos.jp/binary-karuta/
  • 0と1のコンピュータ世界 バイナリで遊ぼう! という本に解説あり
  • 説明があった後、「バイナリかるたのサンプル」の「スライド」をみながら実際に何のファイルなのかという話をしていました。
  • 最後までいかなくても、問題の区切りで終了できるので、最後のセッションに最適だそうで、時間があまりなかったこともあって、スライドの途中で終了しました。

クロージング、後片付け

  • 振り返り
  • 振り返りの中の意見であったライブコーディング (とは言ってなかったけど) がよかったというのは同感でした。
  • 資料は ELF の方も DWARF の方も後日公開してもらえるということでした。バイナリかるたはサイトをみながらだったので、特に別途用意された資料はありませんでした。
Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published