这是我的代码..我必须对数组执行选择排序.这是家庭作业.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
该程序导致首先打开阵列,未排序.然后它会挂起一点点崩溃,没有错误或任何东西.
您需要诊断崩溃.
安装并设置DrWatson以便捕获崩溃数据.
再次运行ML与输出pdb文件的选项
再次触发崩溃 - 你DrWatson应该陷阱.
替代方案:通过调试器运行程序.自VS 2008以来,VS内置了MASM(ML),因此您甚至可以获得源代码调试.我记录激活MASM在VS 2008 SP1快车-免费- (大概以下版本)存在.否则,请使用windbg(不是友好的).
现在我没有完全通过你的算法,但你使用ESP的方式让我感到害怕: 当你在SORT_ARRAY中执行POPAD时,你真的确定ESP仍然指向你的PUSHAD基于堆栈的保存区吗?...
我使用ML编程和维护了非常大的软件,我的建议是永远不要使用ESP,并让MASM在大多数情况下处理(E)BP(LOCAL子句,下面的例子).唯一的例外涉及重型系统编程,例如比特模式改变(进入/离开原始模式)和实现线程监视器(状态保存/恢复).
其他一些:
不再使用跳转,使用.IF/.ELSE/.ENDIF,.REPEAT/.WHILE/.UNTIL等等.
不要为了parms和本地变量而烦恼,让ML伪操作处理parms和局部变量寻址.使用MASM管理的参数传递(通过INVOKE而不是CALL)并使用MASM管理的局部变量(通过LOCAL in-PROC指令).您甚至可以使用如下语法在LOCAL中定义数组
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选项).
整套MASM文档说明HLL结构可以发现有在压缩的.doc和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
玩得开心!;-)