NASM сборка в то время как счетчик циклов
Я пишу цикл while в сборке для компиляции в терминале Linux с nasm и gcc. Программа сравнивает x и y до тех пор, пока y >= x и сообщает количество циклов в конце. Вот код:
segment .data
out1 db "It took ", 10, 0
out2 db "iterations to complete loop. That seems like a lot.", 10, 0
x db 10
y db 2
count db 0
segment .bss
segment .text
global main
extern printf
main:
mov eax, x
mov ebx, y
mov ecx, count
jmp lp ;jump to loop lp
lp:
cmp ebx, eax ;compare x and y
jge end ;jump to end if y >= x
inc eax ;add 1 to x
inc ebx ;add 2 to y
inc ebx
inc ecx ;add 1 to count
jp lp ;repeat loop
end:
push out1 ;print message part 1
call printf
push count ;print count
call printf
push out2 ;print message part 2
call printf
;mov edx, out1 ;
;call print_string ;
;
;mov edx, ecx ;these were other attempts to print
;call print_int ;using an included file
;
;mov edx, out2 ;
;call print_string ;
Это компилируется и запускается в терминале с помощью:
nasm -f elf test.asm
gcc -o test test.o
./test
Вывод терминала выглядит следующим образом:
It took
iterations to complete loop. That seems like a lot.
Segmentation fault (core dumped)
Я не вижу ничего плохого в этой логике. Я думаю, что это синтаксический, но мы только начали изучать ассемблер, и я пробовал все виды различных синтаксисов, таких как скобки вокруг переменных и использование ret
в конце сегмента, но ничего не работает. Я также искал ошибки сегментации, но не нашел ничего действительно полезного. Любая помощь будет оценена, потому что я абсолютный новичок.2 ответа:
Причина сбоя, вероятно, в том, что ваша функция
main
не имеет инструкцииret
. Также обязательно установитеeax
в 0, чтобы сигнализировать об успехе:xor eax, eax ; or `mov eax, 0` if you're more comfortable with that ret
Кроме того, глобальные переменные обозначают указатели, а не значения.
mov eax, x
задаетeax
адресx
. Если вы хотите, чтобы что-то произошло (или не использовать глобальные переменные), вам нужно написать туда ответ.Наконец, вы вызываете
printf
с единственным нестроковым аргументом:push count ;print count call printf
Первым аргументом должен быть форматируйте строку, например
"%i"
. Здесьcount
является указателем на нулевой байт,поэтому вы ничего не получите. С моей головы, вы должны попробовать это:out3 db "%i ", 0 ; snip push ecx push out3 call printf
Я думаю, что ваша проблема может заключаться только в том, что вы ссылаетесь на адреса ваших констант, а не на их внутреннюю ценность. Нужно думать о метке в nasm как о указателе, а не как о значении. Для доступа к нему вам просто нужно использовать
[label]
:segment .data x dw 42 segment .text global main extern printf main: mov eax, x push eax call printf ; will print address of x (like doing cout<<&x in C++) mov eax, [x] push eax call printf ; will print 42 sub esp, 8 xor eax, eax ret
PS: Я не думаю, что кто-то упоминал об этом, но летучие регистры очень часто изменяются при вызове внешнего кода (C или C++ или другого), так как при компиляции те функции, которые вы используете, "переводятся" в сборку и затем связываются с вашим asm файл. ПК не является человеком, поэтому он не различает, что было написано на высоком или низком уровне, процессор просто читает опкоды и операнды, хранящиеся в регистрах и памяти, следовательно, почему внешняя функция при использовании языка низкого уровня (
call printf
) собирается изменить (или нет! всегда зависит от компилятора и архитектуры) регистры, которые вы также используете. Для решения этой проблемы существуют различные решения:
Вы проверяете, какие регистры не изменяются, используя
gcc your_c_file.c -S
и тогда в файлеyour_c_file.s
будет находиться заранее подготовленный ассемблерный код, созданный вашим компилятором из вашего файла C. (Как правило, довольно трудно понять, что есть что, и если вы собираетесь использовать этот метод, проверьте искажение имен, чтобы увидеть, как имена функций будут изменены.)Поместите все регистры, которые вы хотите сохранить, в стек, а затем после вызова поместите их обратно в свои регистры, имея в виду метод LIFO.
- используйте инструкции
PUSHA
иPOPA
, которые нажимают или хлопают все регистры соответственно.Это руководство NASM Глава 3, которая объясняет основы языка для использования: http://www.csie.ntu.edu.tw/~comp03/nasm/nasmdoc3.html
Надеюсь, вам удалось ее решить.