GCC Satıriçi Sembolik Makina Dili
Önceki Linux ile Sembolik Makina Dili Kullanımı Sonraki
GCC Satıriçi Sembolik Makina Dili
GCC satıriçi sembolik makina dili hakındaki bu bölüm sadece x86 uygulamalarını kapsayacaktır. Terimler diğer işlemcilerde farklılık göstereceklerdir. Başvurulabilecek diğer belgeler bu belgenin sonundadır.
GCC içerisinde temel sembolik makina dili sözdizimi oldukça açıktır. Temel sözdizimi ile aşağıdaki gibidir:
    __asm__("movl %esp,%eax");    // bildik görünüyor ?
veya
    __asm__
    ("
      movl $1,%eax                // SYS_exit
      xor  %ebx,%ebx
      int  $0x80
    ");
Sembolik makina dili için girdi ve çıktı olarak kullanılacak bilgilerin tanımlanması ile daha etkili bir kullanım mümkündür. Özel bir giriş/çıkış/değişiklik alanı zorunlu değildir. Kullanım şekli:
    __asm__("asm_deyimleri" : çıkış : giriş : değişiklik);
giriş ve çıkış alanları terim belirteçleri ile gösterilir ve parantez içinde gösterilen C değişkeni onu takip eder. çıkış teriminden önce, onun bir çıkış terimi olduğunu belirtmek için = kullanılmalıdır. Birden çok çıkış, giriş ve değişiklik yazmacı bulunabilir. Her bir "değer" virgül (',') ile birbirinden ayrılmalıdır ve toplamda 10'dan fazla değer girilmemelidir. Terim dizgesi ya yazmacın tam adını ya da kısaltmasını içermelidir.
Tablo 9.1. Kısaltma Tablosu
KısaltmaYazmaç
a%eax  %ax  %al
b%ebx  %bx  %bl
c%ecx  %cx  %cl
d%edx  %dx  %dl
S%esi  %si
D%edi  %di
mbellek (memory)
Örnek 9.5.
__asm__("test %%eax,%%eax", : /* çıktı yok */ : "a"(foo));
veya
__asm__("test %%eax,%%eax", : /* çıktı yok */ : "eax"(foo));
__asm__'den sonra __volatile__ komutunu kullanabilirsiniz:
" bir __asm__ komutunun silinmesini, taşınmasını ve birleştirilmesini __asm__ den sonra __volatile__ yazarak önleyebilirsiniz."
Örnek 9.6.
(Konsol komut satırından info gcc "C Extensions" "Extended Asm" yazarak erişilen "Assembler Instructions with C Expression Operands" sayfasından alınmıştır.)
$ cat inline1.c
#include <stdio.h>

int
main(void)
{
  int foo = 10, bar = 15;

  __asm__ __volatile__
    ("addl %%ebxx,%%eax"
      : "=eax"(foo)                            // çıktı
      : "eax"(foo), "ebx"(bar)                 // girdi
      : "eax"                                  // değişiklik
    );
  printf("foo + bar = %d\n", foo);

  return 0;
}
$
Yazmaçların % yerine %% ile öneklendirildiğini fark etmişsinizdir. Giriş/çıkış/değişiklik alanları kullanıldığında bu zorunludur çünkü genişletilmiş alanlara sahip yazmaçların kullanılması da olasıdır. Bunu daha sonra kısaca açıklayacağım.
"eax" yazmak veya "ax", "al" gibi özel bir yazmaç tanımlamak yerine sadece "a" yazabilirsiniz. Bu tüm genel amaçlı yazmaçlar için geçerlidir (Kısaltma tablosuna bakınız). Bu kullanım kod yazımında her zaman kullanışlı olmadığı için GCC size yazmaç kısaltmaları sağlar. Maksimum 10 (%0-%9) tane kısaltma olduğundan sadece 10 girdi/çıktı tanımlayabilirsiniz.
$ cat inline2.c
int
main(void)
{
  long eax;
  short bx;
  char cl;

  __asm__("nop;nop;nop"); // kodun geri kalanını satıriçi
                          // sembolik makina dilinden ayırmak için

  __volatile__ __asm__(" test %0,%0 test %1,%1 test %2,%2"
    : /* çıktı yok */
    : "a"((long)eax), "b"((short)bx), "c"((char)cl) );

   __asm__("nop;nop;nop");

   return 0;
}
$ gcc -o inline2 inline2.c
$ gdb ./inline2
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnulibc1"...
(no debugging symbols found)...
(gdb) disassemble main
Dump of assembler code for function main:
... start: inline asm ...
0x8048427: nop
0x8048428: nop
0x8048429: nop
0x804842a: mov 0xfffffffc(%ebp),%eax
0x804842d: mov 0xfffffffa(%ebp),%bx
0x8048431: mov 0xfffffff9(%ebp),%cl
0x8048434: test %eax,%eax
0x8048436: test %bx,%bx
0x8048439: test %cl,%cl
0x804843b: nop
0x804843c: nop
0x804843d: nop
... end: inline asm ...
End of assembler dump.
$
Gördüğünüz gibi, üretilen satıriçi sembolik makina dili kodu girdi bölümünde belirtilen değişkenlerin değerlerini yazmaçlara atar ve sonra gerçek kodu üretir. Derleyici, terim boylarını değişkenlerin boylarından yararlanarak otomatik olarak bulur ve böylece %0, %1 ve %2 kısaltmaları ile gösterilen yazmaçlar değerlerini alır. (Yazmaç kısaltmalarını kullanırken komut kısmında terim boyutunu belirtmek derleme sırasında hatalara neden olabilir).
Kısaltmalar terim belirteçlerinde de kullanılabilir. Bu işlem, yazılımcının 10'dan fazla girdi/çıktı tanımlaması yapmasına izin vermez. Bu işlemin aklıma gelen tek kullanım biçimi, terim belirteci olarak "q" kullanılan durumlardır. Terim belirteci olarak "q" kullanıldığı zaman derleyici kendisi a, b, c veya d'den uygun olanı seçer. Eğer yazmaç ataması "q" ile yapılmışsa hangi yazmacın kullanıldığını tahmin edemeyiz ve değişiklik alanıda belirtemeyiz, bu sebepten sadece yazmaç ile ilgili rakam yazılır. Örnek
$ cat inline3.c
#include <stdio.h>

int
main(void)
{
  long eax=1, ebx=2;

  __asm__ __volatile__ (
    "add %0,%2"
    : "=b"((long)ebx)
    : "a"((long)eax), "q"(ebx)
    : "2"
  );

  printf("ebx = %x\n", ebx);

  return 0;
}
$
Önceki Üst Ana Başlık Sonraki
Komut Satırı Argümanları Başlangıç Derleme
Bir Linux Kitaplığı Sayfası