汇编语言学习-call和ret指令


call和ret指令

思维导图

思维导图

关于使用栈来传递参数并用ret返回的实际例子还是需要多看才行。

综合实验

显示字符串

名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串
参数:dh 行号(0-24), dl 列号 0-79, cl颜色, ds:si指向字符串的首地址
返回: 无
应用举例:在屏幕的8行3列,用绿色显示出data段中的字符串

代码

assume cs:code

data segment
    db 'Welcome to masm!',0
data ends

code segment

start:
    mov dh,8
    mov dl,3
    mov cl,2
    mov ax,data
    mov ds,ax
    mov si,0
    call show_str
    
    mov ax,4c00h
    int 21h

show_str:
    push es
    push bp
    push bx

    mov ax,0B800H
    mov es,ax

    ;找行号对应的内存地址
    mov al,160
    mul dh
    mov bp,ax
    sub bp,160
    ;找列对应的内存地址
    mov al,2
    mul dl
    mov di,ax
    sub di,2
    ;把颜色转移一下
    mov bl,cl
    push cx
s: 
    mov cl,ds:[si]
    mov ch,0
    jcxz ok
    mov es:[bp+di],cl
    mov es:[bp+di+1],bl

    add di,2
    add si,1
    jmp short s

ok:
    pop cx
    pop bx
    pop bp
    pop es
    ret
code ends
end start

运行截图

显示字符串

解决除法溢出的问题

用div指令做出发的时候可能产生除法溢出,比如:1000000/10就不能用div指令来算

名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword,除数为word.结果为dword
参数: ax dword的低16位 | dx dword高16位 | cx除数
返回: dx 结果的高16位, ax 结果的低16位, cx 余数
应用举例:计算 1000000/10(F4240H/0AH)
结果: dx = 0001H  ax = 86A0H cx = 0

代码

assume cs:codesg

datasg segment

datasg ends

codesg segment

start:
    mov ax,4240H
    mov dx,000FH
    mov cx,0AH
    call divdw
    mov ax,4c00h
    int 21h
;这里面就是因为 div 被除数默认放在ax | dx(高)和ax(低)中,所以比较麻烦
;除数可以放在寄存器里也可以放在内存单元里,有8/16两种, 8-AL商 AH余数 || 16-AX商 DX余数
;再就是因为数据运算要符合相同的类型,同为16或同为8,在寄存器里面换来换去的就比较麻烦
divdw:
    push ax
    mov ax,dx
    div cl
    mov bl,al
    mov bh,00H
    mov al,ah
    mov ah,00H;bx保留商,ax保留余数

    pop si
    mov dx,si

    mov dx,ax
    mov ax,si
    div cx;32/16 ax余数,dx商

    mov si,bx
    mov bx,dx
    mov dx,si

    mov cx,bx

    ret

codesg ends
end start

运行截图

解决除法溢出的问题

数值显示

将12666以字符串的形式显示到显示器上

名称:dtoc
功能:将word型数据转变为十进制的字符串,字符串以0为结尾符
参数:ax word型数据
    ds:si指向字符串的首地址
返回:无
应用举例: 将12666以十进制的形式在屏幕的8行3列,用绿色显示出来

改进前代码

改进前,主要是利用在内存中的位置,来对字符串进行逆向的输出。因为算余数的话,顺序是66621得倒过来才行


assume cs:code,ds:data

data segment
    db 10 dup(0)
data ends

code segment

start:
    mov ax,12666
    mov bx,data
    mov ds,bx
    mov si,0
    call dtoc
    

    mov dh,8
    mov dl,3
    mov cl,2
    call show_str

    mov ax,4c00h
    int 21h

dtoc:
    mov dx,00
    mov bh,00
    mov bl,10;感觉逻辑没问题啊,商越界了 得用32/16的
    div bx ;为什么会在这里卡住呢,感觉像是无限循环???
    mov ch,00h
    mov cl,dl
    jcxz ok
    add byte ptr cx,0030H
    mov ds:[si],cx
    inc si
    jmp dtoc
ok:
    ;也不是不能操作栈,在之前push进去的,在这里都pop出来就不会有问题,要不然回影响ret指令pop IP
    ;后面你可以再试试,这个程序还是有问题
    sub si,1;运行完之后si=5,然而ds[si]此时刚好是0,所以你得减去个1才行
    ret

show_str:
    push es
    push bp
    push bx

    mov ax,0B800H
    mov es,ax

    ;找行号对应的内存地址
    mov ah,00
    mov al,160
    mul dh
    mov bp,ax
    sub bp,160
    ;找列对应的内存地址
    mov ah,00
    mov al,2
    mul dl
    mov di,ax
    sub di,2
    ;把颜色转移一下
    mov bl,cl
    push cx
s: 
    mov cl,ds:[si]
    mov ch,0
    jcxz ok1
    mov es:[bp+di],cl
    mov es:[bp+di+1],bl

    add di,2
    sub si,1
    jmp short s

ok1:
    pop cx
    pop bx
    pop bp
    pop es
    ret    
    
code ends
end start

改进后代码

改进之后,利用了栈的特性,先将算出来的余数入栈,然后再出栈写到内存里.这样就刚好倒过来了。不过需要注意的是,在子程序中push进去的,在ret之前都要pop出来哦!

assume cs:code,ds:data

data segment
    db 10 dup(0)
data ends

code segment

start:
    mov ax,12666
    mov bx,data
    mov ds,bx
    mov si,0
    call dtoc
    

    mov dh,8
    mov dl,3
    mov cl,2
    call show_str

    mov ax,4c00h
    int 21h

dtoc:
    mov dx,00
    mov bh,00
    mov bl,10;感觉逻辑没问题啊,商越界了 得用32/16的
    div bx ;为什么会在这里卡住呢,感觉像是无限循环???
    mov ch,00h
    mov cl,dl
    jcxz ok
    add byte ptr cx,0030H
    mov ds:[si],cx
    inc si
    jmp dtoc
ok:
    ;也不是不能操作栈,在之前push进去的,在这里都pop出来就不会有问题,要不然回影响ret指令pop IP
    ;后面你可以再试试,这个程序还是有问题
    sub si,1;运行完之后si=5,然而ds[si]此时刚好是0,所以你得减去个1才行
    ret

show_str:
    push es
    push bp
    push bx

    mov ax,0B800H
    mov es,ax

    ;找行号对应的内存地址
    mov ah,00
    mov al,160
    mul dh
    mov bp,ax
    sub bp,160
    ;找列对应的内存地址
    mov ah,00
    mov al,2
    mul dl
    mov di,ax
    sub di,2
    ;把颜色转移一下
    mov bl,cl
    push cx
s: 
    mov cl,ds:[si]
    mov ch,0
    jcxz ok1
    mov es:[bp+di],cl
    mov es:[bp+di+1],bl

    add di,2
    sub si,1
    jmp short s

ok1:
    pop cx
    pop bx
    pop bp
    pop es
    ret    
    
code ends
end start

运行截图

数值显示


文章作者: 美食家李老叭
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 美食家李老叭 !
评论
  目录