Help us understand the problem. What is going on with this article?

IA32(x86)汎用命令対応のアセンブラ実装方法(1)

More than 3 years have passed since last update.

自作OS Advent Calendar 2016 11日目の @Hiroyuki-Nagata です.
前の人は 自分でした,次の人も たぶん自分です.

この記事はいろいろな用語が出てくるので、全て参考リンクを張っています。

OS自作入門でのアセンブラの使われ方

まず、なぜアセンブラが使われているのか?

次にアプリケーションレベルの話

  • libcを使わずシステムコールレベルの命令を実行
    • 作りたてのOSにはシステムコールを呼び出せる関数やライブラリが存在しません
    • これはつまり標準出力に何か出したりメモリを確保したり、割り込み制御かけたりできないということで
    • ということは、そういった低レイヤをまかなうためのライブラリをビルドさせるか、自作するか2択になるわけです
    • OS自作入門では、bootpack.cにそういった命令のシンボル名を書き、その実装をnaskfunc.nasに書いてます
    • 最終的に作ったオブジェクトファイルは作った関数のシンボル名と実装を含むことになり、処理の中で関数が呼ばれると、naskfunc.nasに書かれたアセンブラ処理を実行するという流れになるわけです

アセンブラを実装していく方法

次に、アセンブラを実装していく方法です
今回のターゲットは単にnaskの構文を理解して、構文に対応する機械語を吐ければそれで十分です

  • サンプル
    • 最初のMOVニーモニック1と呼ぶ
    • 単に命令(Instruction)と呼んでいいかもしれない

だいたい全部大文字

        MOV     AL,0x13         ; VGAグラフィックス、320x200x8bitカラー
        MOV     AH,0x00
        INT     0x10
  • naskはインテル記法なので
    • 命令の次にまずDEST(送り先)が来る
    • その次にSRC(送り元)が来る
    • 送り元とか送り先の意味合いは、命令の種類によって変化します

これをもうちょい一般化すると

  • MOV DEST, SRC ← 動作: DEST ← SRC

と書けそうです

準備する資料

大元の種本とすべきなのは インテル® アーキテクチャー・ソフトウェア・デベロッパーズ・マニュアル なんでしょうが、わたしはめんどくさいのでWEBサイトに載っているそれの書き下しを参考にしています。

これを参考にすれば、どういう命令を出したい時にどういう機械語を出せばよいか仕様がわかります

16bit, 32bitモードで出力される機械語の仕様

オペコードから導出される機械語の見取り図

以下は、i386のCPUを動作させるときの機械語(バイナリ)の並びです。

(a) 16-bit instruction mode (リアルモード)
 _________  ___________  ____________  _________
| Opcode  ||MOD-REG-R/M||Displacement||Immediate|
|         ||           ||            ||0-4 bytes|
|1-2 bytes|| 0-1 bytes ||            ||         |
|         ||           ||            ||         |
|         ||           ||            ||         |
 ---------  -----------  ------------  ---------

(b) 32-bit instruction mode (プロテクトモード)
 ........  ........  _________  ___________  .........  _________  _________
:Address ::Operand :| Opcode  ||MOD-REG-R/M|:Scaled   :|Displace-||Immediate|
:size    ::size    :|         ||           |:Index    :|ment     ||0-4bytes |
:0-1bytes::0-1bytes:|1-2 bytes|| 0-1 bytes |:0-1 bytes:|         ||         |
:Prefix  ::        :|         ||           |:         :|         ||         |
:67H     ::66H     :|         ||           |:         :|         ||         |
 ''''''''  ''''''''  ---------  -----------  '''''''''  ---------  ---------

図の中の用語の説明をしておきます
機能レベルの話をしだすと記事がまとまらないので、まず概要のみ書きます。残りは別の記事で。。。

16-bit/32-bit共通

(a) 16-bit instruction mode (リアルモード)
 _________  ___________  ____________  _________
| Opcode  ||MOD-REG-R/M||Displacement||Immediate|
|         ||           ||            ||0-4 bytes|
|1-2 bytes|| 0-1 bytes ||            ||         |
|         ||           ||            ||         |
|         ||           ||            ||         |
 ---------  -----------  ------------  ---------
  • Opcode (オペコード)
    • 例えば INT 0x13という命令であれば0xCD ibというオペコードがそれに対応する
    • アセンブラの出力は 0xcd, 0x13 になる
  • MOD-REG-R/M (ModR/M)
    • 命令自体のオペコードと命令の対象となるレジスタによって変化する1byteのデータ
    • x86のCPUの命令が汚い原因の一つかも
  • Displacement (Disp)

  • Immediate (即値)

    • 即値はそのままの数字のことです、大抵 0x が先頭につく

32-bit

(b) 32-bit instruction mode (プロテクトモード)
 ........  ........  _________  ___________  .........  _________  _________
:Address ::Operand :| Opcode  ||MOD-REG-R/M|:Scaled   :|Displace-||Immediate|
:size    ::size    :|         ||           |:Index    :|ment     ||0-4bytes |
:0-1bytes::0-1bytes:|1-2 bytes|| 0-1 bytes |:0-1 bytes:|         ||         |
:Prefix  ::        :|         ||           |:         :|         ||         |
:67H     ::66H     :|         ||           |:         :|         ||         |
 ''''''''  ''''''''  ---------  -----------  '''''''''  ---------  ---------

32bitモードの最初の2バイトはOverride prefixesと呼ばれる。なぜならそれらは常に存在するとは限らないからだ。 最初の1バイト目は命令に使われるオペランドのアドレスのサイズを変更する。 次の2バイト目はレジスタのサイズを変更する。

  • Address size Prefix byte

    • もし、CPUが16bit命令モードとして(プロテクトモードのみ)で動き、32bitレジスタが使われていればこれは無視される。もし、16bit命令が32bit命令モードで現れるのであれば、 16bitレジスタを選択するためこれが必要
    • 逆に、リアルモードで32bitのアドレッシング・モードを使うときもこれが必要
  • Operand size Prefix byte

    • 16bit命令モードで動作中(リアルモードもしくはプロテクトモード)、32bitレジスタが使われていれば、Override prefixes(0x66)が命令の前に付加される
  • Scaled Index byte (SIB)

    • x86の機械語コード中にあり、実効アドレスを指定したメモリーアクセスをする際の情報を与えるためのバイト。i386の32ビット以降で追加された。ModR/Mではカバーできん部分を指し示す。

これでようやく実装のための準備終了です、次回はより具体的な話を書きたいところです。


  1. Difference between: Opcode, byte code, mnemonics, machine code and assembly ... MNEMONIC: English word MNEMONIC means "A device such as a pattern of letters, ideas, or associations that assists in remembering something.". So, its usually used by assembly language programmers to remember the "OPERATIONS" a machine can do, like "ADD" and "MUL" and "MOV" etc. This is assembler specific. 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away