鱒身(Masu_mi)のブログ

知った事をメモする場所。

RabbitMQ 利用開始

RabbitMQを使う時にだいたい忘れてしまうので次こそはスムースに利用できるように再びメモを残す。

Read more...

pedaを導入した

タイトル通りにpedaを導入した。gdbが豪華になるって目的だ。

peda 導入時のgdb起動結果

Exploitの開発サポートも入るし色々と解析に便利なコマンドも追加される。 とりあえずbt(backtrace) でmainの外側も表示してくれる。 また今回導入するにあたり.gdbinitにgdb初期化処理を書ける事を知った。

gdb拡張はpythonで作れるのでELFの知識強化の材料として勉強するのが良い気がした。

ストレージ関係のツールとか眺めてた

最近はデータ保存の観点で調べてみたり考えてみたりする事が増えてきた。 Storage Weekly で出てきたデータ保持・配信系ミドルウェアやツールを中心に調べてみた。

ストレージ・データベース・オーケストレーション・コンフィギュレーションは網羅的に探したくなるので今度に回す。 BlockChain もストレージやコンテンツ配信系に意外と応用されていたけど、アルゴリズムから押さえたいので勉強してから別途まとめる。

ユーザーデータは、4K・全天球画像・3Dモデルみたいに巨大化する方向とセンシングデータみたいに大量な小さい時系列データの方向が特に増加すると思ってる。

システムデータは今まで通り、リポジトリ・ログ・メトリクス・コンテンツ配信・アーカイブが主軸だけれど、 リポジトリはマシンイメージ・Dockerイメージ・DCOSパッケージが増えていきそう。またコンテンツ配信で学習モデルも加わる気がする。

Read more...

AfterEffect 資料

最近は結婚式準備で時間がなかなか取れていない。

ELF・SQLite・AmbryHaystack ・カーネルソースへの興味を消化しきれないまま AfterEffect を使ってオープニングムービー、プロフィールムービーを作ってる。

AfterEffect はシーンを組み合わせてムービーを作るものではないし、動画形式を整えるものでもないし、まして物理メディアに焼き付けるものでもない。 動画や画像を組み合わせて特殊効果を実現したりするものだ。 なのでAfterEffect を結婚式ムービーに使うのはオーバースペックな上に目的を取り違えている。

ただ使ってみたら簡単にVFXを作れたりと趣味として楽しかった。わくわくする。 ただ顧客と締め切りがあると仕事感が出てきて単純に楽しむだけでは済まなくなってしまうのは悲しいものだ。(まだ全然、終わっていない)

とりあえず目を通すと良さそうな資料を記録しておく。

SQLite4が現れた!

SQLite3の勉強を放置しているうちにSQLite4が出ていた。 なので今回はThe Design Of SQLite4の超訳(すっとばし)と補足を書く。

SQLite3を読んでSQLiteは標準のB-Treeを基盤に仮想テーブルを使って色々なデータ構造をSQLで糊付けする抽象化層ライブラリってイメージを持っていた。 SQLite4は各コンポーネントの責任範囲を明確にして全体を単純に扱えるようにしている印象を受けた。 例えば、 プラガブルなストレージエンジンは、データモデル(トランザクション・データ構造)をデータベース全体で統一させている。 これはテーブル単位でのデータ構造切り替え(仮想テーブル)よりも単純化されていて扱いやすそうに思えた。 また、実行環境オブジェクトは複数のDB接続をユーザー側で明示的に管理しないといけなくしている。

参考資料のリンクを残す

Read more...

ダメな定数

恥を晒しておく。最近、馬鹿な定数を定義してしまった。

定数化によって、マジックナンバー・リテラルを減らすことの目的には、コード修正時の変更箇所を減らしたりコンパイラに検証を任せられる様にすることが含まれる。 またフォーマット文字列の場合は、書式指定子と後続の引数の間で意味的な関係があり切り離すと関連を追い辛く変更箇所が増えてしまう。

そのため、だいたいの場合でフォーマット文字列は定数にせずにプロシージャに閉じ込める方が良い。

良い歳して考えずに定数化した自分が恥ずかしい。。

const format = "%s/%s/%s/hoge"

func Main() {
  fmt.Sprintf(format, "name", "number", "book")
  // ...
  // ...
  fmt.Sprintf(format, "name2", "number2", "book2")
}

go tool nm vs nm

go tool にnmがある。 Linuxだとnmコマンドがあるからメリット薄いけどOSX,Win でも同様に機能して嬉しい。 OSXのotoolはいろいろな機能が統合されててオプション調べるのが辛い。

$ uname -a
Darwin protrout.local 14.5.0 Darwin Kernel Version 14.5.0: Mon Jan 11 18:48:35 PST 2016; root:xnu-2782.50.2~1/RELEASE_X86_64 x86_64
$ go tool nm `which ls`

EFLで使った感じでは基本機能は同じ。当たり前だけどnmコマンドの方がオプションが多くて柔軟に使える。

[復習]main にたどり着く前を追ってみた

先日、mainに至るまで追ってみたが幾つか疑問を残していた。

  • mainからのバックトレースで外側が見えないのは何故か?
  • __libc_start_main のdisassembleとobjdumpの結果が異なる

詳細にmainまでの挙動を解説しているページがあった。 読んだり他を調べた中で印象に残った部分を記録する。資料も最後にまとめておく。

ただし依然mainからの復帰後にバックトレースが表示できる理由がわからないまま。

関心ごと

ELFのインタプリタはld-linux.so

man execveを読めってことでした。

実行ファイルが動的リンクされた a.out 実行形式で、共有ライブラリの スタブを含むものだった場合、実行の開始時に Linux の ダイナミックリンカー ld.so(8) が呼び出され、必要な共有ライブラリをメモリーに読み込んでリンクを行う。

実行ファイルがダイナミックリンクされた ELF 実行形式だった場合、 PT_INTERP セグメントに指定されたインタープリターが必要な 共有ライブラリ (shared library) を読み込むのに使用される。 通常、インタープリターは glibc をリンクしたバイナリでは /lib/ld-linux.so.2 である。

__libc_start_main は動的にロードされる

そのため開始前にはアドレスが決まらない。 言及しているエントリがあった。 そのまえに、nmでシンボルを確認しろよって話でした。

$ nm ./a.out  | grep __libc_start_main
                 U __libc_start_main@@GLIBC_2.2.5

main の呼び出し箇所の確認

解説記事と異なりx86_64環境だけど確認してみた。 __libc_start_mainの最初の引数が main へのポインタになってた。ただ pushじゃなくて%rdiを使っている。

(gdb) x/10i $rip
=> 0x400409 <_start+9>: and    $0xfffffffffffffff0,%rsp
   0x40040d <_start+13>:        push   %rax
   0x40040e <_start+14>:        push   %rsp
   0x40040f <_start+15>:        mov    $0x400570,%r8
   0x400416 <_start+22>:        mov    $0x400500,%rcx
   0x40041d <_start+29>:        mov    $0x4004f0,%rdi
   0x400424 <_start+36>:        callq  0x4003e0 <__libc_start_main@plt>
   0x400429 <_start+41>:        hlt
   0x40042a <_start+42>:        xchg   %ax,%ax
   0x40042c <_start+44>:        nopl   0x0(%rax)
(gdb) x/i 0x4004f0
   0x4004f0 <main>:     push   %rbp

main関数から外はバックトレースで見えない

この記事で main に入るときはフレームポインタ(%ebp)をスタックに積むなどの事前処理を行わないためmainの内外が分離されることが書かれてた。

スタックに呼び元の情報が記録されないのだとすると%rbp, %rspがどう修復されるのかわからない。 ちゃんとStack layoutやret命令がどう動くか確認する必要がありそう。

return address of mainmain呼び出し前の%ripに対応しret命令で復帰するので実行に問題はない。 だけどmainの外側に戻って即座にバックトレースが取得できることは解せない。

debug aid in Go

GoでアサーションやDebug aidを行いたい。

例えば開発時はアサート失敗でpanicさせ気付ける様にしておき、リリースは完全にコードが消えていて欲しい。 そういう時は、ビルドオプションtagsを使いビルドを分岐させる事になる。

マクロ・プリプロセスがあればリリースビルドからデバッグ用コードを簡単に消せるけど、Goにはその様な機能はない。 そのためソースコード上にデバッグ用コードが残る。これが最適化で消されるかを確認した。

tl;dr

以下が判明したためGo言語でも積極的に Assertion, debugaidを利用した開発ができる。 特に定数+条件分岐を使うとリリースビルドから痕跡を完全に消せる。 ただしコミュニティにベタープラクティスとして受け入れられているかは不明。

  • 空の関数は実行バイナリから消える(引数での式の評価は実行される)
  • 定数 + 条件分岐の判定部分は消える
$ uname -a
Linux pit 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
$ go version
go version go1.5.1 linux/amd64

Read more...

Goバイナリのエントリポイント

goでは_startではなく_rt0_amd64_linuxがエントリポイントになっていた。

詳細

試しに下のHelloworld(sample.go)を準備する。

package main

import "fmt"

func main() {
    fmt.Println("Hello world")
}

以下を実行して確認した。

$ go build ./sample.go

$ readelf -e ./sample| grep 'Entry point address'
  Entry point address:               0x456130

$ objdump -f ./sample
./sample:     file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000456130

$ nm ./sample| grep 0456130
0000000000456130 T _rt0_amd64_linux