32位汇编语言学习笔记(28)--一个简单的光标控制程序



这是《Assembly Language step by step programming with linux》第10章的一个程序,里面用了两条光标控制命令:
<ESC>[<Y>;<X>H,这条命令用于输出光标的位置,esc是不可见字符,其ASCII码是27,y和x是控制台屏幕坐标位置,从屏幕的左上角计算。
<ESC>[2J,这条命令用于清屏。

程序源代码如下:

;  Executable name : eatterm
;  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.
;
;  Build using these commands:
;    nasm -f elf -g -F stabs eatterm.asm
;    ld -o eatterm eatterm.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

;-------------------------------------------------------------------------
; ClrScr: 	Clear the Linux console
; UPDATED:	4/21/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

ClrScr:
	push eax	  ; Save pertinent registers
	push ebx
	push ecx
	push edx
	mov ecx,ClearTerm ; Pass offset of terminal control string
	mov edx,CLEARLEN  ; Pass the length of terminal control string
	call WriteStr	  ; Send control string to console
	pop edx		  ; Restore pertinent registers
	pop ecx
	pop ebx
	pop eax	
	ret		  ; Go home


;-------------------------------------------------------------------------
; GotoXY: 	Position the Linux Console cursor to an X,Y position
; UPDATED:	4/21/2009
; IN: 		X in AH, Y in AL
; 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.

GotoXY:
	pushad			; Save caller's registers
	xor ebx,ebx		; Zero EBX
	xor ecx,ecx		; Ditto ECX
; Poke the Y digits:
	mov bl,al		     ; Put Y value into scale term EBX
	mov cx,word [Digits+ebx*2]   ; Fetch decimal digits to CX
	mov word [PosTerm+2],cx	     ; Poke digits into control string
; Poke the X digits:
	mov bl,ah		     ; Put X value into scale term EBX
	mov cx,word [Digits+ebx*2]   ; Fetch decimal digits to CX
	mov word [PosTerm+5],cx	     ; Poke digits into control string
; Send control sequence to stdout:
	mov ecx,PosTerm		; Pass address of the control string
	mov edx,POSLEN		; Pass the length of the control string
	call WriteStr		; Send control string to the console
; Wrap up and go home:
	popad			; Restore caller's registers
	ret			; Go home

;-------------------------------------------------------------------------
; WriteCtr: 	Send a string centered to an 80-char wide Linux console
; UPDATED:	4/21/2009
; IN: 		Y value in AL, String address in ECX, string length in EDX
; 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

WriteCtr:
	push ebx	; Save caller's EBX
	xor ebx,ebx	; Zero EBX
	mov bl,SCRWIDTH	; Load the screen width value to BL
	sub bl,dl	; Take diff. of screen width and string length
	shr bl,1	; Divide difference by two for X value
	mov ah,bl	; GotoXY requires X value in AH
	call GotoXY	; Position the cursor for display
	call WriteStr	; Write the string to the console
	pop ebx		; Restore caller's EBX
	ret		; Go home


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

WriteStr:
	push eax		; Save pertinent registers
	push ebx
	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
	ret			; Go home


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

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

; First we clear the terminal display...
	call ClrScr

; Then we post the ad message centered on the 80-wide console:
	mov al,12
	mov ecx,AdMsg
	mov edx,ADLEN
	call WriteCtr

; Position the cursor for the "Press Enter" prompt:
	mov ax,0117h		; X,Y = 1,23 as a single hex value in AX
	call GotoXY		; Position the cursor

; Display the "Press Enter" prompt:
	mov ecx,Prompt		; Pass offset of the prompt
	mov edx,PROMPTLEN	; Pass the length of the prompt
	call WriteStr		; Send the prompt to the console

; Wait for the user to press Enter:
	mov eax,3		; Code for sys_read
	mov ebx,0		; Specify File Descriptor 0: Stdin	
	int 80H			; Make kernel call

; ...and we're done!
Exit:	mov eax,1		; Code for Exit Syscall
	mov ebx,0		; Return a code of zero	
	int 80H			; Make kernel call

程序分析:

ClrScr函数,用于清除屏幕。
 push eax  
 push ebx
 push ecx
 push edx
 mov ecx,ClearTerm //ecx= ClearTerm
 mov edx,CLEARLEN  //edx= CLEARLEN,CLEARLEN是ClearTerm字节数组的长度。
 call WriteStr   //把控制信息写入标准输出,执行清屏。
 pop edx   
 pop ecx
 pop ebx
 pop eax 
 ret  

GotoXY函数,al保存y坐标,ah保存x坐标。函数用于根据x和y坐标来修改PosTerm字节数组的内容,然后输出这条控制命令到标准输出,对光标进行定位。
 pushad   //保存所有通用寄存器
 xor ebx,ebx  //清零ebx
 xor ecx,ecx  //清零ecx
 mov bl,al      //bl = al,获取y坐标的值
 mov cx,word [Digits+ebx*2]   //Digits+ebx*2的地址作为一个word数的地址,把该word数保存到cx。
 mov word [PosTerm+2],cx   // PosTerm+2的地址作为一个word数的地址,把cx存入该地址。
 mov bl,ah       //bl = ah,获取x坐标的值
 mov cx,word [Digits+ebx*2]    //Digits+ebx*2的地址作为一个word数的地址,把该word数保存到cx。
 mov word [PosTerm+5],cx   // PosTerm+5的地址作为一个word数的地址,把cx存入该地址。
 mov ecx,PosTerm  //ecx =PosTerm
 mov edx,POSLEN  //edx= POSLEN
 call WriteStr  //把控制信息写入标准输出,定位光标的位置。
 popad   //恢复所有通用寄存器
 ret   //返回

WriteCtr函数,先定位光标到指定位置,然后打印字符串信息。
 push ebx  //保存ebx寄存器
 xor ebx,ebx //对ebx寄存器清零
 mov bl,SCRWIDTH //bl= SCRWIDTH,SCRWIDTH的值是80。
 sub bl,dl //bl = bl-dl,等于屏幕宽度减去字符串长度。
 shr bl,1 //bl逻辑右移一位,相当于除以2
 mov ah,bl //ah=bl,保存x的坐标位置
 call GotoXY //调用GotoXY函数,先把光标定位到指定位置。
 call WriteStr //调用WriteStr函数,打印字符串。
 pop ebx  //恢复ebx寄存器
 ret  //返回

WriteStr函数,执行sys_write系统调用,把字符串写入到标准输出。
 push eax  
 push ebx
 mov eax,4  //sys_write系统调用号
 mov ebx,1  //标准输出
 int 80H   //执行系统调用
 pop ebx   
 pop eax
 ret   

_start:
 nop   
 call ClrScr //清屏
 mov al,12 //al=12,y坐标值是12
 mov ecx,AdMsg //ecx = AdMsg
 mov edx,ADLEN //edx= ADLEN
 call WriteCtr //打印一个字符串到标准输出(先定位光标到指定位置)
 mov ax,0117h  //y坐标值是23,x坐标值是1
 call GotoXY  //重新定位光标的位置
 mov ecx,Prompt  
 mov edx,PROMPTLEN 
 call WriteStr  //打印Prompt字符串
 mov eax,3  //sys_read系统调用号
 mov ebx,0  //标准输入 
 int 80H   //执行系统调用,等待用户键入enter键
Exit: mov eax,1  //sys_exit系统调用号
 mov ebx,0  //退出返回码 
 int 80H   //执行系统调用后退出。

makefile文件内容:

eatterm: eatterm.o
	ld -o eatterm eatterm.o
eatterm.o: eatterm.asm
	nasm -f elf -g -F stabs eatterm.asm

测试:

[root@bogon eatterm]# ./eatterm 












                                Eat At Joe's!










Press Enter: 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值