2013-04-27 2 views
9

Возможно ли сгенерировать функции языка ассемблера из C-функций с помощью GCC, чтобы они могли быть вызваны из языковой программы ассемблера? Я знаю, что gcc компилирует C в машинный код (который можно легко разобрать на языке ассемблера), и я уже знаю, что это возможно inline assembly language functions in C, но я еще не нашел способ вызвать функции C из ассемблерных программ, в основном наоборот.Вызов функций C из языка ассемблера x86

Здесь я пытаюсь встроить функцию C в программу сборки x86. Если вложение невозможно, то есть ли другой способ вызвать функцию C из программы языка ассемблера?

.686p 
.model flat,stdcall 
.stack 2048 

.data 

.code 
start: 

invoke ExitProcess, 0 

printSomething PROC ;now I'm attempting to inline a C function here 
    void printSomething(thingToPrint){ 
     printf("This is a C function that I want to invoke from an assembly language program."); 
     printf("There must be some way to do this - is it possible somehow?"); 
    } 
printSomething ENDP 

end start 
+0

Я не помню всех деталей, но вам просто нужно скомпилировать объектные файлы и связать их вместе. Вам просто нужно знать, какие вызовы используются при вызове функции. –

+1

Вы можете добавить код сборки, показывающий, что вы пробовали, и сообщить, как он не может скомпилировать или как он ведет себя неправильно. Было бы намного легче ответить, чтобы указать, в чем проблема с ним. – hyde

+3

Вы можете узнать, как это сделать, написав функцию C, вызывающую функцию, которую вы хотите вызвать, скомпилируете ее на язык ассемблера ('-S') и изучите результаты. Я также хотел бы указать вам на «psABI», но я больше не могу найти копию. – zwol

ответ

17

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

Вам нужно будет сообщить ассемблеру GCC, что ваша подпрограмма printSomething() не указана в вашем файле сборки. В 'C' вы использовали ключевое слово extern. Для сборки вам нужно будет использовать .globl.

.globl printSomething 

Если вы используете другой ассемблер, отличный от GCC, ключевое слово может отличаться.

Следующий большой вопрос: «Как передать аргументы»? Это очень зависит от вашего процессора и ОС. Поскольку заголовок вашего вопроса указывает x86, я собираюсь предположить, что вы используете либо 16-битные, либо 32-битные режимы, и стандартный x86 ABI (в отличие от x86-64, который также отличается от Windows и Linux). Параметры C передаются вызываемой процедуре, нажимая их в стек. Они помещаются в стек справа налево.

Таким образом,

printSomething (arg1, arg2, arg3, arg4); 

переводит ...

pushl arg4 
pushl arg3 
pushl arg2 
pushl arg1 
call printSomething 
addl $0x10, %esp 

Вы можете спросить себя, что это

addl $0x10, %esp 

? Мы передали (ака толкнули) четыре 32-битных аргумента в процедуру (в стек). Хотя подпрограмма знает, что ожидать этих аргументов, она НЕ несет ответственности за то, чтобы выскочить из стека. За это отвечает вызывающий. Итак, после возврата из подпрограммы мы корректируем указатель стека, чтобы отбросить четыре 32-битных аргумента, которые мы ранее вставляли в стек.

В приведенном выше примере я предполагаю, что мы работаем в 32-битном режиме. Если бы это было 16-битный режим, это было бы ...

pushw arg4 
pushw arg3 
pushw arg2 
pushw arg1 
call printSomething 
addw $0x8, %sp 

Я понимаю, что в вашем примере, printSomething() принимает только один (1) аргумента и в моем примере я использовал четыре (4) , Просто отредактируйте мой пример, как нужно.

Для окончательных шагов вам необходимо скомпилировать как ваши C, так и файлы сборки в объектные файлы, связать файлы объектов, а затем выполнить.

Надеюсь, это поможет.

+0

Теперь я задаюсь вопросом, можно ли фактически генерировать процедуры сборки x86 из C-функций с помощью GCC. Можно ли преобразовать каждую функцию в программе C в эквивалентную функцию языка ассемблера, используя GCC или какой-либо другой компилятор C? –

+1

@AndersonGreen - Вы всегда можете попробовать использовать опцию -S. «gcc -S file.c» преобразует файл «file.c» в сборку (называя его file.s). Кроме того, если у вас уже есть исполняемый файл, вы можете использовать «objdump -d exe_file> exe_file.asm», чтобы разобрать «exe_file» и вывести результат в «exe_file.asm». – Sparky

+0

@Sparky В соглашении о процедуре x86 каждая функция имеет «оставить» или эквивалентные инструкции до того, как она вернется к вызывающей. Я думаю, что 'addl $ 0x10,% esp' в вашем примере является избыточным. – StrikeW