Вам необходимо диагностировать ваш сбой.
- Установите и настройте 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
Получайте удовольствие!;-)