您的位置:首页 > 其它

32位汇编语言学习笔记(29)--在NASM中使用宏

2015-01-04 07:32 441 查看

宏的语法规则与汇编指令没有关系,只是为了管理代码复杂度而设计的类似于高级语言的特性。NASM的宏语法格式如下:

%macro 宏名称 参数个数

宏的内容

%endmacro

宏的第一个参数用%1表示,第二个参数用%2表示,依次类推。

《Assembly Language step by step programming with linux》在第10章给出了一个使用宏版本的光标控制程序:

;  Executable name : eatmacro
;  Version         : 1.0
;  Created date    : 2/21/2009
;  Last update     : 2/23/2009
;  Author          : Jeff Duntemann
;  Description     : A simple program in assembly for Linux, using
;		   : NASM 2.05, demonstrating the use of escape
;		   : sequences to do simple "full-screen" text output
;		   ; through macros rather than procedures
;
;  Build using these commands:
;    nasm -f elf -g -F stabs eatmacro.asm
;    ld -o eatmacro eatmacro.o
;
;
section .data		; Section containing initialised data

SCRWIDTH:	equ 80	; By default we assume 80 chars wide
PosTerm:	db 27,"[01;01H"	; <ESC>[<Y>;<X>H
POSLEN:		equ $-PosTerm	; Length of term position string
ClearTerm:      db 27,"[2J"	; <ESC>[2J
CLEARLEN	equ $-ClearTerm	; Length of term clear string
AdMsg: 		db "Eat At Joe's!"	; Ad message
ADLEN: 		equ $-AdMsg		; Length of ad message
Prompt:		db "Press Enter: "	; User prompt
PROMPTLEN:	equ $-Prompt		; Length of user prompt

; This table gives us pairs of ASCII digits from 0-80. Rather than
; calculate ASCII digits to insert in the terminal control string,
; we look them up in the table and read back two digits at once to
; a 16-bit register like DX, which we then poke into the terminal
; control string PosTerm at the appropriate place. See GotoXY.
; If you intend to work on a larger console than 80 X 80, you must
; add additional ASCII digit encoding to the end of Digits. Keep in
; mind that the code shown here will only work up to 99 X 99.
Digits:	db "0001020304050607080910111213141516171819"
db "2021222324252627282930313233343536373839"
db "4041424344454647484950515253545556575859"
db "606162636465666768697071727374757677787980"

SECTION .bss		; Section containing uninitialized data

SECTION .text		; Section containing code

;-------------------------------------------------------------------------
; ExitProg: 	Terminate program and return to Linux
; UPDATED:	4/23/2009
; IN: 		Nothing
; RETURNS:	Nothing
; MODIFIES: 	Nothing
; CALLS:	Kernel sys_exit
; DESCRIPTION:	Calls sys_edit to terminate the program and return
;		control to Linux

%macro	ExitProg 0
mov eax,1		; Code for Exit Syscall
mov ebx,0		; Return a code of zero
int 80H			; Make kernel call
%endmacro

;-------------------------------------------------------------------------
; WaitEnter: 	Wait for the user to press Enter at the console
; UPDATED:	4/23/2009
; IN: 		Nothing
; RETURNS:	Nothing
; MODIFIES: 	Nothing
; CALLS:	Kernel sys_read
; DESCRIPTION:	Calls sys_read to wait for the user to type a newline at
;		the console

%macro	WaitEnter 0
mov eax,3		; Code for sys_read
mov ebx,0		; Specify File Descriptor 0: Stdin
int 80H			; Make kernel call
%endmacro

;-------------------------------------------------------------------------
; WriteStr: 	Send a string to the Linux console
; UPDATED:	4/21/2009
; IN: 		String address in %1, string length in %2
; RETURNS:	Nothing
; MODIFIES: 	Nothing
; CALLS:	Kernel sys_write
; DESCRIPTION:	Displays a string to the Linux console through a
;		sys_write kernel call

%macro WriteStr 2		; %1 = String address; %2 = string length
push eax		; Save pertinent registers
push ebx
mov ecx,%1		; Put string address into ECX
mov edx,%2		; Put string length into EDX
mov eax,4		; Specify sys_write call
mov ebx,1		; Specify File Descriptor 1: Stdout
int 80H			; Make the kernel call
pop ebx			; Restore pertinent registers
pop eax
%endmacro

;-------------------------------------------------------------------------
; ClrScr: 	Clear the Linux console
; UPDATED:	4/23/2009
; IN: 		Nothing
; RETURNS:	Nothing
; MODIFIES: 	Nothing
; CALLS:	Kernel sys_write
; DESCRIPTION:	Sends the predefined control string <ESC>[2J to the
;		console, which clears the full display

%macro ClrScr 0
push eax	  ; Save pertinent registers
push ebx
push ecx
push edx
; Use WriteStr macro to write control string to console:
WriteStr ClearTerm,CLEARLEN
pop edx		  ; Restore pertinent registers
pop ecx
pop ebx
pop eax
%endmacro

;-------------------------------------------------------------------------
; GotoXY: 	Position the Linux Console cursor to an X,Y position
; UPDATED:	4/23/2009
; IN: 		X in %1, Y in %2
; RETURNS:	Nothing
; MODIFIES: 	PosTerm terminal control sequence string
; CALLS:	Kernel sys_write
; DESCRIPTION:	Prepares a terminal control string for the X,Y coordinates
;		passed in AL and AH and calls sys_write to position the
;		console cursor to that X,Y position. Writing text to the
;		console after calling GotoXY will begin display of text
;		at that X,Y position.

%macro GotoXY 2			; %1 is X value; %2 id Y value
pushad			; Save caller's registers
xor edx,edx		; Zero EDX
xor ecx,ecx		; Ditto ECX
; Poke the Y digits:
mov dl,%2		     ; Put Y value into offset term EDX
mov cx,word [Digits+edx*2]   ; Fetch decimal digits to CX
mov word [PosTerm+2],cx	     ; Poke digits into control string
; Poke the X digits:
mov dl,%1		     ; Put X value into offset term EDX
mov cx,word [Digits+edx*2]   ; Fetch decimal digits to CX
mov word [PosTerm+5],cx	     ; Poke digits into control string
; Send control sequence to stdout:
WriteStr PosTerm,POSLEN
; Wrap up and go home:
popad			; Restore caller's registers
%endmacro

;-------------------------------------------------------------------------
; WriteCtr: 	Send a string centered to an 80-char wide Linux console
; UPDATED:	4/23/2009
; IN: 		Y value in %1, String address in %2, string length in %3
; RETURNS:	Nothing
; MODIFIES: 	PosTerm terminal control sequence string
; CALLS:	GotoXY, WriteStr
; DESCRIPTION:	Displays a string to the Linux console centered in an
;		80-column display. Calculates the X for the passed-in
;		string length, then calls GotoXY and WriteStr to send
;		the string to the console

%macro WriteCtr 3	; %1 = row; %2 = String addr; %3 = String length
push ebx	; Save caller's EBX
push edx	; Save caller's EDX
mov edx,%3	; Load string length into EDX
xor ebx,ebx	; Zero EBX
mov bl,SCRWIDTH	; Load the screen width value to BL
sub bl,dl	; Calc diff. of screen width and string length
shr bl,1	; Divide difference by two for X value
GotoXY bl,%1	; Position the cursor for display
WriteStr %2,%3	; Write the string to the console
pop edx		; Restore caller's EDX
pop ebx		; Restore caller's EBX
%endmacro

global 	_start			; Linker needs this to find the entry point!

_start:
nop			; This no-op keeps gdb happy...

; First we clear the terminal display...
ClrScr
; Then we post the ad message centered on the 80-wide console:
WriteCtr 12,AdMsg,ADLEN
; Position the cursor for the "Press Enter" prompt:
GotoXY 1,23
; Display the "Press Enter" prompt:
WriteStr Prompt,PROMPTLEN
; Wait for the user to press Enter:
WaitEnter
; ...and we're done!
ExitProg

makefile文件内容如下:

eatmacro: eatmacro.o
ld -o eatmacro eatmacro.o
eatmacro.o: eatmacro.asm
nasm -f elf -l eatmacro.lst -g -F stabs eatmacro.asm

程序逻辑与第一版光标控制程序是一样的,执行结果也相同。下面分析一下使用宏版本的反汇编的代码,只分析一小段,其余的都类似:

[root@bogon eatmacro]# objdump -d eatmacro

eatmacro: file format elf32-i386

Disassembly of section .text:

08048080 <_start>:

8048080: 90 nop

8048081: 50 push %eax // ClrScr宏展开

8048082: 53 push %ebx

8048083: 51 push %ecx

8048084: 52 push %edx

8048085: 50 push %eax // WriteStr ClearTerm,CLEARLEN宏展开是在这里

8048086: 53 push %ebx

8048087: b9 8c 91 04 08 mov $0x804918c,%ecx //$0x804918c是ClearTerm字节数组的地址

804808c: ba 04 00 00 00 mov $0x4,%edx //$0x4是CLEARLEN

8048091: b8 04 00 00 00 mov $0x4,%eax

8048096: bb 01 00 00 00 mov $0x1,%ebx

804809b: cd 80 int $0x80

804809d: 5b pop %ebx

804809e: 58 pop %eax // WriteStr宏在这里结束

804809f: 5a pop %edx

80480a0: 59 pop %ecx

80480a1: 5b pop %ebx

80480a2: 58 pop %eax // ClrScr宏结束

……

因此可以看出,NASM就是在预处理时,把宏展开,简单的进行了的代码替换。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: