32位汇编语言学习笔记(35)--显示ASCII表

来源:互联网 发布:敏感端口 编辑:程序博客网 时间:2024/06/06 22:18


这个程序出自《Assembly Language step by step programming with linux》第11章,首先需要先介绍几条指令:
jcxz label,当cx寄存器等于0时,跳转。
jecxz label,当ecx寄存器等于0时,跳转。
loopnz label,ecx=ecx-1,当ecx寄存器不等于0时并且ZF标志位未被设置时跳转,如果ecx寄存器等于0,或者ZF标志位已经被设置,就结束循环了。
loopne label,与loopnz相同。
接下来看程序:

SECTION .data; Section containing initialised dataEOL equ 10; Linux end-of-line characterFILLCHRequ 32; Default to ASCII space characterCHRTROWequ 2; Chart begins 2 lines from topCHRTLENequ 32; Each chart line shows 32 chars; This escape sequence will clear the console terminal and place the; text cursor to the origin (1,1) on virtually all Linux consoles:ClrHome db 27,"[2J",27,"[01;01H"CLRLENequ $-ClrHome; Length of term clear stringSECTION .bss; Section containing uninitialized dataCOLSequ 81; Line length + 1 char for EOLROWSequ 25; Number of lines in displayVidBuffresb COLS*ROWS; Buffer size adapts to ROWS & COLSSECTION .text; Section containing codeglobal _start; Linker needs this to find the entry point!; This macro clears the Linux console terminal and sets the cursor position; to 1,1, using a single predefined escape sequence.%macroClearTerminal 0pushad; Save all registersmov eax,4; Specify sys_write callmov ebx,1; Specify File Descriptor 1: Standard Outputmov ecx,ClrHome; Pass offset of the error messagemov edx,CLRLEN; Pass the length of the messageint 80H; Make kernel callpopad; Restore all registers%endmacroShow:pushad; Save all registersmov eax,4; Specify sys_write callmov ebx,1; Specify File Descriptor 1: Standard Outputmov ecx,VidBuff; Pass offset of the buffermov edx,COLS*ROWS; Pass the length of the bufferint 80H; Make kernel callpopad; Restore all registersret; And go home!ClrVid:push eax; Save caller's registerspush ecxpush edicld; Clear DF; we're counting up-memorymov al,FILLCHR; Put the buffer filler char in ALmov edi,VidBuff; Point destination index at buffermov ecx,COLS*ROWS; Put count of chars stored into ECXrep stosb; Blast chars at the buffer; Buffer is cleared; now we need to re-insert the EOL char after each line:mov edi,VidBuff; Point destination at buffer againdec edi; Start EOL position count at VidBuff char 0mov ecx,ROWS; Put number of rows in count registerPtEOL:add edi,COLS; Add column count to EDUmov byte [edi],EOL; Store EOL char at end of rowloop PtEOL; Loop back if still more linespop edi; Restore caller's registerspop ecxpop eaxret; and go home!Ruler:  push eax; Save the registers we changepush ebxpush ecxpush edimov edi,VidBuff; Load video address to EDIdec eax; Adjust Y value down by 1 for address calculationdec ebx; Adjust X value down by 1 for address calculationmov ah,COLS; Move screen width to AHmul ah; Do 8-bit multiply AL*AH to AXadd edi,eax; Add Y offset into vidbuff to EDIadd edi,ebx; Add X offset into vidbuf to EDI; EDI now contains the memory address in the buffer where the ruler; is to begin. Now we display the ruler, starting at that position:    mov al,'1'; Start ruler with digit '1'DoChar: stosb; Note that there's no REP prefix!add al,'1'; Bump the character value in AL up by 1    aaa; Adjust AX to make this a BCD additionadd al,'0'; Make sure we have binary 3 in AL's high nybble    loop DoChar; Go back & do another char until ECX goes to 0pop edi; Restore the registers we changedpop ecxpop ebxpop eaxret; And go home!;-------------------------------------------------------------------------; MAIN PROGRAM:_start:nop; This no-op keeps gdb happy...; Get the console and text display text buffer ready to go:ClearTerminal; Send terminal clear string to consolecall ClrVid; Init/clear the video buffermov eax,1; Start ruler at display position 1,1mov ebx,1mov ecx,32; Make ruler 32 characters widecall Ruler; Generate the ruler; Now let's generate the chart itself:mov edi,VidBuff; Start with buffer address in EDIadd edi,COLS*CHRTROW; Begin table display down CHRTROW linesmov ecx,224; Show 256 chars minus first 32mov al,32; Start with char 32; others won't show.DoLn:mov bl,CHRTLEN; Each line will consist of 32 chars.DoChr:jcxz AllDone; When the full set is printed, quitstosb; Note that there's no REP prefix!inc al; Bump the character value in AL up by 1dec bl; Decrement the line counter by oneloopnz .DoChr; Go back & do another char until BL goes to 0add edi,COLS-CHRTLEN; Move EDI to start of next linejmp .DoLn; Start display of the next line; Having written all that to the buffer, send the buffer to the console:AllDone:call Show; Refresh the buffer to the consoleExit:mov eax,1; Code for Exit Syscallmov ebx,0; Return a code of zeroint 80H; Make kernel call

程序分析:
 mov eax,1 //设置标尺的起始坐标1,1
 mov ebx,1
 mov ecx,32   //标尺的宽度是32个字节
 call Ruler     //把标尺写入缓存

 mov edi,VidBuff  //edi= VidBuff
 add edi,COLS*CHRTROW //edi= VidBuff+ COLS*2
 mov ecx,224  //总循环次数是224=256-32
 mov al,32  //al=32,第一个打印的ASCII码字符
.DoLn: mov bl,CHRTLEN  //bl=32,每行打印的字符数
.DoChr: jcxz AllDone  //cx=0跳转到AllDone,结束外层循环。
 stosb   //填充al值到edi指向的内存。
 inc al   //al=al+1
 dec bl   //bl=bl-1
 loopnz .DoChr //当bl值等于0时,会设置ZF标志位,所以会结束循环,因此,每32次循环后,结束一次内层循环。
 add edi,COLS-CHRTLEN //edi切换到下一行的起始位置
 jmp .DoLn  //进行下一个外层循环,写入下一行ASCII码值。

AllDone:
 call Show  //显示ASCII码表

makefile文件内容:

showchar: showchar.old -o showchar showchar.oshowchar.o: showchar.asmnasm -f elf -g -F stabs showchar.asm

测试:

[root@bogon showchar]# makenasm -f elf -g -F stabs showchar.asmld -o showchar showchar.o[root@bogon showchar]# ./showchar12345678901234567890123456789012                                                                                                                                 !"#$%&'()*+,-./0123456789:;<=>?                                                @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_                                                `abcdefghijklmnopqrstuvwxyz{|}~                                                ������������������������������                                                ��������������������������������                                                ��������������������������������                                                ��������������������������������     




0 0
原创粉丝点击