[资料 from asm.yeah.net] ASM编程环境的构建和MASM32宏

来源(Iczelion 的 Win32asm 教程)

[资料 from asm.yeah.net] ASM编程环境的构建和MASM32宏

Win32汇编编程

作者:Hume/冷雨飘心·发布日期:2002-6-24·阅读次数:16588

Part I: ASM编程环境的构建

   俗云:工欲善其事,必先利其器.

(一)编辑器的选择

   编辑器是不可或缺的,而现在的编辑器也实在太多,在dos下你肯定用过经典的dos自带的edit,或者asmedit,wps等,然而现在平台已经转移到了Windows,我们的选择就更加丰富了,替代edit的是notepad,甚至有word,wps2000这样强大的文字处理工具,然而选择他们并不是写asm的最佳选择,因为他们并不是为asm设计所专门设计的,不能完全满足我们的需要...
   现在有几种比较流行的集成asm环境,其一是asmStudio,国人开发,不过只是适合dos下的asm编写,支持win32ASM的还没有看到;其2是ASMedit,完全是用asm写的,小巧支持语法加亮等功能,也是不错的选择;现在呼声最高的恐怕唯Ketlio正在开发的RadASM了,支持MASM,TASM和FASM的集成环境的构建,有自动语法提示等功能,不过唯一的遗憾是不支持中文,这使人很失望,如果支持中文,肯定是首选.
   此外还有editplus和ultraedit可供我们选择,这二者经过适当设置后即可支持语法加亮,自动填充,和shell执行等功能,使用起来很方便,在editplus中如何实现自动编译链接请参见我以前写的一篇文章.由于具有良好的Unicode支持,所以推荐使用,唯一的缺点就是无法实现win32Api的参数提示和自动填充功能.
   由于功能完善的asm集成编程环境还没有出现,所以我们只能根据各种编辑器的优缺点和自己的偏好加以选择.不要抱怨!谁叫你选择的是ASM???
   我用的是editplus 2.01C.感觉不错,推荐使用.

(二)编译器的选择(compiler)

   现在网上的编译器种类很多,比较著名的有MASM,TASM,NASM,FASM,SPASM,A86,GAS,GoASM等,究竟选择什么作为我们的编译器似乎是每个初学者几乎必问的问题.其实各个编译器互有优缺点,究竟选择什么,取决于你的实际需要.下面介绍一下主要的几种:

   1.MASM和TASM
   Masm是微软的ASM编译器,TASM是编译器巨人Borland公司的产品,5.0版本现在已经可以在其主页免费下载,我最初选择masm的原因很简单,是因为大部分教科书都使用他作为蓝本,在dos时代的机房里面配备的也基本都是MASM.就dos而言,但低版本的masm并不是最佳的,因为borland公司推出了TASM,Tasm完全兼容masm,并且由于编译速度快等优点获得了编程者的厚爱.但在国内使用较多的还是MASM.WIn32下TASM5.0有点力不从心了,这是由于tasm的头文件和库不完整,而Borland也放弃了Tasm的继续开发.相反MASM则不断更新,更由于hutch为Masm作了一个masm32V?.zip的开发包,里面有完整的头文件和库文件,所以win32下使用masm的人数日渐增多,成为主流.

   2.NASM

   NASM(netwide assembler),是一个正在开发中的项目,其目的是支持多种平台的文件格式,比如elf,a.out等unix和linux所使用的文件格式,如果你要在上述平台下写asm,那么最好的选择是nasm,不过nasm当然也可以用于写win32ASM,麻烦的问题和tasm是同样的,那就是缺少头文件和库文件的支持,不过如果你厌倦了MASM的烦琐奇怪有时又容易产生歧义的伪操作符的话,试试Nasm的语法,相信会有所收获.NASM生成obj的链接可以使用Alink.

   3.FASM

   fasm(flat assembler)是一个纯粹用汇编语言写成,并采用自展技术的正在开发的的编译器,fasm最大的优点在于不需要额外的链接步骤而直接生成可执行文件,没有什么烦琐的伪命令,所以写出来的代码看起来十分干净.另外用fasm写16bit exe或com可能是非常好的选择,简单而高效.此外在PE格式的import,export,resource等的处理上也都别具一格.不过目前尚不完善...

   4.其他

   其他诸如spasm,a86等由于我没有用过,所以不妄加评论了.

   所以如果你在写win32asm的话,MASM32仍然是最好的选择.其他:For Coding Pleasure...

   5.资源编译器

   WIn32涉及到资源,你可以用与rc(resourcecompiler)任何兼容的资源编译器,比如用微软的VC自带的资源编译器,或者Borland resource Workshop.大部分开发包自带资源编译器.

(三)链接器(linker)

   基本上述的种类的编译器,都附带有相应的链接器和资源编辑器.只有Nasm是个例外,与nasm配合使
用的链接器有很多,最普遍应用的是alink,目前版本是1.6.

Part II:MASM32宏(Macro)的使用

   如果你已经使用了MASM,那么让我们来看一下masm是什么,masm是MACRO assembler的简称,你喜欢用Macro吗?用MAcro可以缩短源代码,简化程序的编写,便于理解,而masm的宏还是比较强大的,虽然有些地方不够贴心和简洁,下面结合我的头文件简单介绍一下几个常用的宏...

   1)m2m 在masm32包里面
   mov 指令不允许mov mem1,mem,mem*代表地址,你每次都
	  mov eax,mem
          mov mem1,eax

   不会吧,实际上你可以定义一个m2m宏,为了不改变寄存器内容,使用的是堆栈
	  m2m MACRO M1, M2
              push M2
              pop  M1
          ENDM

以后每次在mem到mem的移动就很方便了....

   2)return 在C里面经常遇到return语句,在win32asm里面也经常遇到需要返回值的地方,让我门来定义一个return语句:
        return  MACRO arg:=<0>
                mov eax,arg
                ret
                ENDM

   这样就可以方便地使用return TRUE或者return FALSE了...
   不过这还不是最终的答案我们还可以根据返回的参数进一步优化一下,这是我的优化版本.
	return  MACRO arg:=<0>
                IFIDNI <&arg>,<0>
                 sub eax,eax
                ELSEIFIDNI <&arg>,<1>
                 xor eax,eax
                 inc eax
                ELSE
                 mov   eax,arg
                ENDIF
                ret
                ENDM

   3)CTEXT 有时候你需要在asm里面定义一些字符串可能只用到一次,这时你就可以用CTEXT宏
     CTEXT MACRO y:VARARG                     ;This is a good macro
		LOCAL sym

	CONST segment
		IFIDNI 
,<>
			sym db 0
		ELSE
			sym db y,0
		ENDIF
	CONST ends
		EXITM 

     ENDM

    这样你就可以用inoke LoadLibrary,CTEXT("KERNEL32.dll")方便地使用了,尤其是代码比较长的时候不用翻来翻去,定义数据,然后再offset ****了...呵呵.
    其他的下面的宏功能基本是一致的.
     dsText MACRO name,Text:VARARG
        .data
            name    db Text,0
        .code
     ENDM

    下面这个宏用于在代码段里面定义数据,在链接的时候注意假如/SECTION:.text,EWR否则读写这类数据会产生非法操作.
    szText MACRO name,Text:VARARG
        jmp  @f
            name    db Text,0
        @@:
    ENDM

    你可以根据需要选用.

    4)$invoke宏,用于inline Coding,在C里面你肯定看到过GetModuleFileName(GetModuleHandle(0),&buf);的语句在asm里面依然可以实现...那就是用下面的$invoke宏:
   $invoke Macro fun:REQ,args:VARARG
      IFNB 

           invoke	fun,&args
      ELSE
	   invoke	fun
      ENDIF
      EXITM 

    ENDM

    不过要注意寄存器争用的情况,比如第3个参数用到eax,那么第一、二个参数就不能用这个内嵌宏.
    5)RGB和$RGB

    在GDI编程里面经常遇到用RGB值作为参数的情况,为了简化这以过程可以定义下面的宏
   RGB MACRO red,green,blue
	xor eax,eax
	mov ah,blue
	shl eax,8
	mov ah,green
	mov al,red
    ENDM

    然后在RGB宏后面用eax作为RGB值参数,这诗歌好想法,不过还不够好,因为占用了多余的代码行,实际上我们需要的仅仅是一格RGB值,于是有了下面的宏:
    $RGB MACRO red:REQ, green:REQ, blue:REQ		;This is better...
	EXITM %(red + 256 * (green + (256 * blue)))
    ENDM

    6)pushm和popm
    这时为了简化寄存器的入栈和出栈而设计的,很简单:
    pushm Macro args:VARARG
      IFNB 

	FOR arg,

	    push arg
	ENDM
      ELSE
       .ERR 

      ENDIF
    EndM

      popm Macro args:VARARG
      IFNB 

	FOR arg,

	  pop arg
	ENDM
      ELSE
       .ERR 

      ENDIF
    EndM

    7)数据定义rb,rw,rd,rq....
    你喜欢这种方式吗?比如buf db 260 dup(?)是不是很烦琐用下面的宏就可以rb buf,260是不是更简单呢?这时我喜欢的....
    rb	Macro label:REQ,count
	IFNB 

	  label db &count dup(?)
	ELSE
	  label	db ?
	ENDIF
    EndM

    类似的是rw,rd,rq...等具体参见我的mac.h文件.

    8)revargs将参数反向排列(special thx to lyb)

    在stdcall调用模式里面使用的是反向压入参数的调用约定,MASM的宏并没有提供反向参数的机制,我们得字节写一个宏.
    revargs     MACRO args:VARARG
        LOCAL   target
        target     TEXTEQU <>
        count=0
        FOR     arg,

                target     CATSTR 
,,target
                count=count+1
        ENDM
            IF	count GT 0
                target     SUBSTR target,1,@SizeStr(%target)-1
                EXITM   target
            ENDIF
        ENDM

    用于需要反向排列参数的地方.

    9)iWin32,iWin32i,避免jmp tabel,有两种方法避免生成jmp tabel(thx to EliCZ's macro)

    一种我以前写的一篇文章里面介绍过,就是利用声明
    _imp__&Win32Api&A proto :DWORD,....
    然后
    call dword ptr [_imp__&Win32Api&A]

    格式另一种是ELiCZ的方法,就是声明
    externdef _imp__&Win32Api&A@NUM:DWORD,其中NUM是参数个数
    然后
    call _imp__&Win32Api&A来调用.

    由于用EliCZ的方法写的macro较长,下面根据我的方法写一个宏:

    iWin32	Macro	Win32API:REQ,args:VARARG
        LOCAL	sz1
	sz1	TEXTEQU <>
%	FOR pxx,

	   IFNB 

		 push pxx
		 sz1  CATSTR sz1,<,:DWORD>
	   ENDIF
	ENDM
	sz1 SUBSTR sz1,2,@SizeStr(%sz1)-1
	sz1	CATSTR <_imp__&Win32API>,<  PROTO  >,sz1
	sz1
	call	DWORD PTR [_imp__&Win32API]
        ENDM

下面iWin32i可以根据情况生成对ansi或者UNICODE的调用,前提是定义UNICODE=0或者TRUE...
        iWin32i	Macro	Win32API:REQ,args:VARARG
	IF		UNICODE
	   iWin32	Win32API&W,

	ELSE
	   iWin32	Win32API&A,

	ENDIF
        ENDM

    注意这个宏并没有参数检查,如果你不熟悉APi建议不要使用,你可以用masm包自带的工具转换头文件来避免产生jmp tabel...如果你喜欢宏,那么就用我这种方式.
    宏不同于封装,我们可以用他来简化我们的工作而又可以清楚知道将产生什么代码,为什么不用呢?
                               the way of Hume,2002
                                          humewen@21cn.com

Link: http://www.asm32.net/article_details.aspx?id=2625


浏览次数 402 发布时间 2007-02-23 00:02:27 从属分类 Win32汇编编程 【评论】【 】【打印】【关闭
 
| www.asm32.net | 2006版 | 资料中心 | linux | asm/asm32 | C/C++ | VC++ | java | Python | 书签 | ASP.Net书签 | 京ICP备09029108号-1