我的任务是设计一个dword division子程序( divdw ),它不会在8086程序集中溢出(我使用masm5.0 / masm.exe和masm5.0 / link.exe并调试MS-DOS中的.exe)。 AX
,CX
和DX
用于保存 divdw 的结果。以下代码无法运行。
这是任务:
输入:
(ax)=低位红利16位 (dx)=双字红利的高16位
(cx)= 16位除数
输出:
(ax)=结果的低16位
(dx)=结果的高16位
(CX)=剩余
我用来计算 divdw 的公式:
dividend / divisor = quot(高16位的被除数/除数)+
(rem(高16位被除数/除数)* 2 ^ 16 +低16位被除数)/除数
这是我的代码:
assume cs:code
code segment
start: mov ax,4240h
mov dx,000fh
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
divdw: push bx
push dx ;ss:[0ch]
mov ax,dx
mov dx,0
div cx
mov ax,0 ;rem, only need dx
mov bx,ss:[0ch]
div bx
;; finish 1
push dx
push ax
;; get dx, into ax
mov ax,ss:[0ch]
div cx
;; finish 2
push ax
pop dx ;ax after 2
pop ax ;ax after 1
pop cx ;dx after 1
;; recover bx
pop bx
pop bx
ret
code ends
end start
在此代码中,我尝试使用pop
和push
但未定义堆栈段。这是允许的吗? (在调试器中,我发现SS:SP
已被提供,但push
无法正常工作。)
如果没有,我应该在哪里定义堆栈以及如何使用它?
如果我在主过程中定义了一个堆栈段,似乎我需要在过程的开头保存SS
和SP
值,但是我应该在哪里保存它们?我可以将它们保存在堆栈中,还是必须将它们保存在内存中?
start 主程序是为了测试而给出的。
谢谢!
修改:
谢谢你们俩!在你的帮助下,我完成了这项任务。代码现在如下:
assume cs:code,ss:stack
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,000fh
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
divdw: push bx
push dx ;ss:[0ah]
push ax ;ss:[08h]
mov ax,dx ;ax=0fh
mov dx,0 ;dx=0
div cx ;ax=1,dx=5
push ax ;1, quot, should be dx when ret, as the high 16 bit of result
;; use dx=5 and 4240h to do div
mov ax,ss:[08h] ;ax=4240h. rem, only need dx of last result, use low 16bit of dividend, ie. ax, as ax
div cx ;ax=86a0h,dx=0h
;ax already is low 16bits of quot
mov cx,dx ;rem, store in cx
pop dx ;1, high 16 bits of quot
pop bx ;discard original ax
pop bx ;discard original dx
pop bx ;recover original bx
ret
code ends
end start
编辑于20170724
又一个版本,摆脱了ss:[08h],并使用了另外3个寄存器来存储。我不确定这是否更好,但它确实有效。
assume cs:code,ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,4240h
mov dx,000fh
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
divdw: push bp
mov bp,sp
push si
push bx
push dx
push ax
mov si,sp
mov ax,dx ;ax=0fh
mov dx,0 ;dx=0
div cx ;ax=1,dx=5
push ax ;1, quot, should be dx when ret, as the high 16 bit of result
;; use dx=5 and 4240h to do div
mov ax,ss:[si] ;ax=4240h. rem, only need dx of last result, use low 16bit of dividend, ie. ax, as ax
div cx ;ax=86a0h,dx=0h
;ax already is low 16bits of quot
mov cx,dx ;rem, store in cx
pop dx ;1, high 16 bits of quot
pop bx ;discard original ax
pop bx ;discard original dx
pop bx ;recover original bx
pop si
mov sp,bp
pop bp
ret
code ends
end start
答案 0 :(得分:3)
只要PUSH
的数量等于POP
的数量,您就不必保存它们。
这并不总是方便,但在你的情况下,应该没问题。
除此之外,您最后将保存的DX
值弹出到BX
,这可能是个问题。
编辑:
在这种情况下,我不知道您需要它,但一般情况下,您可以执行此操作来恢复BP
和SP
:
push bp ; first statement of subroutine
mov bp, sp
...
mov sp, bp
pop bp
ret
在子例程中,您可以使用BP
作为调用前压入堆栈的任何参数的基址。同样,您的示例并未显示,但您似乎也没有使用您在AX
注册表中添加的值和语句
mov bx, ss:[0ch]
有点令人困惑。你怎么知道那个地址是什么?
答案 1 :(得分:3)
如果没有,我应该在哪里定义堆栈以及如何使用它?
如何定义堆栈段取决于汇编程序。
排序为JoinClause
和/或->leftjoin('log_simple_calory as LC',
function($join)use($tz_lccreated_date,$dateRange){
$join->on('LC.user_id_fk','=','UA.user_id_fk');
$join->on('LC.is_active','=',DB::raw('1'))
})->whereRaw('date('.$tz_lccreated_date.')'. $dateRange);
。除segment stack
/ assume ss:stack
个程序外,无需直接在启动时修改SS:SP
。
似乎我需要在程序开始时保存ss和sp值,但是我应该在哪里保存它们?
典型程序仅使用单个堆栈段,因此无需保存/修改.com
寄存器。关于model tiny
,不,你显然不能(不应该)将它保存到堆栈中。通常的诀窍是:
SS
但是,如果您真的需要在过程中使用基于堆栈的args,那么它才有用。否则,只需根据需要使用SP
/ push bp
mov bp, sp
... ; use [bp+4] to address the first argument on the stack
.... ; ss segment is assumed by default when [bp] used
mov sp, bp ; if sp was modified by some push/sub instructions
pop bp
ret
。