在这个答案:https://stackoverflow.com/a/8646611/192359中,解释了在调试x86代码时,即使使用FPO(帧指针省略),符号也允许调试器显示调用栈。
给出的解释是:
在x86上,PDB包含FPO信息,允许调试器可靠地展开调用堆栈。
我的问题是这些信息是什么?据我所知,只知道函数是否具有FPO并不能帮助您找到堆栈指针的原始值,因为这取决于运行时信息。
我在这里缺少什么?
答案 0 :(得分:3)
从根本上说,总是可以使用足够的信息 1 来遍历堆栈,除非堆栈或执行上下文已被不可挽回地损坏。
例如,即使rbp
未用作帧指针,返回地址仍然在堆栈的某处,您只需要知道在哪里。对于不在函数体中修改rsp
(间接或直接)的函数,它将处于与rsp
的简单固定偏移处。对于在函数体中修改rsp
的函数(即具有可变堆栈大小的函数),rsp
的偏移量可能取决于函数中的确切位置。
PDB文件只包含这个“边带”信息,允许某人确定函数中任何指令的返回地址。 Hans链接了相关的内存中结构above - 您可以看到,因为它知道局部变量的大小等等,它可以计算rsp
和帧的基数之间的偏移量,因此到达返回地址。它还知道有多少指令字节是“prolog”的一部分,这很重要,因为如果IP仍在该区域中,则应用不同的规则(即,尚未调整堆栈以反映此函数中的本地)。
在64位Windows中,确切的函数调用ABI已经变得更加具体,而所有函数通常必须提供展开信息:不是.pdb
而是直接在.pdb
包含在二进制文件中的部分。因此,即使没有exit()
文件,您也应该能够展开结构合理的64位Windows程序。它允许任何寄存器用作帧指针,并且仍然允许帧指针省略(有一些限制)。有关详细信息,请start here。
1 如果不是这样,问问自己当前运行的函数如何返回?现在,技术上你可以设计一个程序,它以无法返回的方式破坏或忘记堆栈,并且永远不会退出或使用abort()
或//Main upate
public void update(float delta) {
updateFriction();
}
//Movements and Subclasses of them
public void accelerate() {
//find current speed in forward direction
Vector2 currentForwardNormal = ship.getWorldVector(new Vector2(0,1));
float currentSpeed = getForwardVelocity().dot(currentForwardNormal);
//apply necessary force
float force = 0;
if(maxSpeed > currentSpeed) {
force = maxDriveForce;
} else {
force = -maxDriveForce;
}
System.out.println("Current Speed: "+currentSpeed);
System.out.println("Current Forward Normal: "+currentForwardNormal);
ship.applyForceToCenter(currentForwardNormal.scl(force),true);
}
public void rotate(boolean direction) { //true for Up and false for Down
if(direction) {
//torques
}
}
private void updateFriction() {
Vector2 impulse = getLateralVelocity().scl(-ship.getMass());
ship.applyLinearImpulse(impulse, ship.getWorldCenter(), true);
ship.applyAngularImpulse(0.1f * ship.getInertia() * -ship.getAngularVelocity(),true);
}
private Vector2 getLateralVelocity() {
Vector2 currentRightNormal = ship.getWorldVector(new Vector2(1,0));
return currentRightNormal.scl(currentRightNormal.dot(ship.getLinearVelocity()));
}
private Vector2 getForwardVelocity() {
Vector2 currentRightNormal = ship.getWorldVector(new Vector2(0,1));
return currentRightNormal.scl(currentRightNormal.dot(ship.getLinearVelocity()));
}
之类的方法来终止。这是非常不寻常的,不可能在组装之外。