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

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