首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >汇编语言中的选择排序

汇编语言中的选择排序
EN

Stack Overflow用户
提问于 2010-10-26 13:07:36
回答 1查看 7.8K关注 0票数 1

这是我的代码..我必须对数组执行选择排序。这是家庭作业。Irvine32.inc建立了我的记忆模型。任何关于我做错了什么的建议都会有所帮助。我已经把整个过程重做了几次。

代码语言:javascript
复制
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

程序会首先打印出未排序的数组。然后它会挂起一小段时间,然后崩溃,没有错误,或者其他任何东西。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-10-27 16:01:17

你需要诊断你的崩溃。

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

另一种方法是:通过调试器运行程序。从VS2008开始,VS内置了MASM (ML),所以你甚至可以进行源代码调试。我记录了在VS2008ExpressMASM中激活SP1 --免费的--(大概还有后续的版本) there。否则,使用windbg (不友好)。

现在我根本没有看过你的算法,但是你使用ESP的方式有点吓到我了:你真的确定当你在SORT_ARRAY中执行POPAD时ESP仍然指向你的PUSHAD基于堆栈的保存区域吗?...

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

其他几个:

不再使用jumps,使用.IF / .ELSE / .ENDIF、.REPEAT / .WHILE / .UNTIL等。

不要为参数和局部变量的EBP而烦恼,让ML伪操作来处理参数和局部变量寻址。使用MASM管理的参数传递(通过INVOKE而不是CALL)和使用MASM管理的本地变量(通过本地in-PROC指令)。您甚至可以使用如下语法在本地定义数组

代码语言:javascript
复制
Foo[6]: BYTE

在下面的示例中:

使用两个DWORD参数LinBufferBase和BufferSize调用CheckRAMPresent。

在进入和退出时,MASM保存和恢复EAX ECX EBX DI ES,因为我告诉它PROC使用它。

SMAPBuffer、RAMBank和RAMBankEnd是局部(基于堆栈的)变量(SMPOutput是一个结构)。MASM在进入/退出时操纵堆栈指针以分配/释放分配,并管理基于BP的地址模式-查看PROC中的代码如何对参数和本地变量进行寻址。

最后,您将看到.IF .ELSE .ENDIF的示例,甚至还有.REPEAT / .UNTIL示例

请注意,您可以使用条件标志

代码语言:javascript
复制
.IF CARRY?

或类似HLL的条件表达式:

代码语言:javascript
复制
(ES:[DI].RangeType == 1)

甚至是更复杂的:

代码语言:javascript
复制
((ECX >= EAX) && (ECX <= EBX)) || ((EDX >= EAX) && (EDX <= EBX))

这些都会生成完全可预测的代码,所以这仍然是汇编语言。但它只是一种更具可读性和可维护性的程序集。对于所有的HLL伪操作,请查看生成的代码(有一个ML选项可供选择)。

可以在ZIPped、.doc和HTML格式的there中找到解释HLL构造的一整套MASM文档。你可以在其他地方找到它的PDF格式,我的链接(谷歌周围)。到目前为止,程序员指南是最有用的部分。MASM参考手册已基本过时,您更愿意使用英特尔开发人员指南。

代码语言:javascript
复制
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

玩得开心!;-)

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4020853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档