2016-11-17 9 views
-1

Я пытаюсь подсчитать длину строки argv [1] на ассемблере NASM. Думаю, я на правильном пути. Я переместил адрес argv [1], чтобы зарегистрировать eax, и теперь я хочу переместить его по байтам и сравнить с нулевым терминатором строк.Iterate over strings in assembly (NASM)

Каждый раз, когда я запускаю код, он переходит на нулевое сравнение. Неужели я неправильно понял индексацию памяти?

* Отказ от ответственности: Это небольшая часть большого задания на домашнюю работу.

segment .bss 

N: resd 1     ;counter for size of argv[1] 

segment .text 
    global asm_main 

asm_main: 
    enter 0,0    ;setup 
    pusha     ;save all registers 

    mov eax, dword [ebp+8] ;argc to eax 

    mov ebx, dword [ebp+12] ; address of argv to ebx 
    mov eax, dword [ebx+4] ; address of argv[1] to eax 

    mov [N], dword 0  ; N = 0 

    .loop: 

    add eax, [N]   ; advance index by N 
    cmp eax, dword 0  ; check for end of string 
    je .endloop   ; break out of the loop if we're done 


    add [N], dword 1  ; N++  

    jmp .loop    ; loop back for next char 

    .endloop: 

popa 
mov eax, 0 
leave 
ret 
+1

Какая инструкция на самом деле является segfault? 'add eax, [N]' читается с фиксированного адреса, поэтому, если он не будет segfault в первый раз, он не должен выполняться segfault. Используйте отладчик для одношаговой и посмотрите, что находится в regs/mem, когда вы ошибаетесь. –

+1

Наиболее очевидной проблемой является то, что вы никогда не читаете строку, вы просто увеличиваете указатель и сравниваете его с нулем. (И вы увеличиваете eax геометрически, потому что '[N]' растет линейно.) –

+0

Он умирает на линии cmp. Вы правы, строка, которая у меня выше, сравнивает адрес (надеюсь, адрес символа) с ожидаемым значением, а не сам символ. Должен ли я иметь cmp [eax], dword 0? – Eric

ответ

3

Через несколько подсказок и помощи GDB, цикл теперь выглядит следующим образом:

mov [N], dword 0  ; N = 0 

    .loop: 

    cmp [eax], byte 0  ; check for end of string 
    je .endloop  

    add eax, dword 1  ; advance index by 1 byte 
    add [N], dword 1  ; N++  

    jmp .loop    

    .endloop: 

Использование N для увеличения индекса было глупо. Мне нужно было увеличивать на 1.

+2

Обратите внимание, что вам не нужен отдельный счетчик. Вы можете просто выполнить «sub eax, start_of_string» после цикла. (И никогда не держите свои счетчики циклов в памяти, если вы можете этого избежать. Это очень медленно. В большинстве процессоров Intel ваш код будет работать почти в 6 раз медленнее, чем если бы вы сохранили N в регистре (или полностью избегали его), потому что он помещает хранилище/перезагружает обратную поездку в цепочку зависимостей, зависящую от цикла, и латентность хранения-печати составляет 5 циклов на процессорах Intel SnB-семейства.). –

+2

Хотя я ценю, что вы знаете размер данных, которые вы используете, JFYI: 'add eax, dword 1' не нуждается в спецификаторе размера, так как' eax' с одной стороны обеспечивает 32-разрядный контекст инструкции. Так что в таком случае 'add eax, 1' достаточно. Тот, который ниже 'add [N], dword 1' верен, требуется спецификатор размера, по крайней мере, с одной стороны, так как без него он неоднозначен, это имеет смысл также с' byte' или 'word', если' N' будет только байт/слово. И чтобы сделать + -1, x86 имеет выделенные опкоды 'inc' и' dec', сохраняет ввод этого ', 1'. Не знаю, почему мне действительно нравятся эти два. :) – Ped7g