OS 作业3 print_stackframe()

操作系统环境:Linux(X86-64)
特权级:用户态
编程语言:C
参考:https://www.cnblogs.com/whileskies/p/13427861.html

写个递归看看汇编怎么跑的(参数这么多是为了用到栈):

void  dg(int x, int x2, int x3, int x4, int x5, int x6, int x7, int x8) {
    if (x == 10) {
        print_stackframe();
        printf("%d\n", x);
        return;
    }
    dg(x + 1, x2 + 1, x3 + 1, x4 + 1, x5 + 1, x6 + 1, x7 + 1, x8 + 1);
}
int main() {
    dg(1, 1, 1, 1, 1, 1, 1, 1);
    return 0;
}
dg:
.LFB3:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$32, %rsp
	movl	%edi, -4(%rbp)
	movl	%esi, -8(%rbp)
	movl	%edx, -12(%rbp)
	movl	%ecx, -16(%rbp)
	movl	%r8d, -20(%rbp)
	movl	%r9d, -24(%rbp)
	cmpl	$10, -4(%rbp)
	jne	.L13
	call	print_stackframe
	movl	-4(%rbp), %eax
	movl	%eax, %esi
	leaq	.LC3(%rip), %rdi
	movl	$0, %eax
	call	printf@PLT
	jmp	.L12
.L13:
	movl	24(%rbp), %eax
	leal	1(%rax), %r8d
	movl	16(%rbp), %eax
	leal	1(%rax), %edi
	movl	-24(%rbp), %eax
	leal	1(%rax), %r9d
	movl	-20(%rbp), %eax
	leal	1(%rax), %r10d
	movl	-16(%rbp), %eax
	leal	1(%rax), %ecx
	movl	-12(%rbp), %eax
	leal	1(%rax), %edx
	movl	-8(%rbp), %eax
	leal	1(%rax), %esi
	movl	-4(%rbp), %eax
	addl	$1, %eax
	pushq	%r8
	pushq	%rdi
	movl	%r10d, %r8d
	movl	%eax, %edi
	call	dg
	addq	$16, %rsp
.L12:
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE3:
	.size	dg, .-dg

发现函数调用过程

栈形如:

事实上可以用 %rbp 一直去回溯栈,
%rbp+8 就是 %rip
%rbp+16 开始就是传的参数

于是有

static uint64_t read_rbp(void) {
    uint64_t rbp = 0;
    asm volatile("movq %%rbp, %0" : "=r" (rbp));
    return rbp;
}

static uint64_t read_rip(void) {
    uint64_t rip = 0;
    asm volatile("movq 8(%%rbp), %0" : "=r" (rip));
    return rip;
}

#define STACKFRAME_DEPTH 500

static void print_stackframe(void) {
    uint64_t rbp = read_rbp();
    uint64_t rip = read_rip();
    for (int i = 0; i < STACKFRAME_DEPTH; i++) {
        printf("rbp : %016llx, rip : %016llx\n", rbp, rip);
        if (rbp == 0) break;
    
        printf("rbp:0x%016llx rip:0x%016llx \n", rbp, rip);

        printf("args:0x%08x 0x%08x\n",
                *(uint32_t *)(rbp + 16), *(uint32_t *)(rbp + 20));

        // print_debuginfo(rip - 1);
   
        rip = *(uint64_t *)(rbp + 8);
        rbp = *(uint64_t *)(rbp);
    }
    return;
}

输出:

rbp : 00007ffc963e8020, rip : 00005583469e219e
rbp:0x00007ffc963e8020 rip:0x00005583469e219e 
args:0x59613b00 0x00007f63
rbp : 00007ffc963e8050, rip : 00005583469e2214
rbp:0x00007ffc963e8050 rip:0x00005583469e2214 
args:0x00000000 0x00000000
rbp : 00007ffc963e8080, rip : 00005583469e2270
rbp:0x00007ffc963e8080 rip:0x00005583469e2270 
args:0x0000000a 0x00000000
rbp : 00007ffc963e80c0, rip : 00005583469e22c8
rbp:0x00007ffc963e80c0 rip:0x00005583469e22c8 
args:0x00000009 0x00000000
rbp : 00007ffc963e8100, rip : 00005583469e22c8
rbp:0x00007ffc963e8100 rip:0x00005583469e22c8 
args:0x00000008 0x00000000
rbp : 00007ffc963e8140, rip : 00005583469e22c8
rbp:0x00007ffc963e8140 rip:0x00005583469e22c8 
args:0x00000007 0x00000000
rbp : 00007ffc963e8180, rip : 00005583469e22c8
rbp:0x00007ffc963e8180 rip:0x00005583469e22c8 
args:0x00000006 0x00000000
rbp : 00007ffc963e81c0, rip : 00005583469e22c8
rbp:0x00007ffc963e81c0 rip:0x00005583469e22c8 
args:0x00000005 0x00000000
rbp : 00007ffc963e8200, rip : 00005583469e22c8
rbp:0x00007ffc963e8200 rip:0x00005583469e22c8 
args:0x00000004 0x00000000
rbp : 00007ffc963e8240, rip : 00005583469e22c8
rbp:0x00007ffc963e8240 rip:0x00005583469e22c8 
args:0x00000003 0x00000000
rbp : 00007ffc963e8280, rip : 00005583469e22c8
rbp:0x00007ffc963e8280 rip:0x00005583469e22c8 
args:0x00000002 0x00000000
rbp : 00007ffc963e82c0, rip : 00005583469e22c8
rbp:0x00007ffc963e82c0 rip:0x00005583469e22c8 
args:0x00000001 0x00000000
rbp : 00007ffc963e82e0, rip : 00005583469e22ff
rbp:0x00007ffc963e82e0 rip:0x00005583469e22ff 
args:0x59640620 0x00007f63
rbp : 0000000000000000, rip : 00007f6359433083
10

第一次是 printf_stackframe 这个函数
第二次是 dg 函数,但是还没有压栈,所以 args[0] 是初值 0
第三次是上一层 dg,压了一个 9+1=10
以此类推,
最下面应该 main 函数,
最后到 %rbp = 0

posted @ 2024-03-17 21:03  Cold_Chair  阅读(15)  评论(0编辑  收藏  举报