вызов функций сборки из c - PullRequest
27 голосов
/ 13 января 2011

Я пытаюсь использовать функцию в ассемблере, вызванную из 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

Любые указатели комментарии будут оценены.

as func.asm -o func.o

gcc prog.c func.o -o prog

Ответы [ 4 ]

16 голосов
/ 13 января 2011

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

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

9 голосов
/ 13 января 2011

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

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

6 голосов
/ 13 января 2011

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

pushl printtext

скорее, чем

pushl $printtext

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

2 голосов
/ 13 января 2011

После этого:

push printtext
call printf

Вы хотите:

addl $4, %esp

Дальнейшее объяснение:

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

Обновление:

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

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

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

...