#ifndef _NOLIBC_ARCH_MIPS_H
#define _NOLIBC_ARCH_MIPS_H
#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
#include "std.h"
#if !defined(_ABIO32) && !defined(_ABIN32) && !defined(_ABI64)
#error Unsupported MIPS ABI
#endif
#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "hi", "lo"
#else
#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "$0"
#endif
#if defined(_ABIO32)
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"memory", "cc", "at", "v1", \
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", \
_NOLIBC_SYSCALL_CLOBBER_HI_LO
#define _NOLIBC_SYSCALL_STACK_RESERVE "addiu $sp, $sp, -32\n"
#define _NOLIBC_SYSCALL_STACK_UNRESERVE "addiu $sp, $sp, 32\n"
#define _NOLIBC_SYSCALL_REG register long
#else
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"memory", "cc", "at", "v1", \
"10", "11", "12", "13", "14", "15", "24", "25", \
_NOLIBC_SYSCALL_CLOBBER_HI_LO
#define _NOLIBC_SYSCALL_STACK_RESERVE
#define _NOLIBC_SYSCALL_STACK_UNRESERVE
#define _NOLIBC_SYSCALL_REG register long long
#endif
#define __nolibc_syscall0(num) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r"(_num), "=r"(_arg4) \
: "r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r"(_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r"(_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r"(_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2), "r"(_arg3) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3") = __nolibc_arg_to_reg(arg4); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r" (_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#if defined(_ABIO32)
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3") = __nolibc_arg_to_reg(arg4); \
_NOLIBC_SYSCALL_REG _arg5 = __nolibc_arg_to_reg(arg5); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"sw %7, 16($sp)\n" \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r" (_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("a0") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("a1") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg3 __asm__ ("a2") = __nolibc_arg_to_reg(arg3); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("a3") = __nolibc_arg_to_reg(arg4); \
_NOLIBC_SYSCALL_REG _arg5 = __nolibc_arg_to_reg(arg5); \
_NOLIBC_SYSCALL_REG _arg6 = __nolibc_arg_to_reg(arg6); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL_STACK_RESERVE \
"sw %7, 16($sp)\n" \
"sw %8, 20($sp)\n" \
"syscall\n" \
_NOLIBC_SYSCALL_STACK_UNRESERVE \
: "=r" (_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#else
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("$4") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("$5") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg3 __asm__ ("$6") = __nolibc_arg_to_reg(arg3); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("$7") = __nolibc_arg_to_reg(arg4); \
_NOLIBC_SYSCALL_REG _arg5 __asm__ ("$8") = __nolibc_arg_to_reg(arg5); \
\
__asm__ volatile ( \
"syscall\n" \
: "=r" (_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
_NOLIBC_SYSCALL_REG _num __asm__ ("v0") = (num); \
_NOLIBC_SYSCALL_REG _arg1 __asm__ ("$4") = __nolibc_arg_to_reg(arg1); \
_NOLIBC_SYSCALL_REG _arg2 __asm__ ("$5") = __nolibc_arg_to_reg(arg2); \
_NOLIBC_SYSCALL_REG _arg3 __asm__ ("$6") = __nolibc_arg_to_reg(arg3); \
_NOLIBC_SYSCALL_REG _arg4 __asm__ ("$7") = __nolibc_arg_to_reg(arg4); \
_NOLIBC_SYSCALL_REG _arg5 __asm__ ("$8") = __nolibc_arg_to_reg(arg5); \
_NOLIBC_SYSCALL_REG _arg6 __asm__ ("$9") = __nolibc_arg_to_reg(arg6); \
\
__asm__ volatile ( \
"syscall\n" \
: "=r" (_num), "=r"(_arg4) \
: "0"(_num), \
"r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg4 ? -_num : _num; \
})
#endif
#ifndef NOLIBC_NO_RUNTIME
void __start(void);
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector __start(void)
{
__asm__ volatile (
"move $a0, $sp\n"
#if defined(_ABIO32)
"addiu $sp, $sp, -16\n"
#endif
"lui $t9, %hi(_start_c)\n"
"ori $t9, %lo(_start_c)\n"
#if defined(_ABI64)
"lui $t0, %highest(_start_c)\n"
"ori $t0, %higher(_start_c)\n"
"dsll $t0, 0x20\n"
"or $t9, $t0\n"
#endif
"jalr $t9\n"
);
__nolibc_entrypoint_epilogue();
}
#endif
#if defined(_ABIO32)
static __attribute__((unused))
int _sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
{
return __nolibc_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
}
#define _sys_ftruncate64 _sys_ftruncate64
#endif
#endif