GCC - The Complete Reference (537669), страница 63
Текст из файла (страница 63)
Но при этом не обязательно писать на ассемблере всю программу и даже отдельный модуль. Если необходимо сделать чтото особенное на машинном уровне, то обычно самым простым выходом является включение в программу на языке более высокого уровня фрагмента ассемблерного кода. Для этого ОСС предоставляет возможность непосредственного включения команд ассемблера в функции на языке С. По самой своей природе код на языке ассемблера не может быть переносимым. Код, который написан для одной платформы, практически всегда для любой другой платформы будет неправильным. В этом разделе при рассмотрении процедуры вставки ассемблерного кола в программу мы будем использовать синтаксис инструкций, совместимый с ассемблерами семейства процессоров 1пге1.
232 часть (и. внутренняя структура н окружение Конструкция аьв В следующем примере программь) на языке Слля вставки фрагмента ассемблерного кода используется конструкция аввь В этом примере значение переменной, объявленной в коде на языке С, загружается в регистр„сдвигается на один бит вправо лля его деления на 2, и результат затем записывается в другую переменную С. Г* Ьазг.с "Г ()1пс1ибе <еебьо.Ь> ьпе шаьп(ьпг агдс,сЬаг *агат!)) ( 1пе а = ав; 1пг Ьг аеш("шол1 эк1,эйкеах) вЬг ЪЪеах; шот1 ЪЪеах,экв;" и "=г" (Ы :"г"(а) :"Ъеах")) ргьпгг("а=эыт Ь=эы(Хп",а,Ы ; гегигп(0)1 ) Конструкция авт — нечто большее, чем просто удобный способ вставки ассемблерного кода.
Она позволяет использовать синтаксис языка Сдля обращения к переменным. Кроме того, она дает возможность передавать управляющую информацию на этапах генерации кода и сто дальнейшей оптимизации. Таким образом, вы можете генерировать эффективный код, который учитывает ваши особые требования к оптимизации программы. Синтаксис конструкции авт имеет следующий формат: аеш( "шаблон кода на ассемблере" список выходных операндов список входных операндов список исполвэуеных регистров); При желании предотвратить попытки компилятора оптимизировать ассемблерный код следует воспользоваться ключевым словом ыо1ае11е.
Примерно так; аеш ло1аг11е ( Для обеспечения совместимости с РОЯ(Х можно использовать ает н зго1ас11е вместо ключевых слов ает и то1ас11е. Шаблоны ассемблерного кода Шаблон ассемблерного кода состоит из одного или более операторов на языке ассемблера и представляет собой действующий код, непосредственно подстанавливаемый компилятором в объектный модуль.
Инструкции могут адресоваться: к непосредственно разрешаемым значениям (константам); к содержимому регистров; к расположениям в памяти. Далее следуют синтаксические правила, которые применяются к адресуемым величинам: Глава 15. Ассемблер бк)[) 283 ° Перед именем регистра ставятся два знака процента — "твгв". Например, етвевх или твЪев1. Имена регистров процессоров )п(е! начинаются со знака "Ъ", а применение второго знака "Ъ" требуют правила конструкции ввв), так что в нашем случае их должно быть два. ° Адресуемым расположением данных в памяти является один из входных нли выходных операндов. Каждый из них указывается порядковым индексом, соответсвующим его положению в строке объявления.
Первый входной операнд адресуется в шаблоне кода сочетанием тво, второй входной операнд — е1 и тд. Индексы выходных операндов продолжают эту нумерацию. Например, при наличии двух входных операндов первый выходной операнд в шаблоне будет адресован как тв2.
° Расположение в памяти может быть указано его адресом, записанным в регистре процессора. В этом случае имя регистра заключается в круглые скобки. Например, нужно загрузить в регистр т)еа1 один байт из ячейки памяти, адресом которой являешься число, записанное в регистре Ьаевй. Инструкцию для этого действия можно записать так: вючЬ (~Фаев1),Ъжа1 ° Непосредственное значение (константа) обозначается знаком доллара "Ф", сразу за которым следует само число. Например: $8б или $0ху12А.
° Весь фрагмент ассемблерного кода является одной буквенной строкой (с))агас(ег ыппй). Поэтому каждая строка вставляемого кода должна заканчиваться терминатором — символом перехода на следующую строку. В качестве терминатора можно использовать наклонную черту "1 (зеппсо)оп) нли езсаре-последовательность перехода на следующую строку — "),и". Для улучшения читаемости кода допускается вставка символов табуляции (габз). Входные и выходные операнды Входные и выходные операнды состоят из списка переменных, которые должны быть доступными для адресации из вашего ассемблерного кода.
Для указания адреса памяти можно использовать любые выражения языка С, определяемые как адрес расположения. Следующий пример программы — вариация на тему предыдущего. Эта программа удваивает числа, сдвигая влево их двоичное представление, и использует массив для хранения входных и выходных величин. /* доивье.с */ $1пс1иое <вгсьо.Ь> 1пг ва1п(1пс егяс,спег *агяч[)) ( тпс аггеу[2]) агтау[0) = 150) 1пе 1 = 0) ввп( чвоч1 Ъ1,чжеех) вЬ1 '-Фьеск) вюч1 вЪевх,ЪО)" :"=г"(агтау[1+1)) 284 Часть )и. Внутренняя структура и окружение ь"х"(актау[1]) ь"ььеах")) Рк1пск ("аххау[о] =тьь] аххау[1] =ть(]хп",актау [о],актау[1] )) кееикп(О)) Далее приводятся правила синтаксиса, ьоторые применяются к входным и выходным операндам: Выражение языка С, указывающее на адрес данных программы, должно быть заключено в круглые скобки.
Если перед указываемыми расположениями ставится признак ограничения (сола[галл) "х", то он означает, что данные должны быть загружены из входных переменных в свободные регистры до выполнения ассемблерного кода. Применяется во входных операндах. В выходных операндах соответственно применяется пркзкях отракичеккя " с" — ок указывает„что зкачеккя ъ выходные переменные должны быть записаны после выполнения ассемблерного кода. Признак ограничения может указывать назначение для переменных С определенных регистров; "а" ЪЪеах ")ь" яЪе]ьх " с " аььесх "д" тьЪеь]х "в" тьььев1 "ь]" ььЯеь]1 Переменные могут быть адресованы из ассемблерного кода своим адресом памяти без их загрузки в регистры процессора, для этого ставится признак ограничения (сопмга[п() "аь".
Одна и та же переменная может использоваться и для ввода входного значения, и для вывода результата. При этом для этой переменной в выходном операнде применяется признах ограничения (сопя[та[в() "=а", а во входном операнде в признаке ограничения ставится его порядковый индекс. В следующем примере переменная из кода на языке С соипсег используется как для ввода, так и для вывода: ава("1псн ььеь" ь"=а"(соппеек) ь"о"(соисеех))ь Возможно использование любого количества входных и выходных операндов.
В списке они разделяются запятыми. Все выходные и, затем, входные операнды нумеруются последовательно от зо до йп-1, где и — общеее число всех входных и выходных операндов. Например, если операндов в конструкции всего 6, то последний будет иметь адресуемое из ассемблерного кода имя 95. Глава 15. Ассемблер 6(ЧО 285 Список используемых регистров Список регистров, задействованных в ассемблерном коде, (с)оЬЬегег) геяЫегз)— это просто список имен регистров. Между именами ставится запятая. Например: авв( :"айвах", "Ъевг")г Информация о регистрах передается компилятору.
Благодаря этому исключаются ошибки, связанные с использованием этих регистров. Директивы ассемблера бй0 Основным назначением ассемблера является перевод мнемонических инструкций ассемблерного языка (гппепюпгс орсона) в двоичные машинные команды (Ь1пагу орсодез), которые уже могут непосредственно выполняться аппаратной частью или использоваться для хранения данных. В дополнение к этому ассемблер способен воспринимать и обрабатывать директивы ассемблера (аззетЫег б1гесг!тех). Они могут использоваться для применения выравнивания к адресам инструкций, определения макрорасширений, разбиения кода на именованные разделы, объявления именованных констант, обеспечения условного ассемблирования или как упрощенный способ определения данных.
Дальше приводится список директив ассемблера ОЬ) (). Каждая директива нач инается с точки. Некоторые директивы применяются сами по себе. Другие имеют параметры, которые должны стоять в одной строке с именем директивы. И некоторые из директив могут содержать блок ассемблерного кода до соответствующей им закрывающей этот блок директивы. Некоторые из директив, в частности, те, которые используются для размещения отладочной информации в объектном коде, применяются только к одному или к нескольким форматам объектных файлов.
Некоторые из директив распознаются ассемблером, но не вызывают никаких действий. В эту категорию скоро должна войти директива . аьохс. Она пока еще служит для отмены ассемблирования, но в следующей версии она уже не будет поддерживаться. Такиедирективы, как .111в, .арр-й11е, .ехсегп, .1бепс и .1Е1адв, распознаются ассемблером, но никаких действий по ним не предпринимается. Некоторые директивы могут иногда странно себя вести. Применение таких директив связано с историей.
Некоторые устаревшие решения продолжают поддерживаться многими ассемблерами в целях обеспечения переносимости существующих программ. О таких директивах нельзя сказать, что онн бесполезны,— просто при некоторых условиях на более новых платформах они могут вызывать непредсказуемые явления. Примером такой директивы в предлагаемом списке может служить . б111. Многие директивы из списка используют или объявляют программные символы. Скввалом в этом контексте называется имя, имеющее связанные с ннм атрибуты та1пе (значение адреса) и туре (тип).
Значением атрибута ча1пе может быть как абсолютная, так и относительная адресная величина. Атрибут курв определяет размер и способ использования адресуемых данных. 286 Часть |и. Внутренняя структура н окружение .а! 1дп Ьоипс!агу 1, гд!ег] 1,тах!тит] Заполняет нужное количество байт значением Г111егдля применения заданного в поле Ьоцпеуагу выравнивания адреса инструкции, следующей за этой директивой.