Массив отсортирован в порядке убывания

# #sorting #assembly #x86 #irvine32

#сортировка #собрание #x86 #ирвин32

Вопрос:

У меня возникли проблемы с сортировкой моего массива в порядке убывания с помощью пользовательских вводов. Кажется, я не могу переместить свои самые большие элементы в первый элемент массива. Это для задания CS с конкретными требованиями, которым я должен следовать. В принципе, код должен принимать 40 целых чисел DWORD без знака, распечатывать входные данные в массиве, сортировать массив в порядке убывания, а затем снова распечатывать массив.

Вот мой код банкомата:

 Title Assignment 7  COMMENT ! ***************** date: November 21, 2021  ; This program takes up to 40 unsigned dword integers, puts each user input into 1 array. The array gets printed out and the array is sorted in descending order, then printed in descending order.   ***************** !  include irvine32.inc ; =============================================== .data    ; Fill your data here    msg1 byte "Enter up to 40 unsigned dword integers. To end the array, enter 0.", 0  msg2 byte "After each element press enter: ", 0  msg3 byte "Initial array:", 0  msg4 byte "Array sorted in descending order:", 0  arr1 DWORD 40 DUP (?)  arr_length DWORD ?  ;================================================= .code main proc       ; FILL YOUR CODE HERE   ; YOU NEED TO CALL ENTER_ELEM, SORT_ARR AND PRINT_ARR PROCEDURES  ;     mov edx, offset msg1  call writeString  call crlf  mov edx, offset msg2  call writeString  call ReadDec  mov esi, offset arr1    sub esp, 4  push esi  call enter_elem   pop arr_length ; saves array length    call crlf  mov edx, offset msg3  call writeString  mov esi, offset arr1    call crlf  sub esp, 4  push esi  push arr_length  call print_arr   call crlf  mov edx, offset msg4  call writeString  mov esi, offset arr1  sub esp, 4  push esi  push arr_length  call sort_arr   call crlf   mov esi, offset arr1  sub esp, 4  push esi  push arr_length  call print_arr    exit main endp  ; ================================================ ; int enter_elem(arr_addr) ; ; Input: ; ARR_ADDRESS THROUGH THE STACK ; Output: ; ARR_LENGTH THROUGH THE STACK ; Operation: ; Fill the array and count the number of elements ; enter_elem proc    ; FILL YOUR CODE HERE   push ebp  mov ebp, esp  mov esi, [ebp   8] ; array address  xor ebx, ebx ; counter for num of elements in the array  top: cmp eax, 0  je next  mov [esi], eax  add esi, type arr1  call ReadDec  inc ebx  cmp ebx, 40  je next  jmp top    next:    mov [ebp   12], ebx  pop ebp  ret 4     enter_elem endp  ; ================================================ ; void print_arr(arr_addr,arr_len) ; ; Input: ; ? ; Output: ; ? ; Operation: ; print out the array ;  print_arr proc   ; FILL YOUR CODE HERE      push ebp  mov ebp, esp  mov ecx, [ebp   8]  mov esi, [ebp   12]    L1:  mov eax, [esi]  call WriteDec  mov al, " "  call WriteChar  add esi, type arr1  Loop L1   pop ebp  ret 8  print_arr endp  ; ================================================ ; void sort_arr(arr_addr,arr_len) ; ; Input: ; ? ; Output: ; ? ; Operation: ; sort the array ;  sort_arr proc   ; FILL YOUR CODE HERE  ; YOU NEED TO CALL COMPARE_AND_SWAP PROCEDURE     push ebp  mov ebp, esp  mov ecx, [ebp   8]  mov esi, [ebp   12]  L2:  mov edi, esi  add edi, type arr1  push esi  push edi  call compare_and_swap  ;add esi, type arr1  Loop L2   pop ebp  ret 8    sort_arr endp  ; =============================================== ; void compare_and_swap(x_addr,y_addr) ; ; Input: ; ? ; Output: ; ? ; Operation: ; compare and call SWAP ONLY IF Y lt; X  ;  compare_and_swap proc   ; FILL YOUR CODE HERE  ; YOU NEED TO CALL SWAP PROCEDURE    push ebp  mov ebp, esp  mov esi, [ebp   8]  mov edi, [ebp   12]  mov edx, [edi]  mov ebx, [esi]  cmp edx, ebx  jae skipSwap  push edx  push ebx  call swap   skipSwap:  pop ebp  ret 8  compare_and_swap endp  ; ================================================= ; void swap(x_addr,y_addr) ; ; Input: ; ? ; Output: ; ? ; Operation: ; swap the two inputs ;  swap proc   ; FILL YOUR CODE HERE   push ebp  mov ebp, esp  mov ebx, [ebp   8]  mov edx, [ebp   12]  mov [esi], edx  mov [edi], ebx  pop ebp  ret 8    swap endp  end main  

Комментарии:

1. Вы пробовали отладить его? Подход заключается в том, чтобы делать один шаг, пока что-то не пойдет не так! Следите за всеми изменениями состояния (например, в регистрах или памяти) и следите за изменениями потока управления (циклы и т. Д.). Проверьте каждую операцию. Попробуйте сделать это с очень небольшим вводом, возможно, всего 2 числа, чтобы отсортировать и посмотреть, поменяет ли он их местами или даже правильно их прочитает. Однажды поработав для этого, он, вероятно, сделает больше. Также полезно проверить алгоритм, с которым вы начали, запустив его версию C (обычно это делается перед переводом в сборку). Знание того, что алгоритм работает, оставляет только ошибки перевода.

Ответ №1:

В stdcall соглашении о вызове вызываемый объект очищает стек. Это нормально в вашем коде, но параметры перемещаются в стек справа налево. Это то, чего ваш код не делает!

 push esi push arr_length call print_arr  

Вышесказанное не толкает справа налево для void print_arr(arr_addr,arr_len) .

 push arr_length push esi call print_arr  

В процессе enter_elem вы опрашиваете EAX регистр еще до того, как позволите readDec присвоить ему значение. Поднесите call ReadDec к верхней этикетке.

 top:  call ReadDec  cmp eax, 0  je next  mov [esi], eax  add esi, type arr1  inc ebx  cmp ebx, 40  jb top next:  

Ваш процесс sort_arr пытается выполнить пузырчатую сортировку. Проблема в том, что у вас есть только один цикл. И даже эта петля длится слишком долго! например. С 40 элементами этот цикл не должен выполняться более 39 раз.
После этого вам нужно повторить процесс несколько раз, но каждый раз с количеством циклов на 1 меньше (потому что наименьшее значение переместится в конец массива, поэтому больше не нужно беспокоиться).


 push edx push ebx call swap  

Учитывая, что процесс подкачки ожидает два указателя ( void swap(x_addr,y_addr) ), приведенный выше код из proc compare_and_swap, где EDX и EBX где хранятся значения массива, не будет работать.


 mov ebx, [ebp   8] mov edx, [ebp   12] mov [esi], edx mov [edi], ebx  

Процесс обмена здесь срезает углы! Какой смысл иметь два хороших указателя x_addr и y_addr, если вы просто собираетесь использовать ESI и EDI регистрировать стиль deus-ex-machina? т. е. Процесс подкачки не должен знать, что ESI и EDI содержать.

 ; void swap(x_addr,y_addr) swap proc  push ebp  mov ebp, esp  mov ecx, [ebp   8]  mov edx, [ebp   12]  mov eax, [ecx]  mov ebp, [edx]  mov [edx], eax  mov [ecx], ebp  pop ebp  ret 8 swap endp  

Если вы решите использовать этот новый процесс подкачки, то не забудьте сохранить все регистры, от которых могут зависеть вызывающие(ие)!


За исключением вызова enter_elem, который sub esp, 4 используется для возврата результата через стек, три других экземпляра sub esp, 4 являются избыточным кодом.