Ассемблерні вставки в GCC (3 стр.)
Замість ключового слова asm можна також використовувати __asm__ (подвійні підкреслення). Деякі джерела рекомендують використовувати саме __asm__ (asm є (для C) розширенням GNU, і в режимі -ansi, та/або суворої відповідності стандартам (опції виду -std= ) може викликати попередження/помилки компіляції), зокрема Linux kernel використовує саме цю запис.
Існують 2 форми асемблерних вставок: базова та розширена. Всі приклади вище за текстом використовували базову форму.
За замовчуванням, компілятор сприймає асемблерну вставку, що робитьобчислення, і оптимізатор виходить з цього припущення (зокрема, може вважати асемблерну вставку чистою функцією від вхідних операндів і, наприклад, перенести або винести назовні циклу). Це може призвести до неправильної роботи, якщо асемблерна вставка містить побічні ефекти. Для того, щоб вимкнути відповідні оптимізації, можна за asm вказати ключове слово volatile (або __volatile__). Базова форма завжди є volatile (але явна вказівка volatile все одно допустимо). Цитата з документації ( https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile ), що описує (досить ухильно) семантику volatile:
Рекомендується по можливості уникати volatile асемблерних вставок (зокрема - базової форми асемблера), і не перешкоджати нормальній роботі оптимізатора.
Базова форма
У базовій формі AssemblerInstructions вставляються у вихідний файл на асемблері так, без макропідстановок.
У базовій формі відсутні операнди (що дозволяють задати зв'язки із змінними C++), що помітно ускладнює надійну взаємодію з кодом на C++. Крім того (знову ж таки через відсутність операндів) компілятор виходить зприпущення, що базова асемблерна вставка не змінює значення пам'яті, ні регістрів.
Як зазначалося вище, оптимізатор має право викидати/переміщати/дублювати асемблерні вставки. У загальному випадку, згідно з документацією, volatile не дає гарантій проти цієї поведінки. Зокрема немає гарантій відносного порядку прямування команд. Якщо така потрібна, рекомендується використовувати одну загальну асемблерну вставку з кількома інструкціями.
Таким чином, базова форма може бути використана для команд, цінних в основному своїми побічними ефектами, на кшталт
Однак іноді базової форми немає альтернативи: 1. Використання асемблерних вставок на верхньому рівні одиниці трансляції (розширена форма має знаходитися всередині тіла функції). Це може бути використане для встановлення директив асемблера. 2. Використання функції з атрибутом naked (див. https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#Function-Attributes ).
По можливості, рекомендується використовувати розширену форму.
Розширена форма
goto-версія може виконувати перехід на одну з міток (визначених у коді C/C++), зазначених у GotoLabels. Вона не містить OutputOperands, і автоматично є volatile навіть без явної вказівки. Якщо є необхідність змінити змінну всередині goto-вставки, то можна (внаслідок відсутності OutputOperands) скористатися записом на згадку, повідомивши про це компілятор, вказавши "memory" в clobbers. Переходи між різними асемблерними вставками заборонені. Переходи всередині однієї асемблерної вставки не вимагають goto-версії і розглянуті нижче.
AssemblerTemplate - це рядок, який вставляється у вихідний асемблерний файл. Але, на відміну від базової форми, компілятор виробляєній макропідстановки. Макропідстановки використовують символ "%". Крім імен, зіставлених операндам, доступні: %% - генерує одинарний символ % (екранування символу %) %= - генерує унікальне ціле число (корисно для створення унікальних ідентифікаторів) %< - Створює символ < % - генерує символ %> - Створює символ >
OutputOperands, InputOperands, Clobbers задають операнди асемблерної вставки. Сумарна кількість операндів обмежена 30.
OutputOperands
InputOperands
Зауважте, що цей ковзар не дає змогипроцесорз особливих reads past the asm statement. Для того, щоб допомогти вам, потрібний процесор-спеціальний відсоток інструкцій.
GotoLabels
Constraints
Цей номер є дозволено більше, ніж один цифровий. Якщо багаторазові digits є сконцентрованими послідовно, вони є interpreted as single decimal integer. Там є шпилька зміна для ambiguity, тому що він не повинен бути забруднювачем, що '10' може бути interpreted як виконаний 1 operand 1or0 operand.
Це називаєтьсязахоплюючий бікі що це реально рішення є те, що assembler має тільки один operand, що хлопці дві дії, які є різними. Для прикладу, для подальшої інструкції використовує два запуску операційних систем і для запуску операційної системи, але на most CISC machines an add instruction дійсно має тільки двох зоопархів, один з них за допомогою запуску операційної системи: addl #35,r12
Matching constraints є використані в цих circumstances. Більше того, двома учасниками, що матч повинен включати один вхідний-завжди працюючий і один output-тільки-завдання. Більше, digit повинен бути smaller number than the number of the operand that uses it in theобмеження.
«&» застосовується лише до альтернативи, у якій він написаний. У обмеженнях із декількома альтернативами інколи одна альтернатива потребує «&», а інша — ні. Дивіться, наприклад, insn «movdf» 68000.
Операнд, який зчитується інструкцією, може бути прив’язаний до раннього операнда, якщо його єдине використання як введення відбувається до запису раннього результату. Додавання альтернатив цієї форми часто дозволяє GCC виробляти кращий код, коли тільки деякі з прочитаних операндів можуть постраждати від раннього перемикання. Дивіться, наприклад, «mulsi3» insn ARM.
Крім того, якщо операнд earlyclobber також є операндом читання/запису, тоді цей операнд записується лише після його використання.
«&» не позбавляє необхідності писати «=» або «+». Оскільки операнди раннього клоберу завжди записуються, операнд раннього клоберу, призначений лише для читання, є неправильно сформованим і буде відхилений компілятором.
Модифікатор = або + обов'язковий для OutputOperands.