Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 防止DIV指令阻塞AX寄存器_Assembly_Division_Multiplication_X86 16_Emu8086 - Fatal编程技术网

Assembly 防止DIV指令阻塞AX寄存器

Assembly 防止DIV指令阻塞AX寄存器,assembly,division,multiplication,x86-16,emu8086,Assembly,Division,Multiplication,X86 16,Emu8086,我试图在汇编中解决这些简单的乘法和除法运算 5*4 + 35/7 我已经这样做了 mov al,5 mov bl,4 mul bl mov ax,35 mov bl,7 div bl AX寄存器中以前的乘法值被除法的新结果覆盖。如何修复此问题?您需要乘以5*4,然后将值推送到堆栈上。然后进行第二次计算,除法。然后从堆栈中弹出第一个值并将这些值相加。回答主要问题:您可以使用imul reg,reg,imm将乘法运算到不同的寄存器中。或者,您可以只mov ecx,eax将结果保存在di

我试图在汇编中解决这些简单的乘法和除法运算

5*4 + 35/7
我已经这样做了

mov al,5
mov bl,4 
mul bl 

mov ax,35 
mov bl,7 
div bl

AX寄存器中以前的乘法值被除法的新结果覆盖。如何修复此问题?

您需要乘以5*4,然后将值推送到堆栈上。然后进行第二次计算,除法。然后从堆栈中弹出第一个值并将这些值相加。

回答主要问题:您可以使用
imul reg,reg,imm
将乘法运算到不同的寄存器中。或者,您可以只
mov ecx,eax
将结果保存在
div
不需要的寄存器中


因为您没有说明数据来自何处,所以显然要在组装时执行计算

mov eax,  5*4 + 35/7

若您仍然希望在运行时进行计算,则需要从立即数常量、寄存器或内存中的值开始。这里可以方便地混合演示这些操作数(因为
div
没有立即操作数形式)

通常最好使用默认操作数大小,在32位和64位模式下为32位。不过,8比特操作通常并不较慢

mov    eax, 35
div    byte [seven]     ; al = ax/7, ah=ax%7.  wider operand sizes divide edx:eax by the src.

mov    cl, 5
lea    eax, [ecx*4 + eax]  ; al = cl*4 + al.  Ignore the garbage in the high bits.
; result in al

section .rodata
seven:   db 7
div
很慢,所以,因为2的补码溢出可能会导致这种情况


有关在不清除高位的情况下使用
lea
乘以4和相加的理由,请参阅。

Emu8086基于8086指令,因此您只有单操作数版本的MUL和DIV。请注意,是的有符号版本,是的有符号版本。假设您打算执行无符号算术,您的代码可能如下所示:

mov al,5
mov bl,4 
mul bl 
mov cx, ax     ; Save AX to CX

mov ax,35 
mov bl,7 
div bl

xor ah, ah     ; Result(quotient) of DIV in AL, ensure AH is zero
add ax, cx     ; AX=AX+CX
使用MUL和DIV的8086特定指令无法防止AX被破坏。您必须将该值移动到一个临时区域。我们将在上面的代码中使用寄存器CX。由于我们将MUL指令的结果保存到CX中,所以只需将其添加到DIV指令的结果中(商在AL中)。我们将存储在AH中的余数归零,将商保留在AL中。AX现在将包含我们添加到CX中的商(作为16位值),等式的最终结果存储在AX中


乘以4的一种简化方法是将值左移2位。此代码:

mov al,5
mov bl,4 
mul bl 
mov cx, ax     ; Save AX to CX
可简化为:

mov cx, 5
shl cx, 2      ; Multiply CX by 4
8086处理器不支持SHL移位超过1位,除非通过CL寄存器。EMU8086的汇编程序自动将
SHL reg,imm
指令转换为一条或多条
SHL,reg,1
指令。在这种情况下,
SHL CX,2
被翻译为:

shl cx, 1      ; Multiply CX by 2
shl cx, 1      ; Multiply CX by 2 again
大多数8086汇编程序不会为您执行此翻译。或者,可以在CL寄存器中指定要移位的位数。这(或同等)适用于大多数8086汇编程序:

mov cl, 2      ; Number of bits to shift left by in CL
mov dx, 5
shl dx, cl     ; Shift DX to the left by CL(2) is equivalent to multiply by 4

mov ax,35 
mov bl,7 
div bl

xor ah, ah     ; Result(quotient) of DIV in AL, ensure AH is zero
add ax, dx     ; AX=AX+DX
AX寄存器中以前的乘法值被除法的新结果覆盖。我该如何解决这个问题

很简单。将乘法的结果放入一个额外的寄存器(我使用了
DX
),计算表达式的下一项,最后将两个结果相加。重要的是要注意,商仅在
AL
寄存器中,因此在进行加法之前,您需要清除
AH
寄存器!(示例“35/7”中使用的数字在
AH
中产生0的余数,但当要求您编写程序时,您不应指望这一点!)


事实上,现在我想起来了,已经有一段时间了,但我相信问题可能是,艾尔是斧头的一半。因此,当您将一个值移动到ax中时,它会覆盖al。换句话说,al和ah是ax的低位和高位。不需要使用堆栈,但您的一般观点是正确的,即OP会使用
mov ax,35
对mul结果(即ax=al*src)进行重击。x86有7个通用寄存器(不计算堆栈指针,堆栈指针可以用作通用寄存器,但从来都不是)。这也没有标记为8086,因此没有理由不使用2或3个操作数(
imul dest、src、imm
)来保存从eax/edx移出的内容(由
mul
div
隐式使用)。我同意。一旦我意识到al和ah是ax的高低值,那么解决方案显然就是使用另一个寄存器。mov al,5 mov bl,4 mul bl mov cx,35 mov dl,你是在写针对DOS还是EMU8086的16位8086代码?我是为EMU8086写的。是的,我应该指出我的编辑没有改变任何问题。添加标记x86并没有明确说明它是16位、32位还是64位代码。标记本身的措辞包含了这三个标记。一旦OP回答了我在问题下提出的问题,我会添加一个特定的处理器标签。仍然有可能他们的目标是16位代码。我怀疑这是基于他的大学和一些课程的16位代码。@MichaelPetch:我在更仔细地查看编辑后意识到了这一点。我没有从乱七八糟的原稿中看出OP知道问题出在敲击斧头上。还有,我想他可能是在写16位代码,但16位是愚蠢的,所以我故意避免鼓励他。我没有查看他的用户页面,试图弄清楚他上的是哪所大学。多操作数
imul
在普通CPU上仍然可以在16位模式下使用,我一直猜测这是一个DOS问题,而不是没有386特性的糟糕8086。他添加了一条评论,我并不奇怪它是emu8086,所以目标是16位代码。至于多操作数版本的imul直到80286才开始出现(有些是在386中添加的)。我不相信任何多操作数变体在emu8086上工作,因为它是作为8086环境设计的。@MichaelPetch:是的,我知道多操作数
imul
不在8086中。说伊穆尔·伊梅代特加了186个。是的
mov al,5
mov bl,4
mul bl     ; -> Result is in AX
mov dx, ax

mov ax,35 
mov bl,7 
div bl     ; -> Result is in AL

mov ah, 0
add ax, dx ; -> Final result is in AX