随笔 - 1, 文章 - 9, 评论 - 4, 引用 - 0
数据加载中……

__cdecl、__stdcall、__pascal、__fastcall:寄存器小实验

//---------------------------------------------------------------------------

#pragma hdrstop

//---------------------------------------------------------------------------
char one()
{
    
return 'a';
}
//---------------------------------------------------------------------------
__int16 two()
{
    
return 1;
}
//---------------------------------------------------------------------------
__int32 four()
{
    
return 2;
}
//---------------------------------------------------------------------------
__int64 eight()
{
    
return 3;
}
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
    
char i = one();
    __int16 ii = two();
    __int32 iv = four();
    __int64 viii = eight();
    
    
return 0;
}
//---------------------------------------------------------------------------

自己写的小实验,因为突然对asm产生了兴趣。
在跟踪的时候会发现:

mov al, 
0x61 ; return 'a'

mov ax, 
0x0001 ; return 1

mov eax, 
0x00000002 ; return 2

mov eax, 
0x00000003 ; return 3
xor edx, edx

这说明,对于1个byte的数据用的是al,2byte用的是ax,4byte用的是eax,而8byte用的是eax和edx,且eax存储低位,edx存储高位。

另有:
push ebp
mov ebp, esp

这在进入每个函数都会出现,是因为ebp是堆栈指针,用来在堆栈中查找数据,而esp永远指向堆栈头部。mov给ebp相当于给了段位号,ebp就是偏移。

下面关于那几个函数标识:
//---------------------------------------------------------------------------

#pragma hdrstop

//---------------------------------------------------------------------------
void __cdecl cde(int a, int b)
{
    a += b;
}
//---------------------------------------------------------------------------
int __stdcall std(int a, int b)
{
    a = a + b;
    
return a;
}
//---------------------------------------------------------------------------
int __pascal pas(int a, int b)
{
    
if ( a*b > 30 )
        
return b;
    
else
    {
        a += b;
        pas(a, b);
    }
}
//---------------------------------------------------------------------------
void __fastcall fst(int a, int b)
{
    a += b;
}
//---------------------------------------------------------------------------

#pragma argsused
int main(int argc, char* argv[])
{
    cde(1, 2);
    std(2, 3);
    pas(3, 4);
    fst(4, 5);
    
    
return 0;
}
//---------------------------------------------------------------------------

然后跟踪进去:
cde:
push 
0x02
push 
0x01

std:
push 
0x03
push 
0x02

pas:
push 
0x03
push 
0x04

fst
mov edx, 
0x00000005
mov eax, 
0x00000004

+= b
mov eax, [ebp
+0x0c] ; b
add [ebp
+0x08], eax ; b->a

fst
mov [ebp
-0x08], edx ; b
mov [ebp
-0x04], eax ; a

这说明:
__cdecl和__stdcall都是从右向左压入参数,
__pascal是从左向右压入参数,
__fastcall根本就不用内存来存储参数,直接存储在寄存器里面,不过最后那个fst可以看出__fastcall还是又回到内存去了,这点不是很明白。
所以__fastcall是要快的多,其他的变量都存储在内存区域上(不可能一直在寄存器,因为寄存器是大家公用的),它们要操作必须先mov到寄存器上来,而fst就不用,但是同时:寄存器的数量很少,容量很小。

这里想到自己之前的一个严重错误,就是因为在不同编译器下如vc和bc它们给这些标识函数的名称都是不一样的,所以千万不能只以为它们只有名称的不同,这是个很严重的错误,程序必然会死的很惨。其实动动手就知道了,google上讲的都是知识点,来的不实在。

posted on 2008-12-28 09:59 EiN 阅读(337) 评论(0)  编辑 收藏 引用 所属分类: C/C++ and ASM


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理