Sistem Çağrıları
Önceki Linux ile Sembolik Makina Dili Kullanımı Sonraki
Sistem Çağrıları
Bu bölümde linux sistem çağrılarının sembolik makina dilinde kullanımını kısaca anlatılacaktır. Sistem çağrıları, /usr/man/man2 dizini altında bulunan kılavuz dosyalarındaki bütün işlevleri içerir. Ayrıca /usr/include/sys/syscall.h başlık dosyasında da listelenmişlerdir. Bu işlevlerin büyük bir listesi http://www.linuxassembly.org/syscall.html adresinde bulunabilir. Bu işlevler Linux int $0x80 ile de çalıştırılabilir.
Altıdan Az Argüman Alan Sistem Çağrıları
Tüm sistem çağrıları için sistem çağrı numarası %eax içine atılır. Altıdan az argüman alan sistem çağrıları için argümanlar sırasıyla %ebx, %ecx, %edx, %esi, %edi yazmaçlarına atılır. Sistem çağrısından dönen değer %eax içerisinde saklanır.
Sistem çağrı numarasına /usr/include/sys/syscall.h başlık dosyasından bakılabilir. Macrolar SYS_sistem_çağrısının_adı şeklinde ifade edilir , örneğin SYS_exit, SYS_close, vb.
Örnek 9.1. Hello world
/* write.s */

.data
  hello:
  .string "hello world\n"
.text
  .globl _start
_start:
  movl $SYS_write,%eax  // SYS_write = 4
  movl $STDOUT,%ebx     // fd = fileno(stdio)
  movl $hello,%ecx      // buf = str
  movl $12,%edx         // count = 0x6
  int  $0x80

  movl $SYS_exit
write(2) man sayfasına göre, write işlevi
    ssize_t write(int fd, const void *buf, size_t count)
şeklinde belirtilir.
Bundan dolayı fd %ebx içerisine, buf %ecx çerisine, buf %edx içerisine ve SYS_write da %eax içerisine atılır. Bu işlem sistem çağrısının çalıştırılması için bir int $0x80 yönergesi tarafından takip edilir. Sistem çağrısından geri dönen değer %eax içerisinde saklanır.
Aynı işlem beş argümandan az argümanı bulunan sistem çağrılarına uygulanabilir. Sadece kullanılmayan yazmaçlara dokunmayın. open veya fcntl gibi isteğe bağlı fazladan argüman bulunduran sistem çağrıları kendileri atama yaparlar.
Beşten Fazla Argüman Alan Sistem Çağrıları
Argüman sayısı beşten fazla olan sistem çağrılarında da yine sistem çağrı numarası %eax içerisine saklanır fakat argümalar bellekte tutulur ve ilk argümanı gösteren bir gösterici %ebx'e atılır.
Eğer yığıtı kullanıyorsanız parametreler yığıtın içerisine geriye doğru push edilmelidir, örneğin son parametreden ilkine doğru. Daha sonra yığıt gösterici %ebx taban yazmacı içerisine kopyalanmalıdır. Aksi taktirde parametreleri ayrılmış bir bellek alanına kopyalayın ve ilk parametrenin adresini %ebx içerisine koyun.
Örnek 9.2. sistem çağrısı mmap
/* mmap.s */

.data
  fd:
    .long 0
  fdlen:
    .long 0
  mappedptr:
    .long 0

.text
.globl _start
_start:
  subl $24,%esp

// open(file, O_RDONLY);
  movl $SYS_open,%eax
  movl 32(%esp),%ebx     // argv[1], %esp+8+24 de
  xorl %ecx,%ecx         // %ecx'i O_RDONLY, yani 0 yap
  int  $0x80

  test %eax,%eax         // dönen değer < 0 ise çık
  js   exit

  movl %eax,fd           // fd'i sakla

// lseek(fd,0,SEEK_END);
  movl %eax,%ebx
  xorl %ecx,%ecx         // göreli bellek konumunu sıfır yap
  movl $SEEK_END,%edx
  movl $SYS_lseek,%eax
  int   $0x80

  movl %eax,fdlen        // dosya uzunluğunu sakla

  xorl %edx,%edx

// mmap(NULL,fdlen,PROT_READ,MAP_SHARED,fd,0);
  movl %edx,(%esp)
  movl %eax,4(%esp)
  movl $PROT_READ,8(%esp)
  movl $MAP_SHARED,12(%esp)
  movl fd,%eax
  movl %eax,16(%esp)
  movl %edx,20(%esp)

  movl $SYS_mmap,%eax
  movl %esp,%ebx
  int  $0x80

  movl %eax,mappedptr    // göstericiyi sakla

// write(STDOUT, mappedptr, fdlen);
  movl $STDOUT,%ebx
  movl %eax,%ecx
  movl fdlen,%edx
  movl $SYS_write,%eax
  int  $0x80

// munmap(mappedptr, fdlen);
  movl mappedptr,%ebx
  movl fdlen,%ecx
  movl $SYS_munmap,%eax
  int  $0x80

// close(fd);
  movl fd,%ebx           // dosya tanımlayıcıyı yükle
  movl $SYS_close,%eax
  int  $0x80
exit:
// exit(0);
  movl $SYS_exit,%eax
  xorl %ebx,%ebx
  int  $0x80

  ret
Örnek 9.3. mmap()'i C içerisinde kullanmak
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

#define STDOUT 1

void
main(void)
{
  char file[] = "mmap.s";
  char *mappedptr;
  int fd, filelen;

  fd = fopen(file, O_RDONLY);
  filelen = lseek(fd, 0, SEEK_END);
  mappedptr = mmap(NULL, filelen, PROT_READ, MAP_SHARED, fd, 0);
  write(STDOUT, mappedptr, filelen);
  munmap(mappedptr, filelen);
  close(fd);
}
mmap() parametrelerinin bellekte dizilişleri:
%esp%esp+4%esp+8%esp+12%esp+16%esp+20
00000000filelen0000000100000001fd00000000
ASM Karşılığı:
$ cat mmap.s
.include "defines.h"
.data
  file:
    .string "mmap.s"
  fd:
    .long 0
  filelen:
    .long 0
  mappedptr:
    .long 0
.globl main
main:
  push %ebp
  movl %esp,%ebp
  subl $24,%esp

// open($file, $O_RDONLY);
  movl $fd,%ebx          // fd kaydediliyor
  movl %eax,(%ebx)

// lseek($fd,0,$SEEK_END);
  movl $filelen,%ebx     // dosya uzunluğu kaydediliyor
  movl %eax,(%ebx)

  xorl %edx,%edx

// mmap(NULL,$filelen,PROT_READ,MAP_SHARED,$fd,0);
  movl %edx,(%esp)
  movl %eax,4(%esp)      // dosya uzunluğu hala %eax içerisinde
  movl $PROT_READ,8(%esp)
  movl $MAP_SHARED,12(%esp)
  movl $fd,%ebx          // dosya tanımlayıcısı yükleniyor
  movl (%ebx),%eax
  movl %eax,16(%esp)
  movl %edx,20(%esp)
  movl $SYS_mmap,%eax
  movl %esp,%ebx
  int  $0x80

  movl $mappedptr,%ebx   // ptr kaydediliyor
  movl %eax,(%ebx)

// write($stdout, $mappedptr, $filelen);
// munmap($mappedptr, $filelen);
// close($fd);

  movl %ebp,%esp
  popl %ebp

  ret
$
Not
Yukarıdaki kaynak kodu Örnek 9.2 örneğindeki kaynak kodundan farklıdır. Yukarıda bulunan kaynak kodu diğer sistem çağrılarını, bu bölümün konusu olmadıkları için, göstermemektedir. Yukarıdaki kod sadece mmap.s dosyasını açar, oysa Örnek 9.2 kaynak kodu komut satırı parametrelerini okumaktadır. mmap örneği dosya uzunluğunu okumak için de lseek'i kullanmaktadır.
Soket Sistem Çağrıları
Soket sistem çağrıları, %eax içerisine giden, sadece bir sistem çağrı numarası kullanır: SYS_socketcall. Soket işlevleri /usr/include/linux/net.h başlık dosyası içerisinde bulunan ve %ebx'e kaydedilen bir altişlev numarası yolu ile tanımlanır. Sistem çağrı argümanını gösteren bir gösterici %ecx içerisinde saklanır. Soket sistem çağrıları da int $0x80 çağırılarak çalıştırılabilir.
/* socket.s */

.text
.globl _start
_start:
 sub $12,%esp

// socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  movl $AF_INET,(%esp)
  movl $SOCK_STREAM,4(%esp)
  movl $IPPROTO_TCP,8(%esp)

  movl $SYS_socketcall,%eax
  movl $SYS_socketcall_socket,%ebx
  movl %esp,%ecx
  int  $0x80

  movl $SYS_exit,%eax
  xorl %ebx,%ebx
  int  $0x80
  ret
Önceki Üst Ana Başlık Sonraki
Intel ve AT&T Sözdizimi Başlangıç Komut Satırı Argümanları
Bir Linux Kitaplığı Sayfası