Reputation: 189
C code:
long vframe(long n, long idx, long *q) {
long i;
long *p[n];
p[0] = &i;
for (i = 1; i < n; i++)
p[i] = q;
return *p[idx];
}
Portions of generated assembly code:
long vframe(long n, long idx, long *q)
n in %rdi, idx in %rsi, q in %rdx
Only portions of code shown
vframe:
pushq %rbp Save old %rbp
movq %rsp, %rbp Set frame pointer
subq $16, %rsp Allocate space for i (%rsp = s1)
leaq 22(,%rdi,8), %rax
andq $-16, %rax
subq %rax, %rsp Allocate space for array p (%rsp = s2)
leaq 7(%rsp), %rax
shrq $3, %rax
leaq 0(,%rax,8), %r8 Set %r8 to &p[0]
movq %r8, %rcx Set %rcx to &p[0] (%rcx = p)
...
Code for initialization loop
i in %rax and on stack, n in %rdi, p in %rcx, q in %rdx
.L3: loop:
movq %rdx, (%rcx,%rax,8) Set p[i] to q
addq $1, %rax Increment i
movq %rax, -8(%rbp) Store on stack
.L2:
movq -8(%rbp), %rax Retrieve i from stack
cmpq %rdi, %rax Compare i:n
jl .L3 If <, goto loop
...
Code for function exit
leave Restore %rbp and %rsp
ret Return
In the book the author says:
The leaq
instruction in
leaq 22(,%rdi,8), %rax
computes the value 8n + 22
, which is then rounded down to the nearest multiple of 16
by the andq
instruction in
andq $-16, %rax
The resulting value will be 8n + 8
when n
is odd and 8n + 16
when n
is even, and this value is subtracted from s1
to give s2
.
What puzzles me is 8n + 22
. why must it be 22
, not 16, 17, 18, 19, 20, 21, 23
?
Upvotes: 3
Views: 442
Reputation: 31
I also have this problem when I read here now.
and I try to complie the source code by clang
with command:
clang -Og -S source.c -o source.s
in both platform ubuntu18.04 and windows 10,
the assembly file shows:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rsp, %r8
movq %rsp, %r9
leaq 15(,%rdi,8), %r10
andq $-16, %r10
movq %r9, %rax
...
clang
choose 15 even not from 16 to 23,
I read The x86-64 psABI version 1.0,
in section 3.2.2 The Stack Frame
:
The end of the input argument area shall be aligned on a 16 (32 or 64, if __m256 or __m512 is passed on stack) byte boundary. In other words, the value (%rsp + 8) is always a multiple of 16 (32 or 64) when control is transferred to the function entry point. The stack pointer, %rsp, always points to the end of the latest allocated stack frame.
so I think the number is 22
or 15
is not important thing,
the number just leads to the size of e1
and e2
clang
choose 15
, then when n
is even, e1
and e2
will be less than gcc
version,
the key point is to guard 16 bytes align for the end of a stack frame,
or the value of s2 - s1
in a variable-size stack frame.
Upvotes: 2