arch-i386.h 8.8 KB

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