Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
0002 /*
0003  * i386 specific definitions for NOLIBC
0004  * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
0005  */
0006 
0007 #ifndef _NOLIBC_ARCH_I386_H
0008 #define _NOLIBC_ARCH_I386_H
0009 
0010 /* O_* macros for fcntl/open are architecture-specific */
0011 #define O_RDONLY            0
0012 #define O_WRONLY            1
0013 #define O_RDWR              2
0014 #define O_CREAT          0x40
0015 #define O_EXCL           0x80
0016 #define O_NOCTTY        0x100
0017 #define O_TRUNC         0x200
0018 #define O_APPEND        0x400
0019 #define O_NONBLOCK      0x800
0020 #define O_DIRECTORY   0x10000
0021 
0022 /* The struct returned by the stat() syscall, 32-bit only, the syscall returns
0023  * exactly 56 bytes (stops before the unused array).
0024  */
0025 struct sys_stat_struct {
0026     unsigned long  st_dev;
0027     unsigned long  st_ino;
0028     unsigned short st_mode;
0029     unsigned short st_nlink;
0030     unsigned short st_uid;
0031     unsigned short st_gid;
0032 
0033     unsigned long  st_rdev;
0034     unsigned long  st_size;
0035     unsigned long  st_blksize;
0036     unsigned long  st_blocks;
0037 
0038     unsigned long  st_atime;
0039     unsigned long  st_atime_nsec;
0040     unsigned long  st_mtime;
0041     unsigned long  st_mtime_nsec;
0042 
0043     unsigned long  st_ctime;
0044     unsigned long  st_ctime_nsec;
0045     unsigned long  __unused[2];
0046 };
0047 
0048 /* Syscalls for i386 :
0049  *   - mostly similar to x86_64
0050  *   - registers are 32-bit
0051  *   - syscall number is passed in eax
0052  *   - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
0053  *   - all registers are preserved (except eax of course)
0054  *   - the system call is performed by calling int $0x80
0055  *   - syscall return comes in eax
0056  *   - the arguments are cast to long and assigned into the target registers
0057  *     which are then simply passed as registers to the asm code, so that we
0058  *     don't have to experience issues with register constraints.
0059  *   - the syscall number is always specified last in order to allow to force
0060  *     some registers before (gcc refuses a %-register at the last position).
0061  *
0062  * Also, i386 supports the old_select syscall if newselect is not available
0063  */
0064 #define __ARCH_WANT_SYS_OLD_SELECT
0065 
0066 #define my_syscall0(num)                                                      \
0067 ({                                                                            \
0068     long _ret;                                                            \
0069     register long _num __asm__ ("eax") = (num);                           \
0070                                                                           \
0071     __asm__  volatile (                                                   \
0072         "int $0x80\n"                                                 \
0073         : "=a" (_ret)                                                 \
0074         : "0"(_num)                                                   \
0075         : "memory", "cc"                                              \
0076     );                                                                    \
0077     _ret;                                                                 \
0078 })
0079 
0080 #define my_syscall1(num, arg1)                                                \
0081 ({                                                                            \
0082     long _ret;                                                            \
0083     register long _num __asm__ ("eax") = (num);                           \
0084     register long _arg1 __asm__ ("ebx") = (long)(arg1);                   \
0085                                                                           \
0086     __asm__  volatile (                                                   \
0087         "int $0x80\n"                                                 \
0088         : "=a" (_ret)                                                 \
0089         : "r"(_arg1),                                                 \
0090           "0"(_num)                                                   \
0091         : "memory", "cc"                                              \
0092     );                                                                    \
0093     _ret;                                                                 \
0094 })
0095 
0096 #define my_syscall2(num, arg1, arg2)                                          \
0097 ({                                                                            \
0098     long _ret;                                                            \
0099     register long _num __asm__ ("eax") = (num);                           \
0100     register long _arg1 __asm__ ("ebx") = (long)(arg1);                   \
0101     register long _arg2 __asm__ ("ecx") = (long)(arg2);                   \
0102                                                                           \
0103     __asm__  volatile (                                                   \
0104         "int $0x80\n"                                                 \
0105         : "=a" (_ret)                                                 \
0106         : "r"(_arg1), "r"(_arg2),                                     \
0107           "0"(_num)                                                   \
0108         : "memory", "cc"                                              \
0109     );                                                                    \
0110     _ret;                                                                 \
0111 })
0112 
0113 #define my_syscall3(num, arg1, arg2, arg3)                                    \
0114 ({                                                                            \
0115     long _ret;                                                            \
0116     register long _num __asm__ ("eax") = (num);                           \
0117     register long _arg1 __asm__ ("ebx") = (long)(arg1);                   \
0118     register long _arg2 __asm__ ("ecx") = (long)(arg2);                   \
0119     register long _arg3 __asm__ ("edx") = (long)(arg3);                   \
0120                                                                           \
0121     __asm__  volatile (                                                   \
0122         "int $0x80\n"                                                 \
0123         : "=a" (_ret)                                                 \
0124         : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
0125           "0"(_num)                                                   \
0126         : "memory", "cc"                                              \
0127     );                                                                    \
0128     _ret;                                                                 \
0129 })
0130 
0131 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
0132 ({                                                                            \
0133     long _ret;                                                            \
0134     register long _num __asm__ ("eax") = (num);                           \
0135     register long _arg1 __asm__ ("ebx") = (long)(arg1);                   \
0136     register long _arg2 __asm__ ("ecx") = (long)(arg2);                   \
0137     register long _arg3 __asm__ ("edx") = (long)(arg3);                   \
0138     register long _arg4 __asm__ ("esi") = (long)(arg4);                   \
0139                                                                           \
0140     __asm__  volatile (                                                   \
0141         "int $0x80\n"                                                 \
0142         : "=a" (_ret)                                                 \
0143         : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
0144           "0"(_num)                                                   \
0145         : "memory", "cc"                                              \
0146     );                                                                    \
0147     _ret;                                                                 \
0148 })
0149 
0150 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
0151 ({                                                                            \
0152     long _ret;                                                            \
0153     register long _num __asm__ ("eax") = (num);                           \
0154     register long _arg1 __asm__ ("ebx") = (long)(arg1);                   \
0155     register long _arg2 __asm__ ("ecx") = (long)(arg2);                   \
0156     register long _arg3 __asm__ ("edx") = (long)(arg3);                   \
0157     register long _arg4 __asm__ ("esi") = (long)(arg4);                   \
0158     register long _arg5 __asm__ ("edi") = (long)(arg5);                   \
0159                                                                           \
0160     __asm__  volatile (                                                   \
0161         "int $0x80\n"                                                 \
0162         : "=a" (_ret)                                                 \
0163         : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
0164           "0"(_num)                                                   \
0165         : "memory", "cc"                                              \
0166     );                                                                    \
0167     _ret;                                                                 \
0168 })
0169 
0170 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)    \
0171 ({                              \
0172     long _eax  = (long)(num);               \
0173     long _arg6 = (long)(arg6); /* Always in memory */   \
0174     __asm__ volatile (                  \
0175         "pushl  %[_arg6]\n\t"               \
0176         "pushl  %%ebp\n\t"              \
0177         "movl   4(%%esp),%%ebp\n\t"         \
0178         "int    $0x80\n\t"              \
0179         "popl   %%ebp\n\t"              \
0180         "addl   $4,%%esp\n\t"               \
0181         : "+a"(_eax)        /* %eax */      \
0182         : "b"(arg1),        /* %ebx */      \
0183           "c"(arg2),        /* %ecx */      \
0184           "d"(arg3),        /* %edx */      \
0185           "S"(arg4),        /* %esi */      \
0186           "D"(arg5),        /* %edi */      \
0187           [_arg6]"m"(_arg6) /* memory */        \
0188         : "memory", "cc"                \
0189     );                          \
0190     _eax;                           \
0191 })
0192 
0193 /* startup code */
0194 /*
0195  * i386 System V ABI mandates:
0196  * 1) last pushed argument must be 16-byte aligned.
0197  * 2) The deepest stack frame should be set to zero
0198  *
0199  */
0200 __asm__ (".section .text\n"
0201     ".weak _start\n"
0202     "_start:\n"
0203     "pop %eax\n"                // argc   (first arg, %eax)
0204     "mov %esp, %ebx\n"          // argv[] (second arg, %ebx)
0205     "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx)
0206     "xor %ebp, %ebp\n"          // zero the stack frame
0207     "and $-16, %esp\n"          // x86 ABI : esp must be 16-byte aligned before
0208     "sub $4, %esp\n"            // the call instruction (args are aligned)
0209     "push %ecx\n"               // push all registers on the stack so that we
0210     "push %ebx\n"               // support both regparm and plain stack modes
0211     "push %eax\n"
0212     "call main\n"               // main() returns the status code in %eax
0213     "mov %eax, %ebx\n"          // retrieve exit code (32-bit int)
0214     "movl $1, %eax\n"           // NR_exit == 1
0215     "int $0x80\n"               // exit now
0216     "hlt\n"                     // ensure it does not
0217     "");
0218 
0219 #endif // _NOLIBC_ARCH_I386_H