当前位置:  开发笔记 > 编程语言 > 正文

汇编语言中的选择排序

如何解决《汇编语言中的选择排序》经验,为你挑选了1个好方法。

这是我的代码..我必须对数组执行选择排序.这是家庭作业.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> filofel..:

您需要诊断崩溃.

安装并设置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

玩得开心!;-)

推荐阅读
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有