2010-10-26 196 views
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 

該程序導致打印數組首先關閉,未排序。然後它掛起一點點,崩潰,沒有錯誤,或任何東西。

+0

請發表您的結果。解釋你的代碼有什麼問題。 – 2010-10-26 06:07:14

回答

5

您需要診斷您的崩潰。

  • 安裝並設置DrWatson,以便捕獲崩潰數據。
  • 再次用選項輸出一個pdb文件
  • 再次觸發崩潰 - 您DrWatson應該將其陷阱。

替代方法: 通過調試器運行您的程序。 自VS 2008以來,VS內置了MASM(ML),因此您甚至可以獲得源代碼調試。我記錄了在VS 2008 Express SP1中激活MASM - 免費 - (推測可能是以下版本)there。 否則,使用windbg(不友好)。

現在,我沒去,在所有通過你的算法,但你使用ESP的方式有點讓我害怕: 你真的能肯定ESP仍然指向您的PUSHAD基於堆棧的保存區域,當你在執行的SORT_ARRAY POPAD ?...

我已經使用ML編寫和維護了非常大的軟件,我的建議是永遠不要混淆ESP,並讓MASM在大多數情況下處理(E)BP(LOCAL子句,例子下面)。唯一的例外涉及重度系統編程,比如比特模式改變(進入/離開prot模式)和執行線程監視器(狀態保存/恢復)。

其他幾個:
不要再使用跳轉,請使用.IF/.ELSE/.ENDIF,.REPEAT/.WHILE/.UNTIL等等。
不要打擾EBP的parms和局部變量,讓ML僞操作關心parms和局部變量尋址。 使用MASM管理的參數傳遞(通過INVOKE而不是CALL)並使用MASM管理的本地變量(通過LOCAL in-PROC指令)。甚至可以定義LOCAL陣列與語法如

Foo[6]: BYTE 

在下面的示例:
CheckRAMPresent被稱爲具有兩個DWORD PARMS,LinBufferBase和緩衝區大小。
進入和退出後,MASM保存並恢復EAX ECX EBX DI ES,因爲我告訴PROC PROC使用它。
SMAPBuffer,RAMBank和RAMBankEnd是本地(基於堆棧)變量(SMPOutput是STRUCT)。 MASM在進入/​​退出時操縱堆棧指針分配/釋放,並管理基於BP的地址模式 - 請參閱PROC中的代碼如何解決parms和local vars的問題。
最後,您有.IF .ELSE .ENDIF和甚至.REPEAT /的示例。UNTIL
注意,您可以使用條件標誌

.IF CARRY? 

或HLL樣的條件表達式:

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

,甚至更復雜:

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

那些產生完全可預測的代碼,所以這仍然是彙編語言。但它只是一種更易讀/可維護的裝配。 對於所有的HLL僞操作,查看生成的代碼(有一個ML選項)。

解釋HLL結構的整套MASM文檔可以在ZIP格式的.doc & HTML格式中找到there。你可以找到它以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 

玩得開心! ;-)