github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/dmz/nolibc/arch-x86_64.h (about)

     1  /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
     2  /*
     3   * x86_64 specific definitions for NOLIBC
     4   * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
     5   */
     6  
     7  #ifndef _NOLIBC_ARCH_X86_64_H
     8  #define _NOLIBC_ARCH_X86_64_H
     9  
    10  #include "compiler.h"
    11  #include "crt.h"
    12  
    13  /* Syscalls for x86_64 :
    14   *   - registers are 64-bit
    15   *   - syscall number is passed in rax
    16   *   - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
    17   *   - the system call is performed by calling the syscall instruction
    18   *   - syscall return comes in rax
    19   *   - rcx and r11 are clobbered, others are preserved.
    20   *   - the arguments are cast to long and assigned into the target registers
    21   *     which are then simply passed as registers to the asm code, so that we
    22   *     don't have to experience issues with register constraints.
    23   *   - the syscall number is always specified last in order to allow to force
    24   *     some registers before (gcc refuses a %-register at the last position).
    25   *   - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
    26   *     Calling Conventions.
    27   *
    28   * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/home
    29   *
    30   */
    31  
    32  #define my_syscall0(num)                                                      \
    33  ({                                                                            \
    34  	long _ret;                                                            \
    35  	register long _num  __asm__ ("rax") = (num);                          \
    36  									      \
    37  	__asm__ volatile (                                                    \
    38  		"syscall\n"                                                   \
    39  		: "=a"(_ret)                                                  \
    40  		: "0"(_num)                                                   \
    41  		: "rcx", "r11", "memory", "cc"                                \
    42  	);                                                                    \
    43  	_ret;                                                                 \
    44  })
    45  
    46  #define my_syscall1(num, arg1)                                                \
    47  ({                                                                            \
    48  	long _ret;                                                            \
    49  	register long _num  __asm__ ("rax") = (num);                          \
    50  	register long _arg1 __asm__ ("rdi") = (long)(arg1);                   \
    51  									      \
    52  	__asm__ volatile (                                                    \
    53  		"syscall\n"                                                   \
    54  		: "=a"(_ret)                                                  \
    55  		: "r"(_arg1),                                                 \
    56  		  "0"(_num)                                                   \
    57  		: "rcx", "r11", "memory", "cc"                                \
    58  	);                                                                    \
    59  	_ret;                                                                 \
    60  })
    61  
    62  #define my_syscall2(num, arg1, arg2)                                          \
    63  ({                                                                            \
    64  	long _ret;                                                            \
    65  	register long _num  __asm__ ("rax") = (num);                          \
    66  	register long _arg1 __asm__ ("rdi") = (long)(arg1);                   \
    67  	register long _arg2 __asm__ ("rsi") = (long)(arg2);                   \
    68  									      \
    69  	__asm__ volatile (                                                    \
    70  		"syscall\n"                                                   \
    71  		: "=a"(_ret)                                                  \
    72  		: "r"(_arg1), "r"(_arg2),                                     \
    73  		  "0"(_num)                                                   \
    74  		: "rcx", "r11", "memory", "cc"                                \
    75  	);                                                                    \
    76  	_ret;                                                                 \
    77  })
    78  
    79  #define my_syscall3(num, arg1, arg2, arg3)                                    \
    80  ({                                                                            \
    81  	long _ret;                                                            \
    82  	register long _num  __asm__ ("rax") = (num);                          \
    83  	register long _arg1 __asm__ ("rdi") = (long)(arg1);                   \
    84  	register long _arg2 __asm__ ("rsi") = (long)(arg2);                   \
    85  	register long _arg3 __asm__ ("rdx") = (long)(arg3);                   \
    86  									      \
    87  	__asm__ volatile (                                                    \
    88  		"syscall\n"                                                   \
    89  		: "=a"(_ret)                                                  \
    90  		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
    91  		  "0"(_num)                                                   \
    92  		: "rcx", "r11", "memory", "cc"                                \
    93  	);                                                                    \
    94  	_ret;                                                                 \
    95  })
    96  
    97  #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
    98  ({                                                                            \
    99  	long _ret;                                                            \
   100  	register long _num  __asm__ ("rax") = (num);                          \
   101  	register long _arg1 __asm__ ("rdi") = (long)(arg1);                   \
   102  	register long _arg2 __asm__ ("rsi") = (long)(arg2);                   \
   103  	register long _arg3 __asm__ ("rdx") = (long)(arg3);                   \
   104  	register long _arg4 __asm__ ("r10") = (long)(arg4);                   \
   105  									      \
   106  	__asm__ volatile (                                                    \
   107  		"syscall\n"                                                   \
   108  		: "=a"(_ret)                                                  \
   109  		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
   110  		  "0"(_num)                                                   \
   111  		: "rcx", "r11", "memory", "cc"                                \
   112  	);                                                                    \
   113  	_ret;                                                                 \
   114  })
   115  
   116  #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
   117  ({                                                                            \
   118  	long _ret;                                                            \
   119  	register long _num  __asm__ ("rax") = (num);                          \
   120  	register long _arg1 __asm__ ("rdi") = (long)(arg1);                   \
   121  	register long _arg2 __asm__ ("rsi") = (long)(arg2);                   \
   122  	register long _arg3 __asm__ ("rdx") = (long)(arg3);                   \
   123  	register long _arg4 __asm__ ("r10") = (long)(arg4);                   \
   124  	register long _arg5 __asm__ ("r8")  = (long)(arg5);                   \
   125  									      \
   126  	__asm__ volatile (                                                    \
   127  		"syscall\n"                                                   \
   128  		: "=a"(_ret)                                                  \
   129  		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
   130  		  "0"(_num)                                                   \
   131  		: "rcx", "r11", "memory", "cc"                                \
   132  	);                                                                    \
   133  	_ret;                                                                 \
   134  })
   135  
   136  #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
   137  ({                                                                            \
   138  	long _ret;                                                            \
   139  	register long _num  __asm__ ("rax") = (num);                          \
   140  	register long _arg1 __asm__ ("rdi") = (long)(arg1);                   \
   141  	register long _arg2 __asm__ ("rsi") = (long)(arg2);                   \
   142  	register long _arg3 __asm__ ("rdx") = (long)(arg3);                   \
   143  	register long _arg4 __asm__ ("r10") = (long)(arg4);                   \
   144  	register long _arg5 __asm__ ("r8")  = (long)(arg5);                   \
   145  	register long _arg6 __asm__ ("r9")  = (long)(arg6);                   \
   146  									      \
   147  	__asm__ volatile (                                                    \
   148  		"syscall\n"                                                   \
   149  		: "=a"(_ret)                                                  \
   150  		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
   151  		  "r"(_arg6), "0"(_num)                                       \
   152  		: "rcx", "r11", "memory", "cc"                                \
   153  	);                                                                    \
   154  	_ret;                                                                 \
   155  })
   156  
   157  /* startup code */
   158  /*
   159   * x86-64 System V ABI mandates:
   160   * 1) %rsp must be 16-byte aligned right before the function call.
   161   * 2) The deepest stack frame should be zero (the %rbp).
   162   *
   163   */
   164  void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
   165  {
   166  	__asm__ volatile (
   167  		"xor  %ebp, %ebp\n"       /* zero the stack frame                            */
   168  		"mov  %rsp, %rdi\n"       /* save stack pointer to %rdi, as arg1 of _start_c */
   169  		"and  $-16, %rsp\n"       /* %rsp must be 16-byte aligned before call        */
   170  		"call _start_c\n"         /* transfer to c runtime                           */
   171  		"hlt\n"                   /* ensure it does not return                       */
   172  	);
   173  	__builtin_unreachable();
   174  }
   175  
   176  #endif /* _NOLIBC_ARCH_X86_64_H */