liu
liu

Reputation: 189

About Variable-Size Stack Frames, about the alignment of stack frame,an example from CSAPP

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

Answers (1)

froglu
froglu

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

Related Questions