Системный вызов в Linux

Небольшая справка по реализации системного вызова на разных платформах в Linux.

Aссемблерная инструкция

  • intel x86 int $0x80
  • intel x86-64 syscall
  • armv71 svc 0x0

Номер вызова

  • intel x86 регистр EAX
  • intel x86-64 регистр RAX
  • armv71 регистр r7

Передача параметров

Менее 6 параметров:
  • intel x86 регистры EBX, ECX, EDX, ESI, EDI, EBP
  • intel x86-64 регистры RDI, RSI, RDX, R10, R8, R9
  • armv71 регистры r0, r1, r2, r3, r4, r5, r6
Более 6 параметров:
  • intel x86 указатель на область памяти через регистр EBX
  • intel x86-64 запрещено

Возврат результата

  • intel x86 регистр EAX
  • intel x86-64 регистр RAX
  • armv71 регистр r0

Примеры

Реализация на C:
#include <sys/syscall.h>

int main(void)
{
    syscall(SYS_write, 1, "Hello, world\n", 14);
    return 0;
}
intel x86:
#include <asm/unistd.h>
#include <syscall.h>
    .global _start
    .text

message:
    .string "Hello, world\n"

_start:
    # syscall SYS_write
    mov $SYS_write, %eax 
    mov $1, %ebx        # stdout
    mov $message, %ecx 
    mov $14, %edx       # length
    int $0x80

    # exit 0
    mov $SYS_exit, %eax 
    mov $0, %ebx 
    int $0x80
intel x86-64:
#include <asm/unistd.h>
#include <syscall.h>
    .global _start
    .text

message:
    .string "Hello, world\n"

_start:
    # syscall SYS_write
    movl    $SYS_write, %eax
    movl    $1, %edi        # stdout
    movl    $message, %esi
    movl    $14, %edx       # length
    syscall

    # exit 0
    movl    $0, %edi
    movl    $SYS_exit, %eax
    syscall
armv71:
message:
    .ascii "Hello, world\012\000"

    .text
    .align 2
    .global _start

_start:
    mov     r7, #4
    mov     r0, #1
    movw    r1, #:lower16:message
    movt    r1, #:upper16:message
    movl    r2, #14
    svc     0x0

    # exit 0
    mov     r7, #1
    mov     r0, #0
    svc     0x0
Для компиляции
$ gcc -c -o hello.o hello.S
$ ld -o hello hello.o

Архив