LoginSignup
7
4

More than 5 years have passed since last update.

自分で書いたC言語のコードを逆アセンブルしていたところ、妙なオペコードの存在に気づきました。

基本知識

NOP命令

多くのCPUには、「何もしない」命令であるNOP命令が備わっています。CPUによっては、設計時に「全ビット0」のようなパターンを意識的にNOPへ割り当てていることがあります。

x86はそうではなく、もともとはXCHG EAX, EAXEAXレジスタ同士を交換するという、実質何も実行しない命令)をNOPとして使っていました。その後のパイプライン化でEAXレジスタを触らないように最適化されることとなり、x64に至っては(本来32ビットレジスタに触れば上位32ビットはクリアされるはずが)真に何もしない命令となっています。

また、このXCHGから派生したものとは別系統の、0f 1fから始まるオペコードのNOPも実装されています。

WORD PTR

AT&T記法ではmovlandwというように、命令そのものでオペランド幅を表現するようになっています。一方、インテル記法の場合、命令自体はMOVANDのようにオペランド幅を問わず共通となっています。

どこかのオペランドがレジスタなら、幅は決め打ちにできるのですが、メモリと即値の場合、何も書かなければ幅がわかりません。ということで、BYTE PTRWORD PTRDWORD PTRQWORD PTRというものをメモリオペランドの前に補って、どんな幅でメモリをアクセスするのかを(アセンブラレベルで)表現します。

妙なオペコード

objdump -d -M intelとして、自分がCで書いたコードを逆アセンブルしていたのですが、その過程で妙なものを発見しました。

     fa1:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
     fa8:   00 00 00 

なんと、NOP命令に複雑なオペランドを指定してあるのです。これはもしかして、「NOPと見せかけて何かしらの処理を行うのでは」なんてことも思ったのですが、調べてみればやはり「何もしない」とのことでした。

どうやら、これはアライメントを合わせるために埋めてあるものだということでした。そして、1バイトのNOPで埋めるよりデコードの効率がいいので(一度に○命令デコードできるとのこと)、オペランドやプレフィックスを指定して10バイトにしたNOPを使っている、というのが真相でした。

外部リンク

7
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4