反汇编之C++的const

本文详细解析了C++中初始化常量引用时临时对象的创建过程及作用域,通过具体代码示例说明了如何正确使用常量引用避免潜在错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



 


 
  1. #include<iostream>
  2. #include<stdlib.h>
  3. using namespace std;
  4. const int &add( const int &a,const int &b)
  5. {
  6. return a+b;
  7. }
  8. int main()
  9. {
  10. const int &result = add(5,8);
  11. add(11, 8);//重复使用栈.排除虽然栈回收.但值没变的可能性
  12. add(5, 8);
  13. add(5,8);
  14. add(5,8);
  15.     add(5,8);
  16. cout << result << endl;
  17. system("pause");
  18. return 0;
  19. }

   

 

以上结果输出13.原因在于当add的时候参数5,8.将生成2个临时对象(但这个临时对象的生存周期可伴随main).用来保存5,8

main.c 部分反汇编代码



 
  1. 00FC18CE mov dword ptr [ebp-0D4h],8 ;创建一个地址用来保存8
  2. 00FC18D8 mov dword ptr [ebp-0E0h],5 ;创建一个地址用来保存5
  3. 00FC18E2 lea eax,[ebp-0D4h] ;将保存8的地址赋给eax.
  4. 00FC18E8 push eax ;地址压栈
  5. 00FC18E9 lea ecx,[ebp-0E0h] ;将保存5的地址赋给ecx
  6. 00FC18EF push ecx ;将地址压入栈中
  7. 00FC18F0 call add (0FC138Eh)
  8. 00FC18F5 add esp,8 ;回收栈
  9. 00FC18F8 mov dword ptr [result],eax 

 



 
  1. const int &add(const int &a, const int &b)
  2. {
  3. 002217C0 push ebp
  4. 002217C1 mov ebp,esp
  5. 002217C3 sub esp,0CCh ;开辟局部栈空间,大小为0cch
  6. 002217C9 push ebx
  7. 002217CA push esi
  8. 002217CB push edi
  9. 002217CC lea edi,[ebp-0CCh] ;
  10. 002217D2 mov ecx,33h
  11. 002217D7 mov eax,0CCCCCCCCh
  12. 002217DC rep stos dword ptr es:[edi]

注意.以上局部栈空间大小在 esp到esp-0cch之间.当函数调用完此空间将回收(并不是真正意义的回收.只是改变栈指针罢了.原来的数值还在.不过如果此栈被反复调用(这就是为何我重复调用的原因).栈的数据当然改变)



 
  1. 00FC17DE mov eax,dword ptr [a] ;将临时对象5的地址赋给eax (const int &a) [a]保存的是临时对象5的
  2. 00FC17E1 mov ecx,dword ptr [eax] ;将eax保存的值给ecx
  3. 00FC17E3 mov edx,dword ptr [b] ;将临时对象b的地址赋给edx
  4. 00FC17E6 add ecx,dword ptr [edx] ;将edx保存的值加到ecx中
  5. 00FC17E8 mov dword ptr [ebp-0C8h],ecx ;将结果保存到ebp-0c8h中(临时对象)
  6. 00FC17EE lea eax,[ebp-0C8h] ;将结果地址赋给eax
  7. }
  8. 执行完Add函数后将临时对象的地址保存到result引用中
  9. 00FC18F8 mov dword ptr [result],eax 

注意了 return a+b;开辟的临时对象在ebp-0c8h处.处于局部栈之内!!!(ebp~ebp-0xcch).当add调用完后..将此回收地址赋给了result引用.于是出现了结果乱了的情况了

 

2.初始化一个常量引用所引发的临时对象

  当初始化一个常量引用(const reference)时,如果给定的初始化对象类型与目标引用类型不同(但是两者  能够相互转换),需要产生临时对象;

对于局部const int  temp=10这类变量.即使取地址使得其改变也不会有任何变化.

double db=10.000;

int &q=db;

以上会报错.

因为实际他会转化为 int temp=(int) db; int &a=temp;.本意是想通过a可以改变db.但实现却不可以改变(改变的是Temp).因此.编译器将会报错

 

当然如果是 const int &a=db;这样编译器将不会报错.因为const修饰这个temp(db)不会改变的



 
  1. double db = 10;
  2. 00EB1868 movsd xmm0,mmword ptr ds:[0EB6B38h]
  3. 00EB1870 movsd mmword ptr [db],xmm0
  4. const int &q = db;
  5. 00EB1875 cvttsd2si eax,mmword ptr [db] ;db的值10赋给eax
  6. 00EB187A mov dword ptr [ebp-28h],eax ;将eax赋给ebp-28h(就是临时对象)
  7. 00EB187D lea ecx,[ebp-28h]
  8. 00EB1880 mov dword ptr [q],ecx
  9. 转自https://www.cnblogs.com/zengyiwen
### 如何使用工具或方法将C++生成的二进制文件反汇编为汇编代码 要将C++生成的二进制文件反汇编为汇编代码,可以利用多种专业的反汇编工具来完成这一过程。这些工具有助于分析程序的行为以及理解底层实现细节。 #### 在线反汇编工具(Online Disassembler) 一种简单的方法是通过在线反汇编工具(如引用中提到的 Online Disassembler,ODA)。这种工具允许用户上传二进制文件或将字节流直接粘贴到控制台中进行反汇编操作[^1]。它适合快速测试和初步分析场景下的需求。 对于更复杂的功能或者需要本地化支持的情况,则可以选择功能更为强大的桌面级软件: #### Binary Ninja Binary Ninja 是一款跨平台的支持 Windows、Linux 和 macOS 的静态分析框架兼反汇编器[^1]。其特点在于提供直观图形界面的同时还具备脚本扩展能力,能够帮助开发者深入研究目标文件结构及其内部逻辑关系。此外,Binary Ninja 支持插件开发,这使得它可以被定制以满足特定用途的要求。 以下是基于 C++ 编写的一个简单的例子演示如何定义通用模板函数与类来进行数据处理[^2]: ```cpp #include <iostream> #include <vector> template<typename T> void traverseAndPrint(const T& container){ for(auto const &item : container){ std::cout << item << "\n"; } } class Instruction { public: unsigned char opcode; explicit Instruction(unsigned char op):opcode(op){} }; template<typename InstructionType> class InstructionSequence{ private: std::vector<InstructionType> instructions; public: void addInstruction(InstructionType inst){instructions.emplace_back(std::move(inst));} void execute(){ for(auto&& ins:instructions){ printf("Executing instruction with opcode %X\n",ins.opcode); } } }; ``` 在这个示例里我们创建了一个名为 `Instruction` 的小型对象表示单条机器码命令;接着构建了另一个泛型容器类型——`InstructionSequence` 来存储多个这样的实例,并提供了相应接口去逐一遍历执行它们所代表的操作数集合。 当涉及到实际项目时可能还需要考虑其他因素比如链接库版本差异等问题,在某些情况下甚至有必要编写专门的小应用程序调用外部API完成整个流程自动化管理任务。下面给出一段 Python 脚本来说明这一点[^3]: ```python import sys from some_decompiler_module import Decompiler # 假设存在这样一个模块 if __name__ == '__main__': binary_path = r"path_to_your_binary_file" output_dir = r"--output=path_for_output_files" try: decompiler_instance = Decompiler([binary_path, output_dir]) exit_code = decompiler_instance.decompile() sys.exit(exit_code) except Exception as e: print(f"Error occurred during decomposition:{e}") sys.exit(-1) ``` 此段Python代码片段展示了如果有一个假想中的decompilation API可用的话,那么就可以轻松地将其集成至更大的工作流当中去了。 综上所述,无论是初学者还是高级工程师都可以找到适合自己技术水平层次上的解决方案来解决这个问题领域内的挑战。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值