電気ひつじ牧場

技術メモ

構造体を逆アセンブルして中身を見る

個人的に確認したいことがあって、ついでにメモとしてまとめておきます。


struct_sample.c
#include 
int main(){
    struct person {
        int age;
        char *name;
    };
    
    struct person p1;
    p1.age = 20;
    p1.name = "chashu";
    return 0;
}

コンパイル

$ gcc -g -m32 -o struct_sample struct_sample.c

アセンブル

$ objdump -S struct_test 

objdumpのオプションは-dが一般的かもしれないですが-Sを指定するとアセンブリの中にコードも表示してくれます
intel記法が好みなら-M intelで指定できます。

080483db 
: #include int main(){ 80483db: 55 push %ebp 80483dc: 89 e5 mov %esp,%ebp 80483de: 83 ec 10 sub $0x10,%esp int age; char *name; }; struct person p1; p1.age = 20; 80483e1: c7 45 f8 14 00 00 00 movl $0x14,-0x8(%ebp) p1.name = "chashu"; 80483e8: c7 45 fc 80 84 04 08 movl $0x8048480,-0x4(%ebp) return 0; 80483ef: b8 00 00 00 00 mov $0x0,%eax } 80483f4: c9 leave 80483f5: c3 ret

main関数部分です。

80483de:	83 ec 10             	sub    $0x10,%esp

スタックを0x10バイト確保しています。int(4バイト)、charポインタ(4バイト)なので計算が合いませんが多分余分に確保しているのでしょう。

    p1.age = 20;
 80483e1:	c7 45 f8 14 00 00 00 	movl   $0x14,-0x8(%ebp)
    p1.name = "chashu";
 80483e8:	c7 45 fc 80 84 04 08 	movl   $0x8048480,-0x4(%ebp)

$ebp-0x8にp1.age, $ebp-0x4にp1.nameが配置されてますね。構造体に定義されている順番通りにメモリの低位アドレスから配置されます。

続いてgdbでp1.age = 20;をした直後のp1.ageがあるメモリを確認して見ます。

gdb-peda$ x/4b $ebp-0x8
0xffffcfe0:	0x14	0x00	0x00	0x00

表示されている4バイトがp1.ageです。本来は0x00000014なのに1バイトを1かたまりとして逆順になっています。リトルエンディアンというやつです。
$ebp-0x8のようなアドレスがオペランドとして指定された時は、そのアドレスにある値から4バイト先のアドレスまでの値を取得して、逆順に並べて解釈するという処理がされています。
今回は何バイト先まで取得するかはオペコード次第です。

まとめ

・構造体のメンバは定義されている順番通りにメモリの低位アドレスから配置される。
・各メンバの値はリトルエンディアンで配置されている。(もちろんプロセッサに依存します)