Kod assemblera 'w linii' kodu języka C
Ponieważ stosunkowo często zdarzają się sytuację, kiedy należy wykonać pojedyncze instrukcje w języku assemblera, dla których nie ma sensu tworzyć oddzielnego pliku, projektanci kompilatora GCC zaimplementowali możliwość wykonywania instrukcji procesora bezpośrednio w kodzie programu. Ta opcja jest też przydatna, gdy zależy nam na szybkiemu wykonaniu danych instrukcji (nie ma potrzeby wywoływania innej procedury instrukcją CALL ).
Kompilator GNU C dla instrukcji assemblera korzysta z notacji wprowadzonej przez firmę AT&T, która dość znacznie różni się od zalecanej przez firmę Intel. Różnice te są pokazane w tabeli.
Format przykładowej instrukcji assemblera 'w linii' języka C ma następującą postać:
Jeżeli symbol asm jest używany w programie w innym celu, to do oznaczenia instrukcji assemblerowej możemy wykorzystać symbol __asm__. Jeżeli mamy więcej niż jedna instrukcję w kodzie niskiego poziomu, możemy ją napisać w ramach jednej dyrektywy kończąc każdą linię znakami '\n' i '\t'. Jest to wynikiem tego, że każdy ciąg znaków umieszczony w dyrektywie asm jest wysyłany do programu assemblera pośrednio poprzez tworzony na bieżąco plik a następnie przeprowadzana jest assemblacja. Znaki te powodują odpowiednie sformatowanie pliku wejściowego dla assemblera.
Różnice w notacji | Przykład | |
Intel | AT&T | |
Kolejność operandów źródło - przeznaczenie | mov eax, 1 | movl $1, %eax |
Nazwa rejestrów z/bez znaku % | eax | %eax |
Nazwa mnemonika zależy/nie zależy od wielkości argumentu; dodatkowe dyrektywy | mov al, byte ptr foo | movb foo, %al |
Nawias adresu bazowego | [ecx] | (%ecx) |
Adresowanie skalowane bazowo-indeksowe | sub eax, [ebx+ecx*0x4-0x20] | subl -0x20(%ebx,%ecx,0x4), %eax |
Kompilator GCC umożliwia również zastosowanie bardziej złożonego formatu instrukcji assemblera, w której mamy możliwość określenia rejestrów jakie mają być użyte w tej instrukcji, przypisania im wartości stałej bądź zmiennej występującej w języku wysokiego poziomu, przypisaniu wyjścia instrukcji zmiennej wysokiego poziomu, oraz określenia których rejestrów kompilator ma nie używać, gdyż zostały one zajęte przez programistę.
Przykład rozszerzonej instrukcji assemblera 'w linii' języka C ma postać:
W tym przypadku argumenty %1, %2, %0 (maksymalnie %9) oznaczają poszczególne zmienne języka wysokiego poziomu. Odpowiednikiem powyższej instrukcji jest program:
Każde wejście i wyjście instrukcji assemblera składa się z dwóch części: deklaracyjnej oraz z wyrażenia. Wyrażenie jest to po prostu wyrażenie w języku wysokiego poziomu, umieszczone w nawiasach okrągłych ,oznaczające określoną zmienną, bądź też jej wartość.
Część deklaracyjna składa się ze znaku umieszczonego w cudzysłowu określającego jakie rejestry mają być użyte do wygenerowania instrukcji oraz czy instrukcja ma się odnosić do rejestru czy pamięci. W przypadku wejścia instrukcji część deklaracyjna zawiera też znak równości '='.