Как вставить ассемблер в с

Ассемблер в Dev-C++

Давно хотел разобраться с этой темой. И вот наконец собрался.

Дело в том, что инструкции процессора Интел и синтаксис вставок ассемблерного кода в программы на Visual C++ не будут работать в Dev-C++.

Потому что Dev-C++ использует компилятор GCC (бесплатный компилятор языка С++). Этот компилятор имеет встроенный ассемблер, но это не MASM и не TASM с привычным набором команд. Это ассемблер AT&T, синтаксис которого очень сильно отличается от синтаксиса MASM/TASM и подобных.

Я сначала никак не мог понять, почему. Но когда немного познакомился с документацией, то понял.

Оказывается, в компиляторе GCC, как и в Паскале и в Visual C++, есть ключевые слова asm и __asm. Вот только это вовсе не операторные скобки.

По сути это функции, которые вызываются с определённым набором параметров. И в эти функции в качестве параметров передаются инструкции ассемблера!

А здесь я просто в самых общих чертах покажу, как можно использовать вставки на ассемблере в Dev-C++ (это будет также справедливо для других средств разработки, использующих компилятор GCC).

Ассемблер AT&T

Как я уже сказал, этот ассемблер сильно отличается от привычных нам инструкций процессора Интел. Здесь я не буду об этом говорить. Если кому интересно, то основные отличия описаны здесь.

Вставка на ассемблере в Dev-C++

Основной формат вставки кода ассемблера показан ниже:

asm( «Здесь код на ассемблере»);

Как вы могли заметить, здесь используются два варианта встраивания ассемблера: asm и __asm__. Оба варианта правильные. Следует использовать __asm__, если ключевое слово asm конфликтует с каким-либо участком вашей программы (например, в вашей программе есть переменная с именем asm).

Если встраивание кода на ассемблере содержит более одной инструкции, то мы пишем по одной инструкции в строке в двойных кавычках, а также суффикс ’\n’ и ’\t’ для каждой инструкции.

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

Это тоже возможно. Общий формат ассемблерной вставки для компилятора GCC такой:

Не буду здесь подробно всё это расписывать, так как это уже сделано здесь. Там же вы найдёте все подробности использования встроенного ассемблера компилятора GCC (ну хотя не все, а основные).

Я же здесь приведу пример, и на этом успокоюсь.

Для начала не очень хороший пример.

Не очень хороший он потому, что мы изменяем значения регистров, а потом получаем значение регистра eax в переменную х. Но при этом мы не заботимся о том, что состояние этих регистров может быть изменено где-то в другом месте. Так что это может привести к потенциальным неожиданностям.

Теперь попробуем сделать всё чуть более правильно (хотя и не идеально).

Здесь в ассемблерный код мы передаём значения переменных y и z. Значение у помещается в регистр еах (на это указывает буква “a”), а значение z помещается в регистр ebx (на это указывает буква “b”).

Ну вот как-то так. Это, конечно, в самых общих чертах. Если кого интересуют подробности, то см. здесь.

Источник

Ассемблерная вставка в Си

Пытаюсь разобраться, как вставить код на ассемблере в Си код. Беглый поиск по гугл лишь запутал. Попытка что-то скомпилировать из написанного не увенчалась успехом. Может ли кто-нибудь мне привести два варианта рабочего кода, для linux/windows (x64), который бы выражал следующие идеи:

п.с. Я правильно понимаю, что для этих целей нужно использовать GAS? Нет никакой возможности заставить компилятор понимать вставки на NASM?

2 ответа 2

По-моему, более правильный путь использования ассемблера в Си, не вставками и смешиванием Си и ассемблера, а линковкой скомпилированного ассемблера.

Т.е. пишите на любимом NASM (к примеру) в файл test.asm :

Далее, вызываете эту функцию из Си:

При сборке не забывайте указать линковщику, чтобы он линковался с test.o :

Чтобы собрать тоже самое под Linux, вам нужно будет привести ассемблерный код в соответствие с соглашением о передаче параметров в Unix 64-bit (отличается от соглашения для Win64) и указать NASM другой выходной формат:

О соглашениях передачи параметров и об особенностях написания 64-битного кода, в NASM посвящена отдельная глава в документации: Writing 64-bit Code (Unix, Win64)

Синтаксис оператора следующий:

Текст вставки представляет собой строковую константу с ассемблерными инструкциями. В нем могут находиться не только ассемблерные инструкции, но и любые директивы ассемблера GAS.

Операнд имеет следующий вид:

имя_переменной — ни что иное, как имя C-переменой, значение которой вы хотите использовать в ассемблерном коде.

ограничение_типа — строковая константа, описывает допустимый тип операнда.

Итак, этого достаточно, чтобы написать ваш пример:

В общем-то писал по этому документу. Неплохая информация представлена здесь.

Источник

Связь ассемблера с языками высокого уровня

Существуют следующие формы комбинирования программ на языках высокого уровня с ассемблером:

Встроенный ассемблер

При написании ассемблерных вставок используется следующий синтаксис:

КодОперации задает команду ассемблера,
операнды – это операнды команды.
В конце записывается ;, как и в любой команде языка Си.
Комментарии записываются в той форме, которая принята для языка Си.
Если требуется в текст программы на языке Си вставить несколько идущих подряд команд ассемблера, то их объединяют в блок:

Внутри блока текст программы пишется с использованием синтаксиса ассемблера, при необходимости можно использовать метки и идентификаторы. Комментарии в этом случае можно записывать как после ;, так и после //.

Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с

Использование внешних процедур

Для связи посредством внешних процедур создается многофайловая программа. При этом в общем случае возможны два варианта вызова:

СоглашениеПараметрыОчистка стекаРегистры
Pascal (конвенция языка Паскаль)Слева направоПроцедураНет
C (конвенция С)Справа налевоВызывающая программаНет
Fastcall (быстрый или регистровый вызов)Слева направоПроцедураЗадействованы три регистра (EAX,EDX,ECX), далее стек
Stdcall (стандартный вызов)Справа налевоПроцедураНет

Конвенция Pascal заключается в том, что параметры из программы на языке высокого уровня передаются в стеке и возвращаются в регистре АХ/ЕАХ, — это способ, принятый в языке PASCAL (а также в BASIC, FORTRAN, ADA, OBERON, MODULA2), — просто поместить параметры в стек в естественном порядке. В этом случае запись

Конвенция С используется, в первую очередь, в языках С и C++, а также в PROLOG и других. Параметры помещаются в стек в обратном порядке, и, в противоположность PASCAL-конвенции, удаление параметров из стека выполняет вызывающая процедура.
Запись some_proc(a,b,c,d)
будет выглядеть как

Вызванная таким образом процедура может инициализироваться так:

Трансляторы ассемблера поддерживают и такой формат вызова при помощи полной формы директивы proc с указанием языка С:

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

Возврат результата из процедуры

Чтобы возвратить результат в программу на С из процедуры на ассемблере, перед возвратом управления в вызываемой процедуре (на языке ассемблера) необходимо поместить результат в соответствующий регистр:

Тип возвращаемого значенияРегистр
unsigned charal
charal
unsigned shortax
shortax
unsigned inteax
inteax
unsigned long intedx:eax
long intedx:eax

Пример Умножить на 2 первый элемент массива (нумерация элементов ведется с 0).

Чтобы построить проект в Microsoft Visual Studio Express 2010, совместив в нем файлы, написанные на разных языках программирования, выполняем следующие действия.

Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Добавляем в дерево проекта два файла исходного кода:

Второй добавляемый файл исходного кода будет иметь расширение .asm, которое необходимо указать явно.
Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Важно, чтобы файлы программ на C++ и ассемблере имели не только разные расширения, но и имена. В случае совпадающих имен файлов возникнет ошибка при компоновке проекта, поскольку оба файла будут иметь одно и то же имя объектного файла.

Набираем код программы для файлов вызывающей и вызываемой процедур соответственно на C++ и ассемблере.
Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Подключаем инструмент Microsoft Macro Assembler. По правой кнопке мыши для проекта выбираем Настройки построения.
Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
В появившемся окне ставим галочку в строке masm.

Как вставить ассемблер в с. Смотреть фото Как вставить ассемблер в с. Смотреть картинку Как вставить ассемблер в с. Картинка про Как вставить ассемблер в с. Фото Как вставить ассемблер в с
Результат построения отображается в нижней части окна проекта.

Работа с аргументами вещественного типа

При вызове функции с аргументами вещественного типа конфигурация проекта ничем не отличается от описанной выше. Для передачи аргументов необходимо указать их тип.

тип СиКоличество байтТип аргумента ассемблера
float4dword
double8qword

Возвращаемое вещественное значение по умолчанию располагается в вершине стека сопроцессора st(0).

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *