选择以汇编语言排序 [英] selection sort in assembly language

查看:106
本文介绍了选择以汇编语言排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码.我必须对数组执行选择排序.这是功课. Irvine32.inc建立了我的记忆模型.任何有关我做错事情的建议都会有所帮助.我现在已经重做了几遍.

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.

推荐答案

您需要诊断崩溃.

  • 安装并设置DrWatson,以便它捕获崩溃数据.
  • 使用输出pdb文件的选项再次运行ML
  • 再次触发崩溃-您DrWatson应该捕获它.

替代: 通过调试器运行程序. 从VS 2008开始,VS内置了MASM(ML),因此您甚至可以进行源调试.我记录了在VS 2008 Express SP1中激活MASM的情况-免费-(并且可能是以下版本)

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).

现在,我根本不了解您的算法,但是您使用ESP的方式有点让我感到恐惧: 您真的确定当在SORT_ARRAY中执行POPAD时,ESP仍然指向基于PUSHAD堆栈的保存区吗?...

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?...

我已经使用ML编程和维护了非常大的软件,我的建议是永远不要混用ESP,并在大多数情况下让MASM负责(E)BP(LOCAL子句,下面的示例).唯一的例外与繁重的系统编程有关,例如更改位模式(进入/离开保护模式)和实现线程监视器(状态保存/恢复).

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).

其他一些:
不再使用跳转,请使用.IF/.ELSE/.ENDIF,.REPEAT/.WHILE/.UNTIL等,等等.
不必为Epar编写参数和局部变量而烦恼,而让ML伪操作处理Parm和局部变量寻址. 使用MASM管理的参数传递(通过INVOKE而不是CALL),并使用MASM管理的局部变量(通过LOCAL in-PROC指令).您甚至可以使用

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

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
的示例 请注意,您可以使用条件标记

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

.IF CARRY?

或类似HLL的条件表达式:

or HLL-like condition expressions:

(ES:[DI].RangeType == 1)

或更复杂的内容:

((ECX >= EAX) && (ECX <= EBX)) || ((EDX >= EAX) && (EDX <= EBX))

那些生成完全可预测的代码,因此这仍然是汇编语言.但这只是一种更具可读性/可维护性的程序集. 对于所有HLL伪操作,请查看生成的代码(有一个ML选项).

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).

压缩为.doc& HTML格式.您可以找到其他格式为PDF的方法,方法是inkinks(在Google周围). 到目前为止,《程序员指南》是最有用的部分. MASM参考手册大多已过时,您宁可使用Intel开发人员指南.

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.

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

玩得开心! ;-)

这篇关于选择以汇编语言排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆