assembly 在我的随机数数组排序程序中查找无效内存访问时遇到麻烦

cl25kdpy  于 2023-06-30  发布在  其他
关注(0)|答案(2)|浏览(147)

我正在编写一个赋值代码,我需要在MASM中创建一个数组,并在给定数字输入的情况下为其分配随机数。我已经过了作业的选择排序部分,而且我很难找到我没有访问写内存的位置。我得到的错误代码是:
在Project.exe中的0x00000064处引发异常:0xC0000005:访问冲突执行位置0x00000064。
下面是我的代码的其余部分:

INCLUDE Irvine32.inc

.data
    instructions BYTE "This program generates random numbers in the range [100 .. 999], displays the original list, sorts the list, and calculates the median value. Finally, it displays the list sorted in descending order.",0
    unsorted    BYTE "The unsorted random numbers:",0
    median      BYTE "The median is ",0
    sorted      BYTE "The sorted list:",0
    prompt      BYTE "How many numbers should be generated? [10 .. 200]: ",0
    invalid     BYTE "Invalid input",0
    newline     BYTE 0DH, 0AH, 0
    spaceBar    BYTE " ", 0
    array       DWORD 200 DUP(?)
    request     DWORD ?
    medianValue DWORD ?

.code
    main PROC
          call introduction
          call getData
          call generateRandomNumbers
          call displayList
          call calculateMedian
          call displayMedian
          call sortList
          call displayListDescending

          exit
     main ENDP

     introduction PROC
          mov edx, OFFSET instructions
          call WriteString
          call Crlf
          ret
     introduction ENDP

     getData PROC
          mov edx, OFFSET prompt
          call WriteString
          call ReadInt
          cmp eax, 10
          jl invalidInput
          cmp eax, 200
          jg invalidInput
          mov [request], eax
          ret

          invalidInput:
          mov edx, OFFSET invalid
          call WriteString
          call Crlf
          jmp getData
     getData ENDP

     generateRandomNumbers PROC
          mov ecx, [request]
          mov esi, OFFSET array
          generateLoop:
               call RandomRange ; Generates random number in the range [0, 899]
               add eax, 100 ; Adjust the range to [100, 999]
               mov [esi], eax
               add esi, 4
               loop generateLoop
          ret
     generateRandomNumbers ENDP

     displayList PROC
          mov edx, OFFSET unsorted
          call WriteString
          call Crlf
          mov edx, OFFSET newline
          call WriteString
          mov ecx, [request]
          mov esi, OFFSET array
          displayLoop:
          mov eax, [esi]
          call WriteInt
          mov edx, OFFSET spaceBar
          call WriteString
          add esi, 4
          loop displayLoop
          call Crlf
          ret
     displayList ENDP

     calculateMedian PROC
          mov ecx, [request]
          shr ecx, 1
          mov esi, OFFSET array
          mov eax, [esi+ecx*4]
          mov [medianValue], eax
          ret
     calculateMedian ENDP

     displayMedian PROC
          mov edx, OFFSET median
          call WriteString
          call Crlf
          mov edx, OFFSET newline
          call WriteString
          mov edx, [medianValue]
          call WriteInt
          call Crlf
          ret
     displayMedian ENDP
     
    sortList PROC
          mov ecx, [request]
          mov esi, OFFSET array
          mov ebx, OFFSET array
          mov edi, ecx

          sortLoop:
               xor edx, edx
               mov eax, [esi]
               innerLoop:
                    add ebx, 4
                    cmp ebx, edi
                    jge skipExchange
                    mov edx, [ebx]
                    cmp edx, 100
                    jge skipExchange
                    mov eax, edx
                    mov edi, ebx
               skipExchange:
                    loop innerLoop

               cmp esi, edi
               je skipSwap

               push eax
               push [esi]
               call exchangeElements
               skipSwap:
                    add esi, 4
                    cmp edx, 0
                    jne sortLoop
               
               ret

   sortList ENDP

   displayListDescending PROC
          mov edx, OFFSET newline
          call WriteString
          mov ecx, [request]
          mov esi, OFFSET array

          mov eax, ecx           ; Store the value of ecx in eax
          dec eax                ; Decrement eax to get (ecx-1)
          mov ebx, 4
          mul ebx
          shl eax, 2             ; Multiply by 4 (shift left by 2)
          add esi, eax           ; Add the offset to the base address of the array

          displayLoop:
               mov eax, [esi]
               call WriteInt
               mov edx, OFFSET spaceBar
               call WriteString
               sub esi, 4
               loop displayLoop

          call Crlf
          ret
    displayListDescending ENDP


    exchangeElements PROC
          push edx
          mov edx, [esp+12]
          mov ecx, [esp+8]
          mov [esp+12], ecx
          mov [esp+8], edx
          pop edx
          ret
     exchangeElements ENDP

END main

我最好的猜测是在 displayListDescending 过程中抛出异常。我试着简化寄存器,甚至试着跟踪ESI正在跟踪的内容。
我会很感激任何我能得到的帮助。

w3nuxt5m

w3nuxt5m1#

异常

我最好的猜测是在 displayListDescending 过程中抛出异常。
事实上,这就是你的程序从数组之外的内存中读取的地方!数组中最后一个元素的偏移量的计算错误地将索引乘以4**,这样做了两次**。

mov  ecx, [request]
mov  esi, OFFSET array
mov  eax, ecx
dec  eax
mov  ebx, 4             <<<< 1st x 4
mul  ebx
shl  eax, 2             <<<< 2nd x 4
add  esi, eax

解决这个问题的一种方法是写:

mov  ecx, [request]
lea  esi, [array + ecx * 4 - 4]

随机数

generateRandomNumbers PROC
   mov  ecx, [request]
   mov  esi, OFFSET array
 generateLoop:
   call RandomRange ; Generates random number in the range [0, 899]
   add  eax, 100    ; Adjust the range to [100, 999]
   mov  [esi], eax
   add  esi, 4
   loop generateLoop
   ret
generateRandomNumbers ENDP

您没有生成范围[0,899]内的随机数。为此,您需要在call RandomRange之前设置ECX=900。但由于这会与当前循环计数器冲突,因此需要使用另一个寄存器来控制循环:

generateRandomNumbers PROC
   mov  edi, [request]
   mov  esi, OFFSET array
  generateLoop:
   mov  ecx, 900
   call RandomRange ; Generates random number in the range [0, 899]
   add  eax, 100    ; Adjust the range to [100, 999]
   mov  [esi], eax
   add  esi, 4
   dec  edi
   jnz  generateLoop
  ret
generateRandomNumbers ENDP

中位数

mov edx, [medianValue]
call WriteInt
  • WriteInt* 的输入进入EAX。

选区排序

  • sortList* 及其附带的 exchangeElements 过程不可挽救。它们包含了很多令人费解的操作,这也使得我们很难判断它是否是一个真正的选择排序,而不是其他的排序方法。

我写了一个可视化的selection sort algorithm,这样你就可以理解它是如何工作的。虽然它使用16位寄存器,但将其移植到32位应该不难。

d5vmydt9

d5vmydt92#

exchangeElements可能需要一个“ret 8”,因为你在调用它之前推了两个dword。

相关问题