gccのインラインアセンブリを使用して、レジスタの内容、特にgdtr
をC変数に読み込もうとしています。私はhereのようにいくつかのコードを変更していますが、コードは32ビットプロセッサ用に書かれています。したがって、命令を64ビットに適応させる際に、私は誰かが私に説明できると思っていたいくつかの奇妙な動作に遭遇しています。レジスタの内容をC変数に読み込むときに奇妙な動作が発生する
まず、gdtrレジスタの構造をモデル化すると考えられるgdtr
構造体。
struct gdtr64 {
uint16_t limit;
uint64_t addr;
};
十分に単純です。私が手
struct gdtr64 gdtr64 = {0xcccc,0xa2a2a2a2a2a2a2a2};
printf("gdtr64 limit: %x\ngdtr64 addr: %llx\n", gdtr64.limit, gdtr64.addr);
printf("<--asm call-->\n");
__asm__ volatile("sgdt %0\n" : :"m"(gdtr64));
printf("gdtr64 limit: %x\ngdtr64 addr: %llx\n", gdtr64.limit, gdtr64.addr);
を:私は実行を経て、このような構造に出力するレジスタの内容をしようとすると
gdtr64 limit: cccc
gdtr64 addr: a2a2a2a2a2a2a2a2
<--asm call-->
gdtr64 limit: a0
gdtr64 addr: a2a2a2a2a2a2ffff
私が変更されているもの伝えることができるので、呼び出し前の値がちょうどジャンク値です。制限がcccc
から00a0
に更新され、gdtr64.addr
の最後の2バイトが変更されていることがわかります。これは私には分かりません。
実験として、私は、アセンブリセクションにgdtr64.addr
を通過した以外、同じコードを実行:出力は私を驚か
struct gdtr64 gdtr64 = {0xcccc,0xa2a2a2a2a2a2a2a2};
printf("gdtr64 limit: %x\ngdtr64 addr: %llx\n", gdtr64.limit, gdtr64.addr);
printf("<--asm call-->\n");
__asm__ volatile("sgdt %0\n" : :"m"(gdtr64.addr));
printf("gdtr64 limit: %x\ngdtr64 addr: %llx\n", gdtr64.limit, gdtr64.addr);
:
gdtr64 limit: cccc
gdtr64 addr: a2a2a2a2a2a2a2a2
<--asm call-->
gdtr64 limit: cccc
gdtr64 addr: ff8076db40000097
この場合、我々は後に書き始めるにはメモリアドレスはgdtr64.limit
で占められていますが、書かれている内容は大きく異なります。前の例の制限であった00a0
がaddrの最後に移行しました。さもなければ、私達は適切な住所の造りのように見えるものを持っている。
私が使用していたstruct
に固有のものではないかと疑問に思ったので、それはchar
の文字列を試してみることにしました。レジスタは10バイト長である必要があります:
char gdtr_char[10] = "0000000000";
printf("GDTR_CHAR: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \n",
(unsigned char) gdtr_char[0],
(unsigned char) gdtr_char[1],
(unsigned char) gdtr_char[2],
(unsigned char) gdtr_char[3],
(unsigned char) gdtr_char[4],
(unsigned char) gdtr_char[5],
(unsigned char) gdtr_char[6],
(unsigned char) gdtr_char[7],
(unsigned char) gdtr_char[8],
(unsigned char) gdtr_char[9]
);
printf("<--asm call-->\n");
__asm__ volatile("sgdt %0\n" : :"m"(gdtr_char[0]));
printf("GDTR_CHAR: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \n",
(unsigned char) gdtr_char[0],
(unsigned char) gdtr_char[1],
(unsigned char) gdtr_char[2],
(unsigned char) gdtr_char[3],
(unsigned char) gdtr_char[4],
(unsigned char) gdtr_char[5],
(unsigned char) gdtr_char[6],
(unsigned char) gdtr_char[7],
(unsigned char) gdtr_char[8],
(unsigned char) gdtr_char[9]
);
私のCのスキルは開発中です。この結果は次のとおりです。
GDTR_CHAR: 30 30 30 30 30 30 30 30 30 30
<--asm call-->
GDTR_CHAR: 97 00 00 50 dd 76 80 ff ff ff
は再度、初期値はジャンクですが、我々は、レジスタを読んだ後、私たちはすべての10バイトを占めていることを見ることができますが、我々が得たものの逆の順序でしようとすると、私たちの2回目の試験。要約すると、これは別個の「試行」に分割されているにもかかわらず、これらはすべて一括して実行されていました。レジスタの内容は実行(私も奇妙な発見)の間で変更されるようです。すべてのことを言って、私は次の問題の周りに私の頭を包むことはできません:
- なぜGDTRの内容はそれぞれの実行を変更するのですか?
- 構造体と文字配列の使用に違いがあるのはなぜですか?
- GDTのベースメモリアドレスは何ですか(結果は正しいでしょうか?)
ご協力いただければ幸いです。これまで読んでくれてありがとう。
http://forum.osdev.org/viewtopic.php?f=13&t=16600&start=0 – geekosaur