弄了几天的C调用汇编子过程,现总结一下。

开发工具:VC ++ 6.0  MASM32

一、__cdecl调用方式

 

1.  在VC中新建Win32 Console Application, TestASM

 

2.  新建test.c

#include<stdio.h>

extern void swap(int *px, int *py);

int main(void)

{

       int a=1, b=2;

       printf("before swaping, a=%d, b=%d\n", a, b);

       swap(&a, &b);

       printf("after  swaping, a=%d, b=%d\n", a, b);

    return 0;

}

 

3.  使用UltraEdit编辑汇编程序swap.asm

.386

.MODEL FLAT, C

OPTION CASEMAP:NONE

.CODE

  swap PROC a:DWORD, b:DWORD

    PUSH ESI

    PUSH EDI

      MOV ESI, [EBP+8]

     MOV EAX, [ESI]    ;参数1的值->EAX

      MOV EDI, [EBP+12]

      XCHG EAX, [EDI]

      MOV [ESI], EAX

      POP EDI

      POP ESI

      RET

  swap ENDP

END

 

4.  将swap.asm添加到TestASM工程中

VC->Project->Add to project->Files, 文件类型选择“所有文件”,选中汇编源文件swap.asm并添加到工程
或直接编译swap.asm,将生成的swap.obj拷贝到工程目录下

5.  在VC中设置汇编程序编译选项

在VC的FileView中,右击swap.asm->Settings, 切换到“Custom Build”选项卡,

在“Command”中输入:ml /c /coff  $(InputName).asm, 

“Output”中输入 :$(InputName).obj

 

6.  编译链接执行

双击test.c->Compile, 生成test.obj

双击swap.asm->Compile, 生成swap.obj

然后Build, 生成TestASM.exe

最后执行

结果如下:

before swaping, a=1, b=2

after  swaping, a=2, b=1

Press any key to continue

 

二、__stdcall调用方式

1.C源程序

#include<stdio.h>

extern void __stdcall swap(int *px, int *py);

int main(void)

{

       int a=1, b=2;

       printf("before swaping, a=%d, b=%d\n", a, b);

       swap(&a, &b);

       printf("after  swaping, a=%d, b=%d\n", a, b);

    return 0;

}

 

2. 汇编源程序

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

.CODE

  swap PROC a:DWORD, b:DWORD

    PUSH ESI

    PUSH EDI

      MOV ESI, [EBP+8]

     MOV EAX, [ESI]    ;参数1的值->EAX

      MOV EDI, [EBP+12]

      XCHG EAX, [EDI]

      MOV [ESI], EAX

      POP EDI

      POP ESI

      RET

  swap ENDP

END

 

三、总结

 

函数调用约定             __cdecl                   __stdcall
 
相同点               自右向左反序入栈
 
不同点
 函数名修饰符           _FunctionName        _FunctionName@参数字节数
 
 谁清理堆栈参数         调用者               被调用者
 


 

1.       自右向左反序入栈

0040105B   lea         edx,[ebp-8]

0040105E   push        edx

0040105F   lea         eax,[ebp-4]

00401062   push        eax

2.       函数名修饰符

使用dumpbin工具查看swap.obj

__cdecl调用约定: __swap

__stdcall调用约定:__swap@8

 

3.       谁清理堆栈参数

(1)__cdecl调用约定

调用者来清理,如下面的add esp, 8

8:        swap(&a, &b);

0040105B   lea         edx,[ebp-8]

0040105E   push        edx

0040105F   lea         eax,[ebp-4]

00401062   push        eax

00401063   call        @ILT+5(_swap) (0040100a)

00401068   add         esp,8

 

(2)__stdcall调用约定

被调用者负责清理,如下面的ret 8

7:        swap(&a, &b);

0040105B   lea         edx,[ebp-8]

0040105E   push        edx

0040105F   lea         eax,[ebp-4]

00401062   push        eax

00401063   call        @ILT+0(_swap@8) (00401005)



_swap@8:

004010AC   push        ebp

004010AD   mov         ebp,esp

004010AF   push        esi

004010B0   push        edi

004010B1   mov         esi,dword ptr [ebp+8]

004010B4   mov         eax,dword ptr [esi]

004010B6   mov         edi,dword ptr [ebp+0Ch]

004010B9   xchg        eax,dword ptr [edi]

004010BB   mov         dword ptr [esi],eax

004010BD   pop         edi

004010BE   pop         esi

004010BF   leave

004010C0   ret         8