例,计算data段第一行的三次方,并储存到第二行上

assume cs:code,ds:data
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
s: mov bx,[si]
call cube
mov [di],ax
mov [di].2,dx ;这个的含义是[di]的第二个字节
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

这个程序函数是cube,注意想要跳转就用call,想要返回就用ret。这时返回值存在ax和dx中,参数在bx中,可如果有多个参数,寄存器不够时,可以用栈来传递参数

用栈传递参数

例:计算(a-b)^3,a,b为字型数据
参数 进入子程序时,栈顶存放ip,后面依次存放a,b
结果:(dx:ax)=(a-b)^3

difcube: push bp
mov bp,sp
mov ax,[bp+4] ;将a的值送入栈中
sub ax,[bp+6] ;减去b的值
mov bp,ax
mul bp
mul bp
pop bp
ret 4

ret n的含义为,pop ip add sp,n

而ret 4 的原因是此时栈中有2个数据,要想把栈清空,要移动四个单位(字型)。而push bp ,pop bp 是为了保证bp中的数据没有改变

寄存器冲突问题

例 将data段中的字母变为大写,以0结尾

 data segment
db 'fafdsfs',0
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov cx,4

s: mov si,bx
call capital
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
code ends
end start

这个程序实际上是有问题的,因为进行一次capital后,cx的值一定为0,直接退出主程序的循环

要解决这个问题,有两种方案

  1. 找另一个没有使用的寄存器
  2. 不要使用会发生冲突的寄存器

这样实际上是不可能的,例如cx,循环便一定会冲突

解决方案就是,在进入函数前把所用到寄存器的内容保存起来,结束函数在进行使用

由此我们可以得到子程序设计的标准

子程序开始: 子程序中使用的寄存器入栈
子程序内容
子程序所使用寄存器出栈
返回 (retretf

这里要注意一个问题,当把寄存器内容入栈后,sp会发生改变,如果子程序中也要使用栈要注意地址的变化

同时还要注意入账和出栈的顺序

capital: push cx
push si
...
pop si
pop cx

后进先出