如何在VC中汇编,调用Nasm编写的函数

本文介绍如何在VC环境中调用NASM汇编语言编写的排序函数,详细讲解了创建工程、编写汇编代码、配置编译命令及C++中调用方法。
导读:
  我们一般会使用汇编来编写程序中效率瓶颈部分, 而这又包括两种方法, 一是采用内联汇编, 这是十分简洁方便的一个方法, 我们可以不必考虑如寄存器保护, 函数参数退栈之类繁琐的问题, 但其缺点是可移植性不强, 影响代码风格等. 而另一个就是本文要讲的, 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值