Each stack frame consists of three parts: arguments, return address, and locals, in the order larger to smaller address. In the following, we are going to inspect the assembly to verify it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int h(int b1)
{
return 1;
}

int g(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
int z = 0;
h(a1);
return 1;
}

int f()
{
return g(1, 2, 3, 4, 5, 6, 7);
}

Get the assembly using clang -c -S test.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
h:                                      # @h
.cfi_startproc
# BB#0:
pushq %rbp
.Lcfi0:
.cfi_def_cfa_offset 16
.Lcfi1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Lcfi2:
.cfi_def_cfa_register %rbp
movl $1, %eax
movl %edi, -4(%rbp)
popq %rbp
retq
.Lfunc_end0:
.size h, .Lfunc_end0-h
.cfi_endproc

.globl g
.p2align 4, 0x90
.type g,@function
g: # @g
.cfi_startproc
# BB#0:
pushq %rbp
.Lcfi3:
.cfi_def_cfa_offset 16
.Lcfi4:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Lcfi5:
.cfi_def_cfa_register %rbp
subq $48, %rsp
movl 16(%rbp), %eax
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl %edx, -12(%rbp)
movl %ecx, -16(%rbp)
movl %r8d, -20(%rbp)
movl %r9d, -24(%rbp)
movl %eax, -28(%rbp)
movl $0, -32(%rbp)
movl -4(%rbp), %edi
callq h
movl $1, %ecx
movl %eax, -36(%rbp) # 4-byte Spill
movl %ecx, %eax
addq $48, %rsp
popq %rbp
retq
.Lfunc_end1:
.size g, .Lfunc_end1-g
.cfi_endproc

.globl f
.p2align 4, 0x90
.type f,@function
f: # @f
.cfi_startproc
# BB#0:
pushq %rbp
.Lcfi6:
.cfi_def_cfa_offset 16
.Lcfi7:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Lcfi8:
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $1, %edi
movl $2, %esi
movl $3, %edx
movl $4, %ecx
movl $5, %r8d
movl $6, %r9d
movl $7, %eax
movl $7, (%rsp)
movl %eax, -4(%rbp) # 4-byte Spill
callq g
addq $16, %rsp
popq %rbp
retq
.Lfunc_end2:
.size f, .Lfunc_end2-f
.cfi_endproc


.ident "clang version 4.0.1-svn305187-1~exp1 (branches/release_40)"
.section ".note.GNU-stack","",@progbits

The stack frame in memory would look something like (smaller address at top):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
------------------------g stack frame end---------------------------
z = 0 <--- local variables
a7
a6
a5
a4
a3
a2
a1
rbp
return addr <--- auto placed return address from `callq`
7 <--- seventh argument
------------------------g stack frame start---------------------------
eax
rbp