汇编语言中的选择排序

时间:2010-10-26 05:07:36

标签: 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

程序导致首先打开阵列,未排序。然后它会挂起一点点崩溃,没有错误或任何东西。

1 个答案:

答案 0 :(得分:5)

您需要诊断崩溃。

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

替代: 通过调试器运行程序。 自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指令)。您甚至可以使用诸如

之类的语法在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选项)。

可以在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

玩得开心! ;-)