寄付窓口はこちら

アセンブリ、君ならできる! | try! Swift Tokyo 2019 2-13

みなさんにはアプリのデバッグで、結局アセンブリという自分には理解不能な壁を見るだけになった経験があったでしょう。もしくは、なぜUIKitがこのような挙動を示すのかを理解するために、UIKitのメソッドのソードコードをみたくなったこともあるかもしれません。このトークでは、我々のような普通の開発者でもアセンブリを深く学ぶことによって、バグを見つけ出したり、システムフレームワークリバースエンジニアリングを行ったり、自身のコードをより深く理解することができることをお見せします。

f:id:niwatako:20190322163636j:plain

5歳

f:id:niwatako:20190322163736j:plain

大学で電気光学を勉強

2005年Cocoaプログラミングはじめ

仕事はiOSを教えること

f:id:niwatako:20190322163759j:plain

趣味はレトロパソコンを集めること

f:id:niwatako:20190322163812j:plain

15年前に日本に住んでいました

f:id:niwatako:20190322163826j:plain

f:id:niwatako:20190322163842j:plain

アセンブリを語るのに20分では語れません

ほとんどのひとが怖がっているとおもいます。怖がらなくていいということ、そして実務的ヒント

デバッグで知っておくことが助けになると思います

f:id:niwatako:20190322163932j:plain

アセンブリはどんな言語?

f:id:niwatako:20190322163945j:plain

マシンコードはバイナリ、アセンブリは一番近い、そして人間が読めるプログラム。

コンパイルすると、言語が違っても、バイナリコードに成る。アセンブリで人間が読めるので知識として分かるように成る

用語を買うニンしましょう 確認

f:id:niwatako:20190322164029j:plain

64ビットの値が入る

f:id:niwatako:20190322164045j:plain

どのCPUかで違う

汎用レジスタも特定関数向けのようなものもある

CPUの中に入っていて、とても早い

変数と考える事もできる

f:id:niwatako:20190322164137j:plain

f:id:niwatako:20190322164139j:plain

次の用語

ニーモニック

f:id:niwatako:20190322164150j:plain

単純な名前で命令。ニーモニックを使ってCPUの命令を参照する

f:id:niwatako:20190322164213j:plain

f:id:niwatako:20190322164215j:plain

mov 値を別のレジスタに動かす

add 2つの数字を足し合わせる

sub 引く

cmp 比較する、ある意味引き算。

jne jump not equal 最後のオペレーション結果でどこかに飛ばす、ifみたいな

nop なにもしない、遅延を起こす

call ファンクションよびだし

pop スタックのポップ

ret リターン、callのところに戻る

コードごとにオペランドが続く

f:id:niwatako:20190322164332j:plain

mov r8 0x42 は16進数0x42をr8に動かす

最初に命令、intelAT&Tがあるが今日はintelシンタックス

最初のオペランドは宛先、そしてソースの順

f:id:niwatako:20190322164438j:plain

呼び出し規約

f:id:niwatako:20190322164447j:plain

特定レジスタに入れ込んで、addファンクションが探しに行く

どのレジスタでどのargを戻すのかを見ていく

callingコンベンションはCPUなどによってかわる

有名なのはx86、64ビットですと

f:id:niwatako:20190322164548j:plain

このリストはおぼえておいたほうが良いですデバッグの助けになります。

同じコードだが

f:id:niwatako:20190322164606j:plain

最初にAddファンクションが呼ばれる。

適切なレジストリに入れる

最初の2 はrdiに

f:id:niwatako:20190322164642j:plain

rdiから2をとりだし、raiから3を取り出し、5をraxにいれる

return

コントロールがメインファンクションに戻る。

結果を取りに行く

以上が呼び出し規約

同じ簡単な関数で2つの引数で結果を戻す

f:id:niwatako:20190322164727j:plain

Swiftでも同じような見栄え

コンパイルすると

f:id:niwatako:20190322164754j:plain

最適化されていない。

最適化化すると見栄えが変わる。

9行になっているが1行ずつ分けていくとよく分かる

最初の2行、関数のプロローグ、いくつかのものが設定され関数本文で実行できるようにする

つぎに引数をレジスタから確保する

f:id:niwatako:20190322164834j:plain

rdi、rsiからスタックに入れる

rsiに

f:id:niwatako:20190322164923j:plain

加算

f:id:niwatako:20190322164937j:plain

結果を格納

f:id:niwatako:20190322164954j:plain

f:id:niwatako:20190322165009j:plain

戻る・

f:id:niwatako:20190322165022j:plain

どう役立てるか。

最もあるのはデバッギングです。

クラッシュするとアセンブリコードがたくさん出てきます。

全く意味がわからないと思ったりしますが、

有用な情報を得られたりします。

f:id:niwatako:20190322165103j:plain

po $rdi といれればいい

もっと複雑な場合

touch beganをしりたい

b -[UIResponder touchesBegan:withEvent:]

どのオブジェクトでこれが起きたのか。

レジスターで呼び出し規約を使える。

Objecitve-Cは動的DispatchしているのでObjective-C Message Send

rdiでプリントすることが出来る

po $rdi

UITableViewCellContentViewだということが分かる

po (SEL)$rsi

レシーバーとセレクタの引数は1つ目が3つめになるので po (id)$rdx

f:id:niwatako:20190322165407j:plain

LLDBをObjective-Cモードで使える

f:id:niwatako:20190322165411j:plain

コマンドを使ってエイリアスを作れる

f:id:niwatako:20190322165438j:plain

f:id:niwatako:20190322165449j:plain

もうひとつ、役立つツール

f:id:niwatako:20190322165456j:plain

擬似コードを作りアセンブラが何を行っているか分かる。Disassembly、リバースエンジニアリング、どのように実装されているか、Hopperが役に立つ、お金を出したぶんの価値が得られます。

もっとしりたけれ

f:id:niwatako:20190322165541j:plain

今の内容とより多くの情報を得ることが出来ます。

チュートリアルもあります。

f:id:niwatako:20190322165635j:plain

スライドです

f:id:niwatako:20190322165648j:plain

少しは理解していただけたでしょうか、もっと学びたいと思っていただけたでしょうか。

ご清聴ありがとうございます。