教你用Windows API 写一个Thread类(不使用static哦)------(2)

22 篇文章 0 订阅
14 篇文章 0 订阅

    这一文章中我们主要分析VS平台对于函数调用的编译处理,首先我们看一个简单的例子,代码如下:

        
void Hello(){
        }

        int main(){
             Hello();
        }

    然后在VS Command Prompt下面用cl -FA main.cpp 编译一下,你会得到一个汇编的文件main.asm,其内容如下:

;
 Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

 TITLE E:\bossjue\main.cpp
 	.686P
 	.XMM
 	include listing.inc
 	.model flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC ?Hello@@YAXXZ     ; Hello
; Function compile flags: /Odtp
_TEXT SEGMENT
?Hello@@YAXXZ PROC     ; Hello
; File e:\bossjue\main.cpp
; Line 1
 	push ebp
 mov ebp, esp
; Line 2
 	pop ebp
 	ret 0
?Hello@@YAXXZ ENDP     ; Hello
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 4
 	push ebp
 	mov ebp, esp
; Line 5
 	call ?Hello@@YAXXZ    ; Hello
; Line 6
 	xor eax, eax
	pop ebp
 	ret 0
_main ENDP
_TEXT ENDS
END



    别怕,有我给你们解释这些代码,这些代码可以说其实都不用看,只需要看有标记;Line 1、;Line 2……这些行就行了,首先在Lin 4,这是main函数的开始,里面首先保存了栈帧,然后Lin 5那里跳到Hello函数里面去执行Hello里面的代码。也就是说,如果我们写以下的代码也应该是对的。


void Hello(){
}

int main(){
    __asm{
        call Hello
    }
}


 

    可以编译,看到程序正常运行,说明我们的call调用是成功的,在此说明了一点,函数调用最后关键的一步是call调用。

上面只是简单的一个Hello函数,下面我们用难一点的去测试,我们写如下代码:


int Hello(){
    return 100;
}

int main(){
    Hello();
}


 

    这个代码和上面代码的区别在于这个函数Hello 有返回值,同样地用cl -FA main.cpp编译得到main.asm,打开main.asm看到其内容如下:

; 
Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01

 TITLE E:\bossjue\main.cpp
 	.686P
 	.XMM
 include listing.inc
 	.model flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC ?Hello@@YAHXZ     ; Hello
; Function compile flags: /Odtp
_TEXT SEGMENT
?Hello@@YAHXZ PROC     ; Hello
; File e:\bossjue\main.cpp
; Line 1
 	push ebp
 	mov ebp, esp
; Line 2
 	mov eax, 100    ; 00000064H
; Line 3
 	pop ebp
 	ret 0
?Hello@@YAHXZ ENDP     ; Hello
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 5
 	push ebp
 	mov ebp, esp
; Line 6
 	call ?Hello@@YAHXZ    ; Hello
; Line 7
 	xor eax, eax
 	pop ebp
 	ret 0
_main ENDP
_TEXT ENDS
END



    在Line2里面可以看到有一句mov eax, 100,联想到Hello里面返回100,可以猜测VS里面是用eax传递返回值的,其实确实是这样的,可以用下面的代码测试:


#include <iostream>
using namespace std;
int Hello(){
    __asm{
        mov eax, 100
   }
}

int main(){
    cout<<Hello()<<endl;
}



    可以看到输出100,说明我了们的结果是对的,函数的返回值是存放在eax进而的。

下面我们再给Hello传递参数试试,来进一步说明参数传递的原理代码如下


void Hello(int iVA, int iVB){

}

int main(){
    Hello(3, 5);
}


 

    同样的得到汇编的代码如下:

; 
Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

 TITLE E:\bossjue\main.cpp
 	.686P
 	.XMM
 include listing.inc
 	.model flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC ?Hello@@YAXHH@Z     ; Hello
; Function compile flags: /Odtp
_TEXT SEGMENT
_iVA$ = 8      ; size = 4
_iVB$ = 12      ; size = 4
?Hello@@YAXHH@Z PROC     ; Hello
; File e:\bossjue\main.cpp
; Line 1
 	push ebp
 	mov ebp, esp
; Line 3
 	pop ebp
 	ret 0
?Hello@@YAXHH@Z ENDP     ; Hello
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 5
 	push ebp
 	mov ebp, esp
; Line 6
 	push 5
 	push 3
 	call ?Hello@@YAXHH@Z    ; Hello
 	add esp, 8
; Line 7
 	xor eax, eax
 	pop ebp
 	ret 0
_main ENDP
_TEXT ENDS
END



    可以看到,其实不过是把参数用push传递进了stack里面,然后就是一个call而已,当然是主调函数清除stack(一句add esp而已)

为了测试,我们写下如下的代码


#include <stdio.h>

int main(){
    char *lpstrFormat = "%s %d";
    char *lpStr   = "Hello, this year is: ";
    __asm{
        push 2012
        push lpStr
        push lpstrFormat
        call printf
        add esp, 12
   }
}



    然后在命令行里面运行得到了你想要的结果,呵呵。
当然,参数怎么传递的和谁清除stack这个由调用方式决定的,调用方式一般有三种__stdcall, __cdecl, __fastcall,读都可以在网上baidu一下,或者过几天我自己写文章说明。


    到此,一般函数调用的过程已经完全说完了,如果想知道class的成员函数的调用过程,我在下一文章中说明。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值