#include <stdio.h>
#include <stdlib.h>
//通过栈传入值的话
void _fastcall funcFast(int a, int b)
{
001C1B2F pop ecx
001C1B30 mov dword ptr [b],edx
001C1B33 mov dword ptr [a],ecx
printf("%d", a+b);
001C1B36 mov eax,dword ptr [a]
001C1B39 add eax,dword ptr [b]
001C1B3C mov esi,esp
001C1B3E push eax
001C1B3F push 1CE988h
001C1B44 call dword ptr ds:[1D2470h]
001C1B4A add esp,8
001C1B4D cmp esi,esp
001C1B4F call __RTC_CheckEsp (01C13CFh)
}
001C1B54 pop edi
001C1B55 pop esi
001C1B56 pop ebx
001C1B57 add esp,0D8h
001C1B5D cmp ebp,esp
001C1B5F call __RTC_CheckEsp (01C13CFh)
001C1B64 mov esp,ebp
001C1B66 pop ebp
001C1B67 ret
001C1B68 int 3
。。。。。
001C1B7F int 3
void _cdecl funccde(int a,int b)
{
001C1B80 push ebp //栈帧已经变化,esp指向最高,跟随压入的在动
001C1B81 mov ebp,esp
001C1B83 sub esp,0C0h
001C1B89 push ebx
001C1B8A push esi //这三个值的压入是在esp基础上的压入
001C1B8B push edi //edi目的寄存器,esi源寄存器,用于大块数据的移动
001C1B8C lea edi,[ebp-0C0h]
001C1B92 mov ecx,30h
001C1B97 mov eax,0CCCCCCCCh
001C1B9C rep stos dword ptr es:[edi]
printf("%d",a-b);
001C1B9E mov eax,dword ptr [a]
001C1BA1 sub eax,dword ptr [b]
001C1BA4 mov esi,esp
001C1BA6 push eax
001C1BA7 push 1CE988h
001C1BAC call dword ptr ds:[1D2470h]
001C1BB2 add esp,8
001C1BB5 cmp esi,esp
001C1BB7 call __RTC_CheckEsp (01C13CFh)
}
001C1BBC pop edi //cdelc自己进行栈帧的回退
001C1BBD pop esi //通过堆栈进行传值
001C1BBE pop ebx
001C1BBF add esp,0C0h //此处也有增加
001C1BC5 cmp ebp,esp
001C1BC7 call __RTC_CheckEsp (01C13CFh)
001C1BCC mov esp,ebp
001C1BCE pop ebp
001C1BCF ret //没有进行平衡
001C1BD0 int 3
。。。
--- e:\c_study\算法\test\test\c.c ------------------------------------------------
void _stdcall funcstd(int a, int b)
{
001C1BF0 push ebp
001C1BF1 mov ebp,esp
001C1BF3 sub esp,0C0h
001C1BF9 push ebx
001C1BFA push esi
001C1BFB push edi
001C1BFC lea edi,[ebp-0C0h]
001C1C02 mov ecx,30h
001C1C07 mov eax,0CCCCCCCCh
001C1C0C rep stos dword ptr es:[edi]
printf("%d", a*b);
001C1C0E mov eax,dword ptr [a]
001C1C11 imul eax,dword ptr [b]
001C1C15 mov esi,esp
001C1C17 push eax
001C1C18 push 1CE988h
001C1C1D call dword ptr ds:[1D2470h]
001C1C23 add esp,8
001C1C26 cmp esi,esp
001C1C28 call __RTC_CheckEsp (01C13CFh)
}
001C1C2D pop edi
001C1C2E pop esi
001C1C2F pop ebx
001C1C30 add esp,0C0h ///
001C1C36 cmp ebp,esp
001C1C38 call __RTC_CheckEsp (01C13CFh)
001C1C3D mov esp,ebp
001C1C3F pop ebp
001C1C40 ret 8 //栈顶平衡8
--- 无源文件 -----------------------------------------------------------------------
--- e:\c_study\算法\test\test\c.c ------------------------------------------------
//_thiscall只能出现在非静态成员函数中,通过exc来带参
int main()
{
001C1C60 push ebp //保存栈底地址
001C1C61 mov ebp,esp
001C1C63 sub esp,0D8h //开辟栈帧
001C1C69 push ebx
001C1C6A push esi
001C1C6B push edi
001C1C6C lea edi,[ebp-0D8h]
001C1C72 mov ecx,36h
001C1C77 mov eax,0CCCCCCCCh
001C1C7C rep stos dword ptr es:[edi]
int a=12;
001C1C7E mov dword ptr [a],0Ch
int b=11;
001C1C85 mov dword ptr [b],0Bh
funccde(a,b); //压入的时候是否在原来的栈帧之上还是有一段距离隔开
001C1C8C mov eax,dword ptr [b] //在调用者函数栈帧中将值压入栈
001C1C8F push eax
001C1C90 mov ecx,dword ptr [a] //cdel是通过栈帧传递参数,不定参数可以使用 //压入参数的时候是在esp的基础上压入,然后压入ebp,eip的值,开辟栈帧
001C1C93 push ecx //调用方平衡栈
001C1C94 call _funccde (01C143Dh) //call指令包含压入下一条指令的地址
001C1C99 add esp,8 //esp进行偏移
funcstd(a,b);
001C1C9C mov eax,dword ptr [b] //函数栈进行参数传递,不能使用不定参数
001C1C9F push eax //被调放平衡栈
001C1CA0 mov ecx,dword ptr [a]
001C1CA3 push ecx
001C1CA4 call _funcstd@8 (01C13A2h) //没有esp的偏移
funcFast(a,b);
001C1CA9 mov edx,dword ptr [b] //edx和ecx进行传递值
001C1CAC mov ecx,dword ptr [a] //参数过多就会通过寄存器和栈传参数
001C1CAF call @funcFast@8 (01C1249h) //不能使用不定参数
return 0;
001C1CB4 xor eax,eax
}//当参数为0时,无需区分调用方式,使用cdecl和stdcall一样
001C1CB6 pop edi
001C1CB7 pop esi
001C1CB8 pop ebx
001C1CB9 add esp,0D8h
001C1CBF cmp ebp,esp
}
001C1CC1 call __RTC_CheckEsp (01C13CFh) //call用来保存返回来时候的下一条指令的地址,ret用来返回,将压入栈的eip值还原到寄存器中
001C1CC6 mov esp,ebp
001C1CC8 pop ebp //先将ebp还原,然后ret还原eip寄存器,esp寄存器减低
001C1CC9 ret
//_cdecl与_stdcall只在参数平衡栈帧上有所不同,其余部分相同
//但经过优化后,_cdecl调用方式的函数在同一作用域内多次使用,会在效率上比_stdcall高一点
//因为_cdecl可以使用复写传播,_stdcall在函数内平衡参数
//_fastcall调用方式只使用ecx和edx,分别传入第一二个参数,其余的通过栈传入
#include <stdio.h>
#include <stdlib.h>
void _fastcall funcFast(int a, int b)
{
printf("%d", a+b);
}
void _cdecl funccde(int a,int b)
{
printf("%d",a-b);
}
void _stdcall funcstd(int a, int b)
{
printf("%d", a*b);
}
//_thiscall只能出现在非静态成员函数中,通过exc来带参
int main()
{
int a=12;
int b=11;
funccde(a,b);
funcstd(a,b);
funcFast(a,b);
return 0;
}
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) //表明asmlinkage是通过栈来传递参数而不通过寄存器来传递参数
#define fastcall __attribute__((regparm(3)))
//参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数
缺省的时候是通过寄存器传递参数
几种函数的调用方式:
1. stdcall
stdcall调用方式的函数声明为:
int _stdcall function(int a, int b);
stdcall的调用方式意味着:
(1) 参数从右向左依次压入堆栈
(2) 由被调用函数自己来恢复堆栈
(3) 函数名自动加前导下划线,后面紧跟着一个@,其后紧跟着参数的尺寸
上面那个函数翻译成汇编语言将变成:
push b 先压入第二个参数
push a 再压入第一个参数
call function 调用函数
在编译时,此函数的名字被翻译为_function@8
2. cdecl
cdecl调用方式又称为C调用方式,是C语言缺省的调用方式,它的语法为:
int _cdecl function(int a, int b) // 明确指定用C调用方式
cdecl的调用方式决定了:
(1) 参数从右向左依次压入堆栈
(2) 由调用者恢复堆栈
(3) 函数名自动加前导下划线
由于是由调用者来恢复堆栈,因此C调用方式允许函数的参数个数是不固定的,这是C语言的一大特色。
此方式的函数被翻译为:
push b // 先压入第二个参数
push a // 在压入第一个参数
call funtion // 调用函数
add esp, 8 // 清理堆栈 。。。。。需要熟悉一下esp寄存器的功能,建议看一下汇编有关的书,基本都有讲
在编译时,此方式的函数被翻译成:_function
3. fastcall
fastcall 按照名字上理解就可以知道,它是一种快速调用方式。
此方式的函数的第一个和第二个DWORD参数通过ecx和edx传递,
后面的参数从右向左的顺序压入栈。
被调用函数清理堆栈。
函数名修个规则同stdcall
其声明语法为:
int fastcall function(int a, int b);
4. thiscall
thiscall 调用方式是唯一一种不能显示指定的修饰符。它是c++类成员函数缺省的调用方式。由于成员函数调用还有一个this指针,因此必须用这种特殊的调用方式。
thiscall调用方式意味着:
参数从右向左压入栈。
如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压入栈后被压入栈。
参数个数不定的,由调用者清理堆栈,否则由函数自己清理堆栈。
可以看到,对于参数个数固定的情况,它类似于stdcall,不定时则类似于cdecl。
附:
链表的泛型编程:
#define list_entry(ptr, type, member) container_of(ptr, type, member)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ //typeof( ((type *)0)->member )获得该的数据的类型,定义一个变量,初始化
(type *)( (char *)__mptr - offsetof(type,member) );}) //使用mptr来得到该结构体的起始地址,然后将该变量强转类型
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) //member在该类型中的偏移量