- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在一个引用另一个二进制函数的项目中。为了获得上述功能,我需要通过模式匹配/扫描以编程方式找到它们。为了简化此过程,我在一个单独的项目中编译了部分代码,并在反汇编程序中比较两个项目之间的内容,以提取所需的字节信息以扫描功能。
但是,我碰到了VC++的优化正在阻碍某些事情的地步,我想知道是否有一种方法可以禁用每条指令或类似指令的特定优化。
例如,这是目标二进制文件的功能的一部分:
push ebp
mov ebp, esp
push ecx
push [ebp+arg_4]
push [ebp+arg_0]
call sub_00000000
add esp, 8
cmp dword ptr [eax+4], 3
push ebp
mov ebp, esp
push ecx
push [ebp+arg_4]
push [ebp+arg_0]
call sub_00000000
pop ecx
pop ecx
cmp dword ptr [eax+4], 3
最佳答案
I am working on a project that references another binaries functions. In order to obtain said functions, I need to find them programmatically via pattern matching/scanning.
I am wondering if there is a way to disable specific optimizations per-instruction or similar.
__cdecl
函数调用之后通过一系列
pop
或仅通过
add
将适当数量的字节分配给堆栈指针来清理堆栈。
pop
)时会更喜欢
/O1
来清理堆栈。如果有两个以上的参数,或者无论参数数量如何,都在优化速度(
/O2
)时,都将首选
add esp, x
。这适用于所有版本的Visual Studio(我明确测试了VS 6,VS 2005,VS 2008,VS 2010,VS 2013和VS 2015)。这实际上是很合理的。
pop
是1字节指令,而
add esp, x
是3字节指令。因此,只要您执行2个或更少的
pop
,即比
add
小1个字节。一旦执行了三个
pop
,它的大小与
add
相同,但是
add
会更快,所以会获胜。
push ebp
mov ebp, esp
/Oy-
)的情况下进行彻底放弃。
push ecx
push [ebp+arg_4]
push [ebp+arg_0]
call sub_00000000
ecx
在函数中有意义,则它可能是C++类的成员函数,该类遵循
__thiscall
调用约定,并在
this
中传递
ecx
指针。由于将
ecx
压入堆栈,因此您必须调用一个以类对象指针作为第三个参数的自由函数。就像是:
RetVal sub_00000000(int arg_0, int arg_4, CClass* pClass);
add esp, 8
pClass
作为其唯一参数的第二个函数。但是,就像我说的那样,即使MSVC知道它们是
const
,也不会重复使用已经被压入堆栈的参数。它总是从头开始,重新推送第二个函数调用的参数,因此您将看到类似以下内容:
push ebp ; \ prologue
mov ebp, esp ; / code
push esi ; preserve esi
mov esi, ecx ; make copy of ecx
push esi ; \
push [ebp+arg_4] ; | push parameters for 1st function call
push [ebp+arg_0] ; /
call sub_00000000
push esi ; push parameters for 2nd function call
call sub_00000001
add esp, 16 ; clean stack
...
struct Foo
{
bool Caller(int one, int two);
};
struct RetStruct
{
unsigned long lo;
unsigned long hi;
};
RetStruct* Callee(int one, int two, Foo* pFoo);
bool Foo::Caller(int one, int two)
{
return (Callee(one, two, this)->hi == 3);
}
/O1 /Oy-
在VS 2010(或更旧的版本)上对其进行编译(针对大小进行了优化,而没有忽略帧指针),我们得到:
push ebp
mov ebp, esp
push ecx
push DWORD PTR _two$[ebp]
push DWORD PTR _one$[ebp]
call Callee
xor ecx, ecx
add esp, 12
cmp DWORD PTR [eax+4], 3
...
xor ecx, ecx
,它看起来非常接近您的原始代码。好吧,除了我已经指出的有关如何仅从堆栈中清除8个字节没有任何意义的事情。
/O1
切换为
/O2
(即优化速度而不是大小),我们得到:
push ebp
mov ebp, esp
mov eax, DWORD PTR _two$[ebp]
push ecx
mov ecx, DWORD PTR _one$[ebp]
push eax
push ecx
call Callee
xor edx, edx
add esp, 12
cmp DWORD PTR [eax+4], 3
...
xor edx, edx
,改变的是值先被加载到寄存器中,然后被推送,而不是被推送到内存操作数。由于某种原因,MSVC认为这样做速度更快,因此值得增加代码大小。
/O1
和
/O2
获得相同的输出:
push ebp
mov ebp, esp
push ecx
push DWORD PTR _two$[ebp]
push DWORD PTR _one$[ebp]
call Callee
add esp, 12
cmp DWORD PTR [eax+4], 3
...
xor
。 :-)但真正重要的是,我们现在可以优化速度(
/O2
),以获得所需的堆栈清洁行为(
add
而不是
pop
+
pop
),而无需更改将参数压入堆栈的方式。
/O2 /Oy-
。尝试一下,看看它没有满足您的需求。
关于c++ - 我可以控制特定的VC++编译器优化吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44731590/
当应用程序启动时,您将从 ViewController(中间的那个)开始。从那里我在右边添加了 VC。当用户点击此 VC 上的按钮时,我希望该 View 消失(我目前只需将其框架更改为 900 即可实
我在 Xcode 7 中使用简单的主/详细信息分割 View 模板,并希望用户从具有主要类别的高级 Master VC 开始,然后选择一个并深入到各个项目 - 仍然在左侧- 然后当他们从第二个主 VC
我有一个名为“firstVC”的 View Controller 和另一个名为“secondVC”的 View Controller 。第二个 VC 将以模态方式呈现在第一个 VC 上,当用户按下第二
我被困在一个问题上,我有一个案例 我有一个父 VC 它有2个容器[childVC A, childVC B] API 正在调用 childVC (UIViewController) A 一旦 chil
我从呈现的 VC 导航到 VC(让我们调用 VC A)。在 VC A 中,我有一个容器 View ,它有一个 VC(让我们调用 VC B)。从 VC B 我提出了另一个 VC(我们称之为 VC C)。
我有一个主 VC(称为 VC A),它有一个子 VC(VC B)。当我点击 VC B 上的按钮时,我将其作为子 VC 关闭,但是一旦完成,我想实例化另一个 VC(VC C)。我通过在 VC B 上创建
我们正在寻求改变用户退出我们应用程序的方式。为了做到这一点,我们要关闭当前 VC 下面的所有 VC,并将另一个 VC 作为根 VC。现在我们正在这样做,我相信这不会从内存中消除下面的任何 VC。 le
我仅使用 segue 在我的应用程序中导航。 我只是想知道,如果我从 1st-VC 导航到 V2,再到 V3,然后再到 4th-VC,如何直接从 4th-VC 导航回 1st VC,而不返回到 V3、
最新的 Xcode/Swift/iOS。 我有一个主 VC(称为 StartVC),其中包含一个子 VC(称为 TopBarVC)via 和嵌入式 segue。子 VC 包含一个按钮,按下该按钮时,会
我试图将从 map 中获得的地址传递到我的其他 View Controller 中并保持相同的设置(即开关仍然打开) mapVC 名为 MapViewController,tableVC 名为 Add
我有一个嵌入在 navigationcontroller 中的 viewcontroller,它将另一个 viewcontroller 推送到堆栈上。这个推送的 View Controller 有一个
昨天更新后,我在 iPad 上遇到了这个问题:如果我加载第二个 View Controller ,它看起来比第一个 View Controller 小(见下图)。有趣的是,自从我在 iPad 上更新了
我的项目有这样的设计: VC1 ---firstSegue----> VC2 ---secondSegue---> VC3 通过使用协议(protocol)/委托(delegate)方法,我可以毫无问
图像不是从一个 VC 到另一个 VC。 问题是将它显示到主 UIViewController 中的 ImageView 。我已将所有内容正确连接到 Storyboard中。 点击here查看我的 St
如何在vc++中调用vc++dll。 在.h文件中 typedef int (*LPVAR)(char * ptr_f, char *CC); HINSTANCE hDLL; 在.cpp 文件中 hD
当我从 VC1 转到 VC2 时,如果 VC2 被解雇,我可以通过在 VC2 中设置协议(protocol)并让 VC1 符合它,轻松地将数据传回 VC1。我想做类似的事情,但有以下区别 当我从 VC
我有一个 VC(A),它有一个容器 View 并根据 segementControl 值更改它的 VC(B-C),我在 A ViewController 中发送请求并获得响应,我想确保 B 和C Vi
所以我在我的应用程序中实现了通用链接,当按下按钮时,我打开了我的第二个应用程序: UIApplication.shared.open(aUrl!) 我也接到了电话: func application(
我想在 ios 中模拟联系人列表。当点击 + 按钮添加联系人时,会出现一个新的 View Controller ,为您提供文本字段以输入联系人姓名和用于保存该联系人的其他信息。一旦你点击完成按钮,下一
我有两个 ViewControllers - Slider 和 Foo。我将 Slider 添加为 Foo subview 并将其框架设置在 Foo VC 中,但是 Slider 的框架没有改变 ->
我是一名优秀的程序员,十分优秀!