32位汇编语言学习笔记(29)--在NASM中使用宏
2015-01-04 07:32
441 查看
宏的语法规则与汇编指令没有关系,只是为了管理代码复杂度而设计的类似于高级语言的特性。NASM的宏语法格式如下:
%macro 宏名称 参数个数
宏的内容
%endmacro
宏的第一个参数用%1表示,第二个参数用%2表示,依次类推。
《Assembly Language step by step programming with linux》在第10章给出了一个使用宏版本的光标控制程序:
makefile文件内容如下:
程序逻辑与第一版光标控制程序是一样的,执行结果也相同。下面分析一下使用宏版本的反汇编的代码,只分析一小段,其余的都类似:
[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就是在预处理时,把宏展开,简单的进行了的代码替换。
宏的语法规则与汇编指令没有关系,只是为了管理代码复杂度而设计的类似于高级语言的特性。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就是在预处理时,把宏展开,简单的进行了的代码替换。
相关文章推荐
- windows下32位汇编语言学习笔记 第三章 使用MASM
- 32位汇编语言学习笔记(21)--用NASM实现Hello World小程序
- 32位汇编语言学习笔记(41)--fgets等函数的使用
- 32位汇编语言学习笔记(40)--在汇编代码中使用libc库函数
- windows下32位汇编语言学习笔记 第四章 第一个窗口程序 1 (消息的使用和入口代码)
- 汇编语言学习笔记 2 debug 的使用
- windows下32位汇编语言学习笔记 第十章 内存管理部分 2
- 32位汇编语言学习笔记(14)--递归函数的调用
- 汇编语言学习笔记-使用窗体控件
- 32位汇编语言学习笔记(12)--分析switch语句的汇编代码
- 32位汇编语言学习笔记(10)--分析for循环的汇编代码
- windows下32位汇编语言学习笔记
- 32位汇编语言学习笔记(8)--分析do-while循环的汇编代码
- 32位汇编语言学习笔记(16)--变长数组
- 32位汇编语言学习笔记(4)--移位操作
- 32位汇编语言学习笔记(5)--特殊的算术操作
- 32位汇编语言学习笔记(1)--简单示例
- windows下32位汇编语言学习笔记 第十章 内存管理部分 1
- windows下32位汇编语言学习笔记 第四章 第一个窗口程序 (windows的消息机制)
- 32位汇编语言学习笔记(13)--函数的调用