# #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
являются избыточным кодом.