выбор сортировки на ассемблере - PullRequest
1 голос
/ 26 октября 2010

вот мой код .. Я должен выполнить сортировку выбора по массиву. Это домашнее задание. 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

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

1 Ответ

5 голосов
/ 27 октября 2010

Вам необходимо диагностировать ваш сбой.

  • Установите и настройте 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 позаботятся оparms и адресация локальной переменной.Используйте 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, можно найти там в ZIPped.doc & HTML форматы.Вы можете найти его еще в PDF-формате, например (Google вокруг).Руководство программиста, безусловно, самая полезная часть.Справочное руководство 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

Получайте удовольствие!;-)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...