`
hulianwang2014
  • 浏览: 690497 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

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

 
阅读更多

这一文章中我们主要分析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的成员函数的调用过程,我在下一文章中说明。

分享到:
评论

相关推荐

    基于SIP开发软件电话的一些资源(转自YOUTOO)

    而要成功编译ExoSIP,似乎许多人被难住了,直接在XP-sp2上,用VC6,虽然你使用了eXoSIP推荐的winsock2.h,但是会得到一个 sockaddr_storage结构不能识别的错误,因为vc6自带的开发库太古董了...

    detour 2.1

    ---- (2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存,并把权限更改为可读可写可执行。 ---- (3) 把ThreadFuction的二进制机器码写入这片虚存。 ---- (4) 用CreateRemoteThread在该进程上创建一个线程,...

    侯捷- -深入浅出MFC

    产生一个Worker Thread 产生一个UI Thread 线程的结束 线程与同步控制 MFC多线程程序例程 第15章 定制一个AppWizard 到底Wizard是什么? Custom AppWizard的基本操作 剖析AppWizard Components Dialog Templates和...

    C#浏览器编程,学习使用

    在模板窗口中选中“Windows 应用程序”作为项目开发模板,在“名称”、“位置”编辑框中输入自己设定的项目名字和项目存储位置,本讲义使用“CSharp浏览器”作为项目名称,如图4-2所示。 图4-2 输入新建项目的属性...

    Java精华(免费版)

    2、equalsIgnoreCase:忽略大小写的比较,上例中如果您输入的是BYE,则不会退出,因为大小写不同,但是如果使用这个方法,则会退出。 3、indexOf(int ch);返回字符ch在字符串中首次出现的位置 4、substring(int ...

    Visual.C#.编程精彩百例

    实例41 线程Thread Relative Static跟踪与实现 实例42 线程池(ThreadPool)的应用 实例43 多线程互斥运行 实例44 多线程时钟应用程序 实例45 监视多线程 实例46 防止多线程应用程序死锁 实例47 文件同步操作...

    TaskManager

    利用业余时间,写了个貌似windows自带的任务管理器(私下认为其功能更甚windows自带的)。 封装了许多API接口成为类(一些源自网络,一些自己封装),方便C++使用。但是对整个代码的设计比较烂,打算在学完设计模式...

    Java测试题2答案

    定义一个类名为"MyClass.java"的类,并且该类可被一个工程中的所有类访问,那么该类的正确声明应为:CD A double a=1.0; A private class MyClass extends Object B class MyClass extends Object C ...

    Java邮件开发Fundamentals of the JavaMail API

    Fundamentals of the JavaMail API Presented by developerWorks, your source for great tutorials ibm.com/developerWorks Table of Contents If you're viewing this document online, you can click ...

    Java2核心技术卷I+卷2:基础知识(第8版) 代码

    Java 核心技术 卷1 Index Chapter 1: An Introduction to Java 1 Java As a Programming Platform 2 The Java “White Paper” Buzzwords...A Complete Example: Accessing the Windows Registry 975 Index 991

    深入浅出MFC 2e

    产生一个Worker Thread 产生一个UI Thread 线程的结束 线程与同步控制 MFC多线程程序例程 第15章 定制一个AppWizard 到底Wizard是什么? Custom AppWizard的基本操作 剖析AppWizard Components Dialog Templates和...

    Tricks of the Windows video Game Programming---part1

    Tricks of the Windows video Game Programming &lt;br&gt;PART I Windows Programming Foundations 7 1 Journey into the Abyss 9 A Little History.............................................................

    深入浅出MFC【侯捷】

    深入浅出MFC(第二版) 目录 第0章 你一定要知道(导读) 这本书适合谁 你需要什么技术基础 你需要什么软硬件环境 让我们使用同一种语言 本书符号习惯 本书例程的取得 范例程序说明 与前版本之差异 如何联络作者 第...

    微软内部资料-SQL性能优化2

    The boot.ini option /3GB was created for those cases where systems actually support greater than 2 GB of physical memory and an application can make use of it This capability allows memory intensive ...

    《Visual.C#.编程精彩百例》配套光盘.part2

    实例52 在C#中快速调用Windows API 实例53 摄氏温度与华氏温度间相互转换(1) 实例54 摄氏温度与华氏温度间相互转换(2) 实例55 使用FileSystemWatcher组件监视Web服务器 实例56 由颜色名字...

    VC驿站基础班无KEY高清C++教程下载地址

    ③、各种开源控件类的使用; ④、MFC与SDK API中同名函数问题。 5、VC中常用控件的用法讲解 ①、VC中常用控件的用法讲解见:http://www.cctry.com/thread-106-1-1.html ②、VS2008中新增控件的用法讲解。 6、...

    《Visual.C#.编程精彩百例》配套光盘part1

    实例52 在C#中快速调用Windows API 实例53 摄氏温度与华氏温度间相互转换(1) 实例54 摄氏温度与华氏温度间相互转换(2) 实例55 使用FileSystemWatcher组件监视Web服务器 实例56 由颜色名字...

    cuda检测工具 devicequery.exe

    CUDA Device Query (Runtime API) version (CUDART static linking) Detected 1 CUDA Capable device(s) Device 0: "GeForce GTX 650" CUDA Driver Version / Runtime Version 9.1 / 8.0 CUDA Capability Major...

    【VS2010 C# 代码】实时监听鼠标位置

    //调用下一个钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr ...

    cuda检测工具 devicequery.zip(不含源代码,源代码在cuda sdk 8.0里)

    CUDA Device Query (Runtime API) version (CUDART static linking) Detected 1 CUDA Capable device(s) Device 0: "GeForce GTX 760" CUDA Driver Version / Runtime Version 9.2 / 8.0 CUDA Capability Major...

Global site tag (gtag.js) - Google Analytics