今回は以下のC言語プログラムをアセンブリ言語に変換し参照の違いを見ていきます。
※標準関数を使用していない為、.hファイルは一切読み込んでおりません。
void compare() {
int arr[3] = {10, 20, 30};
int *ptr = arr;
arr[0] = 100; // 配列
ptr[1] = 200; // ポインタ
*(ptr + 2) = 300; // ポインタ
}
cmd上にて以下の命令を実行しアセンブリ言語へと変換します。
gcc -S compare.c -masm=intel -o compare.asm
得られたコードは以下の通りです。(適宜注釈を施しております)
.file "compare.c"
.intel_syntax noprefix
.text
.globl compare
.def compare; .scl 2; .type 32; .endef
.seh_proc compare
; 関数入口
compare:
push rbp
.seh_pushreg rbp
mov rbp, rsp
.seh_setframe rbp, 0
sub rsp, 32
.seh_stackalloc 32
.seh_endprologue
; 数列の初期化 arr[3] = {10, 20, 30}
mov DWORD PTR -20[rbp], 10
mov DWORD PTR -16[rbp], 20
mov DWORD PTR -12[rbp], 30
; ポインタの初期化 ptr = arr
lea rax, -20[rbp]
mov QWORD PTR -8[rbp], rax
; arr[0] = 100
mov DWORD PTR -20[rbp], 100
; ptr[1] = 200
mov rax, QWORD PTR -8[rbp]
add rax, 4
mov DWORD PTR [rax], 200
; *(ptr + 2) = 300
mov rax, QWORD PTR -8[rbp]
add rax, 8
mov DWORD PTR [rax], 300
nop
add rsp, 32
pop rbp
ret
.seh_endproc
.ident "GCC: (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r3) 14.2.0"
各変数のメモリ分布
変数 | メモリ上の場所 |
---|---|
ptr | [rbp - 8] (8バイト) |
arr[2] | [rbp - 12] (4バイト) |
arr[1] | [rbp – 16] (4バイト) |
arr[0] | [rbp – 20] (4バイト) |
※intを4バイトとした場合。
arr[0] = 100;
mov DWORD PTR -20[rbp], 100
配列を使用した場合は直接メモリ上の場所を指定して値を入れている。
ptr[1] = 200;
mov rax, QWORD PTR -8[rbp]
add rax, 4
mov DWORD PTR [rax], 200
ポインタを使用した場合はptr変数の値を読み込んでからptr[1]の値を変更している。
*(ptr + 2) = 300;
mov rax, QWORD PTR -8[rbp]
add rax, 8
mov DWORD PTR [rax], 300
ptr[1] = 200;と同様。
*(ptr + 2)とptr[2]は書き方が違うだけで同義である。
arr[0]とptr[1]は書き方は似ているが、配列とポインタで異なりアセンブリ言語上での処理も異なっている。
発見
以下のコードを見てなぜint *ptrで宣言したポインタ変数の大きさが4バイトではなく8バイトになっているのか不思議に思いましたが、ポインタ変数はその型に拘らず32ビットの場合は4バイト、64ビットの場合は8ビット固定の用です。
ポインタ変数は値そのものではなくアドレスを入れる変数なので考えてみれば当たり前なのですが、今更気づきました。
mov QWORD PTR -8[rbp], rax
sizeof()を使用して確かめて見ましたが結果は全て8バイトとなりました。
int *ptr_int;
char *ptr_char;
double *ptr_double;
printf("Size of int*: %zu bytes\n", sizeof(ptr_int));
printf("Size of char*: %zu bytes\n", sizeof(ptr_char));
printf("Size of double*: %zu bytes\n", sizeof(ptr_double));
筆者の環境
windows10 Version 10.0.19045.5608
gcc version 14.2.0 (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r3)
後書
初日投稿です。
良く分からないままに投稿したので改善点があればご指摘頂けると助かります。