这是我的代码..我必须对数组执行选择排序。这是家庭作业。 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
程序导致首先打开阵列,未排序。然后它会挂起一点点崩溃,没有错误或任何东西。
答案 0 :(得分:5)
您需要诊断崩溃。
替代: 通过调试器运行程序。 自VS 2008以来,VS内置了MASM(ML),因此您甚至可以获得源代码调试。我记录了在VS 2008 Express SP1中激活MASM - 免费 - (并且可能是以下版本)there。 否则,请使用windbg(不那么友好)。
现在我没有通过你的算法,但你使用ESP的方式让我感到害怕: 当你在SORT_ARRAY中执行POPAD时,你是否真的确定ESP仍然指向你的PUSHAD基于堆栈的保存区域?...
我使用ML编程和维护了非常大的软件,我的建议是永远不要使用ESP,并让MASM在大多数情况下处理(E)BP(LOCAL子句,下面的示例)。唯一的例外涉及重型系统编程,例如位数模式更改(进入/退出prot模式)和实现线程监控(状态保存/恢复)。
其他一些人:
不要再使用跳转,使用.IF / .ELSE / .ENDIF,.REPEAT / .WHILE / .UNTIL等等。
不要为了parms和本地变量而烦恼,让ML伪操作处理parms和局部变量寻址。
使用MASM管理的参数传递(通过INVOKE而不是CALL)并使用MASM管理的局部变量(通过LOCAL in-PROC指令)。您甚至可以使用诸如
Foo[6]: BYTE
在以下示例中:
使用两个DWORD参数,LinBufferBase和BufferSize调用CheckRAMPresent
进入和退出时,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选项)。
可以在ZIPped .doc&amp; amp;中找到解释HLL结构的整套MASM文档there。 HTML格式。你可以找到它的PDF形式,methinks(谷歌周围)。 程序员指南是迄今为止最有用的部分。 MASM参考手册大部分已过时,您宁可使用英特尔开发人员指南。
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
玩得开心! ;-)