сортировка выбором на ассемблере

вот мой код .. Мне нужно выполнить сортировку выбора в массиве. Это домашнее задание. Irvine32.inc устанавливает мою модель памяти. Любые предложения о том, что я делаю неправильно, будут полезны. Я уже несколько раз все переделывал.

INCLUDE Irvine32.inc
.data
myArray DWORD 10, 12, 3, 5
.code
main PROC
    call Clrscr
    MOV EDI, OFFSET myArray
    MOV ECX, LENGTHOF myArray
    CALL PRINT_ARRAY


    MOV EDI, OFFSET myArray
    MOV ECX, LENGTHOF myArray
    CALL SORT_ARRAY

    CALL CRLF
    MOV EDI, OFFSET myArray
    MOV ECX, LENGTHOF myArray
    CALL PRINT_ARRAY

    exit
main ENDP
;-----------------------------------------------------------------------------
PRINT_ARRAY PROC
; requires edi to be pointing to an array
; requires ecx to be the length of the array
;-----------------------------------------------------------------------------
ARRAYLOOP: MOV EAX, [EDI]
           CALL WRITEINT
           CALL CRLF
           ADD EDI, TYPE myArray
           LOOP ARRAYLOOP
           ret
PRINT_ARRAY ENDP

;-----------------------------------------------------------------------------
SORT_ARRAY PROC
; requires edi to be pointing to an array
; requires ecx to be the length of the array
; 
; ebp points to the minimum value
; esp points to edi + 1 (4 in our case) 
;-----------------------------------------------------------------------------
PUSHAD                          ; push all our registers.. dont want to modify 



OUTER_LOOP: MOV EBX, ECX        ; ebx = inner looper counter
            DEC EBX             ; dont want to compare same offset
                                ; we want it one less in the ebx count  

            MOV EBP, EDI        ; assign our min value array OFFSET
            MOV ESP, EDI        ; our value of j which we will inc      
            ADD ESP, TYPE[EDI]  ; j = i + 1

INNER_LOOP: MOV EAX, [EBP]      ; save our min VALUE to a register

            ; ESP (j)  < EAX (min) ?
            CMP [ESP], EAX  

            ; no, its greater, skip this value
            JGE SKIP_ARRAY_VALUE

            ; yes, array value is less than min
            ; save a new min value
            MOV EBP, ESP

            SKIP_ARRAY_VALUE:

            ADD ESP, TYPE[EDI]
            ; decrement our counter
            DEC EBX

            ; if ebx didnt set the zero flag, keep looping
            JNZ INNER_LOOP

            ; move our min value into the position of edi, and move edi 
            ; to the position of the min value

            MOV EDX, [EDI]                  ; edx = numbers[i]
            MOV EAX, [EBP]                  ; eax = numbers[min] 
            MOV [EDI], EAX                  ; numbers[i] = numbers[min]
            MOV [EBP], EDX                  ; numbers[min] = numbers[i]

            INC EDI
            LOOP OUTER_LOOP

POPAD                           ; pop all registers

RET
SORT_ARRAY ENDP
END main

Программа приводит к печати массива в первую очередь, несортированного. Затем он немного зависает и вылетает, без ошибок или чего-то еще.


person Dalton Conley    schedule 26.10.2010    source источник
comment
Пожалуйста, опубликуйте свои результаты. Объясните, что не так с вашим кодом.   -  person Dr. belisarius    schedule 26.10.2010


Ответы (1)


Вам нужно диагностировать сбой.

  • Установите и настройте DrWatson, чтобы он собирал данные о сбоях.
  • снова запустите ML с параметрами для вывода файла pdb
  • вызвать сбой снова - вы, DrWatson, должны его перехватить.

Альтернатива: запустите программу через отладчик. Начиная с VS 2008, VS имеет встроенный MASM (ML), поэтому вы даже можете получить отладку исходного кода. Я задокументировал активацию MASM в VS 2008 Express SP1 - бесплатно - (и, предположительно, в следующих версиях) ">там. В противном случае используйте windbg (не так дружелюбно).

Теперь я вообще не изучал ваш алгоритм, но то, как вы используете ESP, меня немного пугает: Вы ДЕЙСТВИТЕЛЬНО уверены, что ESP по-прежнему указывает на вашу область сохранения на основе стека PUSHAD, когда вы выполняете POPAD в SORT_ARRAY?.. .

Я программировал и поддерживал очень большие части программного обеспечения, используя ML, и я бы рекомендовал никогда не связываться с ESP и позволить MASM позаботиться об (E)BP в большинстве случаев (предложение LOCAL, пример ниже). Единственные исключения относятся к тяжелому системному программированию, например, изменение режима битности (вход/выход из режима prot) и реализация монитора потоков (сохранение/восстановление состояния).

Некоторые другие:
Больше не используйте переходы, используйте .IF / .ELSE / .ENDIF, .REPEAT / .WHILE / .UNTIL и т. д. и т. п.
Не беспокойтесь о EBP для параметров и локальные переменные, пусть псевдооперации ML позаботятся о параметрах и адресации локальных переменных. Используйте передачу параметров, управляемую MASM (через INVOKE вместо CALL), и используйте локальные переменные, управляемые MASM (через директиву LOCAL in-PROC). Вы даже можете определить массивы в LOCAL с таким синтаксисом, как

Foo[6]: BYTE

В приведенном ниже примере:
CheckRAMPresent вызывается с двумя параметрами DWORD, LinBufferBase и BufferSize.
При входе и выходе MASM сохраняет и восстанавливает EAX ECX EBX DI ES, поскольку я сказал ему, что PROC использует его.
SMAPBuffer, RAMBank и RAMBankEnd — локальные (на основе стека) переменные (SMPOutput — это STRUCT). MASM манипулирует указателем стека для выделения/освобождения при входе/выходе и управляет режимом адресации на основе BP — посмотрите, как код в PROC обращается как к параметрам, так и к локальным переменным.
Наконец, у вас есть примеры .IF. .ELSE .ENDIF и даже .REPEAT / .UNTIL
Обратите внимание, что вы можете использовать условные флаги

.IF CARRY?

или HLL-подобные выражения условия:

(ES:[DI].RangeType == 1)

или даже более сложный:

((ECX >= EAX) && (ECX <= EBX)) || ((EDX >= EAX) && (EDX <= EBX))

Они генерируют полностью предсказуемый код, так что это все еще язык ассемблера. Но это просто гораздо более удобный для чтения/сопровождения вид сборки. Для всех псевдоопераций HLL просмотрите сгенерированный код (для этого есть опция ML).

Весь набор документации MASM, объясняющей конструкции HLL, можно найти здесь в ZIP-архиве. форматы doc и HTML. Вы можете найти его в другом месте в формате PDF, мне кажется (погуглите). Руководство программиста, безусловно, самая полезная часть. Справочное руководство по MASM в основном устарело, вместо него лучше использовать руководство разработчика Intel.

CheckRAMPresent PROC NEAR STDCALL PUBLIC \
                 USES EAX ECX EBX DI ES,
                   LinBufferBase: DWORD,
                   BufferSize:    DWORD

               LOCAL SMAPBuffer: SMAPOutput,
                   RAMBank:      DWORD,
                   RAMBankEnd:   DWORD


 MOV AX,SS                   ; Get ES:DI => SMAP buffer,
 MOV ES,AX
 LEA DI, SMAPBuffer
 MOV ECX, SIZEOF SMAPBuffer  ;  ECX = SMAP buffer size.

 PUSHCONTEXT ASSUMES
 ASSUME DI:PTR SMAPOutput

 XOR EBX,EBX                 ; Set initial continuation pointer.
 MOV RAMBank, EBX            ; Zero the RAM bank tracker.
 MOV RAMBankEnd, EBX

   .REPEAT
   INVOKE GetSMAP
   .BREAK .IF CARRY?
     ; If type is Available, then process that range.
     .IF (ES:[DI].RangeType == 1) ; If Available RAM, check what we have.
     SAVE EBX, ECX
     MOV EAX, ES:[DI].LowBase    ; Get Bank start in EAX,
     MOV EBX, EAX
     ADD EBX, ES:[DI].LowLng     ;   and bank end in EBX.
     MOV ECX, LinBufferBase      ; Get buffer start in ECX
     MOV EDX,ECX
     ADD EDX, BufferSize         ;  and buffer end in EDX.

       ; If either the lower end or the upper end of the buffer
       ; intersects with the bank, take that bank (if this is the
       ; first) or try to coalesce it with the existing one (if we already
       ; have one).
       ; This translates as:
       ; If either the low address (ECX) or the high address (EDX) of the
       ; buffer is within the bank boundaries [EAX - EBX], then the buffer
       ; intersects with the bank.
       .IF   ((ECX >= EAX) && (ECX <= EBX)) \ ; If buffer intersects,
          || ((EDX >= EAX) && (EDX <= EBX))
         ; then if this is the first intersecting RAM bank, too, then
select it.
         .IF (!RAMBank && !RAMBankEnd)
         MOV RAMBank, EAX    ; Remember bank.
         MOV RAMBankEnd, EBX
         .ELSE
         ; We already have a RAM bank.
           ; If this new one starts where the one we have ends,
           ; the end of the new one become the end of the merged blocks.
           ; Else if the end of the new block is the beginning of the one
           ; we have, then the new block is located just before the one we
           ; have and its start become the start of the merged blocks.
           ; Otherwise, the new bank is not contiguous with the previously
           ; computed one and there's nothing we can do (at least using this
           ; algorithm).
           .IF (EAX == RAMBankEnd)
           MOV RAMBankEnd, EBX
           .ELSEIF (EBX == RAMBank)
           MOV RAMBank, EAX
           .ENDIF
         .ENDIF
       .ENDIF
     RESTORE EBX, ECX
     .ENDIF

   .UNTIL (EBX == 0)         ; If SMAP returned EBX == 0, we just did the
                             ; last SMAP bank.

 MOV EAX, LinBufferBase      ; Get buffer start in EAX
 MOV ECX,EAX
 ADD ECX, BufferSize         ;  and buffer end in ECX.

   ; If our start and our end are both in the bank,
   ; we win. Otherwise, we loose.
   .IF (EAX >= RAMBank) && (ECX <= RAMBankEnd)
   CLC
   .ELSE
   STC
   .ENDIF

 RET
CheckRAMPresent ENDP

Повеселись! ;-)

person filofel    schedule 27.10.2010