Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...5164 
 Trees...935 
 Максвелл 3...861 
 Go Web ...814 
 William Gropp...794 
 Ethreal 3...779 
 Ethreal 4...766 
 Gary V.Vaughan-> Libtool...764 
 Rodriguez 6...755 
 Clickhouse...748 
 Steve Pate 1...748 
 Ext4 FS...748 
 Ethreal 1...736 
 Secure Programming for Li...718 
 C++ Patterns 3...711 
 Ulrich Drepper...692 
 Assembler...686 
 DevFS...654 
 Стивенс 9...644 
 MySQL & PosgreSQL...621 
 
  01.01.2024 : 3621733 посещений 

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