NASM汇编教程翻译12 第十二讲 计算器加法

英文原版地址:NASM Assembly Language Tutorials - asmtutor.com

在这个程序中,我们将要使寄存器EAX和EBX加到一起并将结果放入EAX。首先,使用MOV执行将一个整数加载到EAX(本例中是90)。然后用MOV指令将一个整数存入EBX(本例中是9)。现在,我们需要使用ADD执行来执行我们的加法。在这个指令中,EAX和EBX将被加到一起并将答案保留在最左侧的寄存器中(本例中是EAX)。接着我们需要调用整数打印函数来完成这个程序。

functions.asm文件

;------------------------------------------
; void iprint(Integer number)
; 打印整数函数 (itoa)
iprint:
    push    eax             ; 将EAX的值保存在栈上以便函数运行后恢复
    push    ecx             ; 将ECX的值保存在栈上以便函数运行后恢复
    push    edx             ; 将EDX的值保存在栈上以便函数运行后恢复
    push    esi             ; 将ESI的值保存在栈上以便函数运行后恢复
    mov     ecx, 0          ; 最后要打印多少字节的计数器
 
divideLoop:
    inc     ecx             ; 所有要打印的字节计数 —— 字符数
    mov     edx, 0          ; 清空EDX
    mov     esi, 10         ; 将10放入ESI
    idiv    esi             ; EAX除以ESI
    add     edx, 48         ; 转化EDX的值为它的ASCII码表示 —— 调用除法指令后EDX保存余数
    push    edx             ; 将EDX (一个整数的字符串表示) 压到栈上
    cmp     eax, 0          ; 这个整数还能再被除么?
    jnz     divideLoop      ; 如果EAX不是0 跳转到divideLoop标签
 
printLoop:
    dec     ecx             ; 反向计数我们放在栈上的每个字节
    mov     eax, esp        ; 将栈指针放入EAX用于打印
    call    sprint          ; 调用字符串打印函数
    pop     eax             ; 移除栈上最后一个字符来移动ESP指向
    cmp     ecx, 0          ; 我们已经打印了栈上所有字节了么?
    jnz     printLoop       ; ECX不是0跳转到printLoop标签
 
    pop     esi             ; 用开始放到栈上的值恢复ESI
    pop     edx             ; 用开始放到栈上的值恢复EDX
    pop     ecx             ; 用开始放到栈上的值恢复ECX
    pop     eax             ; 用开始放到栈上的值恢复EAX
    ret
 
;------------------------------------------
; void iprintLF(Integer number)
; 带有换行符的整数打印函数 (itoa)
iprintLF:
    call    iprint          ; 调用数字打印函数
 
    push    eax             ; 当我们在这个函数使用EAX时将EAX压到栈上保留
    mov     eax, 0Ah        ; 将0AH放到EAX中 —— 0AH是ASCII码中的换行符
    push    eax             ; 将换行符压到栈上,这样我们就能得到地址
    mov     eax, esp        ; 将当前的栈指针传入EAX用于sprint
    call    sprint          ; 调用sprint函数
    pop     eax             ; 从栈上移除换行符
    pop     eax             ; 恢复调用函数前EAX的初始值
    ret

;------------------------------------------
; int slen(String message)
; 字符串长度计算函数
slen:
    push    ebx
    mov     ebx, eax
 
nextchar:
    cmp     byte [eax], 0
    jz      finished
    inc     eax
    jmp     nextchar
 
finished:
    sub     eax, ebx
    pop     ebx
    ret
 
;------------------------------------------
; void sprint(String message)
; 字符串打印函数
sprint:
    push    edx
    push    ecx
    push    ebx
    push    eax
    call    slen
 
    mov     edx, eax
    pop     eax
 
    mov     ecx, eax
    mov     ebx, 1
    mov     eax, 4
    int     80h
 
    pop     ebx
    pop     ecx
    pop     edx
    ret
 
;------------------------------------------
; void sprintLF(String message)
; 打印字符串和换行符函数
sprintLF:
    call    sprint
 
    push    eax         ; 当我们在这个函数中使用EAX时通过将EAX压入栈来进行保护
    mov     eax, 0AH    ; 将0AH移到EAX中 - 0AH是换行符的ascii码
    push    eax         ; 将换行符放到栈上,以便我们获取地址
    mov     eax, esp    ; 将当前栈指针的地址放到EAX寄存器中给sprint函数
    call    sprint      ; 调用sprint函数
    pop     eax         ; 从栈上移除换行符
    pop     eax         ; 恢复调用函数前EAX原本的值
    ret                 ; 返回程序
 
;------------------------------------------
; void exit()
; 退出程序并复原资源
quit:
    mov     ebx, 0
    mov     eax, 1
    int     80h
    ret

hello.asm文件

%include        'functions.asm'
 
SECTION .text
global  _start
 
_start:
 
    mov     eax, 90     ; 将第一个数放入EAX
    mov     ebx, 9      ; 将第一个数放入EBX
    add     eax, ebx    ; 将EBX加到EAX上
    call    iprintLF    ; 调用带有换行符的整数打印函数
 
    call    quit

编译命令

nasm -f elf hello.asm

链接命令

ld -m elf_i386 hello.o -o hello

执行命令

./hello

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值