汇编语言使用转义字符实现简单的“全屏”文本输出

这是一个运行在Linux下的、简单的汇编程序,使用NASM 2.11,展示了使用转义字符实现简单的“全屏”文本输出

; 可执行文件名    : eatterm
; 版本        : 1.0
; 创建日期    : 7/10/2016
; 最后更新日期    : 7/10/2016
; 作者        : Moonlight Poet
; 描述        : 一个运行在Linux下的、简单的汇编程序,使用NASM 2.11,
;     展示了使用转义字符实现简单的“全屏”文本输出
; 
; 使用以下命令生成:
;     nams -f elf -g -F stabs eatterm.asm
;     ld -o eatterm eatterm.o
; 
SECTION .data            ; 包含已初始化的数据
SCRWIDTH: equ 80        ; 默认情况下我们假设80个字符宽
PosTerm: db 27,"[01;01H"    ; <ESC>[<Y>;<X>H
POSLEN: equ $-PosTerm        ; 术语位置字符串的长度
ClearTerm: db 27,"[2J"        ; <ESC>[2J
CLEARLEN: equ $-ClearTerm    ; 属于清除字符串的长度
AdMsg: db "Eat at Joe's!"    ; 广告消息
ADLEN: equ $-AdMsg        ; 广告消息的长度
Prompt: db "Press Enter: "    ; 用户提示信息
PROMPTLEN: equ $-Prompt        ; 用户提示信息的长度

; 此表为我们提供了0到80之间的数字的以两位表示的ASCII位元(digit)。
; 我们不是通过计算来产生插入终端控制字符串中的ASCII数字,
; 而是在表中查找它们,一次取出两个ASCII位元到一个16位寄存器中,例如DX,
; 然后将该寄存器的值防盗终端控制字符串PosTerm的适当位置。参见GoToXY。
; 如果打算在更大的、超过80x80的控制台上工作,
; 必须在Digits中添加额外的ASCII位元编码。
; 注意:此处显示的代码只能工作在最大99*99的控制台上。
Digits: db "0001020304050607080910111213141516171819"
    db "2021222324252627282930313233343536373839"
    db "4041424344454647484950515253545556575859"
    db "6061626364656667686970717273747576777879"

SECTION .bss            ; 包含未初始化的数据

SECTION .text            ; 包含代码的段

;----------------------------------------------------------------------------------------------------
; ClrScr:    清空Linux控制台
; 最后更新日期:    7/10/2016
; 输入参数:    无
; 返回值:    无
; 修改:        无
; 调用:        内核sys_write
; 描述:        发送预定以的控制字符串<ESC>[2J到控制台,它将清空整个显示器
ClrScr:
    push rax        ; 保存有关寄存器
    push rbx
    push rcx
    push rdx
    mov ecx,ClearTerm    ; 传递终端控制字符串的偏移地址
    mov edx,CLEARLEN    ; 传递终端控制字符串的长度
    call WriteStr        ; 发送终端控制字符串到控制台
    pop rdx            ; 恢复有关寄存器
    pop rcx
    pop rbx
    pop rax
    ret

;----------------------------------------------------------------------------------------------------
; GotoXY:    将Linux控制光标定位到(X,Y)坐标处
; 最后更新日期:    7/10/2016
; 输入参数:    X 存放到 AH,Y 存放到 AL
; 返回值:    没有
; 修改:        PosTerm终端控制序列字符串
; 调用:        内核sys_write
; 描述:        为传递到AL和AH的X,Y坐标准备一个终端控制字符串
;         并且调用sys_write将控制台光标定位到(X,Y)位置
;         在调用GotoXY之后,写文本到控制台将从(X,Y)位置开始显示文本。
GotoXY:
    push rbx    ; 保存主调程序的寄存器
    push rcx
    push rdx
    xor ebx,ebx    ; 清零EBX
    xor ecx,ecx    ; ECX寄存器操作同上
; 插入Y的数字
    mov bl,al            ; 将Y的值放到缩放术语EBX寄存器中
    mov cx,word [Digits+ebx*2]    ; 取出十进制数字放到CX寄存器中
    mov word [PosTerm+2],cx        ; 将数字插入到控制字符串中
; 插入X的数字
    mov bl,ah            ; 将X的值放到缩放术语EBX寄存器中
    mov cx,word [Digits+ebx*2]    ; 取出十进制数字放到CX寄存器中
    mov word [PosTerm+5],cx        ; 将数字插入控制字符串中
; 发送控制序列到标准输出
    mov ecx,PosTerm            ; 传递控制字符串的地址
    mov edx,POSLEN            ; 传递控制字符串的长度
    call WriteStr            ; 发送控制字符串到控制台
; 扫尾,返回:
    pop rdx
    pop rcx
    pop rax
    ret

;----------------------------------------------------------------------------------------------------
; WriteCtr: 发送一个字符串到一个80个字符串宽的Linux控制台的中央位置
; 最后更新日期:    7/10/2016
; 输入参数: 传递Y值到AL中,字符串地址到ECX中,字符串长度到EDX中
; 返回值: 无
; 修改: PosTerm终端控制序列字符串
; 调用: GotoXY, WriteStr
; 描述: 在一个80列宽的Linux控制台显示区域中央显示一个字符串
;     为传入的字符串的长度计算X,
;     然后调用GotoXY和WriteStr将该字符串发送到控制台

WriteCtr:
    push rbx
    xor ebx,ebx
    mov bl,SCRWIDTH
    sub bl,dl
    shr bl,1
    mov ah,bl
    call GotoXY
    call WriteStr
    pop rbx
    ret
;----------------------------------------------------------------------------------------------------
; WriteStr: 发送一个字符串到Linux控制台
; 最后更新日期: 7/10/2016
; 输入参数: 传递字符串地址到ECX中,字符串长度到EDX中
; 返回值: 无
; 修改: 无
; 调用: 内核sys_write
; 描述: 通过一个sys_write内核调用显示一个字符串到Linux控制台
;

WriteStr:
    push rax    ; 保存相关的寄存器
    push rbx
    mov eax,4    ; 指定sys_write调用
    mov ebx,1    ; 指定文件描述符1:标准输出
    int 80h        ; 进行内核调用
    pop rbx        ; 恢复相关的寄存器
    pop rax
    ret        ; 返回

    global _start        ; 连接器需要这个来找到入口点

_start:
    nop        ; 这个无操作指令让gdb感到非常高兴
    
; 首先我们清空终端显示器
    call ClrScr
    
    mov al,12
    mov ecx,AdMsg
    mov edx,ADLEN
    call WriteCtr

    mov ax,0117h
    call GotoXY

    mov ecx,Prompt
    mov edx,PROMPTLEN
    call WriteStr
    
    mov eax,3
    mov ebx,0
    int 80h

Exit:    mov eax,1
    mov ebx,0
    int 80h

效果:

posted @ 2016-07-10 15:33  月光诗人  阅读(1597)  评论(0编辑  收藏  举报