вызов ассемблерных функций из c

Я пытаюсь использовать функцию в сборке, вызванную из проекта C. Эта функция должна вызывать функцию libc, скажем, printf(), но я продолжаю получать ошибку сегментации.

В файле .c у меня есть объявление функции, скажем

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

Будем признательны за любые комментарии pointers.

as func.asm -o func.o

gcc prog.c func.o -o prog

person Community    schedule 13.01.2011    source источник
comment
+1 за название функции   -  person Matt Joiner    schedule 13.01.2011
comment
Приветствуются любые указатели: int *ptr;   -  person Sapph    schedule 13.01.2011
comment
@Sapph +1, но это не помогает :))   -  person    schedule 13.01.2011
comment
@Sapph: Вы имели в виду void*, верно?   -  person user541686    schedule 13.01.2011
comment
@Lambert: Оглядываясь назад, это так болезненно очевидно! Мне стыдно. +1 вам, сэр.   -  person Sapph    schedule 13.01.2011


Ответы (4)


Измените push printtext на push $printtext.

Как бы то ни было, вы загружаете значение с адреса printtext и проталкиваете его, а не проталкиваете адрес. Таким образом, вы передаете 'test' как 32-битное число, а не указатель, а printf пытается интерпретировать это как адрес и дает сбой.

person R.. GitHub STOP HELPING ICE    schedule 13.01.2011

Один из лучших способов начать работу с функциями на ассемблере — написать аналогичную функцию на C, а затем построить ее с помощью параметра компилятора, создающего листинг на ассемблере (-S в gcc). Затем вы можете изучить вывод того, что сделал компилятор, и изменить его по мере необходимости.

Это особенно полезно, если вы вызываете такие функции, как printf, которые используют другое соглашение о вызовах (из-за переменного количества аргументов). Вызов этих функций может сильно отличаться от вызова функций, не использующих varargs.

person Greg Hewgill    schedule 13.01.2011
comment
Очень поучительно... но, как правило, вводит в заблуждение. Настоящая проблема заключается в конкретных деталях ABI о том, какие регистры должны быть сохранены, что они означают и как они взаимодействуют с C ABI. Сначала я пошел по этому пути, а потом понял, что моя сборка будет не лучше, чем то, что сгенерирует компилятор, что было прямо противоположно тому, чего я пытался достичь! - person bbum; 14.01.2011

проблема была в том, что я использовал

pushl printtext

скорее, что

pushl $printtext

Спасибо всем за вашу помощь и извините за потраченное время: P

person Community    schedule 13.01.2011
comment
Вы получили это как раз перед тем, как я написал. Поздравляю с решением вашей проблемы. :-) - person R.. GitHub STOP HELPING ICE; 13.01.2011

После этого:

push printtext
call printf

Ты хочешь:

addl $4, %esp

Дополнительное объяснение:

Поскольку вы используете x86 Linux, я предполагаю, что соглашение о вызовах требует, чтобы вызываемый объект очищал параметры. Поскольку вы поместили указатель перед вызовом printf, ваш стек сместится на 4 после выполнения инструкции ret этой функции.

Обновление:

Да, хорошо, я привык к синтаксису Intel, поэтому у меня в голове был обратный порядок аргументов. На самом деле отсутствие addl обратно в esp не имеет значения, потому что вы правильно восстанавливаете esp возле своего ret. Мое следующее предположение состоит в том, что в строке, которую вы передаете printf, отсутствует завершающий нуль... Позвольте мне посмотреть, что делает gas...

Обновление 2:

Хорошо, gas null завершает строки для вас, поэтому я думаю, что моя вторая догадка была неверной. Похоже, вы нашли проблему, так что вопрос спорный.

person asveikau    schedule 13.01.2011
comment
Я запутался, потому что привык к синтаксису Intel, а не AT&T. Вы на самом деле хотите addl $4, %esp Подождите, дайте мне еще раз взглянуть... - person asveikau; 13.01.2011
comment
@void - Может быть, вы можете проверить в шестнадцатеричном редакторе. Строка, которую вы передаете в printf, завершается нулем? - person asveikau; 13.01.2011
comment
правильно, это 4 доллара, %esp я нашел проблему, я должен был поместить в стек pushl $prittext - person ; 13.01.2011