这一文章中我们主要分析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的成员函数的调用过程,我在下一文章中说明。
分享到:
相关推荐
而要成功编译ExoSIP,似乎许多人被难住了,直接在XP-sp2上,用VC6,虽然你使用了eXoSIP推荐的winsock2.h,但是会得到一个 sockaddr_storage结构不能识别的错误,因为vc6自带的开发库太古董了...
---- (2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存,并把权限更改为可读可写可执行。 ---- (3) 把ThreadFuction的二进制机器码写入这片虚存。 ---- (4) 用CreateRemoteThread在该进程上创建一个线程,...
产生一个Worker Thread 产生一个UI Thread 线程的结束 线程与同步控制 MFC多线程程序例程 第15章 定制一个AppWizard 到底Wizard是什么? Custom AppWizard的基本操作 剖析AppWizard Components Dialog Templates和...
在模板窗口中选中“Windows 应用程序”作为项目开发模板,在“名称”、“位置”编辑框中输入自己设定的项目名字和项目存储位置,本讲义使用“CSharp浏览器”作为项目名称,如图4-2所示。 图4-2 输入新建项目的属性...
2、equalsIgnoreCase:忽略大小写的比较,上例中如果您输入的是BYE,则不会退出,因为大小写不同,但是如果使用这个方法,则会退出。 3、indexOf(int ch);返回字符ch在字符串中首次出现的位置 4、substring(int ...
实例41 线程Thread Relative Static跟踪与实现 实例42 线程池(ThreadPool)的应用 实例43 多线程互斥运行 实例44 多线程时钟应用程序 实例45 监视多线程 实例46 防止多线程应用程序死锁 实例47 文件同步操作...
利用业余时间,写了个貌似windows自带的任务管理器(私下认为其功能更甚windows自带的)。 封装了许多API接口成为类(一些源自网络,一些自己封装),方便C++使用。但是对整个代码的设计比较烂,打算在学完设计模式...
定义一个类名为"MyClass.java"的类,并且该类可被一个工程中的所有类访问,那么该类的正确声明应为:CD A double a=1.0; A private class MyClass extends Object B class MyClass extends Object C ...
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 ...
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
产生一个Worker Thread 产生一个UI Thread 线程的结束 线程与同步控制 MFC多线程程序例程 第15章 定制一个AppWizard 到底Wizard是什么? Custom AppWizard的基本操作 剖析AppWizard Components Dialog Templates和...
Tricks of the Windows video Game Programming <br>PART I Windows Programming Foundations 7 1 Journey into the Abyss 9 A Little History.............................................................
深入浅出MFC(第二版) 目录 第0章 你一定要知道(导读) 这本书适合谁 你需要什么技术基础 你需要什么软硬件环境 让我们使用同一种语言 本书符号习惯 本书例程的取得 范例程序说明 与前版本之差异 如何联络作者 第...
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 ...
实例52 在C#中快速调用Windows API 实例53 摄氏温度与华氏温度间相互转换(1) 实例54 摄氏温度与华氏温度间相互转换(2) 实例55 使用FileSystemWatcher组件监视Web服务器 实例56 由颜色名字...
③、各种开源控件类的使用; ④、MFC与SDK API中同名函数问题。 5、VC中常用控件的用法讲解 ①、VC中常用控件的用法讲解见:http://www.cctry.com/thread-106-1-1.html ②、VS2008中新增控件的用法讲解。 6、...
实例52 在C#中快速调用Windows API 实例53 摄氏温度与华氏温度间相互转换(1) 实例54 摄氏温度与华氏温度间相互转换(2) 实例55 使用FileSystemWatcher组件监视Web服务器 实例56 由颜色名字...
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...
//调用下一个钩子 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr ...
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...