zoukankan      html  css  js  c++  java
  • 汇编语言使用转义字符实现简单的“全屏”文本输出

    这是一个运行在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

    效果:

  • 相关阅读:
    临时表各方式对比
    【译】表变量和临时表的比较(转)
    delete和truncate的一个严重区别
    各种临时表插入数据方式对比(包括自增列和GUID列)
    纤程模式的问题
    转 javascript针对DOM的应用(四)
    转 CSS兼容性(IE和Firefox)技巧大全 (四)
    转 CSS兼容性(IE和Firefox)技巧大全 (五)
    转 javascript针对DOM的应用(三)
    javascript基础知识大全(1)
  • 原文地址:https://www.cnblogs.com/moonlightpoet/p/5657798.html
Copyright © 2011-2022 走看看