assembly 在Visual Studio 2019中抛出预期/未处理的异常

scyqe7ek  于 2023-03-23  发布在  其他
关注(0)|答案(2)|浏览(129)

在我的代码中突出显示的一行中,我得到消息“Exception thrown at 0x002C36C9 in project.exe:0xC0000005:阅读位置0x0058C00A时发生访问冲突”
我一直在尝试一切摆脱它,但它只是不工作,我迫切需要帮助。代码还没有完全完成,但它应该运行一些。代码的目的是复制元素从arrayS到arrayD从索引收到从键盘输入开始。有人请帮助我,代码看起来很好,所以我relaly不知道是什么错了
See highlighted line
我真的不知道如何解释我已经尝试了什么,我试图做的是很简单的,这就是为什么我不明白为什么我得到这个错误。

include Irvine32.inc
ExitProcess proto, dwExitCode: DWORD

.data
  arrayS    BYTE    1, 2, 3, 4, 5   ;array (SOURCE)
  numEl = LENGTHOF arrayS
  arrayD    BYTE    numEl DUP(0)    ;array (DESTINATION)
  startIndex    BYTE    ?        ;store the character in this variable
  exit  EQU     <Invoke ExitProcess,0>
  header    BYTE    "----- Array Copier -----",0
  indexq    BYTE    "Index (0 - 4): ",0
  invalidIn BYTE    "Invalid Input. Try again.",0
  termination   BYTE    "----- Program Terminated -----",0


.code

userInput PROC
  mov edx, OFFSET indexq
  call WriteString
  call ReadInt
  call crlf
  mov startIndex, al

  ret
userInput ENDP

displayTitle PROC 
  mov edx, OFFSET header
  call WriteString
  call crlf

  ret
displayTitle ENDP

copyArray PROC

  mov esi, OFFSET arrayS
  mov edi, OFFSET arrayD
  movzx ebx, startIndex
  mov ecx, numEl

copying:
  mov al, [esi + ebx]
  mov [edi], al
  inc esi
  inc edi
  loop copying

  ret
copyArray ENDP

showArray PROC uses ecx
  mov ecx, numEl
  call crlf
  show:
  mov eax, [edi]                ;moving array element to be displayed
  call WriteInt
  call crlf
  add edi, type arrayD      ;moving through array elements to display
  loop show

  ret
showArray ENDP

main PROC
  call displayTitle
  call userInput
  call copyArray
  call showArray

  exit
main ENDP
END main

编辑基于答案的新版本

include Irvine32.inc
ExitProcess proto, dwExitCode: DWORD

.data
  arrayS    BYTE    1, 2, 3, 4, 5   ;array (SOURCE)
  numEl = LENGTHOF arrayS
  arrayD    BYTE    numEl DUP(0h)   ;array (DESTINATION)
  ptr1  DWORD   arrayS
  ptr2  DWORD   arrayD

  startIndex    BYTE    ?        ;store the character in this variable

  exit  EQU     <Invoke ExitProcess,0>
  header    BYTE    "----- Array Copier -----",0
  indexq    BYTE    "Index (0 - 4): ",0
  invalidIn BYTE    "Invalid Input. Try again.",0
  termination   BYTE    "----- Program Terminated -----",0


.code

userInput PROC ;uses ebx ecx eax
beginning:
  mov edx, OFFSET indexq
  call WriteString
  call ReadInt

check:
  mov ebx, 4h           ;check if below 4, then check 2 if below
  cmp eax, ebx
  jbe check2

error:
  mov edx, OFFSET invalidIn
  call WriteString
  call crlf
  jmp beginning

check2:
  mov ebx, 0h       ;check if above zero, then done if above
  cmp eax, ebx
  jnae error

done:
  mov startIndex, al
  ret

userInput ENDP

displayTitle PROC 
  mov edx, OFFSET header        ;displays title
  call WriteString
  call crlf

  ret
displayTitle ENDP

copyArray PROC ;uses ebx ecx 

  mov esi, OFFSET arrayS        ;moving addresses of arrays into the registers
  mov edi, OFFSET arrayD
  add esi, DWORD PTR startIndex
  mov ecx, numEl
  sub ecx, DWORD PTR startIndex

copying:
  mov al, [esi]     ;copying array elements from arrayS to array D
  mov [edi], al
  inc esi
  inc edi
  loop copying

  ret
copyArray ENDP

showArray PROC ;uses ecx 
  mov edi, OFFSET arrayD
  mov ecx, numEl
show:
  mov eax, 0
  mov al, [edi]             ;moving array element to be displayed
  call WriteHex
  mov al, 'h'
  call WriteChar
  call crlf
  add edi, type arrayD      ;moving through array elements to display
  loop show

  ret
showArray ENDP

main PROC
  call displayTitle
  call userInput
  call copyArray
  call showArray

  exit
main ENDP
END main
s3fp2yjn

s3fp2yjn1#

查看最新版本的代码

userInput 中,* check 2 * 中的代码完全是多余的,因为数字永远小于零的条件根本不可能。

很多数字都 * 小于 * 零,但没有一个 * 小于 * 零!

你可以在不使用EBX的情况下与硬编码的数字4进行比较,但实际上你应该与 numEl 进行比较:

check:
  cmp   eax, numEl     ; numEl is 5 in casu
  jb    done           ; We now k n o w that EAX is [0,4]

copyArray 中,字节大小的 startIndex 被当作双字使用。由于您显然必须将其保留为字节,因此更改代码如下:

mov   edi, OFFSET arrayD
  movzx eax, BYTE PTR startIndex
  mov   esi, OFFSET arrayS
  add   esi, eax
  mov   ecx, numEl
  sub   ecx, eax
copying:
  mov   al, [esi]
  mov   [edi], al
  inc   esi
  inc   edi
  loop  copying
  ret

showArray 中,代码显示目标数组的全部内存,即使可能只有一部分内存被复制的元素填充。

mov   ebx, OFFSET arrayD
  movzx eax, BYTE PTR startIndex
  mov   ecx, numEl
  sub   ecx, eax
show:
  movzx eax, BYTE PTR [ebx]
  call  WriteHex
  mov   eax, 'h'
  call  WriteChar
  call  crlf
  inc   ebx
  loop  show
  ret
fslejnso

fslejnso2#

mov al, [esi + startIndex]

这并不使用地址 startIndex 处的字节,而是使用 startIndex 本身的地址。
在循环之前,将字节加载到寄存器中:

movzx ebx, startIndex
copying:
 mov   al, [esi + ebx]
 mov   [edi], al
 inc   esi
 inc   edi                <<<< You forgot this one!
 loop  copying

提示:如果你将 startIndex 定义为DWORD,那么你可以这样写:

mov   ebx, startIndex
copying:
 mov   al, [esi + ebx]
 mov   [edi], al
 inc   esi
 inc   edi                <<<< You forgot this one!
 loop  copying

以及:

mov   edi, OFFSET arrayD
 mov   esi, OFFSET arrayS
 add   esi, startIndex
 mov   ecx, ...
 rep movsb

进一步检查会发现这些其他错误

userInput

call ReadInt   ; -> EAX
call crlf
mov startIndex, al
  • crlf* 可以清除EAX寄存器。这可能是因为 startIndex 没有接收到用户输入的值!按照以下方式重新排列代码,并将 startIndex 定义为DWORD。对输入的数字执行检查不需要循环。单个cmp就可以完成这项工作:
startIndex  DWORD 0

...

  call ReadInt            ; -> EAX
  cmp  eax, numEl         ; numEl == 5
  jnb  error              ; Not ok if NotBelow 5
  mov  startIndex, eax    ; [0,4]
  call crlf
  jmp  done
error:

copyArray

只有当 startIndex 恰好为0时,使用 numEl 初始化ECX才是正确的。但是使用更大的 startIndex,您可以 * 复制的数组元素的数量会减少。否则,您将从数组外部复制垃圾。

mov   edi, OFFSET arrayD
 mov   esi, OFFSET arrayS
 add   esi, startIndex
 mov   ecx, numEl
 sub   ecx, startIndex
 rep movsb

showArray

您忘记了将地址放入EDI寄存器中。在这里,您也只能清楚地显示之前实际复制的那些元素。

相关问题