gpt4 book ai didi

c - 如何计算我的 frameCount 函数中的堆栈帧数?

转载 作者:行者123 更新时间:2023-12-04 00:14:15 24 4
gpt4 key购买 nike

我有汇编代码,由 frameCount 调用,需要返回 frameCount,但不确定如何检索(然后导航)前一帧的指针引用。

getFP.s

  .globl getFP
getFP:
movq %rbp, %rax
ret

frameCount.c

int frameCount() {
int count = 0;
uint64_t fp = getFP();
uint64_t *sp = &fp;

// how do I get the pointer/offset to pointer to the previous stack frame from here?

return count;
}

更新:

我已更新 frameCount 函数以包含一个遍历堆栈帧链表的循环,但在调用 frameCount 时出现段错误。

main.c

#include <stdio.h>
#include <inttypes.h>
#include "framecount.c"

int main() {
printf("Number of Frames: %d\n", frameCount());

return(0);
}

frameCount.c

#include <stdio.h>
#include <inttypes.h>

uint64_t* getFP();

int frameCount() {
uint64_t* fp = getFP();
uint64_t registerValue1 = *fp;

while (registerValue1 != 0) {
printf("current register value %" PRIx64 "\n", registerValue1);
printf("next register value %" PRIx64 "\n", *(volatile uint64_t *)registerValue1);
count++;
registerValue1 = *(volatile uint64_t *)registerValue1;
}

printf("count=%d\n", count);

return count;
}

输出

current register value 7ffca7c147b0
next register value 401230
current register value 401230
next register value 8d4c5741fa1e0ff3
current register value 8d4c5741fa1e0ff3
Segmentation fault (core dumped)

但是,当我执行以下操作时,我没有遇到段错误,但计数似乎不正确:(更新:删除虚假示例)

更新 2:

即使使用选项 -O0-fno-omit-frame-pointer 运行时仍然出现段错误,这是初始第一次更新的程序集输出:

    .file   "lab7.c"
.text
.section .rodata
.LC0:
.string "%d"
.text
.globl frameCount
.type frameCount, @function
frameCount:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl $0, -4(%rbp)
movl $0, %eax
call getFP
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movq (%rax), %rax
movq %rax, -16(%rbp)
jmp .L2
.L3:
addl $1, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -16(%rbp), %rax
movq (%rax), %rax
movq %rax, -16(%rbp)
.L2:
cmpq $0, -16(%rbp)
jne .L3
movl -4(%rbp), %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size frameCount, .-frameCount
.section .rodata
.LC1:
.string "Number of Frames: %d\n"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, %eax
call frameCount
movl %eax, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (GNU) 10.2.1 20200723 (Red Hat 10.2.1-1)"
.section .note.GNU-stack,"",@progbits

最佳答案

一般来说,这种技术是行不通的。只有在编译器实际使用它们的情况下,这样的遍历堆栈帧才是可能的。在 Linux 和类似操作系统下的 x86-64 上,这不是 ABI 所要求的,并且在启用优化时不是大多数编译器的默认设置,但在 GCC 和 clang 上,您可以使用 -fno-omit-frame 请求它-指针。但是,如果调用链中的某些函数在调用下一个函数时将 %rbp 用于其他用途,则存储的 %rbp 将不会指向前一个,并且您的程序可能会崩溃。有另一种方法可以使用存储在内存中其他位置的展开信息来遍历堆栈,但它很复杂,所以人们经常使用像 libbacktrace 这样的库。而是。

但是,当使用堆栈帧时:您可以查看 how a compiler sets them up :

    pushq   %rbp
movq %rsp, %rbp

由于 x86 push 指令将 %rsp 递减,然后将推送的值存储在 %rsp 指向的新地址,因此 >movq %rsp, %rbp 留下 %rbp 包含存储前一个 %rbp 的地址。堆栈帧顶部的 %rbp 值为 0,因此您可以简单地执行类似

的操作
for (uint64_t *fp = getFP(); fp; fp = (uint64_t *)*fp) count++;

关于c - 如何计算我的 frameCount 函数中的堆栈帧数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65028444/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com