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



这个程序出自《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 data
	EOL 	equ 10		; Linux end-of-line character
	FILLCHR	equ 32		; Default to ASCII space character
	CHRTROW	equ 2		; Chart begins 2 lines from top
	CHRTLEN	equ 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"
	CLRLEN	equ $-ClrHome	; Length of term clear string
	
SECTION .bss			; Section containing uninitialized data	

	COLS	equ 81		; Line length + 1 char for EOL
	ROWS	equ 25		; Number of lines in display
	VidBuff	resb COLS*ROWS	; Buffer size adapts to ROWS & COLS

SECTION .text			; Section containing code

global 	_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.
%macro	ClearTerminal 0
	pushad			; Save all registers
	mov eax,4		; Specify sys_write call
	mov ebx,1		; Specify File Descriptor 1: Standard Output
	mov ecx,ClrHome		; Pass offset of the error message
	mov edx,CLRLEN		; Pass the length of the message
	int 80H			; Make kernel call
	popad			; Restore all registers
%endmacro

Show:	pushad			; Save all registers
	mov eax,4		; Specify sys_write call
	mov ebx,1		; Specify File Descriptor 1: Standard Output
	mov ecx,VidBuff		; Pass offset of the buffer
	mov edx,COLS*ROWS	; Pass the length of the buffer
	int 80H			; Make kernel call
	popad			; Restore all registers
	ret			; And go home!

ClrVid:	push eax		; Save caller's registers
	push ecx
	push edi
	cld			; Clear DF; we're counting up-memory
	mov al,FILLCHR		; Put the buffer filler char in AL
	mov edi,VidBuff		; Point destination index at buffer
	mov ecx,COLS*ROWS	; Put count of chars stored into ECX
	rep 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 again
	dec edi			; Start EOL position count at VidBuff char 0
	mov ecx,ROWS		; Put number of rows in count register
PtEOL:	add edi,COLS		; Add column count to EDU
	mov byte [edi],EOL	; Store EOL char at end of row
	loop PtEOL		; Loop back if still more lines
	pop edi			; Restore caller's registers
	pop ecx
	pop eax
	ret			; and go home!

Ruler:  push eax	; Save the registers we change
	push ebx
	push ecx
	push edi
	mov edi,VidBuff	; Load video address to EDI
	dec eax		; Adjust Y value down by 1 for address calculation
	dec ebx		; Adjust X value down by 1 for address calculation
	mov ah,COLS	; Move screen width to AH
	mul ah		; Do 8-bit multiply AL*AH to AX
	add edi,eax	; Add Y offset into vidbuff to EDI
	add 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 addition
	add al,'0'	; Make sure we have binary 3 in AL's high nybble
    loop DoChar	; Go back & do another char until ECX goes to 0
	pop edi		; Restore the registers we changed
	pop ecx
	pop ebx
	pop eax
	ret		; 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 console
	call ClrVid	; Init/clear the video buffer

	mov eax,1	; Start ruler at display position 1,1
	mov ebx,1
	mov ecx,32	; Make ruler 32 characters wide
	call Ruler	; Generate the ruler

; Now let's generate the chart itself:
	mov edi,VidBuff		; Start with buffer address in EDI
	add edi,COLS*CHRTROW	; Begin table display down CHRTROW lines
	mov ecx,224		; Show 256 chars minus first 32
	mov 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, quit
	stosb			; Note that there's no REP prefix!
	inc al			; Bump the character value in AL up by 1
	dec bl			; Decrement the line counter by one
	loopnz .DoChr	; Go back & do another char until BL goes to 0
	add edi,COLS-CHRTLEN	; Move EDI to start of next line
	jmp .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 console

Exit:	mov eax,1	; Code for Exit Syscall
	mov ebx,0	; Return a code of zero	
	int 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.o
	ld -o showchar showchar.o
showchar.o: showchar.asm
	nasm -f elf -g -F stabs showchar.asm

测试:

[root@bogon showchar]# make
nasm -f elf -g -F stabs showchar.asm
ld -o showchar showchar.o
[root@bogon showchar]# ./showchar

12345678901234567890123456789012                                                
                                                                                
 !"#$%&'()*+,-./0123456789:;<=>?                                                
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_                                                
`abcdefghijklmnopqrstuvwxyz{|}~                                                
������������������������������                                                
��������������������������������                                                
��������������������������������                                                
��������������������������������     




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值