如何打印索引位置x86 Assemby

时间:2016-12-01 08:30:17

标签: assembly x86 masm32 irvine32

我是Assembly的新手并试图完成一项功课,我想知道如何打印数组的索引位置而不是索引的值,我使用ESI作为指针。这里的数组用0和1填充,我想打印1的索引。 样本数组[1 | 1 | 0 | 0 | 1]

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)。 感谢。

3 个答案:

答案 0 :(得分:1)

你必须从@ MargaretBloom的想法开始,数,还有必要修复算法中的其他一些错误:

  • 你有两个loop,问题是,当第一个loop结束时,下一个代码块会执行,再次打印eax,并开始无限循环。< / LI>
  • 您的第二个loop跳转到Show,但应该跳转到PRINT
  • 您在esi后增加je Show,因此当找到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:

答案 1 :(得分: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 * Index)

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,我正在工作)

答案 2 :(得分: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.

如果元素的大小是非平凡的(不是2的幂),或者结构不是平凡的(链表,那么两个指针的差异不与元素的索引相关),你可能想要分别计算索引。为了避免每次获取的mul element_size索引,可能值得将两者混合使用,因此通过指针进行寻址,并分别计数(无用于获取)索引,这将仅用于需要索引的事物。

另外在这个变体中你可以从1索引,但我会避免这种情况,除非它为非程序员提供一些人工输出,因为大多数ASM / C / C ++程序员自然希望索引从0开始(由于我的第一个例子中的指针数学如何工作)。

; 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寻址模式来处理&#34; 0,1,...&#34;索引而不是纯指针:

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

如果你在循环中使用索引很多,这可能是最优的解决方案。如果你很少需要元素索引,纯指针通常会更优。