2010-01-17

C++: 構造体でアドレスを読む

我ながら意味不明なタイトルだ。
やりたいことは、アセンブラが設定した配列をC++(またはC)の構造体に入れるってそれだけなんだけど、何故かはまっている。

アセンブラは適当なアドレスに値を入れる。こんな感じで。
0x00002840: 0x00000000 0x0000000 0x0009fc00 0x00000000
0x00002850: 0x00000001 ...
これが配列の一要素。
っで、まぁこれはE820hで取得したメモリーマップなので、普通にこんな構造体で受け取る。
struct MemoryMapEntry
{
  uint32_t baseAddrLow;
  uint32_t baseAddrHigh;
  uint32_t lengthLow;
  uint32_t lengthHigh;
  uint32_t type;
};

// どこかの関数で
MemoryMapEntry mapEntries = getMemoryMapEntry(); // これはアセンブラ内で定義した。
これで普通ならいけるはずなんだけど、取り出される値がおかしい。上記のアドレスなら、
baseAddrLow  = 0x00000000
baseAddrHigh = 0x00000000
lengthLow    = 0x0009fc00
lengthHigh   = 0x00000000
type         = 0x00000001
になるはずなんだけど、こんな感じに実際にはずれる。
baseAddrLow  = 0x00000000
baseAddrHigh = 0x00000000
lengthLow    = 0x00000000
lengthHigh   = 0x00000000
type         = 0x0009fc00
感じとしては、20バイト取得できてないといけないのだが、12バイトしか取れてない感じ。なぜ?
これが普通の動作なのかなと思い、ちょっと実験してみた。
#include 

struct sample
{
    unsigned int val1;
    unsigned int val2;
    unsigned int val3;
    unsigned int val4;
    unsigned int val5;
};

void* getsample()
{
    static int *addr = (int*)0x404030;
    addr[0] = 0x00000000;
    addr[1] = 0x00000000;
    addr[2] = 0x00000000;
    addr[3] = 0x0009fc00;
    addr[4] = 0x00000001;
    return addr;
}

int main()
{
    sample *s = (sample*)getsample();
    printf("addr: %x\n", s);
    printf("%x, %x, %x, %x, %d\n", s[0].val1, s[0].val2, s[0].val3, s[0].val4, s[0].val5);
    return 0;
}
こんなむちゃくちゃなコードでもなんか動いてるから不思議。
っで、結果は普通に予定通りの値が取れていた。
コンパイラの最適化が効いてるからなのか(何もオプションつけてないけど)、別の要因で直にアドレスから取るのとは違うのかよく分からん。

何より腹が立つのは、以前はまともに動いていたのだ!ページングの実装を終えたらおかしくなった・・・
関係があるのかな、やっぱり・・・

2010/01/17 追記

原因が分かった。
結論: まともに動いていました。
原因: VGAクラスで実装していたprintfメソッドの不具合。
64ビットの数値には%xの書式指定子が対応しておりません・・・
参考にしている人はいないと思うが、
64ビットの整数値を表示したいのに、可変引数のポインタを進める際に(int*)のポインタでやっとりました。つまり、8バイト移動させないといけないところを、4バイトしか進めていなかったっと。
これで2時間悩んだ。printfデバッグの限界やね。と勝手に納得・・・

No comments:

Post a Comment