Форум русскоязычного сообщества Ubuntu


Хотите сделать посильный вклад в развитие Ubuntu и русскоязычного сообщества?
Помогите нам с документацией!

Автор Тема: Segmentation fault в ассемблере.  (Прочитано 789 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Белый пони

  • Автор темы
  • Любитель
  • *
  • Сообщений: 63
    • Просмотр профиля
Segmentation fault в ассемблере.
« : 06 Июнь 2011, 15:34:18 »
Задача из книжки: с помощью функции найти максимальный элемент в массиве и вывести его как exit code.

Написал так:

#  "0" - is the end symbol
#
# OUTPUT: max value as exit code

.section .data

items1:
 .long  10, 14, 100, 44, 3, 113, 5, 0


.section .text

.globl _start
.globl findmax

_start:
#pushing only parameter to the stack
 pushl items1
 call findmax        # result is in %eax
 addl $4, %esp       # scrubbing parameter from the stack

#putting result as exit code to %ebx
 movl %eax, %ebx
 movl $1, %eax
 int $0x80


# "find maximum" function
#
# INPUT: single parameter - pointer to .long data, ended with a zero
#
# VARIABLES:   
#        %ecx - current pointer
#        (%ebx - current value)?
#        %eax - current greater value

#
# RETURN VALUE: maximum number from data array

findmax:
# ENTER FUNCTION
# storing %esp (in %ebp) and %ebp (in the stack)
 pushl %ebp
 movl  %esp, %ebp

 movl 8(%ebp), %ecx  # setting initial data pointer to %ecx
 movl (%ecx), %eax   # setting first element as maximum
 
start_loop:
 addl $4, %ecx       # set pointer to the next element
 cmpl $0, (%ecx)     # if "0" jump to loop ending
 je end_loop

 cmpl %eax, (%ecx)
 jle start_loop

 movl (%ecx), %eax

end_loop:
#EXIT FUNCTION
#maximum is already in %eax as return value
#restoring %esp (from %ebp) and %ebp (from the stack)
 movl %ebp, %esp
 popl %ebp
 ret

Собирается и линкуется нормально, а при исполнении выдаёт ошибку сегментации :(
root@serg:/atest# as findmax.s -o findmax.o
root@serg:/atest# ld findmax.o -o findmax
root@serg:/atest# ./findmax
Segmentation fault
root@serg:/atest# echo $?
139

Пробовал комментить куски кода. И похоже что ошибка появляется на строке " movl (%ecx), %eax":
...
findmax:
# ENTER FUNCTION
# storing %esp (in %ebp) and %ebp (in the stack)
 pushl %ebp
 movl  %esp, %ebp

 movl 8(%ebp), %ecx  # setting initial data pointer to %ecx
 movl (%ecx), %eax  # setting first element as maximum  <---------------- тут       
 
#start_loop:
# addl $4, %ecx       # set pointer to the next element
# cmpl $0, (%ecx)     # if "0" jump to loop ending
# je end_loop
...

Как так?  Я неправильно записываю адрес первого элемента массива в %ecx ?


andrey_p

  • Гость
Re: Segmentation fault в ассемблере.
« Ответ #1 : 07 Июнь 2011, 06:14:58 »
После команды
movl 8(%ebp), %ecxв %ecx - 10. Пользуйся gdb: ассемблить надо так: as findmax.s -g -o findmax.o. Полезные команды в gdb - l, b, i reg, i reg ebp, ну и еще куча.

Если так:
movl %ebp, %ecx
 addl $8, %ecx
то не коредампит, но и не работает :) Дальше сам, а то у меня  на ассемблер сегодня с утра что-то не... эээ... не хочется. )))


Пользователь решил продолжить мысль 07 Июнь 2011, 13:36:28:
Что-то я понял, что давненько не брал в руки ассемблера... :)

Попробовал, но что-то не могу сообразить (от ассемблера мешанина в голове только осталась, надо бы поправить). Могу только порекомендовать свободную книжку Programming from Ground Up - там на странице 31 как-раз аналогичная программа, но без вызова функции - это дальше.
« Последнее редактирование: 07 Июнь 2011, 13:36:28 от andrey_p »

Оффлайн Белый пони

  • Автор темы
  • Любитель
  • *
  • Сообщений: 63
    • Просмотр профиля
Re: Segmentation fault в ассемблере.
« Ответ #2 : 07 Июнь 2011, 14:33:16 »
После команды
movl 8(%ebp), %ecxв %ecx - 10. Пользуйся gdb: ассемблить надо так: as findmax.s -g -o findmax.o. Полезные команды в gdb - l, b, i reg, i reg ebp, ну и еще куча.

Если так:
movl %ebp, %ecx
 addl $8, %ecx
то не коредампит, но и не работает :) Дальше сам, а то у меня  на ассемблер сегодня с утра что-то не... эээ... не хочется. )))


Пользователь решил продолжить мысль [time]Tue Jun  7 13:36:28 2011[/time]:
Что-то я понял, что давненько не брал в руки ассемблера... :)

Попробовал, но что-то не могу сообразить (от ассемблера мешанина в голове только осталась, надо бы поправить). Могу только порекомендовать свободную книжку Programming from Ground Up - там на странице 31 как-раз аналогичная программа, но без вызова функции - это дальше.

Спасибо!

Я как раз по этой книжке и учусь :) Там есть программа поиска максимума, а потом в качестве упражнения советуют сделать её же, только с использованием функции, которой в качестве параметра надо передать указатель на несколько значений.

Покопался с gdb. Похоже проблема в том, что после:
pushl items1в стек пишется первое значение из items1 (10), а не адрес первого элемента. Как записать в стек именно указатель (адрес items1) ?


P.S. Это заметил, копируя параметр из стека в регистр, и проверяя значения регистров с помощью команд i reg и т.д.
Как посмотреть напрямую значения локальных переменных с стеке, или просто несколько "верхних" значений со стека я так и не понял :(  Пробовал info f до и после pushl'a  , пишет, что локальные переменные по неизвестном адресу :(
(Нажмите, чтобы показать/скрыть)
« Последнее редактирование: 07 Июнь 2011, 14:40:15 от Белый пони »

andrey_p

  • Гость
Re: Segmentation fault в ассемблере.
« Ответ #3 : 08 Июнь 2011, 09:41:07 »
Гугля по теме gdb и ассемблер, нашел еще одну свободную книжку - Introduction to Computer Organization with x86-64 Assembly Language & GNU/Linux.
В ней аппендикс как-раз полностью посвящен этому вопросу. Вообщем все можно, но сложновато немного.

Оффлайн Белый пони

  • Автор темы
  • Любитель
  • *
  • Сообщений: 63
    • Просмотр профиля
Re: Segmentation fault в ассемблере.
« Ответ #4 : 08 Июнь 2011, 11:02:08 »
Гугля по теме gdb и ассемблер, нашел еще одну свободную книжку - Introduction to Computer Organization with x86-64 Assembly Language & GNU/Linux.
В ней аппендикс как-раз полностью посвящен этому вопросу. Вообщем все можно, но сложновато немного.
Спасибо за помощь! Книжку скачал:)
Что бы передать в качестве параметра адрес массива, а не первый элемент, надо было просто приписать $:
pushl $items1вместоpushl items1 :)

 

Страница сгенерирована за 0.054 секунд. Запросов: 24.