0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アセンブリ言語に於けるポインタ及び配列の取り扱いの差異を比較 第1回

Last updated at Posted at 2025-04-07

今回は以下のC言語プログラムをアセンブリ言語に変換し参照の違いを見ていきます。
※標準関数を使用していない為、.hファイルは一切読み込んでおりません。

compare.c
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

得られたコードは以下の通りです。(適宜注釈を施しております)

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)

後書
初日投稿です。
良く分からないままに投稿したので改善点があればご指摘頂けると助かります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?