Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org

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