Поиск…


замечания

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

Pros

  1. Производительность. Написав конкретные инструкции по сборке для операции, вы можете добиться большей производительности, чем код сборки, сгенерированный компилятором. Обратите внимание, что эти приросты производительности редки. В большинстве случаев вы можете добиться повышения производительности, просто переставив свой код C, чтобы оптимизатор мог выполнять свою работу.
  2. Аппаратный интерфейс Драйвер устройства или код запуска процессора может потребоваться некоторый код сборки для доступа к правильным регистрам и гарантировать, что определенные операции выполняются в определенном порядке с определенной задержкой между операциями.

Cons

  1. Синтаксис компилятора для встроенной сборки не гарантируется одинаковым от одного компилятора к другому. Если вы пишете код с встроенной сборкой, которая должна поддерживаться разными компиляторами, используйте макросы препроцессора ( #ifdef ), чтобы проверить, какой компилятор используется. Затем напишите отдельный сборный раздел для каждого поддерживаемого компилятора.
  2. Переносимость процессора. Вы не можете писать встроенную сборку для процессора x86 и ожидать, что она будет работать на процессоре ARM. Встроенная сборка предназначена для записи для конкретного семейства процессоров или процессоров. Если у вас встроенная сборка, которую вы хотите поддерживать на разных процессорах, используйте макросы препроцессора, чтобы проверить, на какой процессор компилируется код, и выбрать соответствующий раздел кода сборки.
  3. Будущие изменения производительности Встраиваемая сборка может быть написана в ожидании задержек на основе определенной тактовой частоты процессора. Если программа скомпилирована для процессора с более быстрыми часами, код сборки может работать не так, как ожидалось.

Поддержка gcc Basic asm

Базовая поддержка сборки с gcc имеет следующий синтаксис:

asm [ volatile ] ( AssemblerInstructions )

где AssemblerInstructions - это код прямой сборки для данного процессора. Ключевое слово volatile является необязательным и не имеет никакого эффекта, поскольку gcc не оптимизирует код в базовом выражении asm. AssemblerInstructions может содержать несколько инструкций по сборке. Базовый оператор asm используется, если у вас есть asm-процедура, которая должна существовать вне функции C. Следующий пример приведен в руководстве GCC:

 /* Note that this code will not compile with -masm=intel */
 #define DebugBreak() asm("int $3")

В этом примере вы могли бы использовать DebugBreak() в других местах вашего кода, и он выполнит команду сборки int $3 . Обратите внимание, что даже если gcc не будет изменять какой-либо код в базовом выражении asm, оптимизатор может по-прежнему перемещать последовательные операторы asm. Если у вас есть несколько инструкций по сборке, которые должны выполняться в определенном порядке, включите их в один оператор asm.

Поддержка gcc Extended asm

Расширенная поддержка asm в gcc имеет следующий синтаксис:

asm [volatile] ( AssemblerTemplate
                  : OutputOperands
                  [ : InputOperands
                  [ : Clobbers ] ])
 
 asm [volatile] goto ( AssemblerTemplate
                       :
                       : InputOperands
                       : Clobbers
                       : GotoLabels)

где AssemblerTemplate является шаблоном для команды ассемблера, OutputOperands - это любые переменные C, которые могут быть изменены кодом сборки, InputOperands - это любые переменные C, используемые в качестве входных параметров, Clobbers - это список или регистры, которые изменены кодом сборки, и GotoLabels - любые метки операторов goto, которые могут использоваться в коде сборки.

Расширенный формат используется в функциях C и является более типичным использованием встроенной сборки. Ниже приведен пример ядра Linux для байтового обмена 16-битными и 32-разрядными номерами для ARM-процессора:

/* From arch/arm/include/asm/swab.h in Linux kernel version 4.6.4 */
#if __LINUX_ARM_ARCH__ >= 6

static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
{
    __asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
    return x;
}
#define __arch_swahb32 __arch_swahb32
#define __arch_swab16(x) ((__u16)__arch_swahb32(x))

static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
    __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
    return x;
}
#define __arch_swab32 __arch_swab32

#endif

Каждая секция asm использует переменную x качестве ее входного и выходного параметров. Затем функция C возвращает обработанный результат.

В расширенном формате asm gcc может оптимизировать инструкции сборки в блоке asm, следуя тем же правилам, которые он использует для оптимизации кода C. Если вы хотите, чтобы ваш раздел asm остался нетронутым, используйте ключевое слово volatile для раздела asm.

gcc Встроенная сборка в макросах

Мы можем поместить инструкции сборки внутри макроса и использовать макрос, как вы бы назвали функцию.

#define mov(x,y) \
{ \
    __asm__ ("l.cmov %0,%1,%2" : "=r" (x) : "r" (y), "r" (0x0000000F)); \
}

/// some definition and assignment
unsigned char sbox[size][size];
unsigned char sbox[size][size];

///Using
mov(state[0][1], sbox[si][sj]);

Использование встроенных команд сборки, встроенных в код C, может улучшить время работы программы. Это очень полезно в критичных по времени ситуациях, таких как криптографические алгоритмы, такие как AES. Например, для простой операции сдвига, которая необходима в алгоритме AES, мы можем заменить прямую инструкцию по Rotate Right с помощью оператора сдвига С >> .

В реализации «AES256» в функции «AddRoundKey ()» мы имеем следующие утверждения:

unsigned int w;          // 32-bit
unsigned char subkey[4]; // 8-bit, 4*8 = 32 

subkey[0] = w >> 24;     // hold 8 bit, MSB, leftmost group of 8-bits 
subkey[1] = w >> 16;     // hold 8 bit, second group of 8-bit from left    
subkey[2] = w >> 8;      // hold 8 bit, second group of 8-bit from right
subkey[3] = w;           // hold 8 bit, LSB, rightmost group of 8-bits

/// subkey <- w

Они просто присваивают значение бит w массиву subkey .

Мы можем изменить три смещения + присваивать и назначить выражение C только с одной командой « Rotate Right .

__asm__ ("l.ror  %0,%1,%2" : "=r" (* (unsigned int *) subkey)  : "r" (w), "r" (0x10));

Конечный результат точно такой же.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow