Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8346990
  • 博文数量: 1413
  • 博客积分: 11128
  • 博客等级: 上将
  • 技术积分: 14685
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-13 10:03
个人简介

follow my heart...

文章分类

全部博文(1413)

文章存档

2013年(1)

2012年(5)

2011年(45)

2010年(176)

2009年(148)

2008年(190)

2007年(293)

2006年(555)

分类:

2006-09-15 13:38:09

[点评:NASM使用方式与TASM/MASM相似,在Linux下面应用非常广泛.在windows下面也有版本,强烈建议使用.]


本文主要为有汇编基础, 而习惯了用 VC 的 inline ASM 写代码的朋友们而作.

为什么要使用 NASM?

使用 inline asm 固然方便, 但是却不利于代码的移植. 加上 VC 对新指令集(3D Now! ,XMM 等)的支持速度不够, 使用起来很不方便, 所以我们往往采用外部汇编. 如果你以前熟悉 MASM 或是 TASM, 也不必更换, 否则云风推荐 NASM. NASM 及其文档在 可以下载的到. 使用前最好通读一遍文档. 本文只会强调一些重点部分, 而补充一点遗漏, 而不会全盘复述. NASM 支持各种最新的指令集, 有相当强大的宏语言支持. 你将得到比 VC 的 inline asm 更为灵活的使用空间.

选一个好的编程环境

将 VC 当作 NASM 的编辑环境是完全可行的, 只需要在 Tools->Customize->Tools 下加入 NASM.exe 作为外部工具. 这里不详细介绍. 云风推荐 这款小巧实用的编辑器. 你可以指定各种关键字的颜色, 云风自己制作的语法文件在, 写的还不完备, 很多 nasm 的宏语句尚未加入, 另外还加了一些自己制作的宏. 所以请各位读者酌情修改. 加入 Editplus 的方法是在 Tools-> Preferences->Files->Syntax 里增加一个语法文件. Editplus 支持 output 窗口信息捕获, 在 Tools->Preferences->Tools->User Tools 里增加 NASM.exe, 并选 capture output 就可以了. 当然如果你想制作单独的 win32/pe 文件, 而不是编译成 obj 供 VC link, 那么还需要一个 link 程序. 最好再配合 makefile 使用.

如何编译成可供 VC 连接的 obj

NASM 支持多种输出格式, 虽然 VC 号称是使用的 COFF 格式, 但实际上是有区别的. NASM 除了输出 COFF 格式外, 另外也支持 VC 的目标文件格式, 叫做 win32. 我在 Editplus 的 user tools 里设置的是

	-i I:\nasm\include\ -f win32 -o $(FileNameNoExt).obj $(FileName)
注: 这里的 -i 后是头文件的路径 将编译出来的 obj 加入 VC 的 project 里就可以了. 一般来说, 目标文件有三个段, 分别是 text/data/bss 段.
  • text 段放置代码, 是只读且可运行段
  • data 段放置静态数据, 这些数据会被放置入 exe 文件. 这个段是可读写, 但是不能运行的.
  • bss 段放置动态数据, 这些数据不被放入 exe 文件, 在exe文件被加载入内存后才分配的空间.
一个简单的程序框架是这样的:

[bits 32]

[section .text]
global _func
_func:
; 这里写func 函数的代码

[section .data]

[section .bss]
这里, 用 global 声明了一个可被 C 调用的函数 func (C 函数都有一个下划线前缀) _func: 是这个函数的入口. 在对应的 C 代码里想使用 func 这个函数, 还需要用 extern 声明 func 是外部函数. 如果在 C++ 里使用则还需要将函数说明成 C 调用方式, 方法是用 extern "C" { } 说明

参数的传入和处理

函数的参数处理和其调用方式有关, C 的缺省调用方式是 _cdel 调用方式, C++ 的非静态成员函数采用的是 _thiscall, 关于各种调用方式的处理堆栈的方法, 在 MSDN 里可以查的到. 写 inline asm 可能很少涉及这些, 但是这里却必须搞清楚.

用纯汇编写 win32 程序等

写 WIN32 下的 win32/pe EXE, 我建议使用 Borland 的 obj 格式, 这是因为导入 DLL 中的 API 比较方便. 但是需要注意一些要点:

  • NASM 缺省使用的segment 是 USE16 的, 而在 win32 下必须使用 USE32, 而且必须指定段的类型. 所以必须在源文件头写上这样几行:

    [section .text class=code use32]
    [section .data class=data use32]
    [section .bss class=bss use32]
    %define __SECT__
  • Borland 的 OBJ 文件里可以指定开始的标签(..start), 一般可以写成这样:

    [section .text]
    ..start
    WinMain:
    你的代码将从 WinMain 这里开始运行.
  • 和 C 不一样, 你的主代码没有什么参数传入, 所以你必须自己来得到必要的参数. 比如:

    push dword 0
    call GetModuleHandle ; 获得 hInstance

    获得 Instance 句柄(到 eax).
  • 退出程序也不能直接用 ret, 因为你的程序是一个进程, 而不是一个函数, 所以必须调用:

    push dword 0 ; 退出码
    call ExitProcess
  • 上面的 GetModuleHandle 是 kernel32.dll 里的 API: GetModuleHandleA, 所以需要在汇编源代码中声明导出:
    	import GetModuleHandle kernel32.dll GetModuleHandleA
    extern GetModuleHandle

    另外 ExitProcess 也是这样:

    import ExitProcess kernel32.dll
    extern ExitProcess


    import 的具体用法请参考 NASM 的文档.

善于使用 NASM 强大的宏指令

这本是一个应该很丰富的 Section, 但是时间有限, 只举一个简单的例子, 定义下面这样一个宏:


%imacro callapi 1-*
%define %%api %1
%rotate -1

%rep %0-1
%rotate -1
push dword %2
%endrep

call %%api
%endmacro
然后, 比如你需要调用 MessageBox, 就可以这样写
callapi MessageBox,[hWnd],lpText,lpCap,0
  • hWnd 是一个全局变量保存的窗口句柄, 当然也可以是 0
  • lpText 是文字的字符串指针
  • lpCap 是MessageBox 的标题字符串
另外我自己还做了许多诸如处理函数参数, 保护堆栈等等方便使用的宏, 这里就不一一列出来了. 希望我引个头, 能让更多的朋友喜欢上 NASM
阅读(2576) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~