如何在8086汇编中减去两个64位整数 [英] How to subtract two 64 bit integers in 8086 assembly

查看:186
本文介绍了如何在8086汇编中减去两个64位整数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编写一个名为SUB64的程序,从0x0160和0x0164中的64位整数中减去内存位置0x0150和0x0154中的64位整数.将结果存储在内存位置0x0170和0x0174中.

Write a program called SUB64 to subtract the 64-bit integer in memory locations 0x0150 and 0x0154 from the 64-bit integer in 0x0160 and 0x0164. Store the result in memory location 0x0170 and 0x0174.

我理解将其分成小块的逻辑,因为我们无法将64位装入寄存器.我知道我们首先减去最低有效部分.我正在为实际编码而苦苦挣扎.我们使用哪个GPIO无关紧要吗?这是我的示例,因此也许您可以了解我的想法.也许我离我们并不遥远,但感觉就像是.

I understand the logic behind separating it into smaller pieces since we can't fit 64 bits into the registers. And I know we subtract the least significant pieces first. I'm struggling with actually coding it. Does it matter which GPIO we use? This is my example, so maybe you can see how I'm thinking. Maybe I'm not that far off, but it feels like it.

MOV AX, 0X0150
MOV BX, 0X0154
MOV CX, 0X0160
MOV DX, 0X0164
SUB BX, DX
SUB AX, CX
MOVE 0X0174, BX
MOVE 0X0170, AX

我将64位整数的每半存储到寄存器中.然后,我减去寄存器,然后将它们放入内存位置.十六进制格式可以吗?还是需要像0174h这样的东西?

I stored each half of the 64 bit integer into the registers. Then I subtracted the registers and put them into the memory locations. Is that hex format okay? or does it need to be something like 0174h?

即使这在某种程度上是正确的,我是否需要return语句或标头或任何东西来使其实际编译? (我正在使用NASM和DosBox)

Even if this is somehow correct, do I need a return statement or a header or anything to make this actually compile? (I'm using NASM and DosBox)

这是我必须编写的12个类似程序中的第一个.因此,向正确方向的任何推动都有望使我前进!

This is the first of 12 similar programs I have to write. SO ANY push in the right direction will hopefully get me on my way!

推荐答案

1)

内存位置0x0150和0x154中的64位整数

那不是很精确的任务描述,64b整数在内存中的0x0150到0x0157(总共8个字节)位置.该描述听起来像默认情况下使用的存储单元dword(32位),在16b实模式下,默认数据大小不是很合理.

that's not very exact task description, the 64b integer is in memory at locations from 0x0150 to 0x0157 (8 bytes in total). That description sounds like by default a memory unit dword (32 bits) is used, which in 16b real mode is not very sensible default data size.

2)mov ax,0x0150不会从内存中加载值,而是将常量0x0150加载到ax中.如果要从内存中加载实际值,则必须取消引用该内存地址,例如:

2) mov ax,0x0150 does not load the value from memory, it loads that constant 0x0150 into ax. If you want to load the actual value from memory, you have to dereference that memory address, like for example:

mov si,0x0150  ; set si to contain address of input number1
mov ax,[si]    ; load least significant 16b word (LSW) of it into ax

; you can even use absolute addressing like:
mov  ax,[0x0150]  ; usually not practical, but possible

现在,如果您想放置所有字的所有地址(将使用3 * 4个内存字,num1,num2和结果,它们全部为4个字长),您将很快用完寄存器.但是实际上您可以在16b模式下使用相对寻址,因此这是可能的:

Now if you would want to put all addresses of all words (3 * 4 words of memory will be used, num1, num2 and result, all of them 4 words long), you would run out of registers quickly. But actually you can use relative addressing in 16b mode, so this is possible:

mov   si,0x0150  ; set si to contain address of input number1
mov   ax,[si]
mov   bx,[si+2]
mov   cx,[si+4]
mov   dx,[si+6]
; here dx:cx:bx:ax concatenated into single 64b number contains the number1

但是number2也可以通过number1的基地址来寻址,因此您也可以通过减法来继续:

But the number2 can be addressed by base address of number1 too, so you can also continue by subtraction:

sub   ax,[si+0x10]   ; subtraction of LSW, ignoring CF (borrow)
sbb   bx,[si+0x12]   ; continuing by subtracting adjoining 16 bits
    ; but this time CF will affect the result, to make any "borrowing"
    ; happening while subtracting the LSW to propagate into upper 16 bits
... etc..

关于注释中的问题... CF修改的结果已存储在bx中,旧的CF丢失,CF包含bx - [0x162] - old_borrow的新借用".您可以根据需要 将CF存储在某个地方,CPU指示检测/存储/设置CF的值,但是一旦您计算出15-8为7,则数字为7,最后是7,则您不必无需记住您确实借用了"1"从5中减去8.

About your question in comments... the result modified by CF is already stored in bx, the old CF is lost, CF contains new "borrow" of bx - [0x162] - old_borrow. You can store CF somewhere if you wish, the CPU has instructions to detect/store/set value of CF, but with numbers once you calculate 15 - 8 is 7, the 7 is final, you don't need to remember you did borrow the "1" to subtract 8 from 5.

相对于num1地址,结果地址再次易于计算,因此您只需将结果存储回内存中即可

And the result address is again easy to calculate relatively to num1 address, so you can just store the result back into memory

mov   [si+0x20],ax  ; 0x0150 + 0x20 = 0x0170
mov   [si+0x22],bx
...

我基本上为您提供了完整的解决方案:/...因此,让我们至少添加一些其他信息,以使您有所了解.

And I basically gave you whole solution :/ ... so let's add some more info at least, to make you work it out a bit.

您可以不使用4个16b寄存器来保存单个64b值而执行相同的操作,例如:

You can do the same without using 4 16b registers to hold the single 64b value, like:

mov   ax,[si]
sub   ax,[si+0x10]
mov   [si+0x20],ax
mov   ax,[si+2]
sbb   ax,[si+0x10+2]
mov   [si+0x20+2],ax
...

看了一个之后,您可能会想到一个好主意,

After looking at that one, you may get a great idea, how about:

mov   ax,[si]
sub   ax,[si+0x10]
mov   [si+0x20],ax
add   si,2          ; adjust rather base pointer then changing all those offsets
mov   ax,[si]
sbb   ax,[si+0x10]
mov   [si+0x20],ax
...

行得通吗?不再. add si,2将修改CF,因此下一个sbb不会在减法中继续".在这里要学习的课程是,您应该经常查看说明参考指南以获取详细的信息.描述,包括它会影响哪些标志.使用x86-某些说明可能会让您感到惊讶,例如,上面的代码修改为:

Does it work? Not any more. The add si,2 will modify the CF, so the next sbb does not "continue" in the subtraction. The lesson to learn here is, that you should often check instruction reference guide for detailed ins. description, including which flags it does affect. With x86 - some instruction can surprise you, for example the code above modified to:

mov   ax,[si]
sub   ax,[si+0x10]
mov   [si+0x20],ax
inc   si        ; adjust base pointer
inc   si
mov   ax,[si]
sbb   ax,[si+0x10]
mov   [si+0x20],ax
...

将起作用,因为inc不会影响CF,因此仅修改其他算术标志.

WILL work, because inc does NOT affect CF, only other arithmetic flags are modified.

在不修改任何标志的情况下将两个加到有效寻址寄存器的另一种方法是lea si,[si+2].

Another way to add two to valid addressing register without modifying any flag is lea si,[si+2].

默认情况下,BTW dosbox模拟386+,因此您甚至可以在16b实模式下使用:

BTW dosbox by default emulates 386+, so you can use even in 16b real mode:

mov   si,0x0150
mov   eax,[si]
mov   ebx,[si+4]    ; ebx:eax = 64b number1 (note +4 this time)
sub   eax,[si+0x10]
sbb   ebx,[si+0x14] ; ebx:eax = (number1 - number2)
mov   [si+0x20],eax
...

除非只限于使用8086(80286)指令集,否则80386 CPU将引入32位寄存器.

Unless you were constrained to use only 8086 (80286) instruction sets, the 32 bit registers were introduced with 80386 CPU.

这篇关于如何在8086汇编中减去两个64位整数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆