Вызов функций сборки из c
Я пытаюсь использовать функцию в сборке, вызванную из проекта C. Эта функция должна вызывать функцию libc, скажем printf()
, но я продолжаю получать ошибку сегментации.
В .c файле у меня есть объявление функции let say
int do_shit_in_asm()
В файле .asm у меня есть
.extern printf
.section .data
printtext:
.ascii "test"
.section .text
.global do_shit_in_asm
.type do_shit_in_asm, @function
do_shit_in_asm:
pushl %ebp
movl %esp, %ebp
push printtext
call printf
movl %ebp, %esp
pop %ebp
ret
Любые <забавные > указатели будут оценены.
as func.asm -o func.o
gcc prog.c func.o -o prog
Ответы
Ответ 1
Измените push printtext
на push $printtext
.
Как бы то ни было, вы загружаете значение из адреса printtext
и нажимаете это, а не нажимаете адрес. Таким образом, вы передаете 'test'
как 32-битное число, а не указатель, а printf
пытается интерпретировать это как адрес и сбой.
Ответ 2
Один из лучших способов начать работу с функциями языка ассемблера - написать аналогичную функцию в C, а затем создать его с помощью компилятора, который генерирует список сборок (-S
on gcc). Затем вы можете изучить вывод того, что сделал компилятор, и изменить по мере необходимости.
Это особенно полезно, если вы вызываете такие функции, как printf
, которые используют другое соглашение о вызове (из-за переменного количества аргументов). Вызов этих функций может сильно отличаться от вызова функций, отличных от varargs.
Ответ 3
проблема заключалась в том, что я использовал
pushl printtext
скорее, чем
pushl $printtext
Спасибо всем за вашу помощь и жаль тратить ваше время: P
Ответ 4
После этого:
push printtext
call printf
Вы хотите:
addl $4, %esp
Дальнейшее объяснение:
Поскольку вы используете x86 Linux, я предполагаю, что для вызывающего соглашения требуется, чтобы вызывающий вызывал очистку параметров. Поскольку вы нажали указатель перед вызовом printf
, ваш стек отключен на 4 после выполнения этой команды ret
.
Update:
Да, хорошо, я привык к синтаксису Intel, поэтому я получил порядок аргументов в голове. На самом деле отсутствие addl
back to esp
не имеет значения, потому что вы правильно восстанавливаете esp
рядом с вашим ret
. Моя следующая догадка заключается в том, что строка, передаваемая в printf
, не имеет нулевого ограничителя... Позвольте мне увидеть, что gas
делает...
Обновление 2:
ОК, gas
null завершает строки для вас, поэтому, я думаю, моя вторая догадка была неправильной. Похоже, вы нашли проблему, так что вопрос спорный.