Вход/Регистрация
Программирование для Linux. Профессиональный подход
вернуться

Самьюэл Алекс

Шрифт:

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

bsrl
. Ее использование будет продемонстрировано в разделе 9.4, "Пример".

9.2. Простая ассемблерная вставка

Вот как с помощью функции

asm
осуществляется сдвиг числа на 8 битов вправо:

asm("shrl $8, %0" : "=r" (answer) : "r" (operand) : "cc");

Выражение в скобках состоит из секций, разделенных двоеточиями. В первой секции указана ассемблерная инструкция и ее операнды. Команда

shrl
осуществляет сдвиг первого операнда на указанное число битов вправо. Первый операнд представлен выражением
%0
. Второй операнд — это константа
$8
.

Во второй секции задаются выходные операнды. Единственный такой операнд будет помещен в C-переменную

answer
, которая должна быть адресуемым (левосторонним) значением. В выражении
"=r"
знак равенства обозначает выходной операнд, а буква
r
указывает на то, что значение переменной
answer
заносится в регистр.

В третьей секции перечислены входные операнды. Переменная

operand
содержит значение, подвергаемое битовому сдвигу. Выражение
"r"
означает, что значение переменной записывается в регистр.

Выражение

"cc"
в четвертой секции говорит о том. что инструкция меняет значение регистра
cc
(содержит код завершения).

9.2.1. Преобразование функции asm в ассемблерные инструкции

Компилятор

gcc
интерпретирует функцию
asm
очень просто: он генерирует ассемблерные инструкции, обрабатывающие указанные входные и выходные операнды, после чего заменяет вызов функции заданной инструкцией. Никакой дополнительный анализ не выполняется.

Например, следующий фрагмент программы:

double foo, bar;

asm("mycool_asm %1, %0" : "=r" (bar) : "r" (foo));

будет преобразован в такую последовательность команд x86:

 movl -8(%ebp),%edx

 movl -4(%ebp),%ecx

#APP

 mycool_asm %edx, %edx

#NO_APP

 movl %edx,-16(%ebp)

 movl %ecx,-12(%ebp)

Переменные

foo
и
bar
занимают по два слова в стеке в 32-разрядной архитектуре x86. Регистр
ebp
ссылается на данные, находящиеся в стеке.

Первые две команды копируют переменную foo в регистры

edx
и
ecx
, с которыми работает инструкция
mycool_asm
. Компилятор решил поместить результат в те же самые регистры. Последние две команды копируют результат в переменную
bar
. Выбор нужных регистров и копирование операндов осуществляются автоматически.

9.3. Расширенный синтаксис ассемблерных вставок

В следующих подразделах будет описан синтаксис правил, по которым строятся выражения в функции

asm
. Секции выражения отделяются друг от друга двоеточиями. Мы будем ссылаться на следующую инструкцию, которая вычисляет результат булевого выражения
x > y
:

asm("fucomip %%st(1), %%st; seta %%al" :

 "=a" (result) : "u" (y), "t" (x) : "cc", "st");

Сначала инструкция

fucomip
сравнивает два операнда,
x
и
y
, и помещает значение, обозначающее результат, в регистр
cc
, после чего инструкция
seta
преобразует это значение в 0 или 1.

9.3.1. Ассемблерные инструкции

Первая секция содержит ассемблерные инструкции, заключенные в кавычки. В рассматриваемом примере таких инструкций две:

fucomip
и
seta
. Они разделены точкой с запятой. Если текущий вариант языка ассемблера не допускает такого способа разделения инструкций, воспользуйтесь символом новой строки (
\n
).

Компилятор игнорирует содержимое первого раздела, разве что один уровень символов процента удаляется, т.е. вместо

%%
будет %. Смысл выражения
%%st(1)
и ему подобных зависит от архитектуры компьютера.

Если при компиляции программы, содержащей функцию

asm
, указать опцию
– traditional
или
– ansi
, компилятор
gcc
выдаст предупреждение. Чтобы этого избежать, используйте альтернативное имя
__asm__
.

9.3.2. Выходные операнды

Во второй секции указаны выходные операнды инструкции. Каждому операнду соответствует строка адресации и выражение языка С, записанное в скобках. В случае выходных операндов (все они должны быть левосторонними значениями) строка адресации должна начинаться со знака равенства. Компилятор проверяет, действительно ли каждый выходной операнд является левосторонним значением (т.е может стоять в левой части оператора присваивания).

Список обозначений регистров для конкретной архитектуры можно найти в исходных текстах компилятора

gcc
(конкретнее — в определении макроса
REG_CLASS_FROM_LETTER
). Например, в файле
gcc/config/i386/i386.h
содержатся обозначения, соответствующие архитектуре x86 (табл. 9.1).

  • Читать дальше
  • 1
  • ...
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: