调试程序调试到系统库函数的代码时,总会发现系统函数都是从一条MOV EDI, EDI指令开始的,紧接着这条指令下面才是标准的建立函数局部栈的代码。对系统DLL比如ntdll.dll进行反汇编,可以发现它的每个导出函数都是如此,并且每个导出函数开始处的MOV EDI, EDI上面紧接着5条NOP指令。比如在WinDbg中查看TextOutA周围的代码: 

0:000> u TextOutA-0x0a L 10 

GDI32!NtGdiTransparentBlt+0xa: 

77efc43f ff12            call    dword ptr [edx] 

77efc441 c22c00          ret     2Ch 

77efc444 90              nop 

77efc445 90              nop 

77efc446 90              nop 

77efc447 90              nop 

77efc448 90              nop 

GDI32!TextOutA: 

77efc449 8bff            mov     edi,edi 

77efc44b 55              push    ebp 

77efc44c 8bec            mov     ebp,esp 

很明显,两个字节的MOV EDI,EDI指令什么事情也不做,那么,就有两个问题:第一,为什么不直接从函数体开始而要从这条什么都不做的指令开始呢?第二,即使需要在函数一开始空出两个字节,为什么不直接使用两条NOP指令,而要使用这条MOV指令呢?在网上查阅一些资料后,得到了答案: 

对于第一个问题,答案是为了实现hot-patching技术,即运行时修改一个函数的行为。修改过程如下:把MOV EDI, EDI修改为一条短跳转指令(一条短跳转指令恰好两个字节),把MOV EDI, EDI上面的五个NOP修改为一条长跳转指令(一条长跳转指令恰好五个字节),短跳转指令跳到长跳转指令上,长跳转指令跳到修改后的函数体上。 

对于第二个问题,答案是为了提高效率。执行一条MOV指令比执行两条NOP指令花费更少的时间。 

  

下面是在网上搜索到的相关资料: 

http://blogs.msdn.com/ishai/archive/2004/06/24/165143.aspx 

在这篇日志中作者指出这是一种实现hot-patching和hot-fix的技术,而且解释了为什么不使用detours技术来实现hot-patching。此外,作者提到了具体是如何使用这种技术来实现hot-patching的,但是只是一句话带过。 

  

http://msmvps.com/blogs/kernelmustard/archive/2005/04/25/44413.aspx 

这篇文章中作者从效率和其它方面详细解释了为什么选择用这种技术来实现hot-patching以及为什么要这样实现(短跳转加长跳转而不是一次性长跳转)。 

  

http://xelf.info/knowledge/MemoryCopy.cpp 

这里给出了具体的memcpy的C语言源代码。如果在安装VC6的时候选择了安装CRT源代码,则在VC安装目录的SRC/INTEL/目录中有memcmp.asm等文件,它们就是对应的CRT函数的源代码,这些源代码中也都有详细的注释。 

  

另外,在自己的日志http://blog.csdn.net/jcwKyl/archive/2008/03/25/2217428.aspx里面,曾经对strcmp函数中的MOV
EDI, EDI指令感到困惑,其实只要看看strcmp.asm中的源代码就可以明白,那条MOV EDI, EDI完全是为了内存四字节对齐的。源代码中写的是align 4,在运行时,如果需要一个填充字节,则会填充一条NOP指令,如果需要两个字节来填充,则会填充一条MOV EDI, EDI指令,之所以不用两条NOP,是出于效率的考虑。

最新文章

  1. 学习 opencv---(5) 创建Trackbar(活动条) &图像对比度,亮度值调整
  2. python 多线程就这么简单(转)
  3. For Microsoft Azure Network VNET to VNET Connection
  4. C#的System.ICloneable接口说明
  5. jq:get获取json数据并以表格形式生成到页面
  6. 201521123072《java程序设计》第十周学习总结
  7. RPC vs RESTful
  8. Android文件大头10G
  9. 关于C语言中输出格式
  10. Systemc在VC++2010安装方法及如何在VC++2010运行Noxim模拟器
  11. 如何在centos操作系统上发布.net core的项目
  12. hihocoder 1175
  13. CAShapLayer的使用1
  14. javascript ES6 新特性之 Promise,ES7 async / await
  15. Linux记录-salt-minion安装
  16. 【译】Apache Kafka支持单集群20万分区
  17. 7.11python多进程
  18. 节约内存,请使用标签页管理工具:onetab、better onetab
  19. Android ListView and Tips.
  20. hasura graphql-engine v1.0.0-alpha26 版本新功能

热门文章

  1. linux 查看服务器序列号(S/N)
  2. Spring常见面试题及答案解析
  3. leetcood学习笔记-112-路径总和
  4. web 开发流程
  5. Dart编程运算符
  6. struts2-convention-plugin零配置
  7. 26 函数形参值回传问题——C++解决多个return的一般方法
  8. NX二次开发-UFUN计算两点距离UF_VEC3_distance
  9. Cstring转char、string、int等数据类型的方法(转载)
  10. Python对象继承set类型