导读:
我们一般会使用汇编来编写程序中效率瓶颈部分, 而这又包括两种方法, 一是采用内联汇编, 这是十分简洁方便的一个方法, 我们可以不必考虑如寄存器保护, 函数参数退栈之类繁琐的问题, 但其缺点是可移植性不强, 影响代码风格等. 而另一个就是本文要讲的, VC链接纯汇编函数.好,言归正传, 我们开始
一,工具
1) VC++2003, 本文所讲的操作都是基于此版本.
2) NASM 0.98.39.
NASM(Netwide Assembly)是一个为可移植性与模块化而设计的一个 80x86 的开源汇编器, 其优点有:
1支持相当多的目标文件格式.包括 Linux 和'NetBSD/FreeBSD','a.out','ELF','COFF',微软 16位的'OBJ'和'Win32'。它还可以输出纯二进制文件。
2 支持最新的指令集. 包括'Pentium','P6','MMX','3DNow!','SSE' and 'SSE2'指令集.
大家可以在网上搜到NASM的下载及学习资料, 下面是部分链接:
二,步骤
1 新建一个名位CallNASM的VC工程, 类型为Win32控制台, 接受默认设置.
2 在该工程下新建一个名为Sort.asm的汇编源文件
3 在该文件中输入代码:
[bits 32] ;使用32位模式的处理器
[section .text] ;text段, 代码段,只读并可执行
global _bubble_sort@8; ;申明函数为global的, 这样可以被外部模块调用
_bubble_sort@8: ;定义函数开始,C++中原型为int bubble_sort(int* ;pArray, int dArraysize)
push ebp ;ebp入栈
mov ebp,esp ;esp->ebp
mov esi,[ebp+8]; ;取出第一个参数,数组地址
sub esi, 4 ;数组地址前移一个,为排序做准备
mov ecx,[ebp+12]; ;取第二个参数, 数组长度
.outloop: ;外循环
mov edx,ecx;
.inloop: ;内循环
mov eax, [esi+ecx*4];
mov ebx, [esi+edx*4];
cmp eax, ebx;
jnb .noxchg;
mov [esi+ecx*4], ebx;
mov [esi+edx*4], eax;
.noxchg:
dec edx;
jnz .inloop;
loop .outloop;
mov esp, ebp; ;恢复esp, ebp
pop ebp
ret 8 ;参数退栈 说明:
1) 进入函数
esp为堆栈指针, 进入函数后栈的存储情况及esp指向可能如下:
|参数2|<-------------------- 栈底 |参数1|
|函数返回地址|
|EBP|
|局部变量...|<---------------- esp 也就是说函数参数, 返回地址, ebp寄存器, 局部变量等都会相继压入栈中, 而esp始终指向栈顶, 这里要注意的是, 在汇编中,栈底地址是大于栈顶地址的, 栈是向下生长的.所以, 当我们取参数时栈的情况为:
|参数2| esp+12
|参数1| esp+8
|函数返回地址| esp+4
|EBP| <---------------- esp
此时ebp已入栈, 参数1的地址为:esp+8, 参数2的地址为:esp+12, 但一般我们不直接用esp访问参数, 因为esp随时都会改变(如声明一个局部变量会使esp往下指), 所以我们用ebp保存了这个初始状态下栈的指针, 以便统一访问参数,于是, 取参数的代码为:
mov esi,[ebp+8]; ;取出第一个参数,数组地址
mov ecx,[ebp+12]; ;取第二个参数, 数组长度
2) 算法部分
标准的最简单的冒泡排序法, 二层循环.
3) 退出函数
mov esp, ebp; ;恢复esp
pop ebp
ret 8 ;参数个数
这里第一句恢复esp后, 函数栈中还有4个元素, 然后pop ebp后还剩下3个, ret 8修正两个参数使用的堆栈(如果还有第三个参数, 且大小为4, 则ret 12). 从代码上看esp并没有完全恢复(还剩下 1 个), 但在ret 8之前堆栈应该自动pop了函数的返回地址(不然怎么return:)),函数返回地址的入栈与出栈都是自动完成的.
4 为Sort.asm添加自定义生成属性.
1) 右键->属性, 弹出sort.asm属性页
2) 配置属性->自定义生成步骤->常规
3) 命令行:nasmw $(InputName).asm -f win32 -o $(IntDir)/$(InputName).obj
输出: $(IntDir)/$(InputName).obj
说明:
1)这里将文件$(InputName).asm编译为win32格式obj文件
2)要使这个命令能够成功运行, 应该将nasmw.exe (w表示windows)拷贝到工程目录下, 或者更通用点, 直接拷贝到windows/system32下面
5 在CallNasm.cpp中调用此汇编函数, 代码如下:
#include "stdafx.h"
#include
using namespace std;
//extern function from NASM
extern "C" int _stdcall bubble_sort(int* pArray, int dArraysize);
//helper function to print sort result
void PrintArray(string strBeforeorAfter);
//array to be sorted
int Array[10] = {2, 1, 4, 6, 5, 3, 7, 9, 10, 8};
int _tmain(int argc, _TCHAR* argv[])
{
PrintArray("Before Sort: ");
bubble_sort(Array, 10);
PrintArray("After Sort: ");
return 0;
}
void PrintArray(string strBeforeorAfter)
{
cout<
for(int i = 0; i <10; i++)
{
cout< <<"
用extern引用外部模块的函数,并采用stdcall的调用方式
2) bubble_sort函数在汇编中的名字一般为加上"_"前缀和"@N"后缀, 这里N与参数大小有关
如bubble_sort(int* pArray, int dArraysize)为_bubble_sort@8, 而
bubble_sort(int* pArray)应为_bubble_sort@4.
三, 结论
这样, 我们就能成功的在VC中调用NASM汇编函数了, 事实上, 在VC中调用MASM函数除了汇编语法稍有不同,应该也是类似的.
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=602193
本文转自
http://blog.csdn.net/yanhuang82/archive/2006/02/18/602193.aspx
我们一般会使用汇编来编写程序中效率瓶颈部分, 而这又包括两种方法, 一是采用内联汇编, 这是十分简洁方便的一个方法, 我们可以不必考虑如寄存器保护, 函数参数退栈之类繁琐的问题, 但其缺点是可移植性不强, 影响代码风格等. 而另一个就是本文要讲的, VC链接纯汇编函数.好,言归正传, 我们开始
一,工具
1) VC++2003, 本文所讲的操作都是基于此版本.
2) NASM 0.98.39.
NASM(Netwide Assembly)是一个为可移植性与模块化而设计的一个 80x86 的开源汇编器, 其优点有:
1支持相当多的目标文件格式.包括 Linux 和'NetBSD/FreeBSD','a.out','ELF','COFF',微软 16位的'OBJ'和'Win32'。它还可以输出纯二进制文件。
2 支持最新的指令集. 包括'Pentium','P6','MMX','3DNow!','SSE' and 'SSE2'指令集.
大家可以在网上搜到NASM的下载及学习资料, 下面是部分链接:
二,步骤
1 新建一个名位CallNASM的VC工程, 类型为Win32控制台, 接受默认设置.
2 在该工程下新建一个名为Sort.asm的汇编源文件
3 在该文件中输入代码:
[bits 32] ;使用32位模式的处理器
[section .text] ;text段, 代码段,只读并可执行
global _bubble_sort@8; ;申明函数为global的, 这样可以被外部模块调用
_bubble_sort@8: ;定义函数开始,C++中原型为int bubble_sort(int* ;pArray, int dArraysize)
push ebp ;ebp入栈
mov ebp,esp ;esp->ebp
mov esi,[ebp+8]; ;取出第一个参数,数组地址
sub esi, 4 ;数组地址前移一个,为排序做准备
mov ecx,[ebp+12]; ;取第二个参数, 数组长度
.outloop: ;外循环
mov edx,ecx;
.inloop: ;内循环
mov eax, [esi+ecx*4];
mov ebx, [esi+edx*4];
cmp eax, ebx;
jnb .noxchg;
mov [esi+ecx*4], ebx;
mov [esi+edx*4], eax;
.noxchg:
dec edx;
jnz .inloop;
loop .outloop;
mov esp, ebp; ;恢复esp, ebp
pop ebp
ret 8 ;参数退栈 说明:
1) 进入函数
esp为堆栈指针, 进入函数后栈的存储情况及esp指向可能如下:
|参数2|<-------------------- 栈底 |参数1|
|函数返回地址|
|EBP|
|局部变量...|<---------------- esp 也就是说函数参数, 返回地址, ebp寄存器, 局部变量等都会相继压入栈中, 而esp始终指向栈顶, 这里要注意的是, 在汇编中,栈底地址是大于栈顶地址的, 栈是向下生长的.所以, 当我们取参数时栈的情况为:
|参数2| esp+12
|参数1| esp+8
|函数返回地址| esp+4
|EBP| <---------------- esp
此时ebp已入栈, 参数1的地址为:esp+8, 参数2的地址为:esp+12, 但一般我们不直接用esp访问参数, 因为esp随时都会改变(如声明一个局部变量会使esp往下指), 所以我们用ebp保存了这个初始状态下栈的指针, 以便统一访问参数,于是, 取参数的代码为:
mov esi,[ebp+8]; ;取出第一个参数,数组地址
mov ecx,[ebp+12]; ;取第二个参数, 数组长度
2) 算法部分
标准的最简单的冒泡排序法, 二层循环.
3) 退出函数
mov esp, ebp; ;恢复esp
pop ebp
ret 8 ;参数个数
这里第一句恢复esp后, 函数栈中还有4个元素, 然后pop ebp后还剩下3个, ret 8修正两个参数使用的堆栈(如果还有第三个参数, 且大小为4, 则ret 12). 从代码上看esp并没有完全恢复(还剩下 1 个), 但在ret 8之前堆栈应该自动pop了函数的返回地址(不然怎么return:)),函数返回地址的入栈与出栈都是自动完成的.
4 为Sort.asm添加自定义生成属性.
1) 右键->属性, 弹出sort.asm属性页
2) 配置属性->自定义生成步骤->常规
3) 命令行:nasmw $(InputName).asm -f win32 -o $(IntDir)/$(InputName).obj
输出: $(IntDir)/$(InputName).obj
说明:
1)这里将文件$(InputName).asm编译为win32格式obj文件
2)要使这个命令能够成功运行, 应该将nasmw.exe (w表示windows)拷贝到工程目录下, 或者更通用点, 直接拷贝到windows/system32下面
5 在CallNasm.cpp中调用此汇编函数, 代码如下:
#include "stdafx.h"
#include
using namespace std;
//extern function from NASM
extern "C" int _stdcall bubble_sort(int* pArray, int dArraysize);
//helper function to print sort result
void PrintArray(string strBeforeorAfter);
//array to be sorted
int Array[10] = {2, 1, 4, 6, 5, 3, 7, 9, 10, 8};
int _tmain(int argc, _TCHAR* argv[])
{
PrintArray("Before Sort: ");
bubble_sort(Array, 10);
PrintArray("After Sort: ");
return 0;
}
void PrintArray(string strBeforeorAfter)
{
cout<
for(int i = 0; i <10; i++)
{
cout< <<"
用extern引用外部模块的函数,并采用stdcall的调用方式
2) bubble_sort函数在汇编中的名字一般为加上"_"前缀和"@N"后缀, 这里N与参数大小有关
如bubble_sort(int* pArray, int dArraysize)为_bubble_sort@8, 而
bubble_sort(int* pArray)应为_bubble_sort@4.
三, 结论
这样, 我们就能成功的在VC中调用NASM汇编函数了, 事实上, 在VC中调用MASM函数除了汇编语法稍有不同,应该也是类似的.
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=602193
本文转自
http://blog.csdn.net/yanhuang82/archive/2006/02/18/602193.aspx
本文介绍如何在VC环境中调用NASM汇编语言编写的排序函数,详细讲解了创建工程、编写汇编代码、配置编译命令及C++中调用方法。

897

被折叠的 条评论
为什么被折叠?



