给定的逻辑段
I1 db ? I2 db ? I3 db ? A1 dw 5 dup (6 dup (0fh,4 dup (0))) Data1 ends
- 创建一段代码(例如名称为Code1),在其中实现以下任务:替换代码中的所有单词 三维数组 A1 的值为 0fh,其中 使用索引跟随(通过段中的偏移量)5 个单词 I1,I2,I3(位于地址 I1,I2,I3 的值)。
- 再创建一个逻辑数据段(例如命名为Data2),其中设置指令A2 dw 5 dup(6 dup(0fh,4 dup(0)))
- 创建另一个逻辑代码段(例如,名称为Code2),其中使用链命令执行步骤1的任务 搜索值 0fh。计算后,比较中的值 数组 A1 和 A2。确保控制权无条件移交 使用间接段间控制将段 Code1 转换为段 Code2 转移。
;for MASM 5.00 translator ;for DOS .386 .MODEL flat ; for MASM 5.00
我无法理解此任务中汇编代码的逻辑。
我的代码:
.386
Data1 segment
I1 db ?
I2 db ?
I3 db ?
A1 dw 5 dup (6 dup (0fh,4 dup (0)))
Data1 ends
Data2 segment
A2 dw 5 dup (6 dup (0fh,4 dup (0)))
Data2 ends
Code1 segment use16
assume cs:Code1, ds:Data1
start:
mov [I1], 0
mov [I2], 0
mov [I3], 0
mov ax, DATA1
mov ds, ax
L1:
L2:
L3:
movzx ax, byte ptr [I1]
imul bx, ax, 6*5*2
movzx ax, byte ptr [I2]
imul ecx, ax, 5*2
xor esi,esi
movzx ax, byte ptr [I3]
mov si, ax
lea di, [ecx + esi*2]
cmp A1[bx+di],0fh
jne NEXT
mov ax,0
add ax,[A1+bx+di+2]
add ax,[A1+bx+di+4]
add ax,[A1+bx+di+6]
add ax,[A1+bx+di+8]
add ax,[A1+bx+di+10]
mov [A1+bx+di],ax
NEXT:
inc I3
cmp I3, 5
jle L3
mov I3, 0
inc I2
cmp I2, 6
jle L2
mov I2, 0
inc I1
cmp I1, 5
jle L1
jmp far ptr start2
Code1 ends
Code2 segment use16
assume cs:Code2, ds:Data1, es:Data2
start2:
mov ax,data1
mov ds,ax
mov ax,data2
mov es,ax
mov cx, 150d
mov di, OFFSET A2
mov ax, 0fh
cld
L:
repnz scasw
sub di, 2
xor dx,dx
add dx,[A2+di+2]
add dx,[A2+di+4]
add dx,[A2+di+6]
add dx,[A2+di+8]
add dx,[A2+di+10]
mov [A2+di],dx
add di, 2
dec cx
cmp cx,0
jg L
mov si,OFFSET A1
mov di,OFFSET A2
cld
repz cmpsw
sub si, 2
sub di, 2
mov bx,A1[si]
mov dx,A2[di]
mov ax, bx
sub ax, dx
mov ax,4c00h
int 21h
Code2 ENDS
end start2
使用索引 I1、I2、I3 将三维数组 A1 中的所有字替换为值 0fh 的以下(通过段中的偏移量)5 个字的总和
至少对我来说,这听起来好像你不应该关心读取数组之外的内存。你也是这样解决的。我提到这一点是因为它会影响比较两个数组(A1和A2)的结果;如果数组之后内存中的垃圾有任何不同,那么
repe cmpsw
可能会产生错误的结果。
Data1 segment I1 db ? I2 db ? I3 db ? A1 dw 5 dup (6 dup (0fh,4 dup (0))) Data1 ends Data2 segment A2 dw 5 dup (6 dup (0fh,4 dup (0))) Data2 ends
我假设这些数据段是 16 字节对齐的,并且不保证末尾的填充。我建议如下:
Data1 segment
I1 db 0
I2 db 0
I3 db 0
db 0 <<< Word-alignment for A1 array
A1 dw 5 dup (6 dup (15, 4 dup (0)))
db 0 <<< Filler for consistent results
Data1 ends
Data2 segment
A2 dw 5 dup (6 dup (15, 4 dup (0)))
db 0 <<< Filler for consistent results
Data2 ends
您的三重嵌套循环迭代次数过多!当行中有 5 个元素时,I3 变量中从零开始的索引范围可以从 0 到 4。使用像
cmp I3, 5
jle L3
这样的一对指令,您将允许使用无效索引 5。其他索引也存在同样的错误。
mov [I1], 0 mov [I2], 0 mov [I3], 0 mov ax, DATA1 mov ds, ax
你认为如果在使用这些依赖于 DS 的mov
指令之前
不设置 DS 段寄存器,CPU 会将这些零字节存储在哪里?下面是我对这些嵌套循环的重写。我避免在最内部的循环中一遍又一遍地重复相同的计算,并且我选择仅使用 8086 代码。我知道您可以在实地址模式下使用 x86 指令,但我不喜欢的是您毫无理由地使用 16 位和 32 位寄存器的丑陋组合:
L1:
mov al, 6*5*2
mul I1
mov di, ax ; DI is offset to a plane (a plane of rows and columns)
L2:
mov al, 5*2
mul I2
mov si, ax ; SI is offset to a row within a plane
L3:
xor bx, bx
mov bl, I3
shl bx, 1 ; BX is offset to an element within a row
add bx, si ; Address of current element is A1+di+si+bx
cmp [A1+bx+di], 15
jne NEXT
mov ax, [A1+bx+di+2]
add ax, [A1+bx+di+4]
add ax, [A1+bx+di+6]
add ax, [A1+bx+di+8]
add ax, [A1+bx+di+10]
mov [A1+bx+di], ax
NEXT:
inc I3
cmp I3, 5
jb L3
mov I3, 0
inc I2
cmp I2, 6
jb L2
mov I2, 0
inc I1
cmp I1, 5
jb L1
第二种方法repne scasw
指令因找到值15而停止时,DI寄存器指向查找结果后面,并且CX寄存器包含剩余项目的数量。在循环底部使用
dec cx
是错误的!
add dx,[A2+di+2]
add dx,[A2+di+4]
add dx,[A2+di+6]
add dx,[A2+di+8]
add dx,[A2+di+10]
mov [A2+di],dx
这些指令将A2数组的地址添加两次!一次通过 mov di, offset A2
初始化 DI,第二次通过在寻址模式中提及
[A2+ ...
。以下是我的重写并应用了更正。请注意,不必先将 DI 减 2,然后再将 DI 加 2。稍微调整一下偏移量会更好。偏移量也可以是负数,如
mov es:[di-2], ax
:
mov ax, data1
mov ds, ax
mov ax, data2
mov es, ax
mov cx, 5*6*5
mov di, offset A2
cld
L:
mov ax, 15
repne scasw
mov ax, es:[di]
add ax, es:[di+2]
add ax, es:[di+4]
add ax, es:[di+6]
add ax, es:[di+8]
mov es:[di-2], ax
test cx, cx
jnz L
支票sub si, 2
sub di, 2
mov bx,A1[si]
mov dx,A2[di]
mov ax, bx
sub ax, dx
mov ax,4c00h
int 21h
这里,这些mov
指令将数组的地址相加两次!一次通过 SI / DI 的初始化,第二次通过在寻址模式中提及 A1 / A2。 当然,您应该使用偏移量 -2,这比从索引寄存器中减去 2 更好。
AX = BX - DX
的结果就会丢失!我的建议是返回 DOS.Exitcode AL 中的差异:
mov si, offset A1
mov di, offset A2
repe cmpsw
mov al, [si-2]
sub al, es:[di-2]
mov ah, 4Ch
int 21h