2012-02-07 24 views
1

我有一個關於裝配循環的任務。沒什麼難,因爲它只是課程的開始。我已經完成了所要求的內容,只是想看看我所做的是否正確。另外,我想知道是否有任何不需要或可以刪除​​的內容。 (我喜歡看到不同的方式去了解事情,並能看到更有效的東西)。

在裝配中循環

Evaluate the sum of 2n - 5, where n goes from 1 to 7

這是我做了什麼:

_num1 
    DB 0 

mov cx, 1 ; set counter to 1 
mov eax, 0 ; use eax to keep total 

eval: 
    mov [_num1], cx ; set num1 to cx value 
    shl [_num1], 1  ; double value of num1 
    add eax, [_num1] ; add values of 2n to eax 
    sub eax, 5   ; subtract 5 from eax (total) 
    inc cx    ; increment cx 
    cmp cx, 7   ; check if equal 
    jne eval 
應該

這項工作是否正常?如果是這樣,有沒有改進它的方法?如果不是,實施有什麼問題?

+0

什麼意思「它應該工作正常」?你不嘗試嗎? – 2012-02-07 22:31:20

+0

你有能力運行這個代碼嗎?這應該有助於您確定它是否有效。 – 2012-02-07 22:31:30

+0

@CarlNorum&GregHewgill我目前沒有能力運行此操作。 (我將無法在本週末之前)。如果邏輯是正確的,那麼我認爲我不必調試太多。另一方面,我也在儘早完成任務。 – StartingGroovy 2012-02-07 22:36:19

回答

3

通常我們計算CX下降並循環,直到CX達到零。 LOOP助記符在單個操作中完全如此。但是現在,在大多數CPU上,「dec cx; jnz」這兩個命令的組合速度比LOOP快。只有在將代碼大小優化爲最後一位時才使用LOOP。

而不是使用內存引用(_num1),您可以使用DX寄存器,它沒有在您的代碼中使用。寄存器比內存引用快得多。

另一個經常使用的opimization使用「xor eax,eax」而不是「mov eax,0」。 MOV會變慢,因爲它將4個字節(0x00000000)從存儲器複製到寄存器。 XOR也將清除EAX寄存器,但不訪問任何內存。它也是稍小的代碼。

作爲個人喜好,我會採用更高層次的評論。 「增量cx」對「inc cx」沒有增加任何內容。我更喜歡在高級語言級別的每行更多的評論,比如「eax = eax + 2 * ecx」。

更重要的是,您只爲_num1保留了一個字節,但是繼續爲其分配兩個字節(CX)。這將覆蓋其他數據的一個字節。如果您希望_num1保存兩個字節,請使用「DW」而不是「DB」。另一個問題是混合不同大小的操作數和寄存器。如果您需要32位寄存器,請堅持使用這些寄存器。或者在使用它們之前,您可以清除寄存器的高16位。或者您可以使用MOVZX助記符,當指定數據時將清除高16位。

總而言之:

  • 計數向下從7到1(使用LOOP或DEC ECX; JNZ)
  • 使用寄存器,而不是存儲器的引用,如果可能的話
  • 零寄存器與XOR運算
  • 一些小錯誤
+0

哦,順便說一下:一個好的優化編譯器會用「21」代替所有的代碼。但這可能不是重點。 – Simon 2012-02-07 22:54:04

+0

只是幾個問題。我以爲'mov eax,0'是直接的,並沒有使用內存。感謝'xor'提示。還要感謝關於評論的提示。你是對的,我需要把'DB'改成'DW'。在我參加的課程中,我們沒有太多注意哪些寄存器用於什麼(除了少數選擇)。那麼'ECX'是否合適呢?最後,我沒有在我的帖子中提到這個,所以這是我的錯。我們被要求從記憶中移動至少一次,這就是我爲什麼這樣做的原因。 – StartingGroovy 2012-02-08 00:16:27

+2

@StartingGroovy:'mov eax,0'確實使用立即數,但這隻意味着加載的內存直接在指令操作碼中,因此可能會使指令更長。我認爲我在某處讀到'mov eax,0'不會破壞'eax'的舊值(使用寄存器重命名等),但在現代處理器中可能會有所不同。 – Grizzly 2012-02-08 00:28:28