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
转载注意标注出处:
转自Cold_Chair的博客+原博客地址