[C言語] メモリのスタック領域

void test_function(int a, int b, int c, int d){
    int flag;
    char buffer[10];

    flag = 31337;
    buffer[0] = 'A';
}

int main() {
    test_function(1, 2, 3, 4);
    return 0;
}

$ gcc -g main.c
$ gdb -q ./a.out
Reading symbols from ./a.out…
(gdb) disass main
Dump of assembler code for function main:
0x000000000000087c <+0>: stp x29, x30, [sp, #-16]!
0x0000000000000880 <+4>: mov x29, sp
0x0000000000000884 <+8>: mov w3, #0x4 // #4
0x0000000000000888 <+12>: mov w2, #0x3 // #3
0x000000000000088c <+16>: mov w1, #0x2 // #2
0x0000000000000890 <+20>: mov w0, #0x1 // #1
0x0000000000000894 <+24>: bl 0x814
0x0000000000000898 <+28>: mov w0, #0x0 // #0
0x000000000000089c <+32>: ldp x29, x30, [sp], #16
0x00000000000008a0 <+36>: ret
End of assembler dump.

(gdb) disass test_function
Dump of assembler code for function test_function:
0x0000000000000814 <+0>: stp x29, x30, [sp, #-64]!
0x0000000000000818 <+4>: mov x29, sp
0x000000000000081c <+8>: str w0, [sp, #28]
0x0000000000000820 <+12>: str w1, [sp, #24]
0x0000000000000824 <+16>: str w2, [sp, #20]
0x0000000000000828 <+20>: str w3, [sp, #16]
0x000000000000082c <+24>: adrp x0, 0x10000
0x0000000000000830 <+28>: ldr x0, [x0, #4072]
0x0000000000000834 <+32>: ldr x1, [x0]
0x0000000000000838 <+36>: str x1, [sp, #56]
0x000000000000083c <+40>: mov x1, #0x0 // #0
0x0000000000000840 <+44>: mov w0, #0x7a69 // #31337
0x0000000000000844 <+48>: str w0, [sp, #36]
–Type for more, q to quit, c to continue without paging–
0x0000000000000848 <+52>: mov w0, #0x41 // #65
0x000000000000084c <+56>: strb w0, [sp, #40]
0x0000000000000850 <+60>: nop
0x0000000000000854 <+64>: adrp x0, 0x10000
0x0000000000000858 <+68>: ldr x0, [x0, #4072]
0x000000000000085c <+72>: ldr x2, [sp, #56]
0x0000000000000860 <+76>: ldr x1, [x0]
0x0000000000000864 <+80>: subs x2, x2, x1
0x0000000000000868 <+84>: mov x1, #0x0 // #0
0x000000000000086c <+88>: b.eq 0x874 // b.none
0x0000000000000870 <+92>: bl 0x6a0 <__stack_chk_fail@plt>
0x0000000000000874 <+96>: ldp x29, x30, [sp], #64
0x0000000000000878 <+100>: ret
End of assembler dump.

4, 3, 2, 1はスタックフレームにpushされる

(gdb) list main
6
7 flag = 31337;
8 buffer[0] = ‘A’;
9 }
10
11 int main() {
12 test_function(1, 2, 3, 4);
13 return 0;
14 }
(gdb) break 12
Breakpoint 1 at 0x884: file main.c, line 12.
(gdb) break test_function
Breakpoint 2 at 0x82c: file main.c, line 3.
(gdb) run
Starting program: /home/vagrant/dev/c/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/aarch64-linux-gnu/libthread_db.so.1”.

Breakpoint 1, main () at main.c:12
12 test_function(1, 2, 3, 4);

メモリ中の各セグメントは、低位アドレスから高位アドレスへ向かって並べられていく

– 低位アドレス
テキスト(コード)セグメント
データセグメント
bssセグメント
ヒープセグメント
スタックセグメント
– 高位アドレス

### メモリセグメント

int global_var;
int global_initialized_var = 5;

void function() {
    int stack_var;

    printf("function()のstack_varは、アドレス0x%08xにあります。\n", &stack_var);
}

int main() {
    int stack_var;
    static int static_initialized_var = 5;
    static int static_var;
    int *heap_var_ptr;

    heap_var_ptr = (int *)malloc(4);

    // データセグメントに確保される
    printf("global_initialized_varはアドレス0x%08xにあります。\n", &global_initialized_var);
    printf("static_initialized_varはアドレス0x%08xにあります。\n", &static_initialized_var);

    // bssセグメントに確保される
    printf("static_varはアドレス0x%08xにあります。\n", &static_var);
    printf("global_varはアドレス0x%08xにあります。\n", &global_var);

    // ポインタ変数はヒープセグメント内に確保される
    printf("heap_var_ptrはアドレス0x%08xにあります。\n", heap_var_ptr);

    // 以下の変数はスタックセグメント内に確保される
    printf("stack_varはアドレス0x%08xにあります。\n", &stack_var);

    return 0;
}

$ ./a.out
global_initialized_varはアドレス0xc5b21010にあります。
static_initialized_varはアドレス0xc5b21014にあります。
static_varはアドレス0xc5b21020にあります。
global_varはアドレス0xc5b2101cにあります。
heap_var_ptrはアドレス0xefedb2a0にあります。
stack_varはアドレス0xecf4957cにあります。