当前位置:网站首页>编译器不同,模式不同,对结果的影响
编译器不同,模式不同,对结果的影响
2022-08-09 14:53:00 【黄铎彦】
目录
前言
在上一篇文章中简单提及了这一现象,本文继续探索这个问题
一、c语言代码
#include<stdio.h>
main()
{
int a = 1, b = 1;
printf("%d", a + b);
}二、运行结果
1.直接调试
使用devc++编译的(TDM-GCC 4.9.2 64-bit Release,下同):
“test.exe”(Win32): 已加载“D:\编程\devctest\test.exe”。
“test.exe”(Win32): 已加载“C:\Windows\System32\ntdll.dll”。
“test.exe”(Win32): 已加载“C:\Windows\System32\kernel32.dll”。
“test.exe”(Win32): 已加载“C:\Windows\System32\KernelBase.dll”。
“test.exe”(Win32): 已加载“C:\Windows\System32\msvcrt.dll”。
线程 0x44f0 已退出,返回值为 0 (0x0)。
线程 0x4da8 已退出,返回值为 1 (0x1)。
程序“[16652] test.exe”已退出,返回值为 1 (0x1)。

可以看出返回值不是0。
使用vs2022的debug模式编译的(我把c语言标准改成了最新的,release模式同):
“cTest.exe”(Win32): 已加载“D:\编程\cTest\x64\Debug\cTest.exe”。已加载符号。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\ntdll.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\kernel32.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\KernelBase.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\vcruntime140d.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\ucrtbased.dll”。
线程 0x3ad4 已退出,返回值为 0 (0x0)。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\kernel.appcore.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\msvcrt.dll”。
线程 0x34f8 已退出,返回值为 0 (0x0)。
线程 0x22c0 已退出,返回值为 0 (0x0)。
程序“[2132] cTest.exe”已退出,返回值为 0 (0x0)。
使用vs2022的release模式编译的:
“cTest.exe”(Win32): 已加载“D:\编程\cTest\x64\Release\cTest.exe”。已加载符号。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\ntdll.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\kernel32.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\KernelBase.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\ucrtbase.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\vcruntime140.dll”。
线程 0x17a4 已退出,返回值为 0 (0x0)。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\kernel.appcore.dll”。
“cTest.exe”(Win32): 已加载“C:\Windows\System32\msvcrt.dll”。
线程 0x2ed4 已退出,返回值为 0 (0x0)。
线程 0x52ec 已退出,返回值为 0 (0x0)。
程序“[18804] cTest.exe”已退出,返回值为 0 (0x0)。
2.使用反汇编进行微观观察
使用devc++编译的:
可以看出程序的主入口点不再叫main了。并且语言被识别成了c++。观察了若干行反汇编发现shr指令比较经常使用。
下面是函数mainCRTStartup的反汇编。
0000000000401500 sub rsp,28h
0000000000401504 mov rax,qword ptr [404420h]
000000000040150B mov dword ptr [rax],0
0000000000401511 call 0000000000402110
0000000000401516 call 00000000004011B0
000000000040151B nop
000000000040151C nop
000000000040151D add rsp,28h
0000000000401521 ret
我们找不到和1,1+1或者是2直接相关的指令。下面的调用我就没有再去研究了,因为之后越来越复杂,我对汇编又不太熟悉。0000000000402110h跳转后的函数名叫__security_init_cookie,它没有参数,这个特定的函数在gs_support.c中有定义。
使用vs2022的debug模式编译的:
可以发现主函数的名字没有发生改变。并且语言识别正确。
下面是主函数的反汇编:
1: #include<stdio.h>
2: main()
3: {
00007FF6BA5A1860 push rbp
00007FF6BA5A1862 push rdi
00007FF6BA5A1863 sub rsp,128h
00007FF6BA5A186A lea rbp,[rsp+20h]
00007FF6BA5A186F lea rcx,[__8757079D_源@c (07FF6BA5B1008h)]
00007FF6BA5A1876 call __CheckForDebuggerJustMyCode (07FF6BA5A1361h)
4: int a = 1, b = 1;
00007FF6BA5A187B mov dword ptr [a],1
00007FF6BA5A1882 mov dword ptr [b],1
5: printf("%d", a + b);
00007FF6BA5A1889 mov eax,dword ptr [b]
00007FF6BA5A188C mov ecx,dword ptr [a]
00007FF6BA5A188F add ecx,eax
00007FF6BA5A1891 mov eax,ecx
00007FF6BA5A1893 mov edx,eax
00007FF6BA5A1895 lea rcx,[string "%d" (07FF6BA5A9C10h)]
00007FF6BA5A189C call printf (07FF6BA5A118Bh)
6: }
00007FF6BA5A18A1 xor eax,eax
00007FF6BA5A18A3 lea rsp,[rbp+108h]
00007FF6BA5A18AA pop rdi
00007FF6BA5A18AB pop rbp
00007FF6BA5A18AC ret
我们很明显地看到了电脑老老实实地执行了1+1的计算。整个汇编代码不难和c语言语句对应起来。同时不难发现rcx作为第一参数而rdx作为第二参数。
需要注意:1。大括号不仅仅是大括号,它也会被执行,里面有汇编代码与其对应;2。与devc++的反汇编不同的是,执行右大括号的时候,在微观尺度上visual c通过eax与自身的异或将其清零,从而确保了返回正常的0;3。与devc++相比还特定保护了rdi和rbp的值。
我们又发现了一个特定的函数__CheckForDebuggerJustMyCode,原型如下:
void __fastcall __CheckForDebuggerJustMyCode(unsigned char *JMC_flag);它在debugger_jmc.c中有定义。
使用vs2022的release模式编译的:
“调用堆栈”窗口中初始的显示内容和debug模式没什么区别,程序的主入口点也是叫main。
下面是主函数的反汇编:
1: #include<stdio.h>
2: main()
3: {
00007FF713ED1070 sub rsp,28h
4: int a = 1, b = 1;
5: printf("%d", a + b);
00007FF713ED1074 mov edx,2
00007FF713ED1079 lea rcx,[string "%d" (07FF713ED2250h)]
00007FF713ED1080 call printf (07FF713ED1010h)
6: }
00007FF713ED1085 xor eax,eax
00007FF713ED1087 add rsp,28h
00007FF713ED108B ret
可以看到程序快结束的时候也对eax做了清零的操作。注意,程序并没有执行1+1的运算,而是把结果2直接传送给了edx来当printf函数的第二参数!
同时程序没有调用__CheckForDebuggerJustMyCode函数,也没有对rdi和rbp的值进行保护。
总结
编译器不同,编译模式不同,都会对运行结果产生影响!
边栏推荐
- How do quantitative investors obtain real-time market data?
- 如何保证电脑硬盘格式化后数据不能被恢复?
- 如何灵活运用量化交易接口的优势取长补短?
- 数组学习笔记
- How to make your quantitative trading system have probabilistic advantages and positive return expectations?
- How to use and execute quantitative programmatic trading?
- 经典面试题 之 JVM调优
- 怎么用VS+Qt创建新项目
- docker安装单机版redis、集群版redis
- 英语议论文读写02 Engineering
猜你喜欢

原子的核型结构及氢原子的波尔理论

什么是模板引擎?常见的模板引擎有哪些?thymeleaf的常用指令介绍。

xshell7连接工具下载

navicat for Oraclel链接oracle 报错oracle library is not loaded的解决办法

OpenSSF的开源软件风险评估工具:Scorecards

Regular Expressions for Shell Programming

Database multi-table link query method

Shell -- -- -- -- -- - common gadgets, sort and uniq, tr, the cut

量子力学初步

光线的数值追踪
随机推荐
MySQL 原理与优化:Limit 查询优化
【超级账本开发者系列】专访——肖慧 : 不忘初心,方得始终
突然想分析下房贷利率及利息计算
How to achieve stable profit through the stock quantitative trading interface?
相似图像的检测方法
对程序化交易系统接口有什么误区?
思维导图FreeMind安装问题及简单使用
Seize the opportunity of quantitative trading fund products, and quantitative investment has room for development?
[MySql]实现多表查询-一对一,一对多
OpenSSF's open source software risk assessment tool: Scorecards
C语言——指针和数组、指针数组和数组指针、指针和二维数组
docker安装nacos并且指定容器数据卷,数据库连接等
如何设计一个高并发系统?
OpenCV - 图像模板匹配 matchTemplate
How to flexibly use the advantages of the quantitative trading interface to complement each other?
[Mysql]--Transaction, transaction isolation level, dirty read, non-repeatable read, phantom read analysis
是什么推动了量化交易接口的发展?
Technology Sharing | How to Handle Header Cookies in Interface Automation Testing
如何灵活运用量化交易接口的优势取长补短?
[ERR] 1273 - Unknown collation: ‘utf8mb4_0900_ai_ci‘