Assembly 英特尔8086-反转阵列或在其上反向循环
我一直在尝试编写一个代码,以两种方式反转数组的内容。我用push-and-pop方法做得很好,但我不知道如何用指针的方式来做 我要求任何有帮助的澄清Assembly 英特尔8086-反转阵列或在其上反向循环,assembly,reverse,x86-16,masm,Assembly,Reverse,X86 16,Masm,我一直在尝试编写一个代码,以两种方式反转数组的内容。我用push-and-pop方法做得很好,但我不知道如何用指针的方式来做 我要求任何有帮助的澄清 .model small .data tab db '12345' ,13,10,'$' .code main proc mov ax,@data mov ds,ax mov si,offset tab mov di,offset tab+5 mov cx,5 etiq1:
.model small
.data
tab db '12345' ,13,10,'$'
.code
main proc
mov ax,@data
mov ds,ax
mov si,offset tab
mov di,offset tab+5
mov cx,5
etiq1:
mov bx,[si]
push bx
inc si
loop etiq1
mov cx,5
etiq2:
pop dx
mov ah,02h
int 21h
loop etiq2
main endp
end main
通过堆栈反转字符串数组,并使用字符串原语lodsb
和stosb
。
推循环和弹出循环在遇到终止字符串的回车时结束。CLD
指令需要使lodsb
和stosb
在内存中向上移动。代码将使用DOS.PrintString函数09h一次性打印结果
mov ax, @data
mov ds, ax
mov di, offset tab
mov si, di
mov dx, di
cld
etiq1:
lodsb
push ax
cmp byte ptr [si], 13
jne etiq1
etiq2:
pop ax
stosb
cmp byte ptr [di], 13
jne etiq2
mov ah, 09h ; DOS.PrintString
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
使用指针反转数组的另一种方法。
左侧的元素使用SI
指针读/写,右侧的元素使用相同的指针读/写,但偏移量适当。只要该偏移量保持大于零,循环就可以继续。偏移量必须至少为1,两个地址才能与内存中不同的字节通信
mov ax, @data
mov ds, ax
mov si, offset tab
mov bx, 4 ; 5 elements : last element is at offset 4 from the first element
More:
mov al, [si] ; Read on left side
mov dl, [si+bx] ; Read on right side
mov [si], dl ; Write on left side
mov [si+bx], al ; Write on right side
inc si ; Move to the right
sub bx, 2 ; Next couple of elements is 2 bytes closer to each other
ja More ; Must stay above 0 to address different elements
; Here BX is -1, or 0 for remaining 0, or 1 element
mov dx, offset tab
mov ah, 09h ; DOS.PrintString
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
mov ax, @data
mov ds, ax
mov si, offset tab
mov bx, NumberOfByteSizedElementsMinusOne
jmp Begin
More:
mov ax, [si] ; Read pair on left side
mov dx, [si+bx-1] ; Read pair on right side
xchg al, ah
xchg dl, dh
mov [si], dx ; Write pair on left side
mov [si+bx-1], ax ; Write pair on right side
add si, 2 ; Move to the right
sub bx, 4 ; Next couple of paired elements is 4 bytes closer to each other
Begin:
cmp bx, 3
jge More ; Must stay above 2 to address different paired elements
; Here BX is -1, 0, 1, or 2 for remaining 0, 1, 2, or 3 elements
cmp bx, 0
jle Done
mov al, [si] ; Read on left side
mov dl, [si+bx] ; Read on right side
mov [si], dl ; Write on left side
mov [si+bx], al ; Write on right side
Done:
mov dx, offset tab
mov ah, 09h ; DOS.PrintString
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
下一步是一次读写2个元素的优化。
当然,这只在处理长度一定的数组时才重要,所以不要在有限的5字节数组中!这一次,两个地址的偏移量必须至少为3,才能与内存中不同的字进行对话
mov ax, @data
mov ds, ax
mov si, offset tab
mov bx, 4 ; 5 elements : last element is at offset 4 from the first element
More:
mov al, [si] ; Read on left side
mov dl, [si+bx] ; Read on right side
mov [si], dl ; Write on left side
mov [si+bx], al ; Write on right side
inc si ; Move to the right
sub bx, 2 ; Next couple of elements is 2 bytes closer to each other
ja More ; Must stay above 0 to address different elements
; Here BX is -1, or 0 for remaining 0, or 1 element
mov dx, offset tab
mov ah, 09h ; DOS.PrintString
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
mov ax, @data
mov ds, ax
mov si, offset tab
mov bx, NumberOfByteSizedElementsMinusOne
jmp Begin
More:
mov ax, [si] ; Read pair on left side
mov dx, [si+bx-1] ; Read pair on right side
xchg al, ah
xchg dl, dh
mov [si], dx ; Write pair on left side
mov [si+bx-1], ax ; Write pair on right side
add si, 2 ; Move to the right
sub bx, 4 ; Next couple of paired elements is 4 bytes closer to each other
Begin:
cmp bx, 3
jge More ; Must stay above 2 to address different paired elements
; Here BX is -1, 0, 1, or 2 for remaining 0, 1, 2, or 3 elements
cmp bx, 0
jle Done
mov al, [si] ; Read on left side
mov dl, [si+bx] ; Read on right side
mov [si], dl ; Write on left side
mov [si+bx], al ; Write on right side
Done:
mov dx, offset tab
mov ah, 09h ; DOS.PrintString
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
实际上,您没有在内存中反转数组,只是将其向后打印,每次打印1个字符。反转后的数据仅在堆栈和寄存器中,而不会存储回阵列中。(这很好,如果您不需要那里的数据,就不需要这样做。但是请注意,您没有打印CR LF行结束符,
$
终止符什么也不做:假设它在那里,您可以将整个字符串的地址传递给DOS打印字符串函数。这回答了您的问题吗?顺便说一句,对于以后的x86,执行ev使用bswap
可以反转4或8字节寄存器中的字节,而不是xchg
或rol ax,8
。使用SSSE3,pshufb
可以反转16个字节。请注意,实际上可以保存以允许宽加载循环(部分)在上一次迭代中重叠,因为在执行任一存储之前从两侧加载原始数据。当整个数组小于加载/存储宽度时,您只需要更窄的清理范围来处理这种情况,以避免读取数组外的数据。(在这种情况下,对于2字节加载/存储,它适用于任何大于1的大小,而反转0或1字节数组是不可行的,因此不需要清理。对于大小=2,完全可以加载相同的数据两次并存储两次,或者对于大小=3的重叠加载/存储。)因此,您还可以对结束和开始交叉进行指针比较,如add di,2
/sub-si,2
/cmp di,si
/jbe.loop
,其中si
开始指向以数组最后一个字节结尾的单词。即数组+大小-2
。在16位模式下,您的方式不会更糟,其中索引寻址模式不会占用更多空间。尽管在寻址模式中有一个-1
,但在循环中需要额外的代码字节大小。