aboutsummaryrefslogblamecommitdiff
path: root/include/syscall.h
blob: 0460ede4fd00bb8665e41c1249930ebd0ce7f29f (plain) (tree)























































                                                                                         
// Copyright (c) 2020 Johannes Stoelp

#pragma once

#if !defined(__linux__) || !defined(__x86_64__)
# error "Only supported on linux(x86_64)!"
#endif

// Inline ASM
//   Syntax:
//     asm asm-qualifiers (AssemblerTemplate : OutputOperands : InputOperands : Clobbers)
//
//   Output operand constraints:
//     = | operand (variable) is written to by this instruction
//     + | operand (variable) is written to / read from by this instruction
//
//   Input/Output operand constraints:
//     r | allocate general purpose register
//
//   Machine specific constraints (x86_64):
//     a  | a register (eg rax)
//     d  | d register (eg rdx)
//     D  | di register (eg rdi)
//     S  | si register (eg rsi)
//
//  Local register variables:
//    In case a specific register is required which can not be specified via a
//    machine specific constraint.
//    ```c
//    register long r12 asm ("r12") = 42;
//    asm("nop" : : "r"(r10));
//    ```
//
// Reference:
//   https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
//   https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints
//   https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html

// Linux syscall ABI
//  x86-64
//    #syscall: rax
//    ret     : rax
//    instr   : syscall
//    args    : rdi   rsi   rdx   r10   r8    r9
//
// Reference:
//   syscall(2)

#define argcast(A) ((long)(A))
#define syscall3(n,a1,a2,a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3))

static inline long _syscall3(long n, long a1, long a2, long a3) {
    long ret;
    asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3) : "memory");
    return ret;
}