基础汇编--call方法与函数(两个ASCLL码数相加并输出)

写在前面:
本文为基础汇编程序,演示基础汇编语言的call指令的使用,本文使用实例为Ascll码的47 、25相加, 先转换对应的压缩的bcd码,然后相加,将最终的结果转换为Ascll码输出。本文使用的编译器为emu8086,下载地址

将ascll码转换为压缩的BCD码

很显然,由下图的ascll码表可以看出对于数字字符来说,是对应第三列的每一行的,即ascll码的十进制表示下个位即为该字符,十位是3,所以我们将ascll码转换为BCD码只需要,将十位的3与掉即可,至于压缩,从程序来看吧!

转换程序代码:

    mov ax, word ptr data1 //将47作为字读入寄存器ax [1]
    and ax, 0f0fH //将ax与0000111100001111进行按位与操作 [2]
    xchg ah, al //交换两个操作数, 即 al , ah
    mov cl,4 //给计数器赋值4
    rol ah, cl //进行循环左移,循环左移 cl 次
    or al, ah //按位或操作, 进行压缩
    mov result, al //移动结果47

[1].此时al = 0011 0100 ,ah = 0011 0111 即al = 34, ah = 37
[2].此时进行按位与操作后 al = 0000 0100 , ah = 0000 0111 即 al = 0 4 , ah = 07

将压缩的BCD码转换为Ascll码

类比上边的过程,其实就是一个逆向的过程。

代码:

    mov al, result
    mov ah, al
    and ax, 0f00fH
    mov cl, 4
    shr ah, cl //循环右移
    or ax, 3030H
    xchg ah,al
    mov bx, offset result
    mov [bx], ax  //结果在这里 72

顺序结构的程序

顺序结构,即从主程序的开始到结束,依次顺序执行,最终达到我们想要达到的想法。

以下为这个例子的顺序汇编的源代码:

; multi-segment executable file template.

data segment
    ; add your data here!
    data1 DB '47'
    data2 DB '25'
    pkey DB "The sum of '47' + '25' is "
    result  DB  0
    DB " .", "$"  
ends

stack segment
    dw   128  dup(0)
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    mov es, ax

    ; add your code here
    mov ax, word ptr data1
    and ax, 0f0fH
    xchg ah, al
    mov cl,4
    rol ah, cl
    or al, ah
    mov result, al

    mov ax, word ptr data2
    and ax, 0f0fH
    xchg ah, al
    mov cl,4
    rol ah, cl
    or al, ah

    adc al, result
    daa
    mov result, al

    mov al, result
    mov ah, al
    and ax, 0f00fH
    mov cl, 4
    shr ah, cl
    or ax, 3030H
    xchg ah,al
    mov bx, offset result
    mov [bx], ax     

    mov bx, offset pkey
    mov [bx], ax 


    lea dx, pkey
    mov ah, 9
    int 21h        ; output string at ds:dx

    ; wait for any key....    
    mov ah, 1
    int 21h

    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends
end start ; set entry point and stop the assembler.

可以看到将47 、25转换为压缩的BCD码的过程其实可以抽象为一个算法,利用一个简简单单的函数实现,可以节省下很多的代码,但是这里我们是汇编语言,怎么利用汇编语言实现函数的功能呢?这里我们使用call指令。

利用call指令实现模块化设计(函数)

常见的CPU的CALL指令(“调用”指令)的功能,就是以下两点:
(1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。

而子程序结尾处通常都要编写一条RET指令(“返回”指令),RET指令的功能就是一条:从栈中取出一条数据送入PC。

从上面叙述可以看出,正常情况下,RET指令从栈中取出的一条数据,也就是当初被CALL指令所入栈的下一条指令的所在地址。
因此,RET指令后,CPU的下一条指令就回去执行当初的CALL指令的下一条了。

这里有点像我们的c语言函数
[返回值类型] [函数名] (形参表 …){
return data;
}

那么我们怎么实现call指令后的传参呢,怎么将参数传给我们call的模块呢?

1.寄存器传参
2.变量传参
3.地址表传参
4.堆栈传参

这里我们使用寄存器传参

代码:

; multi-segment executable file template.

data segment
    ; add your data here!
    data1 DB '47'
    data2 DB '25'
    pkey DB "The sum of '47' + '25' is "
    result  DB  0
    DB " .", "$"  
ends

stack segment
    dw   128  dup(0)
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    mov es, ax

    ; add your code here
    mov bx, offset data1
    call asc_bcd
    mov result, al
    mov bx, offset data2
    call asc_bcd

    adc al, result
    daa
    mov result, al

    mov bx, offset result
    call bcd_asc
    mov ax, word ptr result   

    lea dx, pkey
    mov ah, 9
    int 21h        ; output string at ds:dx

    ; wait for any key....    
    mov ah, 1
    int 21h

    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

asc_bcd proc
    mov ax, word ptr [bx]
    and ax, 0f0fH
    xchg ah, al ;交换两个操作数的数据
    mov cl,4
    rol ah, cl ;循环左移,rol dest, count
    or al, ah
    ret
asc_bcd endp

bcd_asc proc
    mov al, [bx]
    mov ah, al
    and ax, 0f00fH
    mov cl, 4
    shr ah, cl ;循环右移 shr dest, count
    or ax, 3030H
    xchg ah,al
    mov [bx], ax
    ret
bcd_asc endp
end start ; set entry point and stop the assembler.

这里的asc_bcd、bcd_asc就像我们c语言中的函数名一样,我们提前将要修改的数据的地址传到我们指定的地方,call这个函数,就可以在其内部利用这个寄存器进行操作,达到模块化编程的目的。

你可能感兴趣的:(汇编,汇编语言)