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

プログラムの結果、配列はソートされずに最初に出力されます。その後、少しハングしてクラッシュし、エラーなどは発生しません。

4

1 に答える 1

5

クラッシュを診断する必要があります。

  • クラッシュデータをキャッチするようにDrWatsonをインストールしてセットアップします。
  • pdbファイルを出力するオプションを指定してMLを再度実行します
  • クラッシュを再度トリガーします-DrWatsonはそれをトラップする必要があります。

代替方法:デバッガーを介してプログラムを実行します。VS 2008以降、VSにはMASM(ML)が組み込まれているため、ソースのデバッグを取得できる場合もあります。VS 2008 Express SP1でMASMをアクティブ化することを文書化しました-無料-(そしておそらく次のバージョン)そこで。それ以外の場合は、windbgを使用します(それほど友好的ではありません)。

アルゴリズムについてはまったく説明しませんでしたが、ESPの使用方法はちょっと怖いです 。SORT_ARRAYでPOPADを実行するときに、ESPがPUSHADスタックベースの保存領域を指していることを本当に確信していますか?...

私はMLを使用して非常に大きなソフトウェアをプログラミングおよび保守してきましたが、ESPを決して混乱させず、ほとんどの状況でMASMに(E)BPを処理さ​​せることをお勧めします(LOCAL句、以下の例)。唯一の例外は、ビットネスモードの変更(protモードの開始/終了)やスレッドモニターの実装(状態の保存/復元)などの重いシステムプログラミングに関連しています。

その他のいくつか:
ジャンプはもう使用しないでください。.IF/ .ELSE / .ENDIF、.REPEAT / .WHILE/.UNTILなどを使用してください。
parmsとローカル変数のEBPを気にしないでください。ML疑似操作で、parmsとローカル変数のアドレス指定を処理してください。MASMで管理されたパラメーターの受け渡し(CALLではなくINVOKEを介して)を使用し、MASMで管理されたローカル変数を(LOCAL in-PROCディレクティブを介して)使用します。次のような構文を使用して、LOCALで配列を定義することもできます。

Foo[6]: BYTE

次のサンプルでは
、​​CheckRAMPresentが2つのDWORDパラメーターLinBufferBaseとBufferSizeで呼び出されます。
エントリと終了時に、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オプションがあります)。

HLL構造を説明するMASMドキュメントの全セットは、ZIP形式の.docおよびHTML形式で見つけることができます。あなたはそれをPDF形式で見つけることができます、methinks(グーグル周り)。プログラマーガイドは、これまでで最も有用な部分です。MASMリファレンスマニュアルはほとんど廃止されており、代わりにIntel開発者ガイドを使用することをお勧めします。

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

楽しむ!;-)

于 2010-10-27T08:01:17.420 に答える