x86とx86_64アセンブラの比較

そろそろx86_64アセンブラも勉強しないと時代に追いつけなるなということをひしひしと感じつつあるので、手始めにx86x86_64の違いを比較してみた。

なんといっても大きいのは、x86_64ではスタックを利用した引数の受け渡しをする必要が減ったこと。
x86では、関数呼び出し時の引数を渡すときはお馴染みの「引数逆順push」で、サブルーチンで引数を受け取るのは

4*(n+1)(%ebp)
ただし32bit引数の場合

だったわけだけど、x86_64では%rax〜%rbpという従来の32bitレジスタを64bitレジスタに拡張したものに加えて、%r8〜%r15という64bitレジスタが増えたため、整数型引数はレジスタに入れて渡すことができるようになっている。
【参考】x64 Assembly Language Programming

ちなみに、「整数型引数以外はどうなんのよ?」という疑問に対しては、こちらの20ページを参照。
http://www.x86-64.org/documentation/abi.pdf
(誤解を恐れずに言うと、実際ポインタだって整数だし整数型以外って実数くらいしかないのか…?)

そんなわけで、x86に比べてx86_64ではpush&pop命令が激減することが予想される。
というわけで、それを実際に検証してみた。
実験対象はLinuxの/usr/bin以下のすべてのバイナリファイル。
登場するニーモニックを出現頻度順に並べてみたのが以下のグラフ。

x86
f:id:levelfour:20140227090850p:plain

x86_64
f:id:levelfour:20140227090859p:plain

うーむ。
push 3位→7位
pop 7位→12位
に転落か。確実には減っている。

気になるのは、x86_64ではaddがトップに躍り出たことなのだけれど、addってそんなに頻出するものなのか…
他に個人的に注目したのは以下のポイント。

①実はトップ1〜3で命令の総数の半分を占めるレベル
→それだけmov、add、call、pushは汎用性が高い

②横軸の数字を見ると、x86に比べてx86_64は命令数が半分くらいになってる
→64bitレジスタになったことでデータのやりとりの効率が上がったのが要因?

x86_64ではlea命令が順位を落としている
x86時代のleaを使ったセコい演算がいらなくなったのだろうか?


このあたりも含めて、x86_64アセンブラを勉強していきたいな。


【蛇足】今回の命令数解析はobjdump->pythonスクリプトでやりました。こういうときにテキスト処理やちょっとした統計解析がサクッとかけてしまうのは、低級言語に比べてLLのいいところかなと。そこまで処理性能を要求される規模ではないし。