编写一个名为SUB64的程序,从0x0160和0x0164中的64位整数中减去内存位置0x0150和0x0154中的64位整数。将结果存储在存储单元0x0170和0x0174中。
我理解将它分成小块的逻辑,因为我们不能将64位装入寄存器。而且我知道我们首先减去最不重要的部分。我正在为实际编码而苦苦挣扎。我们使用哪个GPIO有关系吗?这是我的例子,也许你可以看到我的思考方式。也许我不是那么遥远,但感觉就像它。
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那样?
即使这在某种程度上是正确的,我是否需要一个return语句或一个标题或任何东西来实际编译? (我使用NASM和DosBox)
这是我必须编写的12个类似程序中的第一个。因此,任何朝着正确方向前进的方向都有希望让我继续前行!
答案 0 :(得分:4)
1)
内存位置0x0150和0x154
中的64位整数
这不是非常精确的任务描述,64b整数在内存中位于0x0150到0x0157之间(总共8个字节)。该描述听起来默认使用了一个内存单元dword
(32位),它在16b实模式下不是非常合理的默认数据大小。
2)mov ax,0x0150
不会从内存中加载值,而是将常量0x0150
加载到ax
中。如果要从内存加载实际值,则必须取消引用该内存地址,例如:
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模式下使用相对寻址,所以这是可能的:
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的基地址来解决,所以你也可以继续减法:
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是最终的,你不要&# 39;需要记住你确实借过了" 1"从5中减去8。
结果地址相对于num1地址再次易于计算,因此您只需将结果存储回内存
mov [si+0x20],ax ; 0x0150 + 0x20 = 0x0170
mov [si+0x22],bx
...
我基本上给了你完整的解决方案:/ ...所以让我们至少添加一些信息,让你稍微解决一下。
您可以不使用4个16b寄存器来保存单个64b值,例如:
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
...
看完那个之后,你可能会有一个好主意,怎么样:
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 - 某些指令可能会让您感到惊讶,例如上面的代码修改为:
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,只修改其他算术标志。
在不修改任何标志的情况下将2添加到有效寻址寄存器的另一种方法是lea si,[si+2]
。
BTW dosbox默认模拟386+,因此您甚至可以在16b实模式下使用:
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)指令集,否则32位寄存器是用80386 CPU引入的。