Assembly 英特尔8086-反转阵列或在其上反向循环

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:

我一直在尝试编写一个代码,以两种方式反转数组的内容。我用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:  
    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
,但在循环中需要额外的代码字节大小。