简体   繁体   中英

Printing Stack Frames

So I am currently learning about stack frames, and I wanted to experiment printing the stack frame (manually) of a function.

I have the following picture in mind of a stack frame (I may be wrong):

|                                |  0xffff0fdc
+--------------------------------+
|              ...               |  0xffff0fd8
+--------------------------------+
|           parameter 2          |  0xffff0fd4
+--------------------------------+
|           parameter 1          |  0xffff0fd0
+--------------------------------+
|         return address         |  0xffff0fcc
+--------------------------------+
|        local variable 2        |  0xffff0fc8
+--------------------------------+
|        local variable 1        |  0xffff0fc4
+--------------------------------+

thus I first wrote this function to achieve the above result and print it :

void func(int a,int b)
{
    uint64_t loc = 0;
    uint64_t *sp = &loc;

    printf("%" PRIu64 "\n",*(sp));
    printf("%" PRIu64 "\n",*(sp+4));
    printf("%" PRIu64 "\n",*(sp+8));
    printf("%" PRIu64 "\n",*(sp+12));
}

int main()
{
    func(2,3);
    return 0;
}

and I get :

0

12884901890

51266344552759297

18034967110614932

definitely not what was expected

I also tried "scanning" through the stack to find one of the argument :

while (*sp != a) sp++

without much success. What is wrong with my method ?


I also had another question : Given a recursive function, take simply factorial(int n), how could we spot the address where the base pointer is located in the stack ?


in case you need the assembly code : Note that this only contains the function "func" generated assembly code. I added comments to where the assembly code relates to the source code.

                    pushq   %rbp
                    .cfi_def_cfa_offset 16
                    .cfi_offset 6, -16
                    movq    %rsp, %rbp
                    .cfi_def_cfa_register 6
                    subq    $32, %rsp
                    movl    %edi, -20(%rbp)
                    movl    %esi, -24(%rbp)

                   ***// uint64_t loc = 0;***

                    movq    $0, -16(%rbp)

                   ***// uint64_t *sp = &loc;***

                    leaq    -16(%rbp), %rax
                    movq    %rax, -8(%rbp)

                  ***// printf("%" PRIu64 "\n",*sp);***

                    movq    -8(%rbp), %rax
                    movq    (%rax), %rax
                    movq    %rax, %rsi
                    movl    $.LC0, %edi

                    movl    $0, %eax

                    call    printf

                    ***printf("%" PRIu64 "\n",*(sp+8));***

                    movq    -8(%rbp), %rax
                    addq    $64, %rax
                    movq    (%rax), %rax
                    movq    %rax, %rsi
                    movl    $.LC0, %edi

                    movl    $0, %eax

                    call    printf

                    ***// printf("%" PRIu64 "\n",*(sp+16));***

                    movq    -8(%rbp), %rax
                    subq    $-128, %rax
                    movq    (%rax), %rax
                    movq    %rax, %rsi
                    movl    $.LC0, %edi

                    movl    $0, %eax

                    call    printf

                   ***// printf("%" PRIu64 "\n",*(sp+32));***

                    movq    -8(%rbp), %rax
                    addq    $256, %rax

                    movq    (%rax), %rax
                    movq    %rax, %rsi
                    movl    $.LC0, %edi

                    movl    $0, %eax

                    call    printf

                    leave
                    .cfi_def_cfa 7, 8
                    ret

Any advices to help me undertand the stack better would be greatly appreciated!

PS : I am not allowed to use any external functions

x86-64 does not pass the first few arguments on the stack (type permitting) so you have no chance to print those. Also, the actual stack layout for the locals depends on compiler and settings.

Since you have provided the assembly code, we can examine the layout which looks like this:

        return address
rbp     saved rbp
rbp-8   local variable "sp"
rbp-16  local variable "loc"
rbp-20  local copy of argument "a"
rbp-24  local copy of argument "b"

Also note that a and b are 4 bytes, the rest are 8. Furthermore, C pointer arithmetic scales by item size, so *(sp+4) goes 4 * 8 = 32 bytes not 4 as you probably intended.

If the stack layout is unchanged, you can use this code as illustration:

#include <stdio.h>
#include <stdint.h>
int main();
void func(int a,int b)
{
    uint64_t loc = 0;
    char *sp = (char*)&loc;

    printf("main = %p\n", main);
    printf("return address = %p\n", *(void**)(sp + 24));
    printf("saved rbp = %p\n", *(void**)(sp + 16));
    printf("sp = %p\n", *(void**)(sp + 8));
    printf("loc = %lld\n", *(uint64_t*)(sp));
    printf("a = %d\n", *(int*)(sp - 4));
    printf("b = %d\n", *(int*)(sp - 8));
}

int main()
{
    func(2,3);
    return 0;
}

Sample output:

main = 0x4005e6
return address = 0x4005f9
saved rbp = 0x7ffe057bf240
sp = 0x7ffe057bf220
loc = 0
a = 2
b = 3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM