1*cc6dc5fbSWilly Tarreau /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2*cc6dc5fbSWilly Tarreau /* 3*cc6dc5fbSWilly Tarreau * x86 specific definitions for NOLIBC (both 32- and 64-bit) 4*cc6dc5fbSWilly Tarreau * Copyright (C) 2017-2025 Willy Tarreau <w@1wt.eu> 5*cc6dc5fbSWilly Tarreau */ 6*cc6dc5fbSWilly Tarreau 7*cc6dc5fbSWilly Tarreau #ifndef _NOLIBC_ARCH_X86_H 8*cc6dc5fbSWilly Tarreau #define _NOLIBC_ARCH_X86_H 9*cc6dc5fbSWilly Tarreau 10*cc6dc5fbSWilly Tarreau #include "compiler.h" 11*cc6dc5fbSWilly Tarreau #include "crt.h" 12*cc6dc5fbSWilly Tarreau 13*cc6dc5fbSWilly Tarreau #if !defined(__x86_64__) 14*cc6dc5fbSWilly Tarreau 15*cc6dc5fbSWilly Tarreau /* Syscalls for i386 : 16*cc6dc5fbSWilly Tarreau * - mostly similar to x86_64 17*cc6dc5fbSWilly Tarreau * - registers are 32-bit 18*cc6dc5fbSWilly Tarreau * - syscall number is passed in eax 19*cc6dc5fbSWilly Tarreau * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively 20*cc6dc5fbSWilly Tarreau * - all registers are preserved (except eax of course) 21*cc6dc5fbSWilly Tarreau * - the system call is performed by calling int $0x80 22*cc6dc5fbSWilly Tarreau * - syscall return comes in eax 23*cc6dc5fbSWilly Tarreau * - the arguments are cast to long and assigned into the target registers 24*cc6dc5fbSWilly Tarreau * which are then simply passed as registers to the asm code, so that we 25*cc6dc5fbSWilly Tarreau * don't have to experience issues with register constraints. 26*cc6dc5fbSWilly Tarreau * - the syscall number is always specified last in order to allow to force 27*cc6dc5fbSWilly Tarreau * some registers before (gcc refuses a %-register at the last position). 28*cc6dc5fbSWilly Tarreau * 29*cc6dc5fbSWilly Tarreau * Also, i386 supports the old_select syscall if newselect is not available 30*cc6dc5fbSWilly Tarreau */ 31*cc6dc5fbSWilly Tarreau #define __ARCH_WANT_SYS_OLD_SELECT 32*cc6dc5fbSWilly Tarreau 33*cc6dc5fbSWilly Tarreau #define my_syscall0(num) \ 34*cc6dc5fbSWilly Tarreau ({ \ 35*cc6dc5fbSWilly Tarreau long _ret; \ 36*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \ 37*cc6dc5fbSWilly Tarreau \ 38*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 39*cc6dc5fbSWilly Tarreau "int $0x80\n" \ 40*cc6dc5fbSWilly Tarreau : "=a" (_ret) \ 41*cc6dc5fbSWilly Tarreau : "0"(_num) \ 42*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 43*cc6dc5fbSWilly Tarreau ); \ 44*cc6dc5fbSWilly Tarreau _ret; \ 45*cc6dc5fbSWilly Tarreau }) 46*cc6dc5fbSWilly Tarreau 47*cc6dc5fbSWilly Tarreau #define my_syscall1(num, arg1) \ 48*cc6dc5fbSWilly Tarreau ({ \ 49*cc6dc5fbSWilly Tarreau long _ret; \ 50*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \ 51*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 52*cc6dc5fbSWilly Tarreau \ 53*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 54*cc6dc5fbSWilly Tarreau "int $0x80\n" \ 55*cc6dc5fbSWilly Tarreau : "=a" (_ret) \ 56*cc6dc5fbSWilly Tarreau : "r"(_arg1), \ 57*cc6dc5fbSWilly Tarreau "0"(_num) \ 58*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 59*cc6dc5fbSWilly Tarreau ); \ 60*cc6dc5fbSWilly Tarreau _ret; \ 61*cc6dc5fbSWilly Tarreau }) 62*cc6dc5fbSWilly Tarreau 63*cc6dc5fbSWilly Tarreau #define my_syscall2(num, arg1, arg2) \ 64*cc6dc5fbSWilly Tarreau ({ \ 65*cc6dc5fbSWilly Tarreau long _ret; \ 66*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \ 67*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 68*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 69*cc6dc5fbSWilly Tarreau \ 70*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 71*cc6dc5fbSWilly Tarreau "int $0x80\n" \ 72*cc6dc5fbSWilly Tarreau : "=a" (_ret) \ 73*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), \ 74*cc6dc5fbSWilly Tarreau "0"(_num) \ 75*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 76*cc6dc5fbSWilly Tarreau ); \ 77*cc6dc5fbSWilly Tarreau _ret; \ 78*cc6dc5fbSWilly Tarreau }) 79*cc6dc5fbSWilly Tarreau 80*cc6dc5fbSWilly Tarreau #define my_syscall3(num, arg1, arg2, arg3) \ 81*cc6dc5fbSWilly Tarreau ({ \ 82*cc6dc5fbSWilly Tarreau long _ret; \ 83*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \ 84*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 85*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 86*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("edx") = (long)(arg3); \ 87*cc6dc5fbSWilly Tarreau \ 88*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 89*cc6dc5fbSWilly Tarreau "int $0x80\n" \ 90*cc6dc5fbSWilly Tarreau : "=a" (_ret) \ 91*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ 92*cc6dc5fbSWilly Tarreau "0"(_num) \ 93*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 94*cc6dc5fbSWilly Tarreau ); \ 95*cc6dc5fbSWilly Tarreau _ret; \ 96*cc6dc5fbSWilly Tarreau }) 97*cc6dc5fbSWilly Tarreau 98*cc6dc5fbSWilly Tarreau #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 99*cc6dc5fbSWilly Tarreau ({ \ 100*cc6dc5fbSWilly Tarreau long _ret; \ 101*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \ 102*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 103*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 104*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("edx") = (long)(arg3); \ 105*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("esi") = (long)(arg4); \ 106*cc6dc5fbSWilly Tarreau \ 107*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 108*cc6dc5fbSWilly Tarreau "int $0x80\n" \ 109*cc6dc5fbSWilly Tarreau : "=a" (_ret) \ 110*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 111*cc6dc5fbSWilly Tarreau "0"(_num) \ 112*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 113*cc6dc5fbSWilly Tarreau ); \ 114*cc6dc5fbSWilly Tarreau _ret; \ 115*cc6dc5fbSWilly Tarreau }) 116*cc6dc5fbSWilly Tarreau 117*cc6dc5fbSWilly Tarreau #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 118*cc6dc5fbSWilly Tarreau ({ \ 119*cc6dc5fbSWilly Tarreau long _ret; \ 120*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \ 121*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \ 122*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \ 123*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("edx") = (long)(arg3); \ 124*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("esi") = (long)(arg4); \ 125*cc6dc5fbSWilly Tarreau register long _arg5 __asm__ ("edi") = (long)(arg5); \ 126*cc6dc5fbSWilly Tarreau \ 127*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 128*cc6dc5fbSWilly Tarreau "int $0x80\n" \ 129*cc6dc5fbSWilly Tarreau : "=a" (_ret) \ 130*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 131*cc6dc5fbSWilly Tarreau "0"(_num) \ 132*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 133*cc6dc5fbSWilly Tarreau ); \ 134*cc6dc5fbSWilly Tarreau _ret; \ 135*cc6dc5fbSWilly Tarreau }) 136*cc6dc5fbSWilly Tarreau 137*cc6dc5fbSWilly Tarreau #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 138*cc6dc5fbSWilly Tarreau ({ \ 139*cc6dc5fbSWilly Tarreau long _eax = (long)(num); \ 140*cc6dc5fbSWilly Tarreau long _arg6 = (long)(arg6); /* Always in memory */ \ 141*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 142*cc6dc5fbSWilly Tarreau "pushl %[_arg6]\n\t" \ 143*cc6dc5fbSWilly Tarreau "pushl %%ebp\n\t" \ 144*cc6dc5fbSWilly Tarreau "movl 4(%%esp),%%ebp\n\t" \ 145*cc6dc5fbSWilly Tarreau "int $0x80\n\t" \ 146*cc6dc5fbSWilly Tarreau "popl %%ebp\n\t" \ 147*cc6dc5fbSWilly Tarreau "addl $4,%%esp\n\t" \ 148*cc6dc5fbSWilly Tarreau : "+a"(_eax) /* %eax */ \ 149*cc6dc5fbSWilly Tarreau : "b"(arg1), /* %ebx */ \ 150*cc6dc5fbSWilly Tarreau "c"(arg2), /* %ecx */ \ 151*cc6dc5fbSWilly Tarreau "d"(arg3), /* %edx */ \ 152*cc6dc5fbSWilly Tarreau "S"(arg4), /* %esi */ \ 153*cc6dc5fbSWilly Tarreau "D"(arg5), /* %edi */ \ 154*cc6dc5fbSWilly Tarreau [_arg6]"m"(_arg6) /* memory */ \ 155*cc6dc5fbSWilly Tarreau : "memory", "cc" \ 156*cc6dc5fbSWilly Tarreau ); \ 157*cc6dc5fbSWilly Tarreau _eax; \ 158*cc6dc5fbSWilly Tarreau }) 159*cc6dc5fbSWilly Tarreau 160*cc6dc5fbSWilly Tarreau /* startup code */ 161*cc6dc5fbSWilly Tarreau /* 162*cc6dc5fbSWilly Tarreau * i386 System V ABI mandates: 163*cc6dc5fbSWilly Tarreau * 1) last pushed argument must be 16-byte aligned. 164*cc6dc5fbSWilly Tarreau * 2) The deepest stack frame should be set to zero 165*cc6dc5fbSWilly Tarreau * 166*cc6dc5fbSWilly Tarreau */ 167*cc6dc5fbSWilly Tarreau void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 168*cc6dc5fbSWilly Tarreau { 169*cc6dc5fbSWilly Tarreau __asm__ volatile ( 170*cc6dc5fbSWilly Tarreau "xor %ebp, %ebp\n" /* zero the stack frame */ 171*cc6dc5fbSWilly Tarreau "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */ 172*cc6dc5fbSWilly Tarreau "sub $12, %esp\n" /* sub 12 to keep it aligned after the push %eax */ 173*cc6dc5fbSWilly Tarreau "push %eax\n" /* push arg1 on stack to support plain stack modes too */ 174*cc6dc5fbSWilly Tarreau "call _start_c\n" /* transfer to c runtime */ 175*cc6dc5fbSWilly Tarreau "hlt\n" /* ensure it does not return */ 176*cc6dc5fbSWilly Tarreau ); 177*cc6dc5fbSWilly Tarreau __nolibc_entrypoint_epilogue(); 178*cc6dc5fbSWilly Tarreau } 179*cc6dc5fbSWilly Tarreau 180*cc6dc5fbSWilly Tarreau #else /* !defined(__x86_64__) */ 181*cc6dc5fbSWilly Tarreau 182*cc6dc5fbSWilly Tarreau /* Syscalls for x86_64 : 183*cc6dc5fbSWilly Tarreau * - registers are 64-bit 184*cc6dc5fbSWilly Tarreau * - syscall number is passed in rax 185*cc6dc5fbSWilly Tarreau * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively 186*cc6dc5fbSWilly Tarreau * - the system call is performed by calling the syscall instruction 187*cc6dc5fbSWilly Tarreau * - syscall return comes in rax 188*cc6dc5fbSWilly Tarreau * - rcx and r11 are clobbered, others are preserved. 189*cc6dc5fbSWilly Tarreau * - the arguments are cast to long and assigned into the target registers 190*cc6dc5fbSWilly Tarreau * which are then simply passed as registers to the asm code, so that we 191*cc6dc5fbSWilly Tarreau * don't have to experience issues with register constraints. 192*cc6dc5fbSWilly Tarreau * - the syscall number is always specified last in order to allow to force 193*cc6dc5fbSWilly Tarreau * some registers before (gcc refuses a %-register at the last position). 194*cc6dc5fbSWilly Tarreau * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1 195*cc6dc5fbSWilly Tarreau * Calling Conventions. 196*cc6dc5fbSWilly Tarreau * 197*cc6dc5fbSWilly Tarreau * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/home 198*cc6dc5fbSWilly Tarreau * 199*cc6dc5fbSWilly Tarreau */ 200*cc6dc5fbSWilly Tarreau 201*cc6dc5fbSWilly Tarreau #define my_syscall0(num) \ 202*cc6dc5fbSWilly Tarreau ({ \ 203*cc6dc5fbSWilly Tarreau long _ret; \ 204*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 205*cc6dc5fbSWilly Tarreau \ 206*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 207*cc6dc5fbSWilly Tarreau "syscall\n" \ 208*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 209*cc6dc5fbSWilly Tarreau : "0"(_num) \ 210*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 211*cc6dc5fbSWilly Tarreau ); \ 212*cc6dc5fbSWilly Tarreau _ret; \ 213*cc6dc5fbSWilly Tarreau }) 214*cc6dc5fbSWilly Tarreau 215*cc6dc5fbSWilly Tarreau #define my_syscall1(num, arg1) \ 216*cc6dc5fbSWilly Tarreau ({ \ 217*cc6dc5fbSWilly Tarreau long _ret; \ 218*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 219*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 220*cc6dc5fbSWilly Tarreau \ 221*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 222*cc6dc5fbSWilly Tarreau "syscall\n" \ 223*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 224*cc6dc5fbSWilly Tarreau : "r"(_arg1), \ 225*cc6dc5fbSWilly Tarreau "0"(_num) \ 226*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 227*cc6dc5fbSWilly Tarreau ); \ 228*cc6dc5fbSWilly Tarreau _ret; \ 229*cc6dc5fbSWilly Tarreau }) 230*cc6dc5fbSWilly Tarreau 231*cc6dc5fbSWilly Tarreau #define my_syscall2(num, arg1, arg2) \ 232*cc6dc5fbSWilly Tarreau ({ \ 233*cc6dc5fbSWilly Tarreau long _ret; \ 234*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 235*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 236*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 237*cc6dc5fbSWilly Tarreau \ 238*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 239*cc6dc5fbSWilly Tarreau "syscall\n" \ 240*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 241*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), \ 242*cc6dc5fbSWilly Tarreau "0"(_num) \ 243*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 244*cc6dc5fbSWilly Tarreau ); \ 245*cc6dc5fbSWilly Tarreau _ret; \ 246*cc6dc5fbSWilly Tarreau }) 247*cc6dc5fbSWilly Tarreau 248*cc6dc5fbSWilly Tarreau #define my_syscall3(num, arg1, arg2, arg3) \ 249*cc6dc5fbSWilly Tarreau ({ \ 250*cc6dc5fbSWilly Tarreau long _ret; \ 251*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 252*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 253*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 254*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 255*cc6dc5fbSWilly Tarreau \ 256*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 257*cc6dc5fbSWilly Tarreau "syscall\n" \ 258*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 259*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ 260*cc6dc5fbSWilly Tarreau "0"(_num) \ 261*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 262*cc6dc5fbSWilly Tarreau ); \ 263*cc6dc5fbSWilly Tarreau _ret; \ 264*cc6dc5fbSWilly Tarreau }) 265*cc6dc5fbSWilly Tarreau 266*cc6dc5fbSWilly Tarreau #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 267*cc6dc5fbSWilly Tarreau ({ \ 268*cc6dc5fbSWilly Tarreau long _ret; \ 269*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 270*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 271*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 272*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 273*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("r10") = (long)(arg4); \ 274*cc6dc5fbSWilly Tarreau \ 275*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 276*cc6dc5fbSWilly Tarreau "syscall\n" \ 277*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 278*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 279*cc6dc5fbSWilly Tarreau "0"(_num) \ 280*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 281*cc6dc5fbSWilly Tarreau ); \ 282*cc6dc5fbSWilly Tarreau _ret; \ 283*cc6dc5fbSWilly Tarreau }) 284*cc6dc5fbSWilly Tarreau 285*cc6dc5fbSWilly Tarreau #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 286*cc6dc5fbSWilly Tarreau ({ \ 287*cc6dc5fbSWilly Tarreau long _ret; \ 288*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 289*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 290*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 291*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 292*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("r10") = (long)(arg4); \ 293*cc6dc5fbSWilly Tarreau register long _arg5 __asm__ ("r8") = (long)(arg5); \ 294*cc6dc5fbSWilly Tarreau \ 295*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 296*cc6dc5fbSWilly Tarreau "syscall\n" \ 297*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 298*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 299*cc6dc5fbSWilly Tarreau "0"(_num) \ 300*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 301*cc6dc5fbSWilly Tarreau ); \ 302*cc6dc5fbSWilly Tarreau _ret; \ 303*cc6dc5fbSWilly Tarreau }) 304*cc6dc5fbSWilly Tarreau 305*cc6dc5fbSWilly Tarreau #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 306*cc6dc5fbSWilly Tarreau ({ \ 307*cc6dc5fbSWilly Tarreau long _ret; \ 308*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \ 309*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \ 310*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \ 311*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \ 312*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("r10") = (long)(arg4); \ 313*cc6dc5fbSWilly Tarreau register long _arg5 __asm__ ("r8") = (long)(arg5); \ 314*cc6dc5fbSWilly Tarreau register long _arg6 __asm__ ("r9") = (long)(arg6); \ 315*cc6dc5fbSWilly Tarreau \ 316*cc6dc5fbSWilly Tarreau __asm__ volatile ( \ 317*cc6dc5fbSWilly Tarreau "syscall\n" \ 318*cc6dc5fbSWilly Tarreau : "=a"(_ret) \ 319*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 320*cc6dc5fbSWilly Tarreau "r"(_arg6), "0"(_num) \ 321*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \ 322*cc6dc5fbSWilly Tarreau ); \ 323*cc6dc5fbSWilly Tarreau _ret; \ 324*cc6dc5fbSWilly Tarreau }) 325*cc6dc5fbSWilly Tarreau 326*cc6dc5fbSWilly Tarreau /* startup code */ 327*cc6dc5fbSWilly Tarreau /* 328*cc6dc5fbSWilly Tarreau * x86-64 System V ABI mandates: 329*cc6dc5fbSWilly Tarreau * 1) %rsp must be 16-byte aligned right before the function call. 330*cc6dc5fbSWilly Tarreau * 2) The deepest stack frame should be zero (the %rbp). 331*cc6dc5fbSWilly Tarreau * 332*cc6dc5fbSWilly Tarreau */ 333*cc6dc5fbSWilly Tarreau void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 334*cc6dc5fbSWilly Tarreau { 335*cc6dc5fbSWilly Tarreau __asm__ volatile ( 336*cc6dc5fbSWilly Tarreau "xor %ebp, %ebp\n" /* zero the stack frame */ 337*cc6dc5fbSWilly Tarreau "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */ 338*cc6dc5fbSWilly Tarreau "call _start_c\n" /* transfer to c runtime */ 339*cc6dc5fbSWilly Tarreau "hlt\n" /* ensure it does not return */ 340*cc6dc5fbSWilly Tarreau ); 341*cc6dc5fbSWilly Tarreau __nolibc_entrypoint_epilogue(); 342*cc6dc5fbSWilly Tarreau } 343*cc6dc5fbSWilly Tarreau 344*cc6dc5fbSWilly Tarreau #define NOLIBC_ARCH_HAS_MEMMOVE 345*cc6dc5fbSWilly Tarreau void *memmove(void *dst, const void *src, size_t len); 346*cc6dc5fbSWilly Tarreau 347*cc6dc5fbSWilly Tarreau #define NOLIBC_ARCH_HAS_MEMCPY 348*cc6dc5fbSWilly Tarreau void *memcpy(void *dst, const void *src, size_t len); 349*cc6dc5fbSWilly Tarreau 350*cc6dc5fbSWilly Tarreau #define NOLIBC_ARCH_HAS_MEMSET 351*cc6dc5fbSWilly Tarreau void *memset(void *dst, int c, size_t len); 352*cc6dc5fbSWilly Tarreau 353*cc6dc5fbSWilly Tarreau __asm__ ( 354*cc6dc5fbSWilly Tarreau ".section .text.nolibc_memmove_memcpy\n" 355*cc6dc5fbSWilly Tarreau ".weak memmove\n" 356*cc6dc5fbSWilly Tarreau ".weak memcpy\n" 357*cc6dc5fbSWilly Tarreau "memmove:\n" 358*cc6dc5fbSWilly Tarreau "memcpy:\n" 359*cc6dc5fbSWilly Tarreau "movq %rdx, %rcx\n\t" 360*cc6dc5fbSWilly Tarreau "movq %rdi, %rax\n\t" 361*cc6dc5fbSWilly Tarreau "movq %rdi, %rdx\n\t" 362*cc6dc5fbSWilly Tarreau "subq %rsi, %rdx\n\t" 363*cc6dc5fbSWilly Tarreau "cmpq %rcx, %rdx\n\t" 364*cc6dc5fbSWilly Tarreau "jb 1f\n\t" 365*cc6dc5fbSWilly Tarreau "rep movsb\n\t" 366*cc6dc5fbSWilly Tarreau "retq\n" 367*cc6dc5fbSWilly Tarreau "1:" /* backward copy */ 368*cc6dc5fbSWilly Tarreau "leaq -1(%rdi, %rcx, 1), %rdi\n\t" 369*cc6dc5fbSWilly Tarreau "leaq -1(%rsi, %rcx, 1), %rsi\n\t" 370*cc6dc5fbSWilly Tarreau "std\n\t" 371*cc6dc5fbSWilly Tarreau "rep movsb\n\t" 372*cc6dc5fbSWilly Tarreau "cld\n\t" 373*cc6dc5fbSWilly Tarreau "retq\n" 374*cc6dc5fbSWilly Tarreau 375*cc6dc5fbSWilly Tarreau ".section .text.nolibc_memset\n" 376*cc6dc5fbSWilly Tarreau ".weak memset\n" 377*cc6dc5fbSWilly Tarreau "memset:\n" 378*cc6dc5fbSWilly Tarreau "xchgl %eax, %esi\n\t" 379*cc6dc5fbSWilly Tarreau "movq %rdx, %rcx\n\t" 380*cc6dc5fbSWilly Tarreau "pushq %rdi\n\t" 381*cc6dc5fbSWilly Tarreau "rep stosb\n\t" 382*cc6dc5fbSWilly Tarreau "popq %rax\n\t" 383*cc6dc5fbSWilly Tarreau "retq\n" 384*cc6dc5fbSWilly Tarreau ); 385*cc6dc5fbSWilly Tarreau 386*cc6dc5fbSWilly Tarreau #endif /* !defined(__x86_64__) */ 387*cc6dc5fbSWilly Tarreau #endif /* _NOLIBC_ARCH_X86_H */ 388