Марк Митчелл - Программирование для Linux. Профессиональный подход
- Название:Программирование для Linux. Профессиональный подход
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2002
- Город:Москва
- ISBN:5-8459-0243-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марк Митчелл - Программирование для Linux. Профессиональный подход краткое содержание
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Программирование для Linux. Профессиональный подход - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Во второй секции задаются выходные операнды. Единственный такой операнд будет помещен в 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).
Таблица 9.1. Обозначения регистров в архитектуре Intel x86
Символ регистра | Регистры, которые могут использоваться компилятором gcc |
---|---|
R | Регистры общего назначения (EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP) |
q | Общие регистры хранения данных (EAX, ЕВХ, ECX, EDX) |
f | Регистр для чисел с плавающей запятой |
t | Верхний стековый регистр для чисел с плавающей запятой |
u | Второй после верхнего стековый регистр для чисел с плавающей запятой |
a | Регистр EAX |
b | Регистр EBX |
с | Регистр ECX |
d | Регистр EDX |
x | Регистр SSE (регистр потокового расширения SIMD) |
y | Мультимедийные регистры MMX |
A | Восьмибайтовое значение, формируемое из регистров EAX и EDX |
D | Указатель приемной строки в строковых операциях (EDI) |
S | Указатель исходной строки в строковых операциях (ESI) |
Если есть несколько однотипных операндов, то они разделяются запятыми, как показано в секции входных операндов. Всего можно задавать до десяти операндов, адресуемых как %0
, %1
, … %9
. Если выходные операнды отсутствуют, но есть входные операнды или модифицируемые регистры, то вторую секцию следует оставить пустой или пометить ее комментарием наподобие /* нет выходных данных */
.
9.3.3. Входные операнды
В третьей секции задаются входные операнды. Строка адресации такого операнда не должна содержать знака равенства, в остальном синтаксис совпадает с синтаксисом выходных операндов.
Если требуется указать, что в одной инструкции осуществляется как чтение регистра, так и запись в него, необходимо в строке адресации входного операнда поставить номер выходного операнда. Например, если входной регистр должен быть тем же, что и регистр первого выходного операнда, назначьте ему номер 0. Выходные операнды нумеруются слева направо, начиная с нуля. Если просто указать одинаковое C-выражение для входного и выходного операндов, то это еще не означает, что оба значения будут помещены в один и тот же регистр.
Данную секцию можно пропустить, если входные операнды отсутствуют и следующая секция модифицируемых регистров пуста.
9.3.4. Модифицируемые регистры
Если в качестве побочного эффекта инструкция модифицирует значение одного или нескольких регистров, в функции asm()
должна присутствовать четвертая секция. Например, инструкция fucomip
меняет регистр кода завершения, обозначаемый как cc. Строки, представляющие затираемые регистры, разделяются запятыми. Если инструкция способна изменить произвольную ячейку памяти, в этой секции должно стоять ключевое слово memory
. На основании этой информации компилятор определяет, какие значения должны быть загружены повторно после завершения функции asm()
. При отсутствии данной секции компилятор может сделать неверное предположение о том, что регистры содержат прежние значения, и это скажется на работе программы.
Интервал:
Закладка: