1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
// 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"(r12));
// ```
//
// 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 syscall1(n, a1) _syscall1(n, argcast(a1))
#define syscall3(n, a1, a2, a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3))
static inline long _syscall1(long n, long a1) {
long ret;
asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "memory");
return ret;
}
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;
}
|