2016-12-01 97 views
0

我是新來的大會,並試圖完成作業,我想知道如何打印數組的索引位置,而不是索引值,我使用ESI作爲指針。在這裏,數組填充0和1,我只打印1的索引。 樣品陣列[1 | 1 | 0 | 0 | 1]如何打印索引位置x86 Assemby

PRINT: 
    mov eax,[esi] 
    cmp eax,1 
    je Show 
    add esi,4 
    loop PRINT 
Show: 
    call WriteDec 
    call Crlf 
    loop Show 

輸出應爲(1 2 5)或(0 1 4)。 謝謝。

+5

計數。就像你用'esi'做的一樣,但是從0或1開始,然後按1步進。 –

+1

你不顯示數組是如何定義的。在Assembly中,定義和數據結構通常比代碼本身更重要。如果沒有定義,很難判斷代碼是否工作正常,並且可以修改爲回答您,或者它是否已經包含一些錯誤(例如'mov eax,[esi]'看起來高度可疑......但是從add esi,4'看起來沒問題)。 [mcve]對Assembly來說非常重要。 – Ped7g

+0

但是......再想一遍,也許這個問題在沒有代碼的情況下變得更有意義,因爲如果您要求方法/原則,如何解決問題,我認爲這些作業比解決方案代碼更有意義。 – Ped7g

回答

0

或者添加一個計數器:

mov ebx,1   ; index counter, first element = 1 
PRINT: 
    mov eax,[esi] 
    cmp eax,1 
    jne noShow 

    mov eax,ebx   
    call WriteDec 
    call Crlf 
noShow: 
    add esi,4 
    inc ebx   ; increase counter 
    loop PRINT 

或從ESI(假設ESI = ARRAY + 4 *指數)計算它

PRINT: 
    mov eax,[esi] 
    cmp eax,1 
    jne noShow 

    mov eax, esi  ; load position in index 
    sub eax, ARRAY  ; remove starting position of the array 
    shr eax, 2   ; divide it by 4, to get index position 
    call WriteDec 
    call Crlf 

noShow: 
    add esi,4 
    loop PRINT 

(PS:固定的循環邏輯,這是錯誤的問題)

(PSS:我不能測試代碼ATM,我在工作)

+0

OP的帖子中的代碼已經是錯誤的......最後一個「循環顯示」沒有意義。在你的第一個版本中,它更糟糕,因爲修復它並不容易,因爲你只會在一個路徑上更新'ebx'。 – Ped7g

+3

'shr eax,4'有一個錯字。應該是2 –

+0

oops。你是對的。謝謝,糾正 – Tommylee2k

1

你必須開始@ MargaretBloom的想法,算,也有必要在算法來解決一些其他錯誤:

  • 你有兩個loop,問題是,第一loop結束,下一個代碼塊執行時,和eax打印再次,一個無限循環開始。
  • 你的第二個loop跳轉到Show,但它應該跳轉到PRINT
  • je Show後增加esi,所以當發現的1值指標不遞增,esi應該之前遞增

讓我們來解決那些小問題,我會用edi作爲位置要顯示(可以使用任何其他寄存器):

mov edi, 0  ;◄■■ THIS IS THE POSITION YOU WANT TO DISPLAY (1,2,3,...). 
PRINT:  
    mov eax,[esi] 
    add esi,4  ;◄■■ INCREMENT INDEX HERE. 
    inc edi   ;◄■■ INCREASE POSITION (1,2,3,...). 
    cmp eax,1 
    je Show 
    loop PRINT 
    jmp Finish  ;◄■■ SKIP NEXT BLOCK WHEN FINISH. 
Show: 
    mov eax, edi ;◄■■ DISPLAY POSITION. 
    call WriteDec 
    call Crlf 
    loop PRINT  ;◄■■ JUMP TO PRINT, NOT TO SHOW. 

Finish: 
0

如何...索引位置數組...... ESI作爲指針

首先,數組的定義很重要,如果它是由連續元素組成的簡單平面數組,那麼得到在由地址EDI可以扭轉從涉及的兩個指針計算它的特定元素的索引指出(這需要原開始時間的數組指針還在ESI!):

mov eax,edi 
sub eax,esi  ; eax = (element_pointer - array_pointer) 
; divide eax by <size_of_element> 

; for example your OP code example suggest 
; the array element size is DWORD = 4B 
; then the division/4 can be done simply: 
; shr eax,2 

; for byte arrays there's no need to divide the address 
; difference, eax already contains index, as BYTE size = 1B 

; for other element sizes, which are *not* power-of-two 
; (you can't divide the difference by simply shifting it right) 
; it may be more efficient to address them through separate index 
; or do the: imul/mul (1/el_size) || idiv/div el_size 
; (when there's no way to avoid it) 

; after division the eax contains 0, 1, ... index. 

如果元素的大小是不平凡的(不是冪級別),或者結構不平凡(鏈表,因此兩個指針的差異與元素的索引不相關),您可能需要單獨計數索引。仍然要避免每次獲取索引mul element_size它可能是值得的混合兩個,所以通過指針尋址,並單獨計數(無用的提取)索引,這將只用於你需要索引的東西。因爲大多數ASM/C/C++程序員自然希望在0處開始編制索引(歸因於以下原因):在我的第一個例子中,how-pointer-math是如何工作的)。

; stolen from Toommylee2k, then modified to focus on my explanation 

    xor ebx,ebx   ; first index will be 1 (!) 
    ; so I initialized ebx = 1 - 1 = 0, because 
    ; I will increment it at beginning of loop 

    ; for indexing from 0 the ebx should be initialized to -1 

loop_start: 
    ; update index first, so you can't miss it when branching later 
    lea ebx,[ebx+1] ; ebx = ebx+1 without flags modification 

    ; since *here* "ebx" works as "index", contains "1" for first item 

    ; do whatever you want with pointers, like "esi" in your sample code 
    ; ... 

    ; move to next element of array (avoids multiplication) 
    add esi,size_of_element 
    ; although `imul` on modern CPU will perform quite close to `add` 
    ; so when multiplication is unavoidable, go for it. 

    ; the division on the other hand still costs very likely more 
    ; than having separate register/variable for index counting 

    ; loop till ecx is zero (in much faster way than "loop") 
    dec ecx 
    jnz loop_start 
    ; "loop" is very slow due to historic reasons, to improve compatibility 

而且最終的延伸,當元件尺寸爲[1,2,4,8],可以使用擴展的x86尋址模式爲 「0,1,...」 工作一個索引而不是純指針:

mov ebx,7 ; index "7" = 8th element of array 
lea esi,[array_of_words] ; array pointer 

; addressing through index, supported directly by CPU for size 2 
mov ax,[esi + ebx*2]  ; complex x86 addressing allows this 

; here ax = 8 
... 

.data 
array_of_words: 
    dw 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 

如果您在循環中使用索引很多,這可能是最佳的解決方案。如果你只需要很少的元素索引,純指針通常會更優化。