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...5170 
 Trees...940 
 Максвелл 3...871 
 Go Web ...823 
 William Gropp...803 
 Ethreal 3...787 
 Gary V.Vaughan-> Libtool...773 
 Ethreal 4...771 
 Rodriguez 6...764 
 Ext4 FS...755 
 Clickhouse...754 
 Steve Pate 1...754 
 Ethreal 1...742 
 Secure Programming for Li...732 
 C++ Patterns 3...716 
 Ulrich Drepper...696 
 Assembler...695 
 DevFS...662 
 Стивенс 9...649 
 MySQL & PosgreSQL...632 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org
Все материалы взяты с сайта OS-FAQ

Inline Assembly

Синтаксис

Ниже показан прототип для вызова asm() из C/C++ :

  asm ( assembler template
       : output operands                   (optional)
       : input operands                    (optional)
       : clobbered registers list          (optional)
       );

Example:

  asm ("addl %1,%0" : "=g"(x) : "g"(y));
   // то же самое , что и :  "x+=y"

Assembler Template

Мы используем синтаксис AT&T. Пример :

    asm( "hlt" ); /* halts the CPU */

Output Operands

Output Operands говорят компилятору , куда положить результат инструкции. Output Operands состоит из 2-х частей,первая часть - строковое обозначение регистра, вторая часть - С-переменная в скобках.

Используемые регистры для output - EAX, EBX,ECX,EDX,ESI,EDI, Знак равенства говорит о том , что это output operand.

    int EAX;
     asm( "movl $0, %%eax" : "=a" (EAX) ); /* pathetic way of EAX = 0; */

Можно явно не указывать регистр и вместо него прописывать r - компилятор сам справится с задачей выбора регистра:

   int current_task;
    asm( "ltr %0" : "=r" (current_task) );

Использование %0, %1 расставляет порядок в использовании операндов.

Вместо такой нумерации можно явно прописывать имя переменной :

    int current_task;
     asm( "ltr %[output]" : [output] "=r" (current_task) );

Такую нотацию можно использовать как для операндов output , так и input .


Input Operands

Input Operands позволяют параметризировать ASM-код; т.е. передавать чисто сишные переменные внутрь АСМ-кода.

   // следующая конструкция бесполезна , ибо мы не знаем значений  EDI, ECX и AL ...
    asm( "cld; rep; stosb" );
 
    // корректно , но несколько сложновато :
    asm( "movl %0, %%edi; movl %1, %%ecx; movb %2, %%al; cld; rep; stosb"
        : : "g"(dest),"g"(amount),"g"(value));
 
    // более компактно
    // Мы пишем в память , адрес которой находится в переменной dest , значение value
    // столько раз , сколько это указано в переменной amount
    asm( "cld; rep; stosb" : : "D" (dest), "c" (amount), "a" (value) );

Подразумевается , что входящие параметры - read-only .


Clobbered Registers List

Важно помнить о следующем : компилятор ничего не знает об Assembler. Если в инлайн-конструкции будет отсутствовать output , компилятор может такую строку интерпретировать как угодно или сделать произвольную оптимизацию . . Этого можно избежать еще одним способом - asm volatile.

Нужно позаботиться также о том , чтобы сохранить значения регистров перед тем , как вы будете делать свой собственный асм-вызов .

Clobbered Registers List - список регистров , разделенных запятыми.

Не нужно сильно утруждаться по поводу выбора регистров - компилятор может сделать это сам . .

"movl $0, %0" : "=g" (x) x может быть чем угодно - компилятор может выбрать регистр , а может и память

Отличия At&t синтаксиса от Nasm


Кстати сказать , AT&T синтаксис является стандартом для большинства не-интеловских платформ . В нем есть инструмент - objdump , который позволяет использовать дебаг.

А теперь несколько существенных отличий AT&T синтаксиса от Intel sytnax, :

  • case sensitive. "MOVL" и "movl" вообще говоря разные вещи :-).
  • numerical base - такая же как и в C: 1 - десятичная система, 01 - 8-ричная, 0x01 - 16-ричная.
  • escapes. Спец-символы - также в стиле C-style (\n, \", \#, \\, ...).
  • comments - 2 варианта - либо C-style ("/* ... */") , либо shell style ("#").
  • directives - вначале идет точка (".align 4" - выравнивание на двойное слово, ".word 0x1234" - то же что и "DW 1234h").
  • strings - определяются с помощью 2-х директив ".ascii" и ".asciz" (с последующим добавлением '\0' конец). Example: msg: .ascii "Hello, World!\n"
  • current location address - обозначается точкой (".", равно Intel syntax "$").
  • initializing memory - .fill (почти то же что и Intel syntax 'times db').
    Пример: .fill 0x1fe - (. - START) , 1, 0 ('1' - размер маски в байтах , START - стартовая метка) , это то же что и Intel syntax times 1FEh - ($-$$) db 0.
  • code counter - может устанавливаться много раз, используяu .org директиву (типа .org 0x1fe + START, где START - стартовая метка.
  • 16/32 bit code генерится с помощью .code16 либо .code32 (равно Intel syntax [BITS 16] и [BITS 32]).
  • target CPU - устанавливается с помощью .arch директивы.
  • label declarations оканчиваются двоеточием
  • new identifier в начале строки должен оканчиваться знаком "равно" и значением , например : FOO = 0xF00
  • end of instruction - новая строка либо точка с запятой
  • line continuation - как и в с строка продолжается с помощью ('\')
  • registers - идут с префиксом процента: %eax, %cs, %esp, etc.
  • source, destination: move, load, store, и другие похожие операции всегда подразумевают наличие 'source, destination'. "movl %eax, %ebx" копирует %eax в %ebx. Может и непривычно - кому как .
  • operand size suffixes - добавляется в виде символа в конце инструкцуии : movb для "move byte", movw для "move word", movl для "move long", etc.
  • direct-address operands не имеют префикса. Так, "movl foo, %eax" копирует "foo" в %eax.
  • immediate operands - имеют префикс доллара ($): "pushl $4" . Доллар добавляется к метке в случае: "movl $foo, %eax" копирует значение метки foo в %eax.
  • indexed / indirect operands - используются в формате segment:displacement (base, index, scale), так: movl %eax, %ss:8(%ebp, 2, 3) (то же что и Intel syntax mov dword [ss:ebp + 2 * 3 + 8], eax, копирует значение %eax по смещению (%ebp + (2 *3) + 8) в сегменте %ss).
  • relative (short addressing) - используется для jump и call инструкций. Для использования (near) -адресации, операнд должен иметь префикс (*).
  • far jumps / calls / returns для этого есть специальные инструкции 'ljmp', 'lcall' и 'lret' .

Macros

Встроенные макросы имеют синтаксис :

.macro <name> <args>
 <operations>
 .endm

Пример:

.macro write string
    movw string, %si
    call printstr
 .endm

Что эквивалентно NASM macro:

%macro write 1
    mov si, %1
    call printstr
 %endmacro

Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье