GCC Inline Asm
GNU C Compiler использует inline asm AT&T syntax.
Регистры используются с префиксом `%', переменные с префиксом `$'.
К операндам добавляются окончания ('b' для byte, 'w' для word, 'l' для long word).
В inline asm можно операнды выражать через си-префикс , например :
asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));
angle - входящий параметр
result - выходящий
Символ '=' в операнде '=f' говорит о том , что он выходящий .
Все выходящие параметры должны иметь префикс '='.
Операнды разделяются двоеточием , максимальное их количество = 10 .
В следующем примере bar - входящий параметр , foo - исходящий ,
asm ("combine %2,%0":"=r"(foo):"0" (foo),"g"(bar));
Число "0" указывает на то , что выходящий параметр стоит на втором месте в списке параметров функции .
Следующая команда загружает значение статической переменной $good в регистр ebx :
movl $good, %ebx Intel
Для расширенного варианта inline assembly базовый формат выглядит так :
asm("statements":output_registers:input_registers:clobbered_registers);
Рассмотрим пример :
asm ("cld\n\t" "rep\n\t" "stosl":/* no output registers */:"c"(count)
,"a"(fill_value), "D" (dest): "%ecx", "%edi" );
Команда asm ("cld\n\t" "rep\n\t" "stosl" очищает флаговый регистр .
При этом в регистре ecx находится содержимое переменной count , в регистре eax находится содержимое переменной fill_value ,
и в регистре edi - содержимое переменной dest .
Таблица условных сокращений для регистров :
a - eax
b - ebx
c - ecx
d - edx
S - esi
D - edi
I - constant value (0 to 31)
q,r - динамически выделяемый регистр
Следующий пример asm ("leal (%1,%1,4), %0" : "=r" (x) : "0" (x) );
умножает переменную x на 5 .
Префикс "=q" означает загрузку из регистров eax,ebx,ecx,edx .
Префикс "=r" означает загрузку из регистров esi,edi .
Одну и ту же задачу можно выполнить разными путями :
asm ("leal (%1,%1,4), %0" : "=r" (x_times_5) : "r" (x) );
asm ("leal (%0,%0,4), %0" : "=r" (x) : "0" (x) );
asm ("leal (%%ebx,%%ebx,4), %%ebx" : "=b" (x) : "b" (x) );
Если нужно , чтобы асм-выражение не попало под асм-оптимизацию , нужно использовать префикс
__asm__ __volatile__ (...whatever...);
Несколько примеров :
#define times3(arg1, arg2) \
__asm__ ( \
"leal (%0,%0,2),%0" \
: "=r" (arg2) \
: "0" (arg1) );
#define times5(arg1, arg2) \
__asm__ ( \
"leal (%0,%0,4),%0" \
: "=r" (arg2) \
"0" (arg1) );
#define times9(arg1, arg2) \
__asm__ ( \
"leal (%0,%0,8),%0" \
: "=r" (arg2) \
: "0" (arg1) );
Вызов times5(x,x); приводит к перемножению аргументов , результат сохранен в arg2 .
Cледующий пример - эквивалент функции memcpy():
#define rep_movsl(src, dest, numwords) \
__asm__ __volatile__ ( \
"cld\n\t" \
"rep\n\t" \
"movsl" \
: : "S" (src), "D" (dest), "c" (numwords) \
: "%ecx", "%esi", "%edi" )
Эквивалент memset()
#define RDTSC(llptr) ({ \
__asm__ __volatile__ ( \
".byte 0x0f; .byte 0x31" \
: "=A" (llptr) \
: : "eax", "edx"); })
Следующий пример
asm("foo %1,%0"
: "=r" (output)
: "r" (input1), "0" (input2));
показывает , что второй входящий параметр лежит по тому же адресу , что и выходящий .
В любой инструкции source на первом месте и destination на втором :
mov %eax, %ebx
Ссылка на память типа Indirect memory использует префикс () - следующий пример копирует байт из ячейки памяти,
адрес которой лежит в esi , в регистр al :
movb (%esi), %al
GCC имеет специальный шаблон для inline asm :
asm ( assembler template
: output operands (optional)
: input operands (optional)
: list of clobbered registers (optional)
);
Входящие и выходящие параметры могут быть си-выражениями .
Префикс "m" можно использовать для прямого хранения си-переменных в памяти без использования
регистровых операций - например значение idtr хранится в переменной loc напрямую :
asm ("sidt %0\n" : :"m"(loc));
Один регистр может быть одновременно хранилищем как входящего,так и выходящего параметра :
asm ("incl %0" :"=a"(var):"0"(var));
register constraint "r"
Рассмотрим пример :
int main(void)
{
int x = 10, y;
asm ("movl %1, %%eax;
"movl %%eax, %0;"
:"=r"(y) /* y is output operand */
:"r"(x) /* x is input operand */
:"%eax"); /* %eax is clobbered register */
}
Будет сгенерирован следующий код :
main:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl $10,-4(%ebp)
movl -4(%ebp),%edx /* x=10 is stored in %edx */
#APP /* asm starts here */
movl %edx, %eax /* x is moved to %eax */
movl %eax, %edx /* y is allocated in edx and updated */
#NO_APP /* asm ends here */
movl %edx,-8(%ebp) /* value of y in stack is updated with
the value in %edx */
В нашем случае gcc произвольно выбирает edx для хранения x , после чего сохраняет x в стеке и сохраняет
в edx y .
В следующем примере входящий параметр - переменная op - передается в eax и получаем 4 выходных параметра
в %eax, %ebx, %ecx, %edx :
asm ("cpuid"
: "=a" (_eax),
"=b" (_ebx),
"=c" (_ecx),
"=d" (_edx)
: "a" (op));
Функция strcpy может быть интерпретирована так :
asm ("cld\n
rep\n
movsb"
: /* no input */
:"S"(src), "D"(dst), "c"(count));
Source-указатель положен в esi с использованием префикса src .
Следующий пример показывает системный вызов с 4 параметрами :
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4))); \
__syscall_return(type,__res); \
}
4 параметра ложатся в регистры %ebx, %ecx, %edx, and %esi с помощью констрэйтов b, c, d, and S.
Возвращаемое значение сохраняется в res .
Рассмотрим пример с копированием памяти :
asm ("movl $count, %%ecx;
up: lodsl;
stosl;
loop up;"
: /* no output */
:"S"(src), "D"(dst) /* input */
:"%ecx", "%eax" ); /* clobbered list */
В ecx загружается счетчик .
|
Digi | "4 параметра ложатся"
КЛАДУТСЯ!!!!!!!!!! ё-маё! 2017-10-05 09:58:00 | VAK | "Вызов times5(x,x); приводит к перемножению аргументов"
Как так?
Не понял: вроде множитель адресации 4, а дальше сложение с базой.
Почему параметры перемножаются?
Можт делов том, что параметры ссылаются на одну переменную?
Ятак понимаю, взяли переменную, умеожили на 5, результат вернули в туже переменную. Разве не так? 2017-12-22 09:29:58 | |
|