gpt4 book ai didi

c - GCC 计算 goto 和堆栈指针的值

转载 作者:太空狗 更新时间:2023-10-29 16:47:58 24 4
gpt4 key购买 nike

在 GCC 中,您可以通过获取标签的地址(如 void *addr = &&label)然后跳转到它(跳转*地址)。 GCC manual说你可以从函数的任何地方跳转到这个地址,只是从另一个函数跳转到它是未定义的。

当您跳转到代码时,它无法假设任何有关寄存器值的信息,因此大概是从内存中重新加载它们。然而,堆栈指针的值也不一定定义,例如,您可以从声明额外变量的嵌套范围跳转。

问题是 GCC 如何设法将堆栈指针的值设置为正确的值(它可能太高或太低)?这如何与 -fomit-frame-pointer 交互(如果有)?

最后,为了加分,你可以从哪里跳转到标签的真正限制是什么?例如,您可能可以从中断处理程序中执行此操作。

最佳答案

一般来说,当你有一个带有地址被获取的标签的函数时,gcc 需要确保你可以从函数中的任何间接 goto 跳转到那个标签——所以它需要布局堆栈以便确切的堆栈指针无关紧要(所有内容都从帧指针中索引),或者堆栈指针在所有这些指针中都是一致的。通常,这意味着它在函数启动时分配固定数量的堆栈空间,并且之后永远不会触及堆栈指针。因此,如果您有带变量的内部作用域,则空间将在函数开始时分配并在函数结束时释放,而不是在内部作用域中。只有构造函数和析构函数(如果有的话)需要绑定(bind)到内部范围。

跳转到标签的唯一限制是您注意到的标签——您只能在包含标签的函数中执行此操作。不是来自任何其他函数或中断处理程序或任何东西的任何其他堆栈帧。

编辑

如果您希望能够从一个堆栈帧跳转到另一个堆栈帧,您需要使用 setjmp/longjmp 或类似的东西来展开堆栈。您可以将其与间接 goto 相结合——类似于:

if (target = (void *)setjmp(jmpbuf)) goto *target;

这样您就可以从任何调用的函数调用 longjmp(jmpbuf, label_address); 来展开堆栈,然后跳转到标签。只要 setjmp/longjmp 在中断处理程序中工作,这也将在中断处理程序中工作。还取决于 sizeof(int) == sizeof(void *),但情况并非总是如此。

关于c - GCC 计算 goto 和堆栈指针的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12392454/

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