2016-12-01 22 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

Count. Точно так же, как вы делаете с 'esi', но начинаете с 0 или 1 и делаете шаг 1. –

+1

Вы не показываете, как определяется массив. В сборке определение и структура данных часто важнее самого кода. Без определения трудно определить, работает ли ваш код как есть, и может быть просто изменен, чтобы ответить на него, или он уже содержит некоторую ошибку (например, 'mov eax, [esi]' выглядит очень подозрительно .. но из 'add esi, 4' выглядит нормально). [mcve] очень важна для Ассамблеи. – 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 * 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: Я не могу проверить код атм, я на работе)

+0

Код уже ошибочен в сообщении OP ... последний 'цикл Show' не имеет смысла. В вашем первом варианте это еще хуже, так как его нелегко исправить, потому что вы обновите 'ebx' только одним путем. – Ped7g

+3

Опечатка в 'shr eax, 4'. Должно быть 2 –

+0

oops. ты прав. Спасибо, исправлено – Tommylee2k

1

Вы должны начать Wi е @ MargaretBloom задумке, граф, и это необходимо исправить некоторые другие ошибки в алгоритме:

  • Вы имеете два loop, проблема в том, когда первые loop заканчивается, следующий блок кода выполняется, и eax является снова напечатан, и начинается бесконечный цикл.
  • Ваш второй 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: 
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 индекса для каждой выборки, возможно, стоит смешать эти два, поэтому адресация через указатели и подсчет (бесполезный для выборки) индекса отдельно, который будет использоваться только для того, где вам нужен индекс.

Плюс в этом варианте можно индексировать от 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 режим адресации для работы с "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 

Если вы используете индексы в цикле довольно много, это может быть наиболее оптимальное решение. Если вам нужен индекс элемента только редко, чистые указатели обычно более оптимальны.