• 汇编学习--第十天


    10.5 转移地址在寄存器中的call指令

    call 16位reg

    相当于执行

    push IP

    jmp 标号

    检测点 10.4

    AX=000BH

    这个程序稍微修改一下,就很清晰了。

    assume cs:codesg
    codesg segment
            mov ax,6
            ;首先sp=sp-2=fffeh,将IP=5压入栈中
            ;跳转到ax处,jmp 6
            call ax
            inc ax
            ;在bp的段地址是ss,下面两句相当于
            ;pop bp
            ;add ax,bp
            mov bp,sp
            add ax,ss:[bp]
            
            mov ax,4c00h
            int 21h
    codesg ends
    end

    10.6 转移地址在内存中的call指令

    call word ptr 内存单元地址

    相当于进行

    push IP

    jmp word ptr 内存单元地址

    call dword ptr 内存单元地址

    相当于

    push CS

    push IP

    jmp dword ptr 内存单元地址

    检测点 10.5

    (1)

    ax=3

    在call word ptr ds:[0eh]时,ax=0,将下一条指令IP压入栈中,然后指令跳到ds:[0eh](实际上就是栈顶),所以实际上就是跳到了inc ax执行,最后得到ax = 3

    (2)

    assume cs:code
    data segment
        dw 8 dup (0)
    data ends
    code segment
    start:  mov ax,data
            mov ss,ax
            mov sp,16
            mov word ptr ss:[0],offset s;将标号s的地址存入ss:[0]
            mov ss:[2],cs
            call word ptr ss:[0]
            ;这里首先将CS=076bh和IP=19h压入栈中
            ;再跳转到ss:[0]中的地址处,也就是标号s处
            nop
    s:      mov ax,offset s
            ;将标号s的地址放到ax=001ah
            sub ax,ss:[0ch]
            ;ss:[0ch]也就是IP=0019h
            ;ax=1ah-19h=1
            mov bx,cs
            ;bx=076bh
            sub bx,ss:[0eh]
            ;ss:[0eh]也就是CS=076bh
            ;bx=076bh-076bh=0
            
            mov ax,4c00h
            int 21h
    code ends
    end start

    10.7 call和ret的配合使用

    问题 10.1

    assume cs:code
    code segment
    start:  mov ax,1
            mov cx,3
            call s;将下一指令偏移地址压入栈中,然后跳转到标号s
            mov bx,ax
            mov ax,4c00h
            int 21h
    s:      add ax,ax
            loop s
            ret;pop IP,跳转到call s指令的下一指令
    code ends
    end start

    利用call和ret可以实现子程序机制

    10.8 mul指令

     (1)计算10*100

    assume cs:code
    code segment
    start:  mov al,100
            mov bl,10
            mul bl
            
            mov ax,4c00h
            int 21h
    code ends
    end start

     

    (2)计算100*10000

    assume cs:codesg
    codesg segment
        mov ax,100
        mov bx,10000
        mul bx
        
        mov ax,4c00h
        int 21h
    codesg ends
    end

    10.9 模块化程序设计

    10.10 参数和结果传递问题

    assume cs:code
    data segment
        dw 1,2,3,4,5,6,7,8
        dd 8 dup (0)
    data ends
    code segment
    start:    mov ax,data
            mov ds,ax
            mov si,0
            mov di,16
            
            mov cx,8
    s:        mov bx,[si]
            call cube
            mov [di],ax
            mov [di].2,dx
            add si,2
            add di,4
            loop s
            
            mov ax,4c00h
            int 21h
            
    cube:    mov ax,bx
            mul bx
            mul bx
            ret
            
    code ends
    end start

    10.11 批量数据的传递

    将data段的字符串转换为大写

    assume cs:codesg
    datasg segment
        db 'heyyoubiubiubiu'
    datasg ends
    codesg segment
    start:    mov ax,datasg
            mov ds,ax
            mov si,0
            mov cx,15
            call capital
            
            mov ax,4c00h
            int 21h
            
    capital:    and byte ptr [si],11011111b
            inc si
            loop capital
            ret
    codesg ends
    end start

    附注4 用栈传递参数

    将需要的数据压入栈中,再由子程序出栈

    计算(a-b)^3,a=3,b=1

    assume cs:codesg
    stacksg segment
        db 16 dup (0)
    stacksg ends
    codesg segment
    start:    mov ax,stacksg
            mov ss,ax
            mov sp,16
            
            mov ax,1
            push ax
            mov ax,3
            push ax
            ;将,1,3分别入栈,ss:[sp]=3, ss:[sp+2]=1
            call difcube
            ;将IP入栈,ss:[sp]=IP, ss:[sp+2]=3, ss:[sp+4]=1
            
            mov ax,4c00h
            int 21h
            
    difcube:    push bp
            ;将bp入栈,ss:[sp]=bp,ss:[sp+2]=IP, ss:[sp+4]=3, ss:[sp+6]=1
            mov bp,sp
            mov ax,[bp+4];3
            sub ax,[bp+6];1
            mov bx,ax
            mul bx
            mul bx
            pop bp
            ;bp出栈,ss:[sp]=IP, ss:[sp+2]=3, ss:[sp+4]=1
            ret 4
            ;IP出栈,ss:[sp]=3, ss:[sp+2]=1,并sp=sp-4=10h
    codesg ends
    end start

    10.12 寄存器冲突问题

    问题 10.2

    子程序和主程序循环使用了同一个cx判断,可以将cx入栈

    assume cs:codesg
    datasg segment
        db 'word',0
        db 'unix',0
        db 'wind',0
        db 'good',0
    datasg ends
    codesg segment
    start:    mov ax,datasg
            mov ds,ax
            mov bx,0
            
            mov cx,4
    s:        push cx
            mov si,bx
            call capital
            pop cx
            add bx,5
            loop s
        
            mov ax,4c00h
            int 21h
            
    capital:    mov cl,[si]
            mov ch,0
            jcxz ok
            and byte ptr [si],11011111b
            inc si
            jmp short capital
    ok:        ret
    codesg ends
    end start

    如果我们期望:

    • 1.调用子程序时,不必关心子程序的程序使用了哪些寄存器。
    • 2.编写子程序时,不必关心调用者使用了哪些寄存器。
    • 3.不会发生寄存器冲突

    下面这种会更合适

    assume cs:codesg
    datasg segment
        db 'word',0
        db 'unix',0
        db 'wind',0
        db 'good',0
    datasg ends
    codesg segment
    start:    mov ax,datasg
            mov ds,ax
            mov si,0
            
            mov cx,4
    s:        call capital
            add si,5
            loop s
        
            mov ax,4c00h
            int 21h
            
    capital:    push cx
            push si
    
    change:    mov cl,[si]
            mov ch,0
            jcxz ok
            and byte ptr [si],11011111b
            inc si
            jmp short change
            
    ok:        pop si
            pop cx
            
            ret
    codesg ends
    end start

    实验 10 编写子程序

    1.显示字符串

    步骤:

    1. 将行列值转换为正确的偏移地址,保存到寄存器(起始偏移地址:(行数 - 1) * 160, 列数偏移地址:(列数 - 1) * 2)
    2. 读取字符和属性值,判断是否为0,不是,则存入显示缓冲区
    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:    ;计算行的偏移地址,利用上次得到的结论,起始偏移地址:行数 * 160
                mov al,dh
                mov ah,0
                ;dec ax
                mov bx,160
                push dx;因为下面乘法是16位的,因此dx会被用作高位,原来保存颜色的值会消除
                mul bx
                pop dx
                mov di,ax
                
                ;结算列的偏移地址,地址0开始
                mov bl,dl
                mov bh,0
                dec bx
                add bx,bx
                
                ;显示缓冲区地址
                mov ax,0b800h
                mov es,ax
                
                ;颜色参数值(不变)和字符
                mov ah,cl
    str:            mov al,ds:[si]
                
                ;检查是否遇到尾部的0
                mov cl,al
                mov ch,0
                jcxz ok
                
                ;将字符和属性存入显示缓冲区
                mov es:[bx+di],al
                mov es:[bx+di+1],ah
                
                inc si;字符偏移地址
                add bx,2;列的位置
                loop str
    
    ok:            ret
    code ends
    end start

    2.解决除法溢出

    (1)除数:有8位和16位两种,在一个reg或者内存单元中

    (2)被除数:默认放在AX或者DX和AX中,如果除数为8位,被除数为16位,默认放在AX中;如果除数为16位,被除数为32位,在DX和AX中存放,DX存高六位,AX存低六位。

    (3)结果:如果除数为8位。则AL储存除法操作的商,AH储存除法操作的余数;如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数

    1000/1溢出,al无法存下1000

    assume cs:code
    code segment
    start:    mov bh,1
            mov ax,1000
            div bh
            
            mov ax,4c00h
            int 21h
    code ends
    end start

    11000H/1,ax存放不下商

    assume cs:code
    code segment
    start:    mov ax,1000h
            mov dx,1
            mov bx,1
            div bx
            
            mov ax,4c00h
            int 21h
    code ends
    end start

    解决方法:

    实际上,我们解决的方法是将除法拆分成了两个16位除数,32位被除数的除法

    例如:1000000/10(F4240H/0AH)

    我们将这个除法拆分成:高16位:000FH/0AH  低16位:4240H/0AH  两个除法式子

    然后将第一个的结果放到dx,第二个的结果放到ax,余数放到cx

    这里唯一不同的就是,我们高16位计算的时候,我们相当于把尾数的0省略了,所以真正结果需要乘上  16^尾数0的个数,上面例子就是16^4=65536。

    通过理解 12341000/10 =  int(1234/10) * 10^4 + (rem(1234/10) * 10^4 + 1000) / 10  给的公式也就很好理解了

    这里还需要知道,溢出的基本概念:超过寄存器表示范围的值被舍弃。

    assume cs:code
    stack segment
        dw 8 dup (0)
    stack ends
    code segment
    start:    mov ax,stack
            mov ss,ax
            mov sp,16
            mov ax,4240h
            mov dx,00Fh
            mov cx,0ah
            call divdw
            
            mov ax,4c00h
            int 21h
            
    divdw:    push ax
            ;高16位计算
              mov ax, dx
              mov dx, 0 
              div cx
              mov bx, ax
              ;低16位计算
              pop ax
          ;高16位计算的余数作为了低16位计算的高位,对应公式的rem(H/N)*65536 div cx ;低16位 mov cx, dx ;余数 mov dx, bx ret code ends end start

  • 相关阅读:
    小甲鱼Python第021讲函数:lambda表达式 | 课后测试题及参考答案
    小甲鱼Python第020讲函数:内嵌函数和闭包 | 课后测试题及参考答案
    How to reference two table when lack reference column.
    how find a record import other database.
    when create a table,then show error ora-00952 tablespace tsb_1 not exist
    TELNET_COMMAND
    ORACLE_SPOOL
    OFFICE_EXCEL_Combine text from two or more cells into one cell.
    ORACLE_LPAD_FUNCTION
    ORACLE_PROCEDURE_DROPTABLE
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/11177254.html
Copyright © 2020-2023  润新知