- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
最近,我对分解C代码(非常简单的C代码)产生了兴趣,并遵循了使用Borland C ++ Compiler v 5.5(可以很好地编译C代码)的教程,并且一切正常。然后,我决定尝试自己的C代码,并在Dev C ++(使用gcc)中对其进行编译。在IDA Pro中打开它后,我感到很惊讶,与Borland的gcc相比,gcc的确与众不同。我期望有所不同,但是C代码非常简单,是否只是gcc没有进行太多优化,或者它们使用了不同的默认编译器设置?
C代码
int main(int argc, char **argv)
{
int a;
a = 1;
}
.text:00401150 ; int __cdecl main(int argc,const char **argv,const char *envp)
.text:00401150 _main proc near ; DATA XREF: .data:004090D0
.text:00401150
.text:00401150 argc = dword ptr 8
.text:00401150 argv = dword ptr 0Ch
.text:00401150 envp = dword ptr 10h
.text:00401150
.text:00401150 push ebp
.text:00401151 mov ebp, esp
.text:00401153 pop ebp
.text:00401154 retn
.text:00401154 _main endp
.text:00401220 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
.text:00401220
.text:00401220 ; Attributes: bp-based frame
.text:00401220
.text:00401220 public start
.text:00401220 start proc near
.text:00401220
.text:00401220 var_14 = dword ptr -14h
.text:00401220 var_8 = dword ptr -8
.text:00401220
.text:00401220 push ebp
.text:00401221 mov ebp, esp
.text:00401223 sub esp, 8
.text:00401226 mov [esp+8+var_8], 1
.text:0040122D call ds:__set_app_type
.text:00401233 call sub_401100
.text:00401238 nop
.text:00401239 lea esi, [esi+0]
.text:00401240 push ebp
.text:00401241 mov ebp, esp
.text:00401243 sub esp, 8
.text:00401246 mov [esp+14h+var_14], 2
.text:0040124D call ds:__set_app_type
.text:00401253 call sub_401100
.text:00401258 nop
.text:00401259 lea esi, [esi+0]
.text:00401259 start endp
.text:00401100 sub_401100 proc near ; CODE XREF: .text:004010F1j
.text:00401100 ; start+13p ...
.text:00401100
.text:00401100 var_28 = dword ptr -28h
.text:00401100 var_24 = dword ptr -24h
.text:00401100 var_20 = dword ptr -20h
.text:00401100 var_1C = dword ptr -1Ch
.text:00401100 var_18 = dword ptr -18h
.text:00401100 var_C = dword ptr -0Ch
.text:00401100 var_8 = dword ptr -8
.text:00401100
.text:00401100 push ebp
.text:00401101 mov ebp, esp
.text:00401103 push ebx
.text:00401104 sub esp, 24h ; lpTopLevelExceptionFilter
.text:00401107 lea ebx, [ebp+var_8]
.text:0040110A mov [esp+28h+var_28], offset sub_401000
.text:00401111 call SetUnhandledExceptionFilter
.text:00401116 sub esp, 4 ; uExitCode
.text:00401119 call sub_4012E0
.text:0040111E mov [ebp+var_8], 0
.text:00401125 mov eax, offset dword_404000
.text:0040112A lea edx, [ebp+var_C]
.text:0040112D mov [esp+28h+var_18], ebx
.text:00401131 mov ecx, dword_402000
.text:00401137 mov [esp+28h+var_24], eax
.text:0040113B mov [esp+28h+var_20], edx
.text:0040113F mov [esp+28h+var_1C], ecx
.text:00401143 mov [esp+28h+var_28], offset dword_404004
.text:0040114A call __getmainargs
.text:0040114F mov eax, ds:dword_404010
.text:00401154 test eax, eax
.text:00401156 jz short loc_4011B0
.text:00401158 mov dword_402010, eax
.text:0040115D mov edx, ds:_iob
.text:00401163 test edx, edx
.text:00401165 jnz loc_4011F6
.text:004012E0 sub_4012E0 proc near ; CODE XREF: sub_401000+C6p
.text:004012E0 ; sub_401100+19p
.text:004012E0 push ebp
.text:004012E1 mov ebp, esp
.text:004012E3 fninit
.text:004012E5 pop ebp
.text:004012E6 retn
.text:004012E6 sub_4012E0 endp
最佳答案
编译器的输出可能会有所不同,对于同一源,有时会有很大不同。丰田和本田不同。当然,有四个轮子和一些座位,但是当您查看细节时,它们却有更多不同。
同样,具有不同编译器选项的同一编译器可以并且经常会为同一源代码产生截然不同的输出。即使对于看似简单的程序也是如此。
就您的简单程序而言,它实际上什么都不做(代码不影响输入,输出或函数外部的任何内容),一个好的优化编译器只会得到main:返回一个随机数因为您没有指定返回值。实际上,它应该给出警告或错误。这是我比较编译器输出时遇到的最大问题,它使事情变得很简单,可以看到他们在做什么,但又变得足够复杂,以至于编译器所做的不仅仅是预计算答案并返回答案。
在x86的情况下,我假设这就是您在这里所说的,这些天被微编码了,对于好的代码还是不好的代码,实际上并没有答案,每个处理器家族都在改变他们的勇气,而以前很快的速度却很慢而现在的速度在旧处理器上却很慢。因此,对于像gcc这样的随着新内核而不断发展的编译器,优化既可以是所有x86通用的,也可以是特定于特定系列的(尽管进行了最大优化,但仍会产生不同的代码)。
随着您对反汇编的新兴趣,您将继续看到异同,并找出可以编译同一代码的几种不同方式。差异是可以预期的,即使对于琐碎的程序也是如此。我鼓励您尝试尽可能多的编译器。即使在gcc系列2.x,3.x,4.x中,以及构建它的不同方法也会导致产生不同的代码,尽管它们可能被认为是同一编译器。
仁者见仁,输出好坏。使用调试器的人们将希望它们的代码是可步进的,并且它们的变量是可观察的(以书面代码顺序)。这导致非常大,笨重且缓慢的代码(尤其是x86)。而且,当您进行发行时,最终得到的是一个完全不同的程序,到目前为止,您已经花费了零时间进行调试。此外,为了提高性能,您还冒着编译器优化自己想要做的事情的风险(在上面的示例中,即使进行了较小的优化,也不会分配任何变量,也不会执行任何代码)。或更糟糕的是,您暴露了编译器中的错误,而程序却根本无法正常工作(这就是为什么不建议将-O3用于gcc的原因)。您和/或您会发现C标准中有很多地方是其解释由实现定义。
未优化的代码更容易编译,因为它更加明显。在您的示例中,期望的是在栈上分配一个变量,设置了某种栈指针安排,立即数1最终写入该位置,清理了栈并返回了函数。编译器更难出错,程序更有可能按预期工作。检测和删除无效代码是优化和
那就是风险所在。通常,风险值得得到回报。但这取决于用户,情人眼中的情人。
底线是简短的答案。预期会有差异(甚至会有巨大差异)。默认编译选项因编译器而异。试用编译/优化选项和不同的编译器,然后继续反汇编程序,以便更好地了解所用的语言和编译器。到目前为止,您在正确的轨道上。对于borland输出,它检测到您的程序不执行任何操作,不使用输入变量,不使用返回变量,也不与局部变量相关,并且不使用全局变量或函数资源之外的其他变量。整数a和立即数的赋值是无效代码,一个好的优化程序实际上将删除/忽略这两行代码。因此,它麻烦设置一个堆栈框架,然后清理它不需要做的事情,然后返回。 gcc似乎正在建立一个异常处理程序,即使它不需要,它也很好,开始优化或使用main()以外的函数名,您应该会看到不同的结果。
关于c - GCC和Borland在反汇编C代码方面的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4355610/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!