マクロ解析

現実トウヒのモチベーションが回復 (って何
以下のマクロを解析してみる。

#define _set_gate(gate_addr,type,dpl,addr,seg) \
do { \
  int __d0, __d1; \
  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
    "movw %4,%%dx\n\t" \
    "movl %%eax,%0\n\t" \
    "movl %%edx,%1" \
    :"=m" (*((long *) (gate_addr))), \
     "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
    :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
     "3" ((char *) (addr)),"2" ((seg) << 16)); \
} while (0)

とりあえず、入出力オペランドの部分について解析。

出力オペランド そのいち

最初のヤツ。

"=m" (*((long *) (gate_addr)))

gate_addr を long 型のポインタとして評価し、そのアドレスに出力値が格納される、ってコトだな。"=m" な指定文字列の意味を Simple Constraints から調べたトコロ、

A memory operand is allowed, with any kind of address that the machine supports in general.

(Simple Constraints より引用)と記述されている。レジスタじゃなくってメモリ使うかんね、という宣言のようなものか。
ちなみにこれは %0 として参照することができる。

出力オペランド そのに

次は

"=m" (*(1+(long *) (gate_addr)))

最初のヤツのアドレスに 1 番地加えたアドレスの値、になるの??
む、違うな (long *) でキャストしてあるので 4 bytes 先か。最初のを踏襲すれば、gate_addr を long 型のポインタとして評価し、その 4 bytes 先のアドレスに出力値が格納される、という意味か。

出力オペランド そのさん

"=&a" (__d0)

これは ax レジスタに出力された値は __d0 に保持される、という指示な模様。

出力オペランド そのよん

"=&d" (__d1)

上記と同様に、dx レジスタに出力された値は __d1 に保持される、という指示か。
この_そのさん_と_そのよん_のナニについては微妙にひっかかる点満載なんですが、それは以降の入力オペランドを眺めると分かります。

入力オペランド そのいち

"i" ((short) (0x8000+(dpl<<13)+(type<<8)))

この "i" も頭を痛めた記憶あり。Simple Constraints にも記述があります。以下。

An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time.

(Simple Constraints より引用)

値を使って OK って意味か。括弧内の式もそんな感じではある。これが %4 で参照されるナニである、と。

入力オペランド そのに及びそのさん

出ました。

"3" ((char *) (addr)),"2" ((seg) << 16)

"3" って入出力オペランドで割当てられた "3" 番目のレジスタ又はメモリを指す、そうなんですが、"3" 番目の割り当てってこれか

"=&d" (__d1)

一番白痴的な読みかたをすると、

    1. movw dx, ax で addr のアドレスが __d0 に格納
    2. movw %4 (値は略), dx で __d1 に (値は略) が格納
    3. movl edx, *gate_addr される
    4. movl eax, *(gate_addr+1) される

ってワケワカ。最初の二つって意味ないしー。

って、Assembly Programming Linux (system call) によると unix magazine 2003.2 月号に展開後の疑似コードが出ているとの事。自宅本棚で眠っています。資料の調べ方悪いな。
上記サイトによると、最初に_入力オペランド_で指定されているソレ達が設定されて処理が開始される模様。

  • ((char *) (addr)) が edx に
  • ((seg) << 16)) が eax に

で順に inline assembler なナニが評価されていく、との事。成程ねー。

蛇足ながら以降の処理も記述しておくと

  • dx の値を ax にコピィ
  • ((short) (0x8000+(dpl<<13)+(type<<8))) が dx に格納
  • edx を gate_addr に格納
  • eax を (gate_addr+1) に格納

となる訳ですな。

確かに GCCでインラインアセンブリを使用する方法と留意点等 for x86 でも、最初に入力オペランドで指定されたナニがレジスタやメモリに割当て、とあるな。で、アセンブリなコードが実行されて、出力オペランドで指定された対応する変数等に、とある。

そして、よくよく考えてみれば、こうするしかないようにも読めるんですが ...
# 入力のみ指定、でも微妙だし ...

最後に

上記類推が正しいかどうかは、解析結果と intel のマニュアルの記述とアわせてみる必要はある、はず。(別途調査し、エントリ入れます)
ちなみに色々調べているうちに思い出したんですが、以前にもココでハマって解析を放棄していたようです。ググッて探したソレ達も見たような気がするし、疑似コードなども今ごろになって「成程ねー」と納得している次第でして ... (とほほほ

ブクマしておいてあるのですが、参考リンクを以下に。