call dword ptr xxx与call xxx的比较

来源:互联网 发布:什么是单例模式 java 编辑:程序博客网 时间:2024/04/27 10:07
一:问题
call dword ptr xxx与call xxx

前者为什么比后者就效率了?还有一个问题

#include <iostream>
using namespace std;
int main()
{
cout<<"hello world!"<<endl;
__asm jmp main
return 0;
}

这个函数为啥不是死循环?怎么执行一会就结束?


如果加个计数器
#include <iostream>
using namespace std;

int a;
void Cout()
{
  a++;
  cout<<"hello world!"<<endl;
  __asm jmp main
  return 0;  
}

int main()
{
  __asm jmp Cout
  return 0;
}  

#include <iostream>
using namespace std;

int a;
void Cout()
{
  a++;
  cout<<"hello world!"<<endl;
  __asm call main
  return 0;  
}

int main()
{
  __asm call Cout
  return 0;
}  

第一个程序的a的值要大一些,也就是说jmp是效率的?输入表的调用为什么还要用call ?


上面这几个问题是看加密解密3 P278 关于输入表函数调用部分的思考,想不明白,请前辈高人帮忙!

二:解答:
fenchang说的是对的

//使用默认栈的大小0x100000 提交0x1000(一个页面)
#include "head.h"

int a;
int main()
{
  a++;
  cout<<"hello world!"<<" "<<a<<endl;
  __asm jmp main

  return 0;
  
}

a=12308 

//增大默认的大小为0x200000提交0x1000 
//1.exe
#include "head.h"
#pragma  comment(linker,"/stack:0x200000,0x1000")
int a;
int main()
{
  a++;
  cout<<"hello world!"<<" "<<a<<endl;
  __asm jmp main

  return 0;
  
}

a=24791

1:结论:是预订地址的空间不够导致了程序的退出,继续增大,程序将继续运行,而并不是抢占式多任务操作系统的任务调试会强制夺回CPU控制权


2:原因:进程空间会发生空间预订的现象——PEB TEB 和线程栈空间分配!
   
3:区别死循环
//2.exe
#include "head.h"

int a;
int main(int argc,char **argv)
{
  while(1)
  {
    a++;
    cout<<"hello world!"<<" "<<a<<endl;
  }
  return 0;
}

 与前面例子的区别:

 //1.exe 反汇编
00401005   /E9 06000000       jmp 1.00401010 ;__asm jmp main的位置
0040100A   |CC                int3
0040100B   |CC                int3
0040100C   |CC                int3
0040100D   |CC                int3
0040100E   |CC                int3
0040100F   |CC                int3
00401010   \55                push ebp  ;保存栈帧底
00401011    8BEC              mov ebp,esp ;开辟新栈帧
00401013    83EC 44           sub esp,44 ;保存变量
00401016    53                push ebx  
00401017    56                push esi
00401018    57                push edi
00401019    8D7D BC           lea edi,dword ptr ss:[ebp-44]
0040101C    B9 11000000       mov ecx,11
00401021    B8 CCCCCCCC       mov eax,CCCCCCCC ;实始化操作
00401026    F3:AB             rep stos dword ptr es:[edi]

………………………………………………省略N句……………………………………………………………………
004010A0  ^ E9 60FFFFFF       jmp 1.00401005  ;__asm jmp main 
………………………………………………………………………………………………………………………………
;这里是收复栈空间
004010A5    33C0              xor eax,eax  
004010A7    5F                pop edi
004010A8    5E                pop esi
004010A9    5B                pop ebx
004010AA    83C4 44           add esp,44


显然,程序在不停的支出栈空间,而并没有回收,使用call指令一样进行这样的操作!

//2.exe 反汇编

00401010    55                push ebp
00401011    8BEC              mov ebp,esp
00401013    83EC 44           sub esp,44
00401016    53                push ebx
00401017    56                push esi
00401018    57                push edi
00401019    8D7D BC           lea edi,dword ptr ss:[ebp-44]
0040101C    B9 11000000       mov ecx,11
00401021    B8 CCCCCCCC       mov eax,CCCCCCCC
00401026    F3:AB             rep stos dword ptr es:[edi]
……………………………………………………上面分配栈空间………………………………………………………………
00401028    B8 01000000       mov eax,1
0040102D    85C0              test eax,eax
0040102F    74 7F             je short 2.004010B0 ;whie(1)条件检测位置
00401031    8B0D 34464100     mov ecx,dword ptr ds:[414634] 
00401037    83C1 01           add ecx,1  ;计数器增加
0040103A    890D 34464100     mov dword ptr ds:[414634],ecx
………………………………………………省略N句,这里省略的部分没有栈操作…………………………………………………………
004010AB  ^ E9 78FFFFFF       jmp 2.00401028 ;循环继续

……………………………………………………回收栈空间…………………………………………………………………………
004010B0    33C0              xor eax,eax
004010B2    5F                pop edi
004010B3    5E                pop esi
004010B4    5B                pop ebx
004010B5    83C4 44           add esp,44
 
显然,循环中没有支出任何栈空间!
  

4:call dword ptr [xxxx],与call xxxx
 
  这两者的区别就在于一点IAT——IAT在OD中就是一段jmp xxxx,call动态链接库的DLL文件时我们根本不再需要先jmp一下,再jmp到函数当中!这个过程的实现如下
_declspec在编写DLL文件的导出函数时被程序员加上了,编译器的汇编阶断会将它转换成call dword ptr [xxxx],并加上一个__im__的标志,生成obj文件教给链接器处理的时候,链接器看到__im__就会直接修改为__im__xxxx!

5:jmp比call效率为什么要用call而不用jmp
A:如果使用jmp我们要自已回收栈空间,这样是浪费程序员的时候,因为程序中很大部分的功能都需要调用函数,所以这个功能被提取出来以方便操作——call!
B:C/C++也用这种方式,是因为它存在的基础是汇编语言,就像遗传!