汇编语言中的选择排序
这是我的代码..我必须对数组执行选择排序。这是家庭作业。 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
该程序首先打印出未排序的数组。然后它挂起一点然后崩溃,没有错误或任何东西。
here is my code.. I have to perform a selection sort on an array. It is homework. The Irvine32.inc sets up my memory model. Any suggestions to what I'm doing wrong would be helpful. I've redone the entire thing a few times now.
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
The program results in printing the array out first off, unsorted. Then it hangs for a little bit and crashes, no errors, or anything.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要诊断您的崩溃。
选择:
通过调试器运行您的程序。
从 VS 2008 开始,VS 内置了 MASM (ML),因此您甚至可以进行源代码调试。我记录了在 VS 2008 Express SP1 中激活 MASM - 免费 - (大概是以下版本)
现在我根本没有仔细研究你的算法,但你使用 ESP 的方式有点让我害怕:
当您在 SORT_ARRAY 中执行 POPAD 时,您真的确定 ESP 仍然指向您的 PUSHAD 基于堆栈的保存区域吗?...
我已经使用 ML 编程和维护了非常大的软件片段,我的建议是永远不要搞乱 ESP,并在大多数情况下让 MASM 处理 (E)BP(LOCAL 子句,下面的示例)。唯一的例外与繁重的系统编程有关,例如位数模式更改(进入/离开 prot 模式)和实现线程监视器(状态保存/恢复)。
其他一些:
不要再使用跳转,使用 .IF / .ELSE / .ENDIF、.REPEAT / .WHILE / .UNTIL 等。
不要为参数和局部变量的 EBP 操心,让 ML 伪操作来处理参数和局部变量寻址。
使用 MASM 管理的参数传递(通过 INVOKE 而不是 CALL)并使用 MASM 管理的局部变量(通过 LOCAL in-PROC 指令)。您甚至可以使用如下所示的语法在 LOCAL 中定义数组
:
使用两个 DWORD 参数(LinBufferBase 和 BufferSize)调用 CheckRAMPresent。
在进入和退出时,MASM 保存并恢复 EAX ECX EBX DI ES,因为我告诉它 PROC 使用它。
SMAPBuffer、RAMBank 和 RAMBankEnd 是本地(基于堆栈)变量(SMPOutput 是一个 STRUCT)。 MASM 操纵堆栈指针在进入/退出时分配/释放,并管理基于 BP 的地址模式 - 查看 PROC 中的代码如何寻址参数和本地变量。
最后,您有 .IF .ELSE .ENDIF 甚至 .REPEAT / .UNTIL 的示例
请注意,您可以使用条件标志
或类似 HLL 的条件表达式:
甚至更复杂:
它们会生成完全可预测的代码,因此这仍然是汇编语言。但这只是一种更具可读性/可维护性的程序集。
对于所有 HLL 伪操作,请查看生成的代码(有一个 ML 选项)。
解释 HLL 构造的整套 MASM 文档可以在 ZIPped 中那里找到。文档与HTML 格式。我想,你还可以找到 PDF 格式的文件(谷歌)。
程序员指南是迄今为止最有用的部分。 MASM 参考手册大部分已经过时,您宁愿使用英特尔开发人员指南。
玩得开心! ;-)
You need to diagnose your crash.
Alternative:
Run your program through a debugger.
Since VS 2008, VS has MASM (ML) built-in, so you might even be able to get source debugging. I documented activating MASM in VS 2008 Express SP1 - free - (and presumably following versions) there.
Otherwise, use windbg (not as friendly).
Now I didn't go at all through your algorithm, but the way you use ESP kinda scares me:
Are you REALLY sure ESP still points to your PUSHAD stack-based save area when you execute the POPAD in SORT_ARRAY?...
I have programmed and maintained very large software pieces using ML, and my recommendation would be to never messup with ESP, and let MASM take care of (E)BP in most circumstances (LOCAL clause, example below). The only exceptions relate to heavy systems programming, like bitness mode changing (entering / leaving prot mode) and implementing a threading monitor (state saving / restoration).
A few others:
Don't use jumps anymore, use .IF / .ELSE / .ENDIF, .REPEAT / .WHILE / .UNTIL, etc. and the like.
Don't bother with EBP for parms and local vars, let ML pseudo-ops take care of parms and local variable addressing.
Use MASM-managed parameter passing (through INVOKE instead of CALL) and use MASM-managed local variables (through the LOCAL in-PROC directive). You can even define arrays in LOCAL with a syntax such as
In the sample that follows:
CheckRAMPresent is called with two DWORD Parms, LinBufferBase and BufferSize.
Upon entry and exit, MASM saves and restore EAX ECX EBX DI ES because I told it the PROC uses it.
SMAPBuffer, RAMBank and RAMBankEnd are local (stack based) variables (SMPOutput is a STRUCT). MASM manipulates the stack pointer to allocated / deallocate upon entry / exit, and manages the BP-based address mode - see how the code in the PROC addresses both the parms and the local vars.
Finally, you have examples of .IF .ELSE .ENDIF and even a .REPEAT / .UNTIL
Note that you can use condition flags
or HLL-like condition expressions:
or even the more complex:
Those generate totally predictable code, so this is still assembly language. But it's just a much more readable / maintainable kind of assembly.
For all the HLL pseudo-ops, look at the generated code (there's an ML option for that).
The whole set of MASM documentation explaining the HLL constructs can be found there in ZIPped .doc & HTML formats. You can find it elsewere in PDF form, methinks (Google around).
The Programmer's Guide is by far the most useful part. The MASM reference manual is mostly obsolete, you'd rather use the Intel developer's guide instead.
Have fun! ;-)