X86 64 linux syscall

yamnikov-oleg / calling_conventions.md

Source: man syscall

Architecture calling conventions

Every architecture has its own way of invoking and passing arguments to the kernel. The details for various architectures are listed in the two tables below.

The first table lists the instruction used to transition to kernel mode, (which might not be the fastest or best way to transition to the kernel, so you might have to refer to vdso(7) ), the register used to indicate the system call number, and the register used to return the system call result.

arch/ABI instruction syscall # retval Notes
arm/OABI swi NR a1 NR is syscall #
arm/EABI swi 0x0 r7 r0
arm64 svc #0 x8 x0
blackfin excpt 0x0 P0 R0
i386 int $0x80 eax eax
ia64 break 0x100000 r15 r8 See below
mips syscall v0 v0 See below
parisc ble 0x100(%sr2, %r0) r20 r28
s390 svc 0 r1 r2 See below
s390x svc 0 r1 r2 See below
sparc/32 t 0x10 g1 o0
sparc/64 t 0x6d g1 o0
x86_64 syscall rax rax See below
x32 syscall rax rax See below

For s390 and s390x, NR (the system call number) may be passed directly with «svc NR» if it is less than 256.

The x32 ABI uses the same instruction as the x86_64 ABI and is used on the same processors. To differentiate between them, the bit mask __X32_SYSCALL_BIT is bitwise-ORed into the system call number for system calls under the x32 ABI.

On a few architectures, a register is used to indicate simple boolean failure of the system call: ia64 uses r10 for this purpose, and mips uses a3.

The second table shows the registers used to pass the system call arguments.

arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes
arm/OABI a1 a2 a3 a4 v1 v2 v3
arm/EABI r0 r1 r2 r3 r4 r5 r6
arm64 x0 x1 x2 x3 x4 x5
blackfin R0 R1 R2 R3 R4 R5
i386 ebx ecx edx esi edi ebp
ia64 out0 out1 out2 out3 out4 out5
mips/o32 a0 a1 a2 a3 See below
mips/n32,64 a0 a1 a2 a3 a4 a5
parisc r26 r25 r24 r23 r22 r21
s390 r2 r3 r4 r5 r6 r7
s390x r2 r3 r4 r5 r6 r7
sparc/32 o0 o1 o2 o3 o4 o5
sparc/64 o0 o1 o2 o3 o4 o5
x86_64 rdi rsi rdx r10 r8 r9
x32 rdi rsi rdx r10 r8 r9

The mips/o32 system call convention passes arguments 5 through 8 on the user stack.

Note that these tables don’t cover the entire calling convention — some architectures may indiscriminately clobber other registers not listed here.

Review: cb4c4e8 on 2 Dec 2015.

32-bit system call numbers and entry vectors

Источник

Direct Operating System Access via Syscalls

Normally, to interact with the outside world (files, network, etc) from assembly language, you just call an existing function, usually the exact same function you’d call from C or C++. But sometimes, such as when you’re implementing a C library, when there is no C library call to access the functionality you need, or when your code needs to operate behind enemy lines, you want to talk to the OS kernel directly.

In fact, to get anything dangerous done, like talking directly to the screen or keyboard, you *must* talk to the OS kernel, because the hardware itself has been instructed to not let you access those things. On our x86 machines, the IOPL (I/O Privilege Level) flag values range from 0 (kernel mode, anything is allowed) to 3 (user mode, no hardware access is allowed). The hardware lets you give up IOPL rights easily, but there’s only one way to gain IOPL rights: make a system call. This makes system calls the primary gateway to kernel functionality.

How you do a syscall depends on your OS and architecture. For Linux:

Architecture Syscall
instruction
Syscall
number in
return
value
arg0 arg1 arg2 arg3 arg4 arg5
x86_64 syscall rax rax rdi rsi rdx r10 r8 r9
x86 int 0x80 eax eax ebx ecx edx esi edi ebp
arm svc 0 r7 r0 r0 r1 r2 r3 r4 r5
arm64 svc 0 x8 x0 x0 x1 x2 x3 x4 x5

Table from the excellent Chromium OS syscall pages (Google’s Chromium OS uses the Linux kernel, and hence the Linux syscalls).

Linux 64-bit x86 System Calls

On a 64-bit x86 Linux machine, there’s a special instruction «syscall» to make system calls: a request to the kernel to do something.

You identify which system call you’d like to make by loading a syscall number into register rax. A full list of syscall numbers is here, or on /usr/include/asm/unistd_64.h.

Here we’re calling the magic operating system call «fork();», which creates a new process.

Syscall parameters are passed in registers rdi, rsi, rdx, r10, r8, r9, which you’ll notice is *somewhat* like a function call but with slightly different registers! The return value, normally an integer error code, is returned in rax.

Here’s a direct syscall for: write(1,»Yo\n»,3);

Linux 32-bit x86 Syscalls

The older 32-bit x86 syscall interface uses a software interrupt, «int 0x80». As with the 64-bit interface, register rax describes what to do (open a file, write data, etc). The registers ebx, ecx, edx, esi, and edi have the parameters describing how to do it. This register-based parameter passing is similar to how we call functions in 64-bit x86, but using different register numbers and smaller 32-bit registers, and the Linux kernel allows the use of this convention both in 32 and 64 bit mode.

«int 0x80» uses a special x86 instruction to do this called «int», short for interrupt. More generally, an «interrupt» is a hardware feature where the CPU saves what it was doing and does something else for a while. For example, every time a packet arrives from the network, the network card will interrupt the CPU, so some low-level operating system code can look at the packet and decide if it should keep running the current program, or switch to some new program (such as the web browser, or a network server). Handling interrupts is the central responsibility of the operating system.

The operating system allows you to perform a wide variety of almost magical features. For example, Linux syscall number 2 is «fork», which creates a complete duplicate of your process.

The return value comes back in rax. If it’s negative, that indicates an error, which are listed in errno.h.

Konstantin Boldyshev has a list of common Linux syscalls. The full list of Linux syscalls is in /usr/include/asm/unistd_32.h. Here’s a netrun-friendly version of his Linux example:

This same «int 0x80» approach works on both 32-bit or 64-bit Linux systems, *BUT* since the above is a 32-bit interface, any parameters you pass need to fit in 32 bits. In particular, if you have a pointer to some data on the stack, the pointer (0x7fffffffbcde or something) is too big to fit, so you get «bad address» errors (EFAULT, error -14).

Linux 32-bit ARM Syscalls

The syscall arguments go in registers as usual, and support r0-r5. Here we’re calling the «write» syscall. Rather than hardcoding the string length, we compute it with the fancy «.» (the current address) minus «msg» (the start of the string) pointer arithmetic.

Before the 2006 «embedded API (EABI)», the syscall number wasn’t in r7, it was inside the svc/swi instruction, which was a pain for the kernel because it needed to go back and read the instruction to extract those bits.

Syscalls on non-Linux systems

Other operating systems such as BSD UNIX store syscall parameters on the stack, like the 32-bit x86 function call interface.

In ancient 16-bit DOS mode, you access DOS functionality via INT 0x21, with the equivalent of a system call number in register AH.

In a PC BIOS boot block, you can access BIOS functionality via several interrupts, including INT 0x10 for screen access, or INT 0x13 for disk access.

On modern 32-bit Windows, you use the sysenter instruction, with the system call number in eax (table of Windows system call numbers). Older pre-XP windows used interrupt 0x2E.

Источник

Читайте также:  How to update directx windows 10
Оцените статью