Dal*_*ley 1 sorting assembly masm irvine32
这是我的代码..我必须对数组执行选择排序.这是家庭作业.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
Run Code Online (Sandbox Code Playgroud)
该程序导致首先打开阵列,未排序.然后它会挂起一点点崩溃,没有错误或任何东西.
您需要诊断崩溃.
替代方案:通过调试器运行程序.自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
Run Code Online (Sandbox Code Playgroud)
在下面的示例中:
使用两个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?
Run Code Online (Sandbox Code Playgroud)
或类似HLL的条件表达式:
(ES:[DI].RangeType == 1)
Run Code Online (Sandbox Code Playgroud)
甚至更复杂的:
((ECX >= EAX) && (ECX <= EBX)) || ((EDX >= EAX) && (EDX <= EBX))
Run Code Online (Sandbox Code Playgroud)
那些生成完全可预测的代码,所以这仍然是汇编语言.但它只是一种更具可读性/可维护性的装配体.对于所有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
Run Code Online (Sandbox Code Playgroud)
玩得开心!;-)