我正在查看一些编译器输出,当调用一个函数时,它通常会开始设置调用堆栈,如下所示:
private func randomProduct() -> String { // Return String, not Int
let myArray1 = ["Nintendo Classic Mini NES", "Microsoft Office 2016 Home and Business", "Rubie's Deluxe Muscle Chest Batman Child", "Giro Dime", "Varta Powersports AGM 12V 12Ah 512014010A514", "Pohl-Boskamp Gelomyrtol Forte", "Panasonic ES-LV9N-S803", "Traxxas X-Maxx (77076-4)", "GoPro HERO 4", "Bose Lifestyle 650", "WMF Function 4 Kochtopf-Set 4-teilig", "Microsoft Surface Book", "Hewlett-Packard HP Color LaserJet Pro M252dw (B4A22A)", "Apple iPhone 7", "X-lite X-403GT Elegance", "Denon AVR-X3300W", "Hasbro Spiel des Lebens Banking", "Avent SCD 630/26", "Ray-Ban Aviator Metal RB3025"]
return myArray1[Int(arc4random_uniform(UInt32(myArray1.count)))] // Remove the Int()
}
因此,我们将调用例程的基指针保存在堆栈中,向上移动我们自己的基指针,然后将几个寄存器的内容存储在堆栈中。然后在例程结束时将它们恢复为原始值,如下所示:
PUSH EBP
MOV EBP, ESP
PUSH EDI
PUSH ESI
PUSH EBX
到目前为止,这么好。但是,我注意到在一个例程中,设置调用堆栈的代码看起来有点不同。事实上,它看起来像这样:
LEA ESP, [EBP-0Ch]
POP EBX
POP ESI
POP EDI
POP EBP
RET
由于多种原因,这令人困惑。首先,方法结束代码与上面引用的另一种方法相同,特别是期望在堆栈上可以获得保存的EBP副本。
另一方面,如果我理解正确,IN AL, DX
PUSH EDI
PUSH ESI
PUSH EBX
命令会读入IN AL, DX
寄存器,该寄存器与AL
寄存器相同,因此下一个命令就在这里是
EAX
因为程序想要将它在堆栈上分配的一些东西归零。
问题:我想知道我在这里发生了什么,我不明白。被翻译为XOR EAX, EAX
的机器代码是单字节IN AL, DX
,而是一对指令
推动EBP
MOV EBP,ESP
将对应于三个字节EC
。反汇编程序是否以某种方式误读了这个?或者是依赖于我不理解的副作用的东西?
如果有人好奇,这个机器代码是由CLR的JIT编译器生成的,我用Visual Studio调试器查看它。这是C#中的最小复制:
55 88 EC
然而,请注意,这似乎是不确定的;有时我似乎得到class C {
string s = "";
public void f(string s) {
this.s = s;
}
}
版本,而有时候IN AL, DX
后跟PUSH EBP
。
编辑:我开始强烈怀疑反汇编程序错误 - 我只是在另一种情况下显示MOV EBP, ESP
(操作码IN AL, DX
)和两个内存中的前面字节是EC
。因此,反汇编程序可能只是对方法的切入点感到困惑。 (虽然我仍然希望了解 发生的原因!)
答案 0 :(得分:7)
听起来像是在使用VS2015。你的结论是正确的,它的调试引擎有一个很多的错误。是的,地址不对。不是唯一的问题,它不能正确恢复断点,你很容易在代码中看到INT3指令。当抖动重新生成代码并替换存根调用时,它无法正确刷新反汇编。你不能相信你看到的任何东西。
我建议您使用工具>选项>调试>常规并勾选“使用托管兼容模式”复选框。这迫使调试器使用较旧的调试引擎VS2010 vintage。它更稳定。
您将丢失此引擎的某些功能,例如返回值检查和64位编辑+继续。进行这种调试时不会错过。然而,您将看到假代码地址,这在以前一直很常见,因此所有CALL地址都是错误的,您无法轻松识别到CLR的调用。反复翻转引擎是一种解决方法,但当然是一个很大的烦恼。
这也没有奏效,我看到更新中没有任何改进。但毫无疑问,它们有一个很大的错误列表可以解决,VS2015在它完成之前就已经发布了。希望VS2017更好,我们很快就会发现。
答案 1 :(得分:2)