Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1 @@
sysroot
+115
View File
@@ -0,0 +1,115 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for nolibc installation and tests
include ../../scripts/Makefile.include
# we're in ".../tools/include/nolibc"
ifeq ($(srctree),)
srctree := $(patsubst %/tools/include/,%,$(dir $(CURDIR)))
endif
# when run as make -C tools/ nolibc_<foo> the arch is not set
ifeq ($(ARCH),)
include $(srctree)/scripts/subarch.include
ARCH = $(SUBARCH)
endif
# OUTPUT is only set when run from the main makefile, otherwise
# it defaults to this nolibc directory.
OUTPUT ?= $(CURDIR)/
architectures := arm arm64 loongarch m68k mips openrisc parisc powerpc riscv s390 sh sparc x86
arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures)))
all_files := \
alloca.h \
assert.h \
byteswap.h \
compiler.h \
crt.h \
ctype.h \
dirent.h \
elf.h \
endian.h \
err.h \
errno.h \
fcntl.h \
getopt.h \
inttypes.h \
limits.h \
math.h \
nolibc.h \
poll.h \
sched.h \
signal.h \
stackprotector.h \
std.h \
stdarg.h \
stdbool.h \
stddef.h \
stdint.h \
stdlib.h \
string.h \
sys.h \
sys/auxv.h \
sys/ioctl.h \
sys/mman.h \
sys/mount.h \
sys/prctl.h \
sys/ptrace.h \
sys/random.h \
sys/reboot.h \
sys/resource.h \
sys/select.h \
sys/stat.h \
sys/syscall.h \
sys/sysmacros.h \
sys/time.h \
sys/timerfd.h \
sys/types.h \
sys/uio.h \
sys/utsname.h \
sys/wait.h \
time.h \
types.h \
unistd.h \
stdio.h \
# install all headers needed to support a bare-metal compiler
all: headers
install: help
help:
@echo "Supported targets under nolibc:"
@echo " all call \"headers\""
@echo " clean clean the sysroot"
@echo " headers prepare a multi-arch sysroot in \$${OUTPUT}sysroot"
@echo " headers_standalone like \"headers\", and also install kernel headers"
@echo " help this help"
@echo ""
@echo "These targets may also be called from tools as \"make nolibc_<target>\"."
@echo ""
@echo "Currently using the following variables:"
@echo " ARCH = $(ARCH)"
@echo " OUTPUT = $(OUTPUT)"
@echo ""
# installs headers for all archs at once.
headers:
$(Q)mkdir -p "$(OUTPUT)sysroot/include"
$(Q)cp --parents $(arch_files) $(all_files) "$(OUTPUT)sysroot/include/"
headers_standalone: headers
$(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot
CFLAGS_s390 := -m64
CFLAGS := $(CFLAGS_$(ARCH))
headers_check: headers_standalone
$(Q)for header in $(filter-out crt.h std.h,$(all_files)); do \
$(CC) $(CFLAGS) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \
-I$(or $(objtree),$(srctree))/usr/include -include $$header -include $$header || exit 1; \
done
clean:
$(call QUIET_CLEAN, nolibc) rm -rf "$(OUTPUT)sysroot"
+15
View File
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* alloca() for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_ALLOCA_H
#define _NOLIBC_ALLOCA_H
#define alloca(size) __builtin_alloca(size)
#endif /* _NOLIBC_ALLOCA_H */
+209
View File
@@ -0,0 +1,209 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* ARM specific definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
#ifndef _NOLIBC_ARCH_ARM_H
#define _NOLIBC_ARCH_ARM_H
#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
#include "std.h"
/* Syscalls for ARM in ARM or Thumb modes :
* - registers are 32-bit
* - stack is 8-byte aligned
* ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html)
* - syscall number is passed in r7
* - arguments are in r0, r1, r2, r3, r4, r5
* - the system call is performed by calling svc #0
* - syscall return comes in r0.
* - only lr is clobbered.
* - the arguments are cast to long and assigned into the target registers
* which are then simply passed as registers to the asm code, so that we
* don't have to experience issues with register constraints.
* - the syscall number is always specified last in order to allow to force
* some registers before (gcc refuses a %-register at the last position).
* - in thumb mode without -fomit-frame-pointer, r7 is also used to store the
* frame pointer, and we cannot directly assign it as a register variable,
* nor can we clobber it. Instead we assign the r6 register and swap it
* with r7 before calling svc, and r6 is marked as clobbered.
* We're just using any regular register which we assign to r7 after saving
* it.
*
* Also, ARM supports the old_select syscall if newselect is not available
*/
#define __ARCH_WANT_SYS_OLD_SELECT
#if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \
!defined(NOLIBC_OMIT_FRAME_POINTER)
/* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */
#define _NOLIBC_SYSCALL_REG "r6"
#define _NOLIBC_THUMB_SET_R7 "eor r7, r6\neor r6, r7\neor r7, r6\n"
#define _NOLIBC_THUMB_RESTORE_R7 "mov r7, r6\n"
#else /* we're in ARM mode */
/* in Arm mode we can directly use r7 */
#define _NOLIBC_SYSCALL_REG "r7"
#define _NOLIBC_THUMB_SET_R7 ""
#define _NOLIBC_THUMB_RESTORE_R7 ""
#endif /* end THUMB */
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0"); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r"(_num) \
: "r"(_arg1), \
"r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0") = (long)(arg1); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r" (_num) \
: "r"(_arg1), \
"r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0") = (long)(arg1); \
register long _arg2 __asm__ ("r1") = (long)(arg2); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r" (_num) \
: "r"(_arg1), "r"(_arg2), \
"r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0") = (long)(arg1); \
register long _arg2 __asm__ ("r1") = (long)(arg2); \
register long _arg3 __asm__ ("r2") = (long)(arg3); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
"r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0") = (long)(arg1); \
register long _arg2 __asm__ ("r1") = (long)(arg2); \
register long _arg3 __asm__ ("r2") = (long)(arg3); \
register long _arg4 __asm__ ("r3") = (long)(arg4); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0") = (long)(arg1); \
register long _arg2 __asm__ ("r1") = (long)(arg2); \
register long _arg3 __asm__ ("r2") = (long)(arg3); \
register long _arg4 __asm__ ("r3") = (long)(arg4); \
register long _arg5 __asm__ ("r4") = (long)(arg5); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
register long _arg1 __asm__ ("r0") = (long)(arg1); \
register long _arg2 __asm__ ("r1") = (long)(arg2); \
register long _arg3 __asm__ ("r2") = (long)(arg3); \
register long _arg4 __asm__ ("r3") = (long)(arg4); \
register long _arg5 __asm__ ("r4") = (long)(arg5); \
register long _arg6 __asm__ ("r5") = (long)(arg6); \
\
__asm__ volatile ( \
_NOLIBC_THUMB_SET_R7 \
"svc #0\n" \
_NOLIBC_THUMB_RESTORE_R7 \
: "=r"(_arg1), "=r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6), "r"(_num) \
: "memory", "cc", "lr" \
); \
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"mov r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */
"bl _start_c\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
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 /* _NOLIBC_ARCH_ARM_H */
@@ -0,0 +1,155 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* ARM64 specific definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
#ifndef _NOLIBC_ARCH_ARM64_H
#define _NOLIBC_ARCH_ARM64_H
#include "compiler.h"
#include "crt.h"
/* Syscalls for ARM64 :
* - registers are 64-bit
* - stack is 16-byte aligned
* - syscall number is passed in x8
* - arguments are in x0, x1, x2, x3, x4, x5
* - the system call is performed by calling svc 0
* - syscall return comes in x0.
* - the arguments are cast to long and assigned into the target registers
* which are then simply passed as registers to the asm code, so that we
* don't have to experience issues with register constraints.
*/
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0"); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r"(_arg1) \
: "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0") = (long)(arg1); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r"(_arg1) \
: "r"(_arg1), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0") = (long)(arg1); \
register long _arg2 __asm__ ("x1") = (long)(arg2); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r"(_arg1) \
: "r"(_arg1), "r"(_arg2), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0") = (long)(arg1); \
register long _arg2 __asm__ ("x1") = (long)(arg2); \
register long _arg3 __asm__ ("x2") = (long)(arg3); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r"(_arg1) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0") = (long)(arg1); \
register long _arg2 __asm__ ("x1") = (long)(arg2); \
register long _arg3 __asm__ ("x2") = (long)(arg3); \
register long _arg4 __asm__ ("x3") = (long)(arg4); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r"(_arg1) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0") = (long)(arg1); \
register long _arg2 __asm__ ("x1") = (long)(arg2); \
register long _arg3 __asm__ ("x2") = (long)(arg3); \
register long _arg4 __asm__ ("x3") = (long)(arg4); \
register long _arg5 __asm__ ("x4") = (long)(arg5); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r" (_arg1) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("x8") = (num); \
register long _arg1 __asm__ ("x0") = (long)(arg1); \
register long _arg2 __asm__ ("x1") = (long)(arg2); \
register long _arg3 __asm__ ("x2") = (long)(arg3); \
register long _arg4 __asm__ ("x3") = (long)(arg4); \
register long _arg5 __asm__ ("x4") = (long)(arg5); \
register long _arg6 __asm__ ("x5") = (long)(arg6); \
\
__asm__ volatile ( \
"svc #0\n" \
: "=r" (_arg1) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6), "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */
"bl _start_c\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_ARM64_H */
@@ -0,0 +1,157 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* LoongArch specific definitions for NOLIBC
* Copyright (C) 2023 Loongson Technology Corporation Limited
*/
#ifndef _NOLIBC_ARCH_LOONGARCH_H
#define _NOLIBC_ARCH_LOONGARCH_H
#include "compiler.h"
#include "crt.h"
/* Syscalls for LoongArch :
* - stack is 16-byte aligned
* - syscall number is passed in a7
* - arguments are in a0, a1, a2, a3, a4, a5
* - the system call is performed by calling "syscall 0"
* - syscall return comes in a0
* - the arguments are cast to long and assigned into the target
* registers which are then simply passed as registers to the asm code,
* so that we don't have to experience issues with register constraints.
*/
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8"
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0"); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "=r"(_arg1) \
: "r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "+r"(_arg1) \
: "r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "+r"(_arg1) \
: "r"(_arg2), \
"r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), \
"r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
register long _arg4 __asm__ ("a3") = (long)(arg4); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
register long _arg4 __asm__ ("a3") = (long)(arg4); \
register long _arg5 __asm__ ("a4") = (long)(arg5); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
register long _arg4 __asm__ ("a3") = (long)(arg4); \
register long _arg5 __asm__ ("a4") = (long)(arg5); \
register long _arg6 __asm__ ("a5") = (long)(arg6); \
\
__asm__ volatile ( \
"syscall 0\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
"r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */
"bl _start_c\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_LOONGARCH_H */
@@ -0,0 +1,143 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* m68k specific definitions for NOLIBC
* Copyright (C) 2025 Daniel Palmer<daniel@thingy.jp>
*
* Roughly based on one or more of the other arch files.
*
*/
#ifndef _NOLIBC_ARCH_M68K_H
#define _NOLIBC_ARCH_M68K_H
#include "compiler.h"
#include "crt.h"
#define _NOLIBC_SYSCALL_CLOBBERLIST "memory"
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("d0") = (num); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r"(_num) \
: "r"(_num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("d0") = (num); \
register long _arg1 __asm__ ("d1") = (long)(arg1); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r"(_num) \
: "r"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("d0") = (num); \
register long _arg1 __asm__ ("d1") = (long)(arg1); \
register long _arg2 __asm__ ("d2") = (long)(arg2); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("d0") = (num); \
register long _arg1 __asm__ ("d1") = (long)(arg1); \
register long _arg2 __asm__ ("d2") = (long)(arg2); \
register long _arg3 __asm__ ("d3") = (long)(arg3); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("d0") = (num); \
register long _arg1 __asm__ ("d1") = (long)(arg1); \
register long _arg2 __asm__ ("d2") = (long)(arg2); \
register long _arg3 __asm__ ("d3") = (long)(arg3); \
register long _arg4 __asm__ ("d4") = (long)(arg4); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("d0") = (num); \
register long _arg1 __asm__ ("d1") = (long)(arg1); \
register long _arg2 __asm__ ("d2") = (long)(arg2); \
register long _arg3 __asm__ ("d3") = (long)(arg3); \
register long _arg4 __asm__ ("d4") = (long)(arg4); \
register long _arg5 __asm__ ("d5") = (long)(arg5); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("d0") = (num); \
register long _arg1 __asm__ ("d1") = (long)(arg1); \
register long _arg2 __asm__ ("d2") = (long)(arg2); \
register long _arg3 __asm__ ("d3") = (long)(arg3); \
register long _arg4 __asm__ ("d4") = (long)(arg4); \
register long _arg5 __asm__ ("d5") = (long)(arg5); \
register long _arg6 __asm__ ("a0") = (long)(arg6); \
\
__asm__ volatile ( \
"trap #0\n" \
: "+r" (_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#ifndef NOLIBC_NO_RUNTIME
void _start(void);
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"movel %sp, %sp@-\n"
"jsr _start_c\n"
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_M68K_H */
@@ -0,0 +1,297 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* MIPS specific definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
#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
/* Syscalls for MIPS ABI O32 :
* - WARNING! there's always a delayed slot!
* - WARNING again, the syntax is different, registers take a '$' and numbers
* do not.
* - registers are 32-bit
* - stack is 8-byte aligned
* - syscall number is passed in v0 (starts at 0xfa0).
* - arguments are in a0, a1, a2, a3, then the stack. The caller needs to
* leave some room in the stack for the callee to save a0..a3 if needed.
* - Many registers are clobbered, in fact only a0..a2 and s0..s8 are
* preserved. See: https://www.linux-mips.org/wiki/Syscall as well as
* scall32-o32.S in the kernel sources.
* - the system call is performed by calling "syscall"
* - syscall return comes in v0, and register a3 needs to be checked to know
* if an error occurred, in which case errno is in v0.
* - the arguments are cast to long and assigned into the target registers
* which are then simply passed as registers to the asm code, so that we
* don't have to experience issues with register constraints.
*
* Syscalls for MIPS ABI N32, same as ABI O32 with the following differences :
* - arguments are in a0, a1, a2, a3, t0, t1, t2, t3.
* t0..t3 are also known as a4..a7.
* - stack is 16-byte aligned
*/
#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 /* _ABIN32 || _ABI64 */
/* binutils, GCC and clang disagree about register aliases, use numbers instead. */
#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 /* _ABIO32 */
#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 /* _ABIN32 || _ABI64 */
#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 /* _ABIO32 */
#ifndef NOLIBC_NO_RUNTIME
/* startup code, note that it's called __start on MIPS */
void __start(void);
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector __start(void)
{
__asm__ volatile (
"move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */
#if defined(_ABIO32)
"addiu $sp, $sp, -16\n" /* the callee expects to save a0..a3 there */
#endif /* _ABIO32 */
"lui $t9, %hi(_start_c)\n" /* ABI requires current function address in $t9 */
"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 /* _ABI64 */
"jalr $t9\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#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 /* _NOLIBC_ARCH_MIPS_H */
@@ -0,0 +1,160 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* OpenRISC specific definitions for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_ARCH_OPENRISC_H
#define _NOLIBC_ARCH_OPENRISC_H
#include "compiler.h"
#include "crt.h"
/*
* Syscalls for OpenRISC:
* - syscall number is passed in r11
* - arguments are in r3, r4, r5, r6, r7, r8
* - the system call is performed by calling l.sys 1
* - syscall return value is in r11
*/
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"r12", "r13", "r15", "r17", "r19", "r21", "r23", "r25", "r27", "r29", "r31", "memory"
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("r11") = (num); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: \
: "r3", "r4", "r5", "r6", "r7", "r8", \
_NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("r11") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: "r"(_arg1) \
: "r4", "r5", "r6", "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("r11") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2) \
: "r5", "r6", "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("r11") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3) \
: "r6", "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("r11") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
register long _arg4 __asm__ ("r6") = (long)(arg4); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \
: "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("r11") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
register long _arg4 __asm__ ("r6") = (long)(arg4); \
register long _arg5 __asm__ ("r7") = (long)(arg5); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \
: "r8", _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("r11") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
register long _arg4 __asm__ ("r6") = (long)(arg4); \
register long _arg5 __asm__ ("r7") = (long)(arg5); \
register long _arg6 __asm__ ("r8") = (long)(arg6); \
\
__asm__ volatile ( \
"l.sys 1\n" \
: "+r"(_num) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_num; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void _start_wrapper(void);
void __attribute__((weak,noreturn))
__nolibc_entrypoint __nolibc_no_stack_protector
_start_wrapper(void)
{
__asm__ volatile (
".global _start\n" /* The C function will have a prologue, */
".type _start, @function\n" /* corrupting "sp/r1" */
".weak _start\n"
"_start:\n"
"l.jal _start_c\n" /* transfer to c runtime */
"l.or r3,r1,r1\n" /* save stack pointer to r3, as arg1 of _start_c */
".size _start, .-_start\n"
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_OPENRISC_H */
@@ -0,0 +1,185 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* parisc/hppa (32-bit) specific definitions for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_ARCH_PARISC_H
#define _NOLIBC_ARCH_PARISC_H
#if defined(__LP64__)
#error 64-bit not supported
#endif
#include "compiler.h"
#include "crt.h"
/* Syscalls for parisc :
* - syscall number is passed in r20
* - arguments are in r26 to r21
* - the system call is performed by calling "ble 0x100(%sr2, %r0)",
* the instruction after that is in the delay slot and executed before
* the jump to 0x100 actually happens, use it to load the syscall number
* - syscall return comes in r28
* - the arguments are cast to long and assigned into the target
* registers which are then simply passed as registers to the asm code,
* so that we don't have to experience issues with register constraints.
*/
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"memory", "%r1", "%r2", "%r4", "%r20", "%r29", "%r31"
#define __nolibc_syscall0(num) \
({ \
register long _ret __asm__ ("r28"); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %1, %%r20\n\t" \
: "=r"(_ret) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST, \
"%r21", "%r22", "%r23", "%r24", "%r25", "%r26" \
); \
_ret; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _ret __asm__ ("r28"); \
register long _arg1 __asm__ ("r26") = (long)(arg1); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %2, %%r20\n\t" \
: "=r"(_ret), \
"+r"(_arg1) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST, \
"%r21", "%r22", "%r23", "%r24", "%r25" \
); \
_ret; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _ret __asm__ ("r28"); \
register long _arg1 __asm__ ("r26") = (long)(arg1); \
register long _arg2 __asm__ ("r25") = (long)(arg2); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %3, %%r20\n\t" \
: "=r"(_ret), \
"+r"(_arg1), "+r"(_arg2) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST, \
"%r21", "%r22", "%r23", "%r24" \
); \
_ret; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _ret __asm__ ("r28"); \
register long _arg1 __asm__ ("r26") = (long)(arg1); \
register long _arg2 __asm__ ("r25") = (long)(arg2); \
register long _arg3 __asm__ ("r24") = (long)(arg3); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %4, %%r20\n\t" \
: "=r"(_ret), \
"+r"(_arg1), "+r"(_arg2), "+r"(_arg3) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST, \
"%r21", "%r22", "%r23" \
); \
_ret; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _ret __asm__ ("r28"); \
register long _arg1 __asm__ ("r26") = (long)(arg1); \
register long _arg2 __asm__ ("r25") = (long)(arg2); \
register long _arg3 __asm__ ("r24") = (long)(arg3); \
register long _arg4 __asm__ ("r23") = (long)(arg4); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %5, %%r20\n\t" \
: "=r"(_ret), \
"+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST, \
"%r21", "%r22" \
); \
_ret; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _ret __asm__ ("r28"); \
register long _arg1 __asm__ ("r26") = (long)(arg1); \
register long _arg2 __asm__ ("r25") = (long)(arg2); \
register long _arg3 __asm__ ("r24") = (long)(arg3); \
register long _arg4 __asm__ ("r23") = (long)(arg4); \
register long _arg5 __asm__ ("r22") = (long)(arg5); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %6, %%r20\n\t" \
: "=r"(_ret), \
"+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4), \
"+r"(_arg5) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST, \
"%r21" \
); \
_ret; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _ret __asm__ ("r28"); \
register long _arg1 __asm__ ("r26") = (long)(arg1); \
register long _arg2 __asm__ ("r25") = (long)(arg2); \
register long _arg3 __asm__ ("r24") = (long)(arg3); \
register long _arg4 __asm__ ("r23") = (long)(arg4); \
register long _arg5 __asm__ ("r22") = (long)(arg5); \
register long _arg6 __asm__ ("r21") = (long)(arg6); \
\
__asm__ volatile ( \
"ble 0x100(%%sr2, %%r0)\n\t" \
"copy %7, %%r20\n\t" \
: "=r"(_ret), \
"+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4), \
"+r"(_arg5), "+r"(_arg6) \
: "r"(num) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_ret; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
".import $global$\n" /* Set up the dp register */
"ldil L%$global$, %dp\n"
"ldo R%$global$(%r27), %dp\n"
"b _start_c\n" /* Call _start_c, the load below is executed first */
"ldo -4(%r24), %r26\n" /* The sp register is special on parisc.
* r24 points to argv. Subtract 4 to get &argc.
* Pass that as first argument to _start_c.
*/
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_PARISC_H */
@@ -0,0 +1,233 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* PowerPC specific definitions for NOLIBC
* Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org>
*/
#ifndef _NOLIBC_ARCH_POWERPC_H
#define _NOLIBC_ARCH_POWERPC_H
#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
#include "std.h"
/* Syscalls for PowerPC :
* - stack is 16-byte aligned
* - syscall number is passed in r0
* - arguments are in r3, r4, r5, r6, r7, r8, r9
* - the system call is performed by calling "sc"
* - syscall return comes in r3, and the summary overflow bit is checked
* to know if an error occurred, in which case errno is in r3.
* - the arguments are cast to long and assigned into the target
* registers which are then simply passed as registers to the asm code,
* so that we don't have to experience issues with register constraints.
*/
#define _NOLIBC_SYSCALL_CLOBBERLIST \
"memory", "cr0", "r12", "r11", "r10", "r9"
#define __nolibc_syscall0(num) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num) \
: \
: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \
); \
_ret; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num) \
: "0"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \
); \
_ret; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num), "+r"(_arg2) \
: "0"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5" \
); \
_ret; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3) \
: "0"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6" \
); \
_ret; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
register long _arg4 __asm__ ("r6") = (long)(arg4); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \
"+r"(_arg4) \
: "0"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7" \
); \
_ret; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
register long _arg4 __asm__ ("r6") = (long)(arg4); \
register long _arg5 __asm__ ("r7") = (long)(arg5); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \
"+r"(_arg4), "+r"(_arg5) \
: "0"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST, "r8" \
); \
_ret; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _ret __asm__ ("r3"); \
register long _num __asm__ ("r0") = (num); \
register long _arg1 __asm__ ("r3") = (long)(arg1); \
register long _arg2 __asm__ ("r4") = (long)(arg2); \
register long _arg3 __asm__ ("r5") = (long)(arg3); \
register long _arg4 __asm__ ("r6") = (long)(arg4); \
register long _arg5 __asm__ ("r7") = (long)(arg5); \
register long _arg6 __asm__ ("r8") = (long)(arg6); \
\
__asm__ volatile ( \
" sc\n" \
" bns+ 1f\n" \
" neg %0, %0\n" \
"1:\n" \
: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \
"+r"(_arg4), "+r"(_arg5), "+r"(_arg6) \
: "0"(_arg1) \
: _NOLIBC_SYSCALL_CLOBBERLIST \
); \
_ret; \
})
#if !defined(__powerpc64__) && !defined(__clang__)
/* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0),
* "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but
* works with __attribute__((__optimize__("-fno-stack-protector")))
*/
#ifdef __nolibc_no_stack_protector
#undef __nolibc_no_stack_protector
#define __nolibc_no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
#endif
#endif /* !__powerpc64__ */
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
#ifdef __powerpc64__
#if _CALL_ELF == 2
/* with -mabi=elfv2, save TOC/GOT pointer to r2
* r12 is global entry pointer, we use it to compute TOC from r12
* https://www.llvm.org/devmtg/2014-04/PDFs/Talks/Euro-LLVM-2014-Weigand.pdf
* https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.pdf
*/
__asm__ volatile (
"addis 2, 12, .TOC. - _start@ha\n"
"addi 2, 2, .TOC. - _start@l\n"
);
#endif /* _CALL_ELF == 2 */
__asm__ volatile (
"mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */
"li 0, 0\n" /* zero the frame pointer */
"stdu 1, -32(1)\n" /* the initial stack frame */
"bl _start_c\n" /* transfer to c runtime */
);
#else
__asm__ volatile (
"mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */
"li 0, 0\n" /* zero the frame pointer */
"stwu 1, -16(1)\n" /* the initial stack frame */
"bl _start_c\n" /* transfer to c runtime */
);
#endif
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#if !defined(__powerpc64__)
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 /* _NOLIBC_ARCH_POWERPC_H */
@@ -0,0 +1,158 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* RISCV (32 and 64) specific definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
#ifndef _NOLIBC_ARCH_RISCV_H
#define _NOLIBC_ARCH_RISCV_H
#include "compiler.h"
#include "crt.h"
/* Syscalls for RISCV :
* - stack is 16-byte aligned
* - syscall number is passed in a7
* - arguments are in a0, a1, a2, a3, a4, a5
* - the system call is performed by calling ecall
* - syscall return comes in a0
* - the arguments are cast to long and assigned into the target
* registers which are then simply passed as registers to the asm code,
* so that we don't have to experience issues with register constraints.
*/
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0"); \
\
__asm__ volatile ( \
"ecall\n\t" \
: "=r"(_arg1) \
: "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
\
__asm__ volatile ( \
"ecall\n" \
: "+r"(_arg1) \
: "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
\
__asm__ volatile ( \
"ecall\n" \
: "+r"(_arg1) \
: "r"(_arg2), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
\
__asm__ volatile ( \
"ecall\n\t" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
register long _arg4 __asm__ ("a3") = (long)(arg4); \
\
__asm__ volatile ( \
"ecall\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
register long _arg4 __asm__ ("a3") = (long)(arg4); \
register long _arg5 __asm__ ("a4") = (long)(arg5); \
\
__asm__ volatile ( \
"ecall\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("a7") = (num); \
register long _arg1 __asm__ ("a0") = (long)(arg1); \
register long _arg2 __asm__ ("a1") = (long)(arg2); \
register long _arg3 __asm__ ("a2") = (long)(arg3); \
register long _arg4 __asm__ ("a3") = (long)(arg4); \
register long _arg5 __asm__ ("a4") = (long)(arg5); \
register long _arg6 __asm__ ("a5") = (long)(arg6); \
\
__asm__ volatile ( \
"ecall\n" \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
".option push\n"
".option norelax\n"
"lla gp, __global_pointer$\n"
".option pop\n"
"mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */
"call _start_c\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_RISCV_H */
@@ -0,0 +1,200 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* s390 specific definitions for NOLIBC
*/
#ifndef _NOLIBC_ARCH_S390_H
#define _NOLIBC_ARCH_S390_H
#include "types.h"
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
#include "std.h"
/* Syscalls for s390:
* - registers are 64-bit
* - syscall number is passed in r1
* - arguments are in r2-r7
* - the system call is performed by calling the svc instruction
* - syscall return value is in r2
* - r1 and r2 are clobbered, others are preserved.
*
* Link s390 ABI: https://github.com/IBM/s390x-abi
*
*/
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("1") = (num); \
register long _rc __asm__ ("2"); \
\
__asm__ volatile ( \
"svc 0\n" \
: "=d"(_rc) \
: "d"(_num) \
: "memory", "cc" \
); \
_rc; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
register long _arg4 __asm__ ("5") = (long)(arg4); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
register long _arg4 __asm__ ("5") = (long)(arg4); \
register long _arg5 __asm__ ("6") = (long)(arg5); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \
"d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("1") = (num); \
register long _arg1 __asm__ ("2") = (long)(arg1); \
register long _arg2 __asm__ ("3") = (long)(arg2); \
register long _arg3 __asm__ ("4") = (long)(arg3); \
register long _arg4 __asm__ ("5") = (long)(arg4); \
register long _arg5 __asm__ ("6") = (long)(arg5); \
register long _arg6 __asm__ ("7") = (long)(arg6); \
\
__asm__ volatile ( \
"svc 0\n" \
: "+d"(_arg1) \
: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \
"d"(_arg6), "d"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */
"aghi %r15, -160\n" /* allocate new stackframe */
"xc 0(8,%r15), 0(%r15)\n" /* clear backchain */
"brasl %r14, _start_c\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
struct s390_mmap_arg_struct {
unsigned long addr;
unsigned long len;
unsigned long prot;
unsigned long flags;
unsigned long fd;
unsigned long offset;
};
static __attribute__((unused))
void *_sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset)
{
struct s390_mmap_arg_struct args = {
.addr = (unsigned long)addr,
.len = (unsigned long)length,
.prot = prot,
.flags = flags,
.fd = fd,
.offset = (unsigned long)offset
};
return (void *)__nolibc_syscall1(__NR_mmap, &args);
}
#define _sys_mmap _sys_mmap
static __attribute__((unused))
pid_t _sys_fork(void)
{
return __nolibc_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0);
}
#define _sys_fork _sys_fork
static __attribute__((unused))
pid_t _sys_vfork(void)
{
return __nolibc_syscall5(__NR_clone, 0, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0);
}
#define _sys_vfork _sys_vfork
#endif /* _NOLIBC_ARCH_S390_H */
+164
View File
@@ -0,0 +1,164 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* SuperH specific definitions for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_ARCH_SH_H
#define _NOLIBC_ARCH_SH_H
#include "compiler.h"
#include "crt.h"
/*
* Syscalls for SuperH:
* - registers are 32bit wide
* - syscall number is passed in r3
* - arguments are in r4, r5, r6, r7, r0, r1, r2
* - the system call is performed by calling trapa #31
* - syscall return value is in r0
*/
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
register long _arg1 __asm__ ("r4") = (long)(arg1); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num), "r"(_arg1) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
register long _arg1 __asm__ ("r4") = (long)(arg1); \
register long _arg2 __asm__ ("r5") = (long)(arg2); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num), "r"(_arg1), "r"(_arg2) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
register long _arg1 __asm__ ("r4") = (long)(arg1); \
register long _arg2 __asm__ ("r5") = (long)(arg2); \
register long _arg3 __asm__ ("r6") = (long)(arg3); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
register long _arg1 __asm__ ("r4") = (long)(arg1); \
register long _arg2 __asm__ ("r5") = (long)(arg2); \
register long _arg3 __asm__ ("r6") = (long)(arg3); \
register long _arg4 __asm__ ("r7") = (long)(arg4); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
register long _arg1 __asm__ ("r4") = (long)(arg1); \
register long _arg2 __asm__ ("r5") = (long)(arg2); \
register long _arg3 __asm__ ("r6") = (long)(arg3); \
register long _arg4 __asm__ ("r7") = (long)(arg4); \
register long _arg5 __asm__ ("r0") = (long)(arg5); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_arg5) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("r3") = (num); \
register long _ret __asm__ ("r0"); \
register long _arg1 __asm__ ("r4") = (long)(arg1); \
register long _arg2 __asm__ ("r5") = (long)(arg2); \
register long _arg3 __asm__ ("r6") = (long)(arg3); \
register long _arg4 __asm__ ("r7") = (long)(arg4); \
register long _arg5 __asm__ ("r0") = (long)(arg5); \
register long _arg6 __asm__ ("r1") = (long)(arg6); \
\
__asm__ volatile ( \
"trapa #31" \
: "=r"(_ret) \
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_arg5), "r"(_arg6) \
: "memory", "cc" \
); \
_ret; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void _start_wrapper(void);
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start_wrapper(void)
{
__asm__ volatile (
".global _start\n" /* The C function will have a prologue, */
".type _start, @function\n" /* corrupting "sp" */
".weak _start\n"
"_start:\n"
"mov sp, r4\n" /* save argc pointer to r4, as arg1 of _start_c */
"bsr _start_c\n" /* transfer to c runtime */
"nop\n" /* delay slot */
".size _start, .-_start\n"
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_ARCH_SH_H */
@@ -0,0 +1,209 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* SPARC (32bit and 64bit) specific definitions for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_ARCH_SPARC_H
#define _NOLIBC_ARCH_SPARC_H
#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
/*
* Syscalls for SPARC:
* - registers are native word size
* - syscall number is passed in g1
* - arguments are in o0-o5
* - the system call is performed by calling a trap instruction
* - syscall return value is in o0
* - syscall error flag is in the carry bit of the processor status register
*/
#ifdef __arch64__
#define _NOLIBC_SYSCALL "t 0x6d\n" \
"bcs,a %%xcc, 1f\n" \
"sub %%g0, %%o0, %%o0\n" \
"1:\n"
#else
#define _NOLIBC_SYSCALL "t 0x10\n" \
"bcs,a 1f\n" \
"sub %%g0, %%o0, %%o0\n" \
"1:\n"
#endif /* __arch64__ */
#define __nolibc_syscall0(num) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0"); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0") = (long)(arg1); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0") = (long)(arg1); \
register long _arg2 __asm__ ("o1") = (long)(arg2); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0") = (long)(arg1); \
register long _arg2 __asm__ ("o1") = (long)(arg2); \
register long _arg3 __asm__ ("o2") = (long)(arg3); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0") = (long)(arg1); \
register long _arg2 __asm__ ("o1") = (long)(arg2); \
register long _arg3 __asm__ ("o2") = (long)(arg3); \
register long _arg4 __asm__ ("o3") = (long)(arg4); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0") = (long)(arg1); \
register long _arg2 __asm__ ("o1") = (long)(arg2); \
register long _arg3 __asm__ ("o2") = (long)(arg3); \
register long _arg4 __asm__ ("o3") = (long)(arg4); \
register long _arg5 __asm__ ("o4") = (long)(arg5); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
register long _num __asm__ ("g1") = (num); \
register long _arg1 __asm__ ("o0") = (long)(arg1); \
register long _arg2 __asm__ ("o1") = (long)(arg2); \
register long _arg3 __asm__ ("o2") = (long)(arg3); \
register long _arg4 __asm__ ("o3") = (long)(arg4); \
register long _arg5 __asm__ ("o4") = (long)(arg5); \
register long _arg6 __asm__ ("o5") = (long)(arg6); \
\
__asm__ volatile ( \
_NOLIBC_SYSCALL \
: "+r"(_arg1) \
: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
"r"(_num) \
: "memory", "cc" \
); \
_arg1; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
/*
* Save argc pointer to o0, as arg1 of _start_c.
* Account for the window save area, which is 16 registers wide.
*/
#ifdef __arch64__
"add %sp, 128 + 2047, %o0\n" /* on sparc64 / v9 the stack is offset by 2047 */
#else
"add %sp, 64, %o0\n"
#endif
"b,a _start_c\n" /* transfer to c runtime */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
static pid_t getpid(void);
static __attribute__((unused))
pid_t _sys_fork(void)
{
pid_t parent, ret;
parent = getpid();
ret = __nolibc_syscall0(__NR_fork);
/* The syscall returns the parent pid in the child instead of 0 */
if (ret == parent)
return 0;
else
return ret;
}
#define _sys_fork _sys_fork
static __attribute__((unused))
pid_t _sys_vfork(void)
{
pid_t parent, ret;
parent = getpid();
ret = __nolibc_syscall0(__NR_vfork);
/* The syscall returns the parent pid in the child instead of 0 */
if (ret == parent)
return 0;
else
return ret;
}
#define _sys_vfork _sys_vfork
#endif /* _NOLIBC_ARCH_SPARC_H */
+393
View File
@@ -0,0 +1,393 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* x86 specific definitions for NOLIBC (both 32- and 64-bit)
* Copyright (C) 2017-2025 Willy Tarreau <w@1wt.eu>
*/
#ifndef _NOLIBC_ARCH_X86_H
#define _NOLIBC_ARCH_X86_H
#include "compiler.h"
#include "crt.h"
#if !defined(__x86_64__)
/* Syscalls for i386 :
* - mostly similar to x86_64
* - registers are 32-bit
* - syscall number is passed in eax
* - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
* - all registers are preserved (except eax of course)
* - the system call is performed by calling int $0x80
* - syscall return comes in eax
* - the arguments are cast to long and assigned into the target registers
* which are then simply passed as registers to the asm code, so that we
* don't have to experience issues with register constraints.
* - the syscall number is always specified last in order to allow to force
* some registers before (gcc refuses a %-register at the last position).
*
* Also, i386 supports the old_select syscall if newselect is not available
*/
#define __ARCH_WANT_SYS_OLD_SELECT
#define __nolibc_syscall0(num) \
({ \
long _ret; \
register long _num __asm__ ("eax") = (num); \
\
__asm__ volatile ( \
"int $0x80\n" \
: "=a" (_ret) \
: "0"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
long _ret; \
register long _num __asm__ ("eax") = (num); \
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
\
__asm__ volatile ( \
"int $0x80\n" \
: "=a" (_ret) \
: "r"(_arg1), \
"0"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
long _ret; \
register long _num __asm__ ("eax") = (num); \
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
\
__asm__ volatile ( \
"int $0x80\n" \
: "=a" (_ret) \
: "r"(_arg1), "r"(_arg2), \
"0"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
long _ret; \
register long _num __asm__ ("eax") = (num); \
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
register long _arg3 __asm__ ("edx") = (long)(arg3); \
\
__asm__ volatile ( \
"int $0x80\n" \
: "=a" (_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
"0"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
long _ret; \
register long _num __asm__ ("eax") = (num); \
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
register long _arg3 __asm__ ("edx") = (long)(arg3); \
register long _arg4 __asm__ ("esi") = (long)(arg4); \
\
__asm__ volatile ( \
"int $0x80\n" \
: "=a" (_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"0"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
long _ret; \
register long _num __asm__ ("eax") = (num); \
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
register long _arg3 __asm__ ("edx") = (long)(arg3); \
register long _arg4 __asm__ ("esi") = (long)(arg4); \
register long _arg5 __asm__ ("edi") = (long)(arg5); \
\
__asm__ volatile ( \
"int $0x80\n" \
: "=a" (_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"0"(_num) \
: "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
long _eax = (long)(num); \
long _arg6 = (long)(arg6); /* Always in memory */ \
__asm__ volatile ( \
"pushl %[_arg6]\n\t" \
"pushl %%ebp\n\t" \
"movl 4(%%esp),%%ebp\n\t" \
"int $0x80\n\t" \
"popl %%ebp\n\t" \
"addl $4,%%esp\n\t" \
: "+a"(_eax) /* %eax */ \
: "b"(arg1), /* %ebx */ \
"c"(arg2), /* %ecx */ \
"d"(arg3), /* %edx */ \
"S"(arg4), /* %esi */ \
"D"(arg5), /* %edi */ \
[_arg6]"m"(_arg6) /* memory */ \
: "memory", "cc" \
); \
_eax; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
/*
* i386 System V ABI mandates:
* 1) last pushed argument must be 16-byte aligned.
* 2) The deepest stack frame should be set to zero
*
*/
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"xor %ebp, %ebp\n" /* zero the stack frame */
"mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */
"sub $12, %esp\n" /* sub 12 to keep it aligned after the push %eax */
"push %eax\n" /* push arg1 on stack to support plain stack modes too */
"call _start_c\n" /* transfer to c runtime */
"hlt\n" /* ensure it does not return */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#else /* !defined(__x86_64__) */
/* Syscalls for x86_64 :
* - registers are 64-bit
* - syscall number is passed in rax
* - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
* - the system call is performed by calling the syscall instruction
* - syscall return comes in rax
* - rcx and r11 are clobbered, others are preserved.
* - the arguments are cast to long and assigned into the target registers
* which are then simply passed as registers to the asm code, so that we
* don't have to experience issues with register constraints.
* - the syscall number is always specified last in order to allow to force
* some registers before (gcc refuses a %-register at the last position).
* - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
* Calling Conventions.
*
* Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/home
*
*/
#define __nolibc_syscall0(num) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall1(num, arg1) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "r"(_arg1), \
"0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall2(num, arg1, arg2) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "r"(_arg1), "r"(_arg2), \
"0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall3(num, arg1, arg2, arg3) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
"0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
register long long _arg4 __asm__ ("r10") = __nolibc_arg_to_reg(arg4); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
register long long _arg4 __asm__ ("r10") = __nolibc_arg_to_reg(arg4); \
register long long _arg5 __asm__ ("r8") = __nolibc_arg_to_reg(arg5); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
long long _ret; \
register long long _num __asm__ ("rax") = (num); \
register long long _arg1 __asm__ ("rdi") = __nolibc_arg_to_reg(arg1); \
register long long _arg2 __asm__ ("rsi") = __nolibc_arg_to_reg(arg2); \
register long long _arg3 __asm__ ("rdx") = __nolibc_arg_to_reg(arg3); \
register long long _arg4 __asm__ ("r10") = __nolibc_arg_to_reg(arg4); \
register long long _arg5 __asm__ ("r8") = __nolibc_arg_to_reg(arg5); \
register long long _arg6 __asm__ ("r9") = __nolibc_arg_to_reg(arg6); \
\
__asm__ volatile ( \
"syscall\n" \
: "=a"(_ret) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
"r"(_arg6), "0"(_num) \
: "rcx", "r11", "memory", "cc" \
); \
_ret; \
})
#ifndef NOLIBC_NO_RUNTIME
/* startup code */
/*
* x86-64 System V ABI mandates:
* 1) %rsp must be 16-byte aligned right before the function call.
* 2) The deepest stack frame should be zero (the %rbp).
*
*/
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
"xor %ebp, %ebp\n" /* zero the stack frame */
"mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */
"call _start_c\n" /* transfer to c runtime */
"hlt\n" /* ensure it does not return */
);
__nolibc_entrypoint_epilogue();
}
#endif /* NOLIBC_NO_RUNTIME */
#define NOLIBC_ARCH_HAS_MEMMOVE
void *memmove(void *dst, const void *src, size_t len);
#define NOLIBC_ARCH_HAS_MEMCPY
void *memcpy(void *dst, const void *src, size_t len);
#define NOLIBC_ARCH_HAS_MEMSET
void *memset(void *dst, int c, size_t len);
__asm__ (
".pushsection .text.nolibc_memmove_memcpy\n"
".weak memmove\n"
".weak memcpy\n"
"memmove:\n"
"memcpy:\n"
"movq %rdx, %rcx\n\t"
"movq %rdi, %rax\n\t"
"movq %rdi, %rdx\n\t"
"subq %rsi, %rdx\n\t"
"cmpq %rcx, %rdx\n\t"
"jb 1f\n\t"
"rep movsb\n\t"
"retq\n"
"1:" /* backward copy */
"leaq -1(%rdi, %rcx, 1), %rdi\n\t"
"leaq -1(%rsi, %rcx, 1), %rsi\n\t"
"std\n\t"
"rep movsb\n\t"
"cld\n\t"
"retq\n"
".popsection\n"
".pushsection .text.nolibc_memset\n"
".weak memset\n"
"memset:\n"
"xchgl %eax, %esi\n\t"
"movq %rdx, %rcx\n\t"
"pushq %rdi\n\t"
"rep stosb\n\t"
"popq %rax\n\t"
"retq\n"
".popsection\n"
);
#endif /* !defined(__x86_64__) */
#endif /* _NOLIBC_ARCH_X86_H */
+39
View File
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
#ifndef _NOLIBC_ARCH_H
#define _NOLIBC_ARCH_H
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
#include "arch-x86.h"
#elif defined(__ARM_EABI__)
#include "arch-arm.h"
#elif defined(__aarch64__)
#include "arch-arm64.h"
#elif defined(__mips__)
#include "arch-mips.h"
#elif defined(__powerpc__)
#include "arch-powerpc.h"
#elif defined(__riscv)
#include "arch-riscv.h"
#elif defined(__s390x__)
#include "arch-s390.h"
#elif defined(__loongarch__)
#include "arch-loongarch.h"
#elif defined(__sparc__)
#include "arch-sparc.h"
#elif defined(__m68k__)
#include "arch-m68k.h"
#elif defined(__sh__)
#include "arch-sh.h"
#elif defined(__or1k__)
#include "arch-openrisc.h"
#elif defined(__hppa__)
#include "arch-parisc.h"
#else
#error Unsupported Architecture
#endif
#endif /* _NOLIBC_ARCH_H */
+36
View File
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Assert for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_ASSERT_H
#define _NOLIBC_ASSERT_H
#include "errno.h"
#include "stdio.h"
#include "stdlib.h"
#endif /* _NOLIBC_ASSERT_H */
/* NDEBUG needs to be evaluated on *each* inclusion */
#ifdef assert
#undef assert
#endif
#ifndef NDEBUG
#define assert(expr) \
({ \
if (!(expr)) { \
fprintf(stderr, "%s: %s:%d: %s: Assertion `%s' failed.\n", \
program_invocation_short_name, __FILE__, __LINE__, __func__, \
#expr); \
abort(); \
} \
})
#else
#define assert(expr) ((void)0)
#endif
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Byte swapping for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_BYTESWAP_H
#define _NOLIBC_BYTESWAP_H
#include "stdint.h"
#include <linux/swab.h>
#define bswap_16(_x) __swab16(_x)
#define bswap_32(_x) __swab32(_x)
#define bswap_64(_x) __swab64(_x)
#endif /* _NOLIBC_BYTESWAP_H */
@@ -0,0 +1,93 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* NOLIBC compiler support header
* Copyright (C) 2023 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_COMPILER_H
#define _NOLIBC_COMPILER_H
#if defined(__has_attribute)
# define __nolibc_has_attribute(attr) __has_attribute(attr)
#else
# define __nolibc_has_attribute(attr) 0
#endif
#if defined(__has_feature)
# define __nolibc_has_feature(feature) __has_feature(feature)
#else
# define __nolibc_has_feature(feature) 0
#endif
#define __nolibc_aligned(alignment) __attribute__((aligned(alignment)))
#define __nolibc_aligned_as(type) __nolibc_aligned(__alignof__(type))
#if __nolibc_has_attribute(naked)
# define __nolibc_entrypoint __attribute__((naked))
# define __nolibc_entrypoint_epilogue()
#else
# define __nolibc_entrypoint __attribute__((optimize("Os", "omit-frame-pointer")))
# define __nolibc_entrypoint_epilogue() __builtin_unreachable()
#endif /* __nolibc_has_attribute(naked) */
#if defined(__SSP__) || defined(__SSP_STRONG__) || defined(__SSP_ALL__) || defined(__SSP_EXPLICIT__)
#define _NOLIBC_STACKPROTECTOR
#endif /* defined(__SSP__) ... */
#if __nolibc_has_attribute(no_stack_protector)
# define __nolibc_no_stack_protector __attribute__((no_stack_protector))
#else
# define __nolibc_no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
#endif /* __nolibc_has_attribute(no_stack_protector) */
#if __nolibc_has_attribute(__fallthrough__)
# define __nolibc_fallthrough do { } while (0); __attribute__((__fallthrough__))
#else
# define __nolibc_fallthrough do { } while (0)
#endif /* __nolibc_has_attribute(fallthrough) */
#if defined(__STDC_VERSION__)
# define __nolibc_stdc_version __STDC_VERSION__
#else
# define __nolibc_stdc_version 0
#endif
#define __nolibc_version(_major, _minor, _patch) ((_major) * 10000 + (_minor) * 100 + (_patch))
#ifdef __GNUC__
# define __nolibc_gnuc_version \
__nolibc_version(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#else
# define __nolibc_gnuc_version 0
#endif /* __GNUC__ */
#ifdef __clang__
# define __nolibc_clang_version \
__nolibc_version(__clang_major__, __clang_minor__, __clang_patchlevel__)
#else
# define __nolibc_clang_version 0
#endif /* __clang__ */
#if __nolibc_stdc_version >= 201112L || \
__nolibc_gnuc_version >= __nolibc_version(4, 6, 0) || \
__nolibc_clang_version >= __nolibc_version(3, 0, 0)
# define __nolibc_static_assert(_t) _Static_assert(_t, "")
#else
# define __nolibc_static_assert(_t)
#endif
/* Make the optimizer believe the variable can be manipulated arbitrarily. */
#define _NOLIBC_OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "+r" (var))
#if __nolibc_has_feature(undefined_behavior_sanitizer)
# if defined(__clang__)
# define __nolibc_no_sanitize_undefined __attribute__((no_sanitize("function")))
# else
# define __nolibc_no_sanitize_undefined __attribute__((no_sanitize_undefined))
# endif
#else
# define __nolibc_no_sanitize_undefined
#endif
#endif /* _NOLIBC_COMPILER_H */
+121
View File
@@ -0,0 +1,121 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* C Run Time support for NOLIBC
* Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org>
*/
#ifndef _NOLIBC_CRT_H
#define _NOLIBC_CRT_H
#define __nolibc_arg_to_reg(_a) \
__builtin_choose_expr(__builtin_classify_type(_a) == __builtin_classify_type(NULL), \
(unsigned long)(_a), (_a))
#ifndef NOLIBC_NO_RUNTIME
#include "compiler.h"
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));
void _start(void);
static void __stack_chk_init(void);
static void exit(int);
static char *strrchr(const char *s, int c);
extern void (*const __preinit_array_start[])(int, char **, char**) __attribute__((weak));
extern void (*const __preinit_array_end[])(int, char **, char**) __attribute__((weak));
extern void (*const __init_array_start[])(int, char **, char**) __attribute__((weak));
extern void (*const __init_array_end[])(int, char **, char**) __attribute__((weak));
extern void (*const __fini_array_start[])(void) __attribute__((weak));
extern void (*const __fini_array_end[])(void) __attribute__((weak));
#ifndef NOLIBC_IGNORE_ERRNO
extern char *program_invocation_name __attribute__((weak));
extern char *program_invocation_short_name __attribute__((weak));
static __inline__
char *__nolibc_program_invocation_short_name(char *long_name)
{
char *short_name;
short_name = strrchr(long_name, '/');
if (!short_name || !short_name[0])
return long_name;
return short_name + 1;
}
#endif /* NOLIBC_IGNORE_ERRNO */
void _start_c(long *sp);
__attribute__((weak,used)) __nolibc_no_sanitize_undefined __nolibc_no_stack_protector
void _start_c(long *sp)
{
long argc;
char **argv;
char **envp;
int exitcode;
void (* const *ctor_func)(int, char **, char **);
void (* const *dtor_func)(void);
const unsigned long *auxv;
/* silence potential warning: conflicting types for 'main' */
int _nolibc_main(int, char **, char **) __asm__ ("main");
/* initialize stack protector */
__stack_chk_init();
/*
* sp : argc <-- argument count, required by main()
* argv: argv[0] <-- argument vector, required by main()
* argv[1]
* ...
* argv[argc-1]
* null
* environ: environ[0] <-- environment variables, required by main() and getenv()
* environ[1]
* ...
* null
* _auxv: _auxv[0] <-- auxiliary vector, required by getauxval()
* _auxv[1]
* ...
* null
*/
/* assign argc and argv */
argc = *sp;
argv = (void *)(sp + 1);
/* find environ */
environ = envp = argv + argc + 1;
/* find _auxv */
for (auxv = (void *)envp; *auxv++;)
__asm__("");
_auxv = auxv;
#ifndef NOLIBC_IGNORE_ERRNO
if (argc > 0 && argv[0]) {
program_invocation_name = argv[0];
program_invocation_short_name = __nolibc_program_invocation_short_name(argv[0]);
}
#endif /* NOLIBC_IGNORE_ERRNO */
for (ctor_func = __preinit_array_start; ctor_func < __preinit_array_end; ctor_func++)
(*ctor_func)(argc, argv, envp);
for (ctor_func = __init_array_start; ctor_func < __init_array_end; ctor_func++)
(*ctor_func)(argc, argv, envp);
/* go to application */
exitcode = _nolibc_main(argc, argv, envp);
for (dtor_func = __fini_array_end; dtor_func > __fini_array_start;)
(*--dtor_func)();
exit(exitcode);
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_CRT_H */
+102
View File
@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* ctype function definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_CTYPE_H
#define _NOLIBC_CTYPE_H
#include "std.h"
/*
* As much as possible, please keep functions alphabetically sorted.
*/
static __attribute__((unused))
int isascii(int c)
{
/* 0x00..0x7f */
return (unsigned int)c <= 0x7f;
}
static __attribute__((unused))
int isblank(int c)
{
return c == '\t' || c == ' ';
}
static __attribute__((unused))
int iscntrl(int c)
{
/* 0x00..0x1f, 0x7f */
return (unsigned int)c < 0x20 || c == 0x7f;
}
static __attribute__((unused))
int isdigit(int c)
{
return (unsigned int)(c - '0') < 10;
}
static __attribute__((unused))
int isgraph(int c)
{
/* 0x21..0x7e */
return (unsigned int)(c - 0x21) < 0x5e;
}
static __attribute__((unused))
int islower(int c)
{
return (unsigned int)(c - 'a') < 26;
}
static __attribute__((unused))
int isprint(int c)
{
/* 0x20..0x7e */
return (unsigned int)(c - 0x20) < 0x5f;
}
static __attribute__((unused))
int isspace(int c)
{
/* \t is 0x9, \n is 0xA, \v is 0xB, \f is 0xC, \r is 0xD */
return ((unsigned int)c == ' ') || (unsigned int)(c - 0x09) < 5;
}
static __attribute__((unused))
int isupper(int c)
{
return (unsigned int)(c - 'A') < 26;
}
static __attribute__((unused))
int isxdigit(int c)
{
return isdigit(c) || (unsigned int)(c - 'A') < 6 || (unsigned int)(c - 'a') < 6;
}
static __attribute__((unused))
int isalpha(int c)
{
return islower(c) || isupper(c);
}
static __attribute__((unused))
int isalnum(int c)
{
return isalpha(c) || isdigit(c);
}
static __attribute__((unused))
int ispunct(int c)
{
return isgraph(c) && !isalnum(c);
}
#endif /* _NOLIBC_CTYPE_H */
+100
View File
@@ -0,0 +1,100 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Directory access for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_DIRENT_H
#define _NOLIBC_DIRENT_H
#include "compiler.h"
#include "stdint.h"
#include "types.h"
#include "fcntl.h"
#include <linux/limits.h>
struct dirent {
ino_t d_ino;
char d_name[NAME_MAX + 1];
};
/* See comment of FILE in stdio.h */
typedef struct {
char dummy[1];
} DIR;
static __attribute__((unused))
DIR *fdopendir(int fd)
{
if (fd < 0) {
SET_ERRNO(EBADF);
return NULL;
}
return (DIR *)(intptr_t)~fd;
}
static __attribute__((unused))
DIR *opendir(const char *name)
{
int fd;
fd = open(name, O_RDONLY);
if (fd == -1)
return NULL;
return fdopendir(fd);
}
static __attribute__((unused))
int closedir(DIR *dirp)
{
intptr_t i = (intptr_t)dirp;
if (i >= 0) {
SET_ERRNO(EBADF);
return -1;
}
return close(~i);
}
static __attribute__((unused))
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
{
char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64);
struct linux_dirent64 *ldir = (void *)buf;
intptr_t i = (intptr_t)dirp;
int fd, ret;
if (i >= 0)
return EBADF;
fd = ~i;
ret = _sys_getdents64(fd, ldir, sizeof(buf));
if (ret < 0)
return -ret;
if (ret == 0) {
*result = NULL;
return 0;
}
/*
* getdents64() returns as many entries as fit the buffer.
* readdir() can only return one entry at a time.
* Make sure the non-returned ones are not skipped.
*/
ret = _sys_lseek(fd, ldir->d_off, SEEK_SET);
if (ret < 0)
return -ret;
entry->d_ino = ldir->d_ino;
/* the destination should always be big enough */
strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name));
*result = entry;
return 0;
}
#endif /* _NOLIBC_DIRENT_H */
+15
View File
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Shim elf.h header for NOLIBC.
* Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_SYS_ELF_H
#define _NOLIBC_SYS_ELF_H
#include <linux/elf.h>
#endif /* _NOLIBC_SYS_ELF_H */
+32
View File
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Byte order conversion for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_ENDIAN_H
#define _NOLIBC_ENDIAN_H
#include "stdint.h"
#include <asm/byteorder.h>
#define htobe16(_x) __cpu_to_be16(_x)
#define htole16(_x) __cpu_to_le16(_x)
#define be16toh(_x) __be16_to_cpu(_x)
#define le16toh(_x) __le16_to_cpu(_x)
#define htobe32(_x) __cpu_to_be32(_x)
#define htole32(_x) __cpu_to_le32(_x)
#define be32toh(_x) __be32_to_cpu(_x)
#define le32toh(_x) __le32_to_cpu(_x)
#define htobe64(_x) __cpu_to_be64(_x)
#define htole64(_x) __cpu_to_le64(_x)
#define be64toh(_x) __be64_to_cpu(_x)
#define le64toh(_x) __le64_to_cpu(_x)
#endif /* _NOLIBC_ENDIAN_H */
+87
View File
@@ -0,0 +1,87 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* formatted error message for NOLIBC
* Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_ERR_H
#define _NOLIBC_ERR_H
#include "errno.h"
#include "stdarg.h"
#include "sys.h"
static __attribute__((unused))
void vwarn(const char *fmt, va_list args)
{
fprintf(stderr, "%s: ", program_invocation_short_name);
vfprintf(stderr, fmt, args);
fprintf(stderr, ": %m\n");
}
static __attribute__((unused))
void vwarnx(const char *fmt, va_list args)
{
fprintf(stderr, "%s: ", program_invocation_short_name);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
}
static __attribute__((unused))
void warn(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vwarn(fmt, args);
va_end(args);
}
static __attribute__((unused))
void warnx(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vwarnx(fmt, args);
va_end(args);
}
static __attribute__((noreturn, unused))
void verr(int eval, const char *fmt, va_list args)
{
vwarn(fmt, args);
exit(eval);
}
static __attribute__((noreturn, unused))
void verrx(int eval, const char *fmt, va_list args)
{
warnx(fmt, args);
exit(eval);
}
static __attribute__((noreturn, unused))
void err(int eval, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
verr(eval, fmt, args);
va_end(args);
}
static __attribute__((noreturn, unused))
void errx(int eval, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
verrx(eval, fmt, args);
va_end(args);
}
#endif /* _NOLIBC_ERR_H */
+32
View File
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Minimal errno definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_ERRNO_H
#define _NOLIBC_ERRNO_H
#include <linux/errno.h>
#ifndef NOLIBC_IGNORE_ERRNO
#define SET_ERRNO(v) do { errno = (v); } while (0)
int errno __attribute__((weak));
char *program_invocation_name __attribute__((weak)) = (char *)"";
char *program_invocation_short_name __attribute__((weak)) = (char *)"";
#else
#define SET_ERRNO(v) do { } while (0)
#define program_invocation_name ""
#define program_invocation_short_name ""
#endif
/* errno codes all ensure that they will not conflict with a valid pointer
* because they all correspond to the highest addressable memory page.
*/
#define MAX_ERRNO 4095
#endif /* _NOLIBC_ERRNO_H */
+74
View File
@@ -0,0 +1,74 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* fcntl definition for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_FCNTL_H
#define _NOLIBC_FCNTL_H
#include "arch.h"
#include "types.h"
#include "sys.h"
#define __nolibc_open_flags(_flags) ((_flags) | O_LARGEFILE)
#define __nolibc_open_mode(_flags) \
({ \
mode_t _mode; \
va_list args; \
\
va_start(args, (_flags)); \
_mode = va_arg(args, mode_t); \
va_end(args); \
\
_mode; \
})
/*
* int openat(int dirfd, const char *path, int flags[, mode_t mode]);
*/
static __attribute__((unused))
int _sys_openat(int dirfd, const char *path, int flags, mode_t mode)
{
return __nolibc_syscall4(__NR_openat, dirfd, path, flags, mode);
}
static __attribute__((unused))
int openat(int dirfd, const char *path, int flags, ...)
{
return __sysret(_sys_openat(dirfd, path, __nolibc_open_flags(flags),
__nolibc_open_mode(flags)));
}
/*
* int open(const char *path, int flags[, mode_t mode]);
*/
static __attribute__((unused))
int _sys_open(const char *path, int flags, mode_t mode)
{
return __nolibc_syscall4(__NR_openat, AT_FDCWD, path, flags, mode);
}
static __attribute__((unused))
int open(const char *path, int flags, ...)
{
return __sysret(_sys_open(path, __nolibc_open_flags(flags), __nolibc_open_mode(flags)));
}
/*
* int creat(const char *path, mode_t mode);
*/
static __attribute__((unused))
int creat(const char *path, mode_t mode)
{
return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
#endif /* _NOLIBC_FCNTL_H */
+101
View File
@@ -0,0 +1,101 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* getopt function definitions for NOLIBC, adapted from musl libc
* Copyright (C) 2005-2020 Rich Felker, et al.
* Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_GETOPT_H
#define _NOLIBC_GETOPT_H
struct FILE;
static struct FILE *const stderr;
static int fprintf(struct FILE *stream, const char *fmt, ...);
__attribute__((weak,unused,section(".data.nolibc_getopt")))
char *optarg;
__attribute__((weak,unused,section(".data.nolibc_getopt")))
int optind = 1, opterr = 1, optopt;
static __attribute__((unused))
int getopt(int argc, char * const argv[], const char *optstring)
{
static int __optpos;
int i;
char c, d;
char *optchar;
if (!optind) {
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind])
return -1;
if (argv[optind][0] != '-') {
if (optstring[0] == '-') {
optarg = argv[optind++];
return 1;
}
return -1;
}
if (!argv[optind][1])
return -1;
if (argv[optind][1] == '-' && !argv[optind][2])
return optind++, -1;
if (!__optpos)
__optpos++;
c = argv[optind][__optpos];
optchar = argv[optind] + __optpos;
__optpos++;
if (!argv[optind][__optpos]) {
optind++;
__optpos = 0;
}
if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
i = 0;
d = 0;
do {
d = optstring[i++];
} while (d && d != c);
if (!d || d != c || c == ':') {
optopt = c;
if (optstring[0] != ':' && opterr)
fprintf(stderr, "%s: unrecognized option: %c\n", argv[0], *optchar);
return '?';
}
if (optstring[i] == ':') {
optarg = NULL;
if (optstring[i + 1] != ':' || __optpos) {
optarg = argv[optind++];
if (__optpos)
optarg += __optpos;
__optpos = 0;
}
if (optind > argc) {
optopt = c;
if (optstring[0] == ':')
return ':';
if (opterr)
fprintf(stderr, "%s: option requires argument: %c\n",
argv[0], *optchar);
return '?';
}
}
return c;
}
#endif /* _NOLIBC_GETOPT_H */
@@ -0,0 +1,3 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
#include "nolibc.h"
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Shim limits.h header for NOLIBC.
* Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/
#include "nolibc.h"
+31
View File
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* math definitions for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_SYS_MATH_H
#define _NOLIBC_SYS_MATH_H
static __inline__
double fabs(double x)
{
return x >= 0 ? x : -x;
}
static __inline__
float fabsf(float x)
{
return x >= 0 ? x : -x;
}
static __inline__
long double fabsl(long double x)
{
return x >= 0 ? x : -x;
}
#endif /* _NOLIBC_SYS_MATH_H */
+142
View File
@@ -0,0 +1,142 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/* nolibc.h
* Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu>
*/
/*
* This file is designed to be used as a libc alternative for minimal programs
* with very limited requirements. It consists of a small number of syscall and
* type definitions, and the minimal startup code needed to call main().
* All syscalls are declared as static functions so that they can be optimized
* away by the compiler when not used.
*
* Syscalls are split into 3 levels:
* - The lower level is the arch-specific syscall() definition, consisting in
* assembly code in compound expressions. These are called __nolibc_syscall0() to
* __nolibc_syscall6() depending on the number of arguments. All input arguments
* are castto a long stored in a register. These expressions always return
* the syscall's return value as a signed long value which is often either
* a pointer or the negated errno value.
*
* - The second level is mostly architecture-independent. It is made of
* static functions called _sys_<name>() which rely on __nolibc_syscallN()
* depending on the syscall definition. These functions are responsible
* for exposing the appropriate types for the syscall arguments (int,
* pointers, etc) and for setting the appropriate return type (often int).
* A few of them are architecture-specific because the syscalls are not all
* mapped exactly the same among architectures. For example, some archs do
* not implement select() and need pselect6() instead, so the _sys_select()
* function will have to abstract this.
*
* - The third level is the libc call definition. It exposes the lower raw
* _sys_<name>() calls in a way that looks like what a libc usually does,
* takes care of specific input values, and of setting errno upon error.
* There can be minor variations compared to standard libc calls.
*
* The errno variable is declared static and unused. This way it can be
* optimized away if not used. However this means that a program made of
* multiple C files may observe different errno values (one per C file). For
* the type of programs this project targets it usually is not a problem. The
* resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO
* macro, in which case the errno value will never be assigned.
*
* Some stdint-like integer types are defined. These are valid on all currently
* supported architectures, because signs are enforced, ints are assumed to be
* 32 bits, longs the size of a pointer and long long 64 bits. If more
* architectures have to be supported, this may need to be adapted.
*
* Some macro definitions like the O_* values passed to open(), and some
* structures like the sys_stat struct depend on the architecture.
*
* The definitions start with the architecture-specific parts, which are picked
* based on what the compiler knows about the target architecture, and are
* completed with the generic code. Since it is the compiler which sets the
* target architecture, cross-compiling normally works out of the box without
* having to specify anything.
*
* Finally some very common libc-level functions are provided. It is the case
* for a few functions usually found in string.h, ctype.h, or stdlib.h.
*
* The nolibc.h file is only a convenient entry point which includes all other
* files. It also defines the NOLIBC macro, so that it is possible for a
* program to check this macro to know if it is being built against and decide
* to disable some features or simply not to include some standard libc files.
*
* A simple static executable may be built this way :
* $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
* -static -include nolibc.h -o hello hello.c -lgcc
*
* Simple programs meant to be reasonably portable to various libc and using
* only a few common includes, may also be built by simply making the include
* path point to the nolibc directory:
* $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
* -I../nolibc -o hello hello.c -lgcc
*
* The available standard (but limited) include files are:
* ctype.h, errno.h, signal.h, stdarg.h, stdbool.h stdio.h, stdlib.h,
* string.h, time.h
*
* In addition, the following ones are expected to be provided by the compiler:
* float.h, stddef.h
*
* The following ones which are part to the C standard are not provided:
* assert.h, locale.h, math.h, setjmp.h, limits.h
*
* A very useful calling convention table may be found here :
* http://man7.org/linux/man-pages/man2/syscall.2.html
*
* This doc is quite convenient though not necessarily up to date :
* https://w3challs.com/syscalls/
*
*/
#ifndef _NOLIBC_H
#define _NOLIBC_H
#include "std.h"
#include "arch.h"
#include "types.h"
#include "sys.h"
#include "sys/auxv.h"
#include "sys/ioctl.h"
#include "sys/mman.h"
#include "sys/mount.h"
#include "sys/prctl.h"
#include "sys/ptrace.h"
#include "sys/random.h"
#include "sys/reboot.h"
#include "sys/resource.h"
#include "sys/select.h"
#include "sys/stat.h"
#include "sys/syscall.h"
#include "sys/sysmacros.h"
#include "sys/time.h"
#include "sys/timerfd.h"
#include "sys/uio.h"
#include "sys/utsname.h"
#include "sys/wait.h"
#include "ctype.h"
#include "elf.h"
#include "sched.h"
#include "signal.h"
#include "unistd.h"
#include "stdbool.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#include "stackprotector.h"
#include "dirent.h"
#include "fcntl.h"
#include "getopt.h"
#include "poll.h"
#include "math.h"
#include "err.h"
#include "byteswap.h"
#include "endian.h"
#include "assert.h"
#include "alloca.h"
/* Used by programs to avoid std includes */
#define NOLIBC
#endif /* _NOLIBC_H */
+51
View File
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* poll definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_POLL_H
#define _NOLIBC_POLL_H
#include "arch.h"
#include "sys.h"
#include <linux/poll.h>
#include <linux/time.h>
/*
* int poll(struct pollfd *fds, int nfds, int timeout);
*/
static __attribute__((unused))
int _sys_poll(struct pollfd *fds, int nfds, int timeout)
{
#if defined(__NR_ppoll_time64)
struct __kernel_timespec t;
if (timeout >= 0) {
t.tv_sec = timeout / 1000;
t.tv_nsec = (timeout % 1000) * 1000000;
}
return __nolibc_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
#else
struct __kernel_old_timespec t;
if (timeout >= 0) {
t.tv_sec = timeout / 1000;
t.tv_nsec = (timeout % 1000) * 1000000;
}
return __nolibc_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
#endif
}
static __attribute__((unused))
int poll(struct pollfd *fds, int nfds, int timeout)
{
return __sysret(_sys_poll(fds, nfds, timeout));
}
#endif /* _NOLIBC_POLL_H */
+50
View File
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* sched function definitions for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_SCHED_H
#define _NOLIBC_SCHED_H
#include "sys.h"
#include <linux/sched.h>
/*
* int setns(int fd, int nstype);
*/
static __attribute__((unused))
int _sys_setns(int fd, int nstype)
{
return __nolibc_syscall2(__NR_setns, fd, nstype);
}
static __attribute__((unused))
int setns(int fd, int nstype)
{
return __sysret(_sys_setns(fd, nstype));
}
/*
* int unshare(int flags);
*/
static __attribute__((unused))
int _sys_unshare(int flags)
{
return __nolibc_syscall1(__NR_unshare, flags);
}
static __attribute__((unused))
int unshare(int flags)
{
return __sysret(_sys_unshare(flags));
}
#endif /* _NOLIBC_SCHED_H */
+26
View File
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* signal function definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_SIGNAL_H
#define _NOLIBC_SIGNAL_H
#include "std.h"
#include "arch.h"
#include "types.h"
#include "sys.h"
/* This one is not marked static as it's needed by libgcc for divide by zero */
int raise(int signal);
__attribute__((weak,unused,section(".text.nolibc_raise")))
int raise(int signal)
{
return _sys_kill(_sys_getpid(), signal);
}
#endif /* _NOLIBC_SIGNAL_H */
@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Stack protector support for NOLIBC
* Copyright (C) 2023 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_STACKPROTECTOR_H
#define _NOLIBC_STACKPROTECTOR_H
#include "compiler.h"
#ifndef NOLIBC_NO_RUNTIME
#if defined(_NOLIBC_STACKPROTECTOR)
#include "sys.h"
#include "stdlib.h"
/* The functions in this header are using raw syscall macros to avoid
* triggering stack protector errors themselves
*/
void __stack_chk_fail(void);
__attribute__((weak,used,noreturn,section(".text.nolibc_stack_chk")))
void __stack_chk_fail(void)
{
pid_t pid;
__nolibc_syscall3(__NR_write, STDERR_FILENO, "!!Stack smashing detected!!\n", 28);
pid = __nolibc_syscall0(__NR_getpid);
__nolibc_syscall2(__NR_kill, pid, SIGABRT);
for (;;);
}
void __stack_chk_fail_local(void);
__attribute__((weak,noreturn,section(".text.nolibc_stack_chk")))
void __stack_chk_fail_local(void)
{
__stack_chk_fail();
}
__attribute__((weak,used,section(".data.nolibc_stack_chk")))
uintptr_t __stack_chk_guard;
static __nolibc_no_stack_protector void __stack_chk_init(void)
{
__nolibc_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard),
GRND_INSECURE | GRND_NONBLOCK);
/* a bit more randomness in case getrandom() fails, ensure the guard is never 0 */
if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard)
__stack_chk_guard ^= (uintptr_t) &__stack_chk_guard;
}
#else /* !defined(_NOLIBC_STACKPROTECTOR) */
static void __stack_chk_init(void) {}
#endif /* defined(_NOLIBC_STACKPROTECTOR) */
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_STACKPROTECTOR_H */
+34
View File
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Standard definitions and types for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
#ifndef _NOLIBC_STD_H
#define _NOLIBC_STD_H
/* Declare a few quite common macros and types that usually are in stdlib.h,
* stdint.h, ctype.h, unistd.h and a few other common locations. Please place
* integer type definitions and generic macros here, but avoid OS-specific and
* syscall-specific stuff, as this file is expected to be included very early.
*/
#include "stdint.h"
#include "stddef.h"
#include <linux/types.h>
/* those are commonly provided by sys/types.h */
typedef uint64_t dev_t;
typedef uint64_t ino_t;
typedef unsigned int mode_t;
typedef signed int pid_t;
typedef unsigned int uid_t;
typedef unsigned int gid_t;
typedef unsigned long nlink_t;
typedef int64_t off_t;
typedef signed long blksize_t;
typedef signed long blkcnt_t;
typedef __kernel_time64_t time_t;
#endif /* _NOLIBC_STD_H */
+16
View File
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Variadic argument support for NOLIBC
* Copyright (C) 2005-2020 Rich Felker, et al.
*/
#ifndef _NOLIBC_STDARG_H
#define _NOLIBC_STDARG_H
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define va_copy(d, s) __builtin_va_copy(d, s)
#endif /* _NOLIBC_STDARG_H */
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Boolean types support for NOLIBC
* Copyright (C) 2024 Thomas Weißschuh <linux@weissschuh.net>
*/
#ifndef _NOLIBC_STDBOOL_H
#define _NOLIBC_STDBOOL_H
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#endif /* _NOLIBC_STDBOOL_H */
+24
View File
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Stddef definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_STDDEF_H
#define _NOLIBC_STDDEF_H
#include "stdint.h"
/* note: may already be defined */
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef offsetof
#define offsetof(TYPE, FIELD) __builtin_offsetof(TYPE, FIELD)
#endif
#endif /* _NOLIBC_STDDEF_H */
+132
View File
@@ -0,0 +1,132 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Standard definitions and types for NOLIBC
* Copyright (C) 2023 Vincent Dagonneau <v@vda.io>
*/
#ifndef _NOLIBC_STDINT_H
#define _NOLIBC_STDINT_H
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef unsigned long long uint64_t;
typedef signed long long int64_t;
typedef __SIZE_TYPE__ size_t;
typedef signed long ssize_t;
typedef unsigned long uintptr_t;
typedef signed long intptr_t;
typedef signed long ptrdiff_t;
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
typedef int32_t int_least32_t;
typedef uint32_t uint_least32_t;
typedef int64_t int_least64_t;
typedef uint64_t uint_least64_t;
typedef int8_t int_fast8_t;
typedef uint8_t uint_fast8_t;
typedef ssize_t int_fast16_t;
typedef size_t uint_fast16_t;
typedef ssize_t int_fast32_t;
typedef size_t uint_fast32_t;
typedef int64_t int_fast64_t;
typedef uint64_t uint_fast64_t;
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
/* limits of integral types */
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
#define INT64_MIN (-9223372036854775807LL-1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX (9223372036854775807LL)
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX (18446744073709551615ULL)
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#define SIZE_MAX ((size_t)(__LONG_MAX__) * 2 + 1)
#define INTPTR_MIN (-__LONG_MAX__ - 1)
#define INTPTR_MAX __LONG_MAX__
#define PTRDIFF_MIN INTPTR_MIN
#define PTRDIFF_MAX INTPTR_MAX
#define UINTPTR_MAX SIZE_MAX
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST16_MIN INTPTR_MIN
#define INT_FAST32_MIN INTPTR_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MAX INTPTR_MAX
#define INT_FAST32_MAX INTPTR_MAX
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX SIZE_MAX
#define UINT_FAST32_MAX SIZE_MAX
#define UINT_FAST64_MAX UINT64_MAX
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
#ifndef INT_MIN
#define INT_MIN (-__INT_MAX__ - 1)
#endif
#ifndef INT_MAX
#define INT_MAX __INT_MAX__
#endif
#ifndef LONG_MIN
#define LONG_MIN (-__LONG_MAX__ - 1)
#endif
#ifndef LONG_MAX
#define LONG_MAX __LONG_MAX__
#endif
#ifndef ULONG_MAX
#define ULONG_MAX ((unsigned long)(__LONG_MAX__) * 2 + 1)
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-__LONG_LONG_MAX__ - 1)
#endif
#ifndef LLONG_MAX
#define LLONG_MAX __LONG_LONG_MAX__
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX ((unsigned long long)(__LONG_LONG_MAX__) * 2 + 1)
#endif
#endif /* _NOLIBC_STDINT_H */
File diff suppressed because it is too large Load Diff
+543
View File
@@ -0,0 +1,543 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* stdlib function definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_STDLIB_H
#define _NOLIBC_STDLIB_H
#include "std.h"
#include "arch.h"
#include "types.h"
#include "sys.h"
#include "string.h"
#include <linux/auxvec.h>
struct nolibc_heap {
size_t len;
char user_p[] __attribute__((__aligned__));
};
/* Buffer used to store int-to-ASCII conversions. Will only be implemented if
* any of the related functions is implemented. The area is large enough to
* store "18446744073709551615" or "-9223372036854775808" and the final zero.
*/
static __attribute__((unused)) char itoa_buffer[21];
/*
* As much as possible, please keep functions alphabetically sorted.
*/
static __inline__
int abs(int j)
{
return j >= 0 ? j : -j;
}
static __inline__
long labs(long j)
{
return j >= 0 ? j : -j;
}
static __inline__
long long llabs(long long j)
{
return j >= 0 ? j : -j;
}
/* must be exported, as it's used by libgcc for various divide functions */
void abort(void);
__attribute__((weak,unused,noreturn,section(".text.nolibc_abort")))
void abort(void)
{
_sys_kill(_sys_getpid(), SIGABRT);
for (;;);
}
static __attribute__((unused))
long atol(const char *s)
{
unsigned long ret = 0;
unsigned long d;
int neg = 0;
if (*s == '-') {
neg = 1;
s++;
}
while (1) {
d = (*s++) - '0';
if (d > 9)
break;
ret *= 10;
ret += d;
}
return neg ? -ret : ret;
}
static __attribute__((unused))
int atoi(const char *s)
{
return atol(s);
}
static __attribute__((unused))
void free(void *ptr)
{
struct nolibc_heap *heap;
if (!ptr)
return;
heap = container_of(ptr, struct nolibc_heap, user_p);
munmap(heap, heap->len);
}
#ifndef NOLIBC_NO_RUNTIME
/* getenv() tries to find the environment variable named <name> in the
* environment array pointed to by global variable "environ" which must be
* declared as a char **, and must be terminated by a NULL (it is recommended
* to set this variable to the "envp" argument of main()). If the requested
* environment variable exists its value is returned otherwise NULL is
* returned.
*/
static __attribute__((unused))
char *getenv(const char *name)
{
int idx, i;
if (environ) {
for (idx = 0; environ[idx]; idx++) {
for (i = 0; name[i] && name[i] == environ[idx][i];)
i++;
if (!name[i] && environ[idx][i] == '=')
return &environ[idx][i+1];
}
}
return NULL;
}
#endif /* NOLIBC_NO_RUNTIME */
static __attribute__((unused))
void *malloc(size_t len)
{
struct nolibc_heap *heap;
/* Always allocate memory with size multiple of 4096. */
len = sizeof(*heap) + len;
len = (len + 4095UL) & -4096UL;
heap = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE,
-1, 0);
if (__builtin_expect(heap == MAP_FAILED, 0))
return NULL;
heap->len = len;
return heap->user_p;
}
static __attribute__((unused))
void *calloc(size_t size, size_t nmemb)
{
size_t x;
if (__builtin_expect(__builtin_mul_overflow(size, nmemb, &x), 0)) {
SET_ERRNO(ENOMEM);
return NULL;
}
/*
* No need to zero the heap, the MAP_ANONYMOUS in malloc()
* already does it.
*/
return malloc(x);
}
static __attribute__((unused))
void *realloc(void *old_ptr, size_t new_size)
{
struct nolibc_heap *heap;
size_t user_p_len;
void *ret;
if (!old_ptr)
return malloc(new_size);
heap = container_of(old_ptr, struct nolibc_heap, user_p);
user_p_len = heap->len - sizeof(*heap);
/*
* Don't realloc() if @user_p_len >= @new_size, this block of
* memory is still enough to handle the @new_size. Just return
* the same pointer.
*/
if (user_p_len >= new_size)
return old_ptr;
ret = malloc(new_size);
if (__builtin_expect(!ret, 0))
return NULL;
memcpy(ret, heap->user_p, user_p_len);
munmap(heap, heap->len);
return ret;
}
/* Converts the unsigned 64bit integer <in> to base <base> ascii into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero. The buffer is filled from the first byte, and the number
* of characters emitted (not counting the trailing zero) is returned.
* The function uses 'multiply by reciprocal' for the divisions and
* requires the caller pass the correct reciprocal.
*
* Note that unlike __div64_const32() in asm-generic/div64.h there isn't
* an extra shift done (by ___p), the reciprocal has to be lower resulting
* in a slightly low quotient.
* Keep things simple by correcting for the error.
* This also saves calculating the 'low * low' product (e2 below) which is
* very unlikely to be significant.
*
* Some maths:
* recip = p2 / base - e1; // With e1 < base.
* q = (recip * in - e2) / p2; // With e2 < p2.
* = base / in - (e1 * in + e2) / p2;
* > base / in - (e1 * p2 + p2) / p2;
* = base / in - ((e1 + 1) * p2) / p2;
* > base / in - base;
* So the maximum error is less than 'base'.
* Hence the largest possible digit is '2 * base - 1'.
* For base 10 e1 is 6 and you can get digits of 15 (eg from 2**64-1).
* Error e1 is largest for a base that is a factor of 2**64+1, the smallest is 274177
* and converting 2**42-1 in base 274177 does generate a digit of 274177+274175.
* This all means only a single correction is needed rather than a loop.
*
* __int128 isn't used for mips because gcc prior to 10.0 will call
* __multi3 for MIPS64r6. The same also happens for SPARC and clang.
*/
#define _NOLIBC_U64TOA_RECIP(base) ((base) & 1 ? ~0ull / (base) : (1ull << 63) / ((base) / 2))
static __attribute__((unused, noinline))
int _nolibc_u64toa_base(uint64_t in, char *buffer, unsigned int base, uint64_t recip)
{
unsigned int digits = 0;
unsigned int dig;
uint64_t q;
char *p;
/* Generate least significant digit first */
do {
#if defined(__SIZEOF_INT128__) && !defined(__mips__) && !defined(__sparc__)
q = ((unsigned __int128)in * recip) >> 64;
#else
uint64_t p = (uint32_t)in * (recip >> 32);
q = (in >> 32) * (recip >> 32) + (p >> 32);
p = (uint32_t)p + (in >> 32) * (uint32_t)recip;
q += p >> 32;
#endif
dig = in - q * base;
/* Correct for any rounding errors */
if (dig >= base) {
dig -= base;
q++;
}
if (dig > 9)
dig += 'a' - '0' - 10;
buffer[digits++] = '0' + dig;
} while ((in = q));
buffer[digits] = 0;
/* Order reverse to result */
for (p = buffer + digits - 1; p > buffer; buffer++, p--) {
dig = *buffer;
*buffer = *p;
*p = dig;
}
return digits;
}
/* Converts the unsigned long integer <in> to its hex representation into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The
* buffer is filled from the first byte, and the number of characters emitted
* (not counting the trailing zero) is returned.
*/
static __inline__ __attribute__((unused))
int utoh_r(unsigned long in, char *buffer)
{
return _nolibc_u64toa_base(in, buffer, 16, _NOLIBC_U64TOA_RECIP(16));
}
/* converts unsigned long <in> to an hex string using the static itoa_buffer
* and returns the pointer to that string.
*/
static __inline__ __attribute__((unused))
char *utoh(unsigned long in)
{
utoh_r(in, itoa_buffer);
return itoa_buffer;
}
/* Converts the unsigned long integer <in> to its string representation into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for
* 4294967295 in 32-bit). The buffer is filled from the first byte, and the
* number of characters emitted (not counting the trailing zero) is returned.
*/
static __inline__ __attribute__((unused))
int utoa_r(unsigned long in, char *buffer)
{
return _nolibc_u64toa_base(in, buffer, 10, _NOLIBC_U64TOA_RECIP(10));
}
/* Converts the signed long integer <in> to its string representation into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for
* -2147483648 in 32-bit). The buffer is filled from the first byte, and the
* number of characters emitted (not counting the trailing zero) is returned.
*/
static __attribute__((unused))
int itoa_r(long in, char *buffer)
{
char *ptr = buffer;
int len = 0;
if (in < 0) {
in = -(unsigned long)in;
*(ptr++) = '-';
len++;
}
len += utoa_r(in, ptr);
return len;
}
/* for historical compatibility, same as above but returns the pointer to the
* buffer.
*/
static __inline__ __attribute__((unused))
char *ltoa_r(long in, char *buffer)
{
itoa_r(in, buffer);
return buffer;
}
/* converts long integer <in> to a string using the static itoa_buffer and
* returns the pointer to that string.
*/
static __inline__ __attribute__((unused))
char *itoa(long in)
{
itoa_r(in, itoa_buffer);
return itoa_buffer;
}
/* converts long integer <in> to a string using the static itoa_buffer and
* returns the pointer to that string. Same as above, for compatibility.
*/
static __inline__ __attribute__((unused))
char *ltoa(long in)
{
itoa_r(in, itoa_buffer);
return itoa_buffer;
}
/* converts unsigned long integer <in> to a string using the static itoa_buffer
* and returns the pointer to that string.
*/
static __inline__ __attribute__((unused))
char *utoa(unsigned long in)
{
utoa_r(in, itoa_buffer);
return itoa_buffer;
}
/* Converts the unsigned 64-bit integer <in> to its hex representation into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from
* the first byte, and the number of characters emitted (not counting the
* trailing zero) is returned.
*/
static __inline__ __attribute__((unused))
int u64toh_r(uint64_t in, char *buffer)
{
return _nolibc_u64toa_base(in, buffer, 16, _NOLIBC_U64TOA_RECIP(16));
}
/* converts uint64_t <in> to an hex string using the static itoa_buffer and
* returns the pointer to that string.
*/
static __inline__ __attribute__((unused))
char *u64toh(uint64_t in)
{
u64toh_r(in, itoa_buffer);
return itoa_buffer;
}
/* Converts the unsigned 64-bit integer <in> to its string representation into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero (21 bytes for 18446744073709551615). The buffer is filled from
* the first byte, and the number of characters emitted (not counting the
* trailing zero) is returned.
*/
static __inline__ __attribute__((unused))
int u64toa_r(uint64_t in, char *buffer)
{
return _nolibc_u64toa_base(in, buffer, 10, _NOLIBC_U64TOA_RECIP(10));
}
/* Converts the signed 64-bit integer <in> to its string representation into
* buffer <buffer>, which must be long enough to store the number and the
* trailing zero (21 bytes for -9223372036854775808). The buffer is filled from
* the first byte, and the number of characters emitted (not counting the
* trailing zero) is returned.
*/
static __attribute__((unused))
int i64toa_r(int64_t in, char *buffer)
{
char *ptr = buffer;
int len = 0;
if (in < 0) {
in = -(uint64_t)in;
*(ptr++) = '-';
len++;
}
len += u64toa_r(in, ptr);
return len;
}
/* converts int64_t <in> to a string using the static itoa_buffer and returns
* the pointer to that string.
*/
static __inline__ __attribute__((unused))
char *i64toa(int64_t in)
{
i64toa_r(in, itoa_buffer);
return itoa_buffer;
}
/* converts uint64_t <in> to a string using the static itoa_buffer and returns
* the pointer to that string.
*/
static __inline__ __attribute__((unused))
char *u64toa(uint64_t in)
{
u64toa_r(in, itoa_buffer);
return itoa_buffer;
}
static __attribute__((unused))
uintmax_t __strtox(const char *nptr, char **endptr, int base, intmax_t lower_limit, uintmax_t upper_limit)
{
const char signed_ = lower_limit != 0;
unsigned char neg = 0, overflow = 0;
uintmax_t val = 0, limit, old_val;
char c;
if (base < 0 || base > 36) {
SET_ERRNO(EINVAL);
goto out;
}
while (isspace(*nptr))
nptr++;
if (*nptr == '+') {
nptr++;
} else if (*nptr == '-') {
neg = 1;
nptr++;
}
if (signed_ && neg)
limit = -(uintmax_t)lower_limit;
else
limit = upper_limit;
if ((base == 0 || base == 16) &&
(strncmp(nptr, "0x", 2) == 0 || strncmp(nptr, "0X", 2) == 0)) {
base = 16;
nptr += 2;
} else if (base == 0 && strncmp(nptr, "0", 1) == 0) {
base = 8;
nptr += 1;
} else if (base == 0) {
base = 10;
}
while (*nptr) {
c = *nptr;
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'a' && c <= 'z')
c = c - 'a' + 10;
else if (c >= 'A' && c <= 'Z')
c = c - 'A' + 10;
else
goto out;
if (c >= base)
goto out;
nptr++;
old_val = val;
val *= base;
val += c;
if (val > limit || val < old_val)
overflow = 1;
}
out:
if (overflow) {
SET_ERRNO(ERANGE);
val = limit;
}
if (endptr)
*endptr = (char *)nptr;
return neg ? -val : val;
}
static __attribute__((unused))
long strtol(const char *nptr, char **endptr, int base)
{
return __strtox(nptr, endptr, base, LONG_MIN, LONG_MAX);
}
static __attribute__((unused))
unsigned long strtoul(const char *nptr, char **endptr, int base)
{
return __strtox(nptr, endptr, base, 0, ULONG_MAX);
}
static __attribute__((unused))
long long strtoll(const char *nptr, char **endptr, int base)
{
return __strtox(nptr, endptr, base, LLONG_MIN, LLONG_MAX);
}
static __attribute__((unused))
unsigned long long strtoull(const char *nptr, char **endptr, int base)
{
return __strtox(nptr, endptr, base, 0, ULLONG_MAX);
}
static __attribute__((unused))
intmax_t strtoimax(const char *nptr, char **endptr, int base)
{
return __strtox(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX);
}
static __attribute__((unused))
uintmax_t strtoumax(const char *nptr, char **endptr, int base)
{
return __strtox(nptr, endptr, base, 0, UINTMAX_MAX);
}
#endif /* _NOLIBC_STDLIB_H */
+346
View File
@@ -0,0 +1,346 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* string function definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_STRING_H
#define _NOLIBC_STRING_H
#include "arch.h"
#include "std.h"
static void *malloc(size_t len);
/*
* As much as possible, please keep functions alphabetically sorted.
*/
static __attribute__((unused))
int memcmp(const void *s1, const void *s2, size_t n)
{
size_t ofs = 0;
int c1 = 0;
while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {
ofs++;
}
return c1;
}
#ifndef NOLIBC_ARCH_HAS_MEMMOVE
/* might be ignored by the compiler without -ffreestanding, then found as
* missing.
*/
void *memmove(void *dst, const void *src, size_t len);
__attribute__((weak,unused,section(".text.nolibc_memmove")))
void *memmove(void *dst, const void *src, size_t len)
{
size_t dir, pos;
pos = len;
dir = -1;
if (dst < src) {
pos = -1;
dir = 1;
}
while (len) {
pos += dir;
((char *)dst)[pos] = ((const char *)src)[pos];
len--;
}
return dst;
}
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */
#ifndef NOLIBC_ARCH_HAS_MEMCPY
/* must be exported, as it's used by libgcc on ARM */
void *memcpy(void *dst, const void *src, size_t len);
__attribute__((weak,unused,section(".text.nolibc_memcpy")))
void *memcpy(void *dst, const void *src, size_t len)
{
size_t pos = 0;
while (pos < len) {
((char *)dst)[pos] = ((const char *)src)[pos];
pos++;
}
return dst;
}
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */
#ifndef NOLIBC_ARCH_HAS_MEMSET
/* might be ignored by the compiler without -ffreestanding, then found as
* missing.
*/
void *memset(void *dst, int b, size_t len);
__attribute__((weak,unused,section(".text.nolibc_memset")))
void *memset(void *dst, int b, size_t len)
{
char *p = dst;
while (len--) {
/* prevent gcc from recognizing memset() here */
__asm__ volatile("");
*(p++) = b;
}
return dst;
}
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */
#ifndef NOLIBC_ARCH_HAS_MEMCHR
static __attribute__((unused))
void *memchr(const void *s, int c, size_t len)
{
char *p = (char *)s;
while (len--) {
if (*p == (char)c)
return p;
p++;
}
return NULL;
}
#endif /* #ifndef NOLIBC_ARCH_HAS_MEMCHR */
static __attribute__((unused))
char *strchr(const char *s, int c)
{
while (*s) {
if (*s == (char)c)
return (char *)s;
s++;
}
return NULL;
}
static __attribute__((unused))
int strcmp(const char *a, const char *b)
{
unsigned int c;
int diff;
while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
;
return diff;
}
static __attribute__((unused))
char *strcpy(char *dst, const char *src)
{
char *ret = dst;
while ((*dst++ = *src++));
return ret;
}
/* this function is only used with arguments that are not constants or when
* it's not known because optimizations are disabled. Note that gcc 12
* recognizes an strlen() pattern and replaces it with a jump to strlen(),
* thus itself, hence the asm() statement below that's meant to disable this
* confusing practice.
*/
size_t strlen(const char *str);
__attribute__((weak,unused,section(".text.nolibc_strlen")))
size_t strlen(const char *str)
{
size_t len;
for (len = 0; str[len]; len++)
__asm__("");
return len;
}
/* do not trust __builtin_constant_p() at -O0, as clang will emit a test and
* the two branches, then will rely on an external definition of strlen().
*/
#if defined(__OPTIMIZE__)
#define nolibc_strlen(x) strlen(x)
#define strlen(str) ({ \
__builtin_constant_p((str)) ? \
__builtin_strlen((str)) : \
nolibc_strlen((str)); \
})
#endif
static __attribute__((unused))
size_t strnlen(const char *str, size_t maxlen)
{
size_t len;
for (len = 0; (len < maxlen) && str[len]; len++);
return len;
}
static __attribute__((unused))
char *strdup(const char *str)
{
size_t len;
char *ret;
len = strlen(str);
ret = malloc(len + 1);
if (__builtin_expect(ret != NULL, 1))
memcpy(ret, str, len + 1);
return ret;
}
static __attribute__((unused))
char *strndup(const char *str, size_t maxlen)
{
size_t len;
char *ret;
len = strnlen(str, maxlen);
ret = malloc(len + 1);
if (__builtin_expect(ret != NULL, 1)) {
memcpy(ret, str, len);
ret[len] = '\0';
}
return ret;
}
static __attribute__((unused))
size_t strlcat(char *dst, const char *src, size_t size)
{
size_t len = strnlen(dst, size);
/*
* We want len < size-1. But as size is unsigned and can wrap
* around, we use len + 1 instead.
*/
while (len + 1 < size) {
dst[len] = *src;
if (*src == '\0')
break;
len++;
src++;
}
if (len < size)
dst[len] = '\0';
while (*src++)
len++;
return len;
}
static __attribute__((unused))
size_t strlcpy(char *dst, const char *src, size_t size)
{
size_t len;
for (len = 0; len < size; len++) {
dst[len] = src[len];
if (!dst[len])
return len;
}
if (size)
dst[size-1] = '\0';
while (src[len])
len++;
return len;
}
static __attribute__((unused))
char *strncat(char *dst, const char *src, size_t size)
{
char *orig = dst;
while (*dst)
dst++;
while (size && (*dst = *src)) {
src++;
dst++;
size--;
}
*dst = 0;
return orig;
}
static __attribute__((unused))
int strncmp(const char *a, const char *b, size_t size)
{
unsigned int c;
int diff = 0;
while (size-- &&
!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
;
return diff;
}
static __attribute__((unused))
char *strncpy(char *dst, const char *src, size_t size)
{
size_t len;
for (len = 0; len < size; len++)
if ((dst[len] = *src))
src++;
return dst;
}
static __attribute__((unused))
char *strrchr(const char *s, int c)
{
const char *ret = NULL;
while (*s) {
if (*s == (char)c)
ret = s;
s++;
}
return (char *)ret;
}
static __attribute__((unused))
char *strstr(const char *haystack, const char *needle)
{
size_t len_haystack, len_needle;
len_needle = strlen(needle);
if (!len_needle)
return NULL;
len_haystack = strlen(haystack);
while (len_haystack >= len_needle) {
if (!memcmp(haystack, needle, len_needle))
return (char *)haystack;
haystack++;
len_haystack--;
}
return NULL;
}
static __attribute__((unused))
int tolower(int c)
{
if (c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
return c;
}
static __attribute__((unused))
int toupper(int c)
{
if (c >= 'a' && c <= 'z')
return c - 'a' + 'A';
return c;
}
#endif /* _NOLIBC_STRING_H */
+945
View File
@@ -0,0 +1,945 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Syscall definitions for NOLIBC (those in man(2))
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_SYS_H
#define _NOLIBC_SYS_H
#include "std.h"
/* system includes */
#include <linux/unistd.h>
#include <linux/signal.h> /* for SIGCHLD */
#include <linux/termios.h>
#include <linux/mman.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/time.h>
#include <linux/auxvec.h>
#include <linux/fcntl.h> /* for O_* and AT_* */
#include <linux/sched.h> /* for CLONE_* */
#include <linux/stat.h> /* for statx() */
#include "errno.h"
#include "stdarg.h"
#include "types.h"
/* Syscall return helper: takes the syscall value in argument and checks for an
* error in it. This may only be used with signed returns (int or long), but
* not with pointers. An error is any value < 0. When an error is encountered,
* -ret is set into errno and -1 is returned. Otherwise the returned value is
* passed as-is with its type preserved.
*/
#define __sysret(arg) \
({ \
__typeof__(arg) __sysret_arg = (arg); \
(__sysret_arg < 0) /* error ? */ \
? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \
: __sysret_arg; /* return original value */ \
})
/* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile
* time validation and a debugging hook.
*/
#if defined(NOLIBC_COMPILE_TIME_ENOSYS)
static __inline__ int __nolibc_enosys(const char *syscall, ...)
{
(void)syscall;
return -ENOSYS;
}
#elif __nolibc_has_attribute(error)
__attribute__((error("system call not implemented")))
extern int __nolibc_enosys(const char *syscall, ...);
#else
static __inline__ int __nolibc_enosys(const char *syscall, ...)
{
extern int __nolibc_enosys_error;
(void)syscall;
return __nolibc_enosys_error;
}
#endif
/*
* Helper for 32-bit machines where a 64-bit syscall arg needs to be split into
* two 32-bit parts while making sure the order of the low/high parts are correct
* for the endianness:
* __NOLIBC_LLARGPART(x, 0), __NOLIBC_LLARGPART(x, 1)
*/
#define __NOLIBC_LLARGPART(_arg, _part) \
(((union { long long ll; long l[2]; }) { .ll = _arg }).l[_part])
/* Functions in this file only describe syscalls. They're declared static so
* that the compiler usually decides to inline them while still being allowed
* to pass a pointer to one of their instances. Each syscall exists in two
* versions:
* - the "internal" ones, which matches the raw syscall interface at the
* kernel level, which may sometimes slightly differ from the documented
* libc-level ones. For example most of them return either a valid value
* or -errno. All of these are prefixed with "_sys_". They may be called
* by non-portable applications if desired.
*
* - the "exported" ones, whose interface must closely match the one
* documented in man(2), that applications are supposed to expect. These
* ones rely on the internal ones, and set errno.
*
* Each syscall will be defined with the two functions, sorted in alphabetical
* order applied to the exported names.
*
* In case of doubt about the relevance of a function here, only those which
* set errno should be defined here. Wrappers like those appearing in man(3)
* should not be placed here.
*/
/*
* int brk(void *addr);
* void *sbrk(intptr_t inc)
*/
static __attribute__((unused))
void *_sys_brk(void *addr)
{
return (void *)(unsigned long)__nolibc_syscall1(__NR_brk, addr);
}
static __attribute__((unused))
int brk(void *addr)
{
void *ret = _sys_brk(addr);
if (!ret) {
SET_ERRNO(ENOMEM);
return -1;
}
return 0;
}
static __attribute__((unused))
void *sbrk(intptr_t inc)
{
/* first call to find current end */
void *ret = _sys_brk(NULL);
if (ret && _sys_brk(ret + inc) == ret + inc)
return ret + inc;
SET_ERRNO(ENOMEM);
return (void *)-1;
}
/*
* int chdir(const char *path);
* int fchdir(int fildes);
*/
static __attribute__((unused))
int _sys_chdir(const char *path)
{
return __nolibc_syscall1(__NR_chdir, path);
}
static __attribute__((unused))
int chdir(const char *path)
{
return __sysret(_sys_chdir(path));
}
static __attribute__((unused))
int _sys_fchdir(int fildes)
{
return __nolibc_syscall1(__NR_fchdir, fildes);
}
static __attribute__((unused))
int fchdir(int fildes)
{
return __sysret(_sys_fchdir(fildes));
}
/*
* int chmod(const char *path, mode_t mode);
*/
static __attribute__((unused))
int _sys_chmod(const char *path, mode_t mode)
{
#if defined(__NR_fchmodat)
return __nolibc_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0);
#else
return __nolibc_syscall2(__NR_chmod, path, mode);
#endif
}
static __attribute__((unused))
int chmod(const char *path, mode_t mode)
{
return __sysret(_sys_chmod(path, mode));
}
/*
* int chown(const char *path, uid_t owner, gid_t group);
*/
static __attribute__((unused))
int _sys_chown(const char *path, uid_t owner, gid_t group)
{
#if defined(__NR_fchownat)
return __nolibc_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0);
#else
return __nolibc_syscall3(__NR_chown, path, owner, group);
#endif
}
static __attribute__((unused))
int chown(const char *path, uid_t owner, gid_t group)
{
return __sysret(_sys_chown(path, owner, group));
}
/*
* int chroot(const char *path);
*/
static __attribute__((unused))
int _sys_chroot(const char *path)
{
return __nolibc_syscall1(__NR_chroot, path);
}
static __attribute__((unused))
int chroot(const char *path)
{
return __sysret(_sys_chroot(path));
}
/*
* int close(int fd);
*/
static __attribute__((unused))
int _sys_close(int fd)
{
return __nolibc_syscall1(__NR_close, fd);
}
static __attribute__((unused))
int close(int fd)
{
return __sysret(_sys_close(fd));
}
/*
* int dup(int fd);
*/
static __attribute__((unused))
int _sys_dup(int fd)
{
return __nolibc_syscall1(__NR_dup, fd);
}
static __attribute__((unused))
int dup(int fd)
{
return __sysret(_sys_dup(fd));
}
/*
* int dup2(int old, int new);
*/
static __attribute__((unused))
int _sys_dup2(int old, int new)
{
#if defined(__NR_dup3)
int ret, nr_fcntl;
#ifdef __NR_fcntl64
nr_fcntl = __NR_fcntl64;
#else
nr_fcntl = __NR_fcntl;
#endif
if (old == new) {
ret = __nolibc_syscall2(nr_fcntl, old, F_GETFD);
return ret < 0 ? ret : old;
}
return __nolibc_syscall3(__NR_dup3, old, new, 0);
#else
return __nolibc_syscall2(__NR_dup2, old, new);
#endif
}
static __attribute__((unused))
int dup2(int old, int new)
{
return __sysret(_sys_dup2(old, new));
}
/*
* int dup3(int old, int new, int flags);
*/
#if defined(__NR_dup3)
static __attribute__((unused))
int _sys_dup3(int old, int new, int flags)
{
return __nolibc_syscall3(__NR_dup3, old, new, flags);
}
static __attribute__((unused))
int dup3(int old, int new, int flags)
{
return __sysret(_sys_dup3(old, new, flags));
}
#endif
/*
* int execve(const char *filename, char *const argv[], char *const envp[]);
*/
static __attribute__((unused))
int _sys_execve(const char *filename, char *const argv[], char *const envp[])
{
return __nolibc_syscall3(__NR_execve, filename, argv, envp);
}
static __attribute__((unused))
int execve(const char *filename, char *const argv[], char *const envp[])
{
return __sysret(_sys_execve(filename, argv, envp));
}
/*
* void exit(int status);
*/
static __attribute__((noreturn,unused))
void _sys_exit(int status)
{
__nolibc_syscall1(__NR_exit, status & 255);
while(1); /* shut the "noreturn" warnings. */
}
static __attribute__((noreturn,unused))
void _exit(int status)
{
_sys_exit(status);
}
static __attribute__((noreturn,unused))
void exit(int status)
{
_exit(status);
}
/*
* pid_t fork(void);
*/
#ifndef _sys_fork
static __attribute__((unused))
pid_t _sys_fork(void)
{
#if defined(__NR_clone)
/* note: some archs only have clone() and not fork(). Different archs
* have a different API, but most archs have the flags on first arg and
* will not use the rest with no other flag.
*/
return __nolibc_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0);
#else
return __nolibc_syscall0(__NR_fork);
#endif
}
#endif
static __attribute__((unused))
pid_t fork(void)
{
return __sysret(_sys_fork());
}
#ifndef _sys_vfork
static __attribute__((unused))
pid_t _sys_vfork(void)
{
#if defined(__NR_clone)
/* See the note in _sys_fork(). */
return __nolibc_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0);
#elif defined(__NR_vfork)
return __nolibc_syscall0(__NR_vfork);
#endif
}
#endif
static __attribute__((unused))
pid_t vfork(void)
{
return __sysret(_sys_vfork());
}
/*
* int fsync(int fd);
*/
static __attribute__((unused))
int _sys_fsync(int fd)
{
return __nolibc_syscall1(__NR_fsync, fd);
}
static __attribute__((unused))
int fsync(int fd)
{
return __sysret(_sys_fsync(fd));
}
/*
* int getdents64(int fd, struct linux_dirent64 *dirp, int count);
*/
static __attribute__((unused))
int _sys_getdents64(int fd, struct linux_dirent64 *dirp, int count)
{
return __nolibc_syscall3(__NR_getdents64, fd, dirp, count);
}
static __attribute__((unused))
int getdents64(int fd, struct linux_dirent64 *dirp, int count)
{
return __sysret(_sys_getdents64(fd, dirp, count));
}
/*
* uid_t geteuid(void);
*/
static __attribute__((unused))
uid_t _sys_geteuid(void)
{
#if defined(__NR_geteuid32)
return __nolibc_syscall0(__NR_geteuid32);
#else
return __nolibc_syscall0(__NR_geteuid);
#endif
}
static __attribute__((unused))
uid_t geteuid(void)
{
return _sys_geteuid();
}
/*
* pid_t getpgid(pid_t pid);
*/
static __attribute__((unused))
pid_t _sys_getpgid(pid_t pid)
{
return __nolibc_syscall1(__NR_getpgid, pid);
}
static __attribute__((unused))
pid_t getpgid(pid_t pid)
{
return __sysret(_sys_getpgid(pid));
}
/*
* pid_t getpgrp(void);
*/
static __attribute__((unused))
pid_t _sys_getpgrp(void)
{
return _sys_getpgid(0);
}
static __attribute__((unused))
pid_t getpgrp(void)
{
return _sys_getpgrp();
}
/*
* pid_t getpid(void);
*/
static __attribute__((unused))
pid_t _sys_getpid(void)
{
return __nolibc_syscall0(__NR_getpid);
}
static __attribute__((unused))
pid_t getpid(void)
{
return _sys_getpid();
}
/*
* pid_t getppid(void);
*/
static __attribute__((unused))
pid_t _sys_getppid(void)
{
return __nolibc_syscall0(__NR_getppid);
}
static __attribute__((unused))
pid_t getppid(void)
{
return _sys_getppid();
}
/*
* pid_t gettid(void);
*/
static __attribute__((unused))
pid_t _sys_gettid(void)
{
return __nolibc_syscall0(__NR_gettid);
}
static __attribute__((unused))
pid_t gettid(void)
{
return _sys_gettid();
}
#ifndef NOLIBC_NO_RUNTIME
static unsigned long getauxval(unsigned long key);
/*
* int getpagesize(void);
*/
static __attribute__((unused))
int getpagesize(void)
{
return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT);
}
#endif /* NOLIBC_NO_RUNTIME */
/*
* uid_t getuid(void);
*/
static __attribute__((unused))
uid_t _sys_getuid(void)
{
#if defined(__NR_getuid32)
return __nolibc_syscall0(__NR_getuid32);
#else
return __nolibc_syscall0(__NR_getuid);
#endif
}
static __attribute__((unused))
uid_t getuid(void)
{
return _sys_getuid();
}
/*
* int kill(pid_t pid, int signal);
*/
static __attribute__((unused))
int _sys_kill(pid_t pid, int signal)
{
return __nolibc_syscall2(__NR_kill, pid, signal);
}
static __attribute__((unused))
int kill(pid_t pid, int signal)
{
return __sysret(_sys_kill(pid, signal));
}
/*
* int link(const char *old, const char *new);
*/
static __attribute__((unused))
int _sys_link(const char *old, const char *new)
{
#if defined(__NR_linkat)
return __nolibc_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0);
#else
return __nolibc_syscall2(__NR_link, old, new);
#endif
}
static __attribute__((unused))
int link(const char *old, const char *new)
{
return __sysret(_sys_link(old, new));
}
/*
* off_t lseek(int fd, off_t offset, int whence);
*/
static __attribute__((unused))
off_t _sys_lseek(int fd, off_t offset, int whence)
{
#if defined(__NR_llseek) || defined(__NR__llseek)
__kernel_loff_t loff = 0;
int ret, nr_llseek;
off_t result;
#if defined(__NR_llseek)
nr_llseek = __NR_llseek;
#else
nr_llseek = __NR__llseek;
#endif
ret = __nolibc_syscall5(nr_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence);
if (ret < 0)
result = ret;
else
result = loff;
return result;
#else
return __nolibc_syscall3(__NR_lseek, fd, offset, whence);
#endif
}
static __attribute__((unused))
off_t lseek(int fd, off_t offset, int whence)
{
return __sysret(_sys_lseek(fd, offset, whence));
}
/*
* int mkdir(const char *path, mode_t mode);
*/
static __attribute__((unused))
int _sys_mkdir(const char *path, mode_t mode)
{
#if defined(__NR_mkdirat)
return __nolibc_syscall3(__NR_mkdirat, AT_FDCWD, path, mode);
#else
return __nolibc_syscall2(__NR_mkdir, path, mode);
#endif
}
static __attribute__((unused))
int mkdir(const char *path, mode_t mode)
{
return __sysret(_sys_mkdir(path, mode));
}
/*
* int rmdir(const char *path);
*/
static __attribute__((unused))
int _sys_rmdir(const char *path)
{
#if defined(__NR_rmdir)
return __nolibc_syscall1(__NR_rmdir, path);
#else
return __nolibc_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
#endif
}
static __attribute__((unused))
int rmdir(const char *path)
{
return __sysret(_sys_rmdir(path));
}
/*
* int mknod(const char *path, mode_t mode, dev_t dev);
*/
static __attribute__((unused))
long _sys_mknod(const char *path, mode_t mode, dev_t dev)
{
#if defined(__NR_mknodat)
return __nolibc_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev);
#else
return __nolibc_syscall3(__NR_mknod, path, mode, dev);
#endif
}
static __attribute__((unused))
int mknod(const char *path, mode_t mode, dev_t dev)
{
return __sysret(_sys_mknod(path, mode, dev));
}
/*
* int pipe2(int pipefd[2], int flags);
* int pipe(int pipefd[2]);
*/
static __attribute__((unused))
int _sys_pipe2(int pipefd[2], int flags)
{
return __nolibc_syscall2(__NR_pipe2, pipefd, flags);
}
static __attribute__((unused))
int pipe2(int pipefd[2], int flags)
{
return __sysret(_sys_pipe2(pipefd, flags));
}
static __attribute__((unused))
int pipe(int pipefd[2])
{
return pipe2(pipefd, 0);
}
/*
* int pivot_root(const char *new, const char *old);
*/
static __attribute__((unused))
int _sys_pivot_root(const char *new, const char *old)
{
return __nolibc_syscall2(__NR_pivot_root, new, old);
}
static __attribute__((unused))
int pivot_root(const char *new, const char *old)
{
return __sysret(_sys_pivot_root(new, old));
}
/*
* ssize_t read(int fd, void *buf, size_t count);
*/
static __attribute__((unused))
ssize_t _sys_read(int fd, void *buf, size_t count)
{
return __nolibc_syscall3(__NR_read, fd, buf, count);
}
static __attribute__((unused))
ssize_t read(int fd, void *buf, size_t count)
{
return __sysret(_sys_read(fd, buf, count));
}
/*
* int sched_yield(void);
*/
static __attribute__((unused))
int _sys_sched_yield(void)
{
return __nolibc_syscall0(__NR_sched_yield);
}
static __attribute__((unused))
int sched_yield(void)
{
return __sysret(_sys_sched_yield());
}
/*
* int setpgid(pid_t pid, pid_t pgid);
*/
static __attribute__((unused))
int _sys_setpgid(pid_t pid, pid_t pgid)
{
return __nolibc_syscall2(__NR_setpgid, pid, pgid);
}
static __attribute__((unused))
int setpgid(pid_t pid, pid_t pgid)
{
return __sysret(_sys_setpgid(pid, pgid));
}
/*
* pid_t setpgrp(void)
*/
static __attribute__((unused))
pid_t setpgrp(void)
{
return setpgid(0, 0);
}
/*
* pid_t setsid(void);
*/
static __attribute__((unused))
pid_t _sys_setsid(void)
{
return __nolibc_syscall0(__NR_setsid);
}
static __attribute__((unused))
pid_t setsid(void)
{
return __sysret(_sys_setsid());
}
/*
* int symlink(const char *old, const char *new);
*/
static __attribute__((unused))
int _sys_symlink(const char *old, const char *new)
{
#if defined(__NR_symlinkat)
return __nolibc_syscall3(__NR_symlinkat, old, AT_FDCWD, new);
#else
return __nolibc_syscall2(__NR_symlink, old, new);
#endif
}
static __attribute__((unused))
int symlink(const char *old, const char *new)
{
return __sysret(_sys_symlink(old, new));
}
/*
* mode_t umask(mode_t mode);
*/
static __attribute__((unused))
mode_t _sys_umask(mode_t mode)
{
return __nolibc_syscall1(__NR_umask, mode);
}
static __attribute__((unused))
mode_t umask(mode_t mode)
{
return _sys_umask(mode);
}
/*
* int umount2(const char *path, int flags);
*/
static __attribute__((unused))
int _sys_umount2(const char *path, int flags)
{
return __nolibc_syscall2(__NR_umount2, path, flags);
}
static __attribute__((unused))
int umount2(const char *path, int flags)
{
return __sysret(_sys_umount2(path, flags));
}
/*
* int unlink(const char *path);
*/
static __attribute__((unused))
int _sys_unlink(const char *path)
{
#if defined(__NR_unlinkat)
return __nolibc_syscall3(__NR_unlinkat, AT_FDCWD, path, 0);
#else
return __nolibc_syscall1(__NR_unlink, path);
#endif
}
static __attribute__((unused))
int unlink(const char *path)
{
return __sysret(_sys_unlink(path));
}
/*
* ssize_t write(int fd, const void *buf, size_t count);
*/
static __attribute__((unused))
ssize_t _sys_write(int fd, const void *buf, size_t count)
{
return __nolibc_syscall3(__NR_write, fd, buf, count);
}
static __attribute__((unused))
ssize_t write(int fd, const void *buf, size_t count)
{
return __sysret(_sys_write(fd, buf, count));
}
/*
* int memfd_create(const char *name, unsigned int flags);
*/
static __attribute__((unused))
int _sys_memfd_create(const char *name, unsigned int flags)
{
return __nolibc_syscall2(__NR_memfd_create, name, flags);
}
static __attribute__((unused))
int memfd_create(const char *name, unsigned int flags)
{
return __sysret(_sys_memfd_create(name, flags));
}
#endif /* _NOLIBC_SYS_H */
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* auxv definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_AUXV_H
#define _NOLIBC_SYS_AUXV_H
#ifndef NOLIBC_NO_RUNTIME
#include "../crt.h"
static __attribute__((unused))
unsigned long getauxval(unsigned long type)
{
const unsigned long *auxv = _auxv;
unsigned long ret;
if (!auxv)
return 0;
while (1) {
if (!auxv[0] && !auxv[1]) {
ret = 0;
break;
}
if (auxv[0] == type) {
ret = auxv[1];
break;
}
auxv += 2;
}
return ret;
}
#endif /* NOLIBC_NO_RUNTIME */
#endif /* _NOLIBC_SYS_AUXV_H */
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Ioctl definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_IOCTL_H
#define _NOLIBC_SYS_IOCTL_H
#include "../sys.h"
#include <linux/ioctl.h>
/*
* int ioctl(int fd, unsigned long cmd, ... arg);
*/
static __attribute__((unused))
long _sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
return __nolibc_syscall3(__NR_ioctl, fd, cmd, arg);
}
#define ioctl(fd, cmd, arg) __sysret(_sys_ioctl(fd, cmd, (unsigned long)(arg)))
#endif /* _NOLIBC_SYS_IOCTL_H */
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* mm definition for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_MMAN_H
#define _NOLIBC_SYS_MMAN_H
#include "../arch.h"
#include "../sys.h"
#ifndef _sys_mmap
static __attribute__((unused))
void *_sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset)
{
int n;
#if defined(__NR_mmap2)
n = __NR_mmap2;
offset >>= 12;
#else
n = __NR_mmap;
#endif
return (void *)(unsigned long)__nolibc_syscall6(n, addr, length, prot, flags, fd, offset);
}
#endif
static __attribute__((unused))
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
void *ret = _sys_mmap(addr, length, prot, flags, fd, offset);
if ((unsigned long)ret >= -4095UL) {
SET_ERRNO(-(long)ret);
ret = MAP_FAILED;
}
return ret;
}
static __attribute__((unused))
void *_sys_mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address)
{
return (void *)(unsigned long)__nolibc_syscall5(__NR_mremap, old_address, old_size,
new_size, flags, new_address);
}
static __attribute__((unused))
void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address)
{
void *ret = _sys_mremap(old_address, old_size, new_size, flags, new_address);
if ((unsigned long)ret >= -4095UL) {
SET_ERRNO(-(long)ret);
ret = MAP_FAILED;
}
return ret;
}
static __attribute__((unused))
int _sys_munmap(void *addr, size_t length)
{
return __nolibc_syscall2(__NR_munmap, addr, length);
}
static __attribute__((unused))
int munmap(void *addr, size_t length)
{
return __sysret(_sys_munmap(addr, length));
}
#endif /* _NOLIBC_SYS_MMAN_H */
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Mount definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_MOUNT_H
#define _NOLIBC_SYS_MOUNT_H
#include "../sys.h"
#include <linux/mount.h>
/*
* int mount(const char *source, const char *target,
* const char *fstype, unsigned long flags,
* const void *data);
*/
static __attribute__((unused))
int _sys_mount(const char *src, const char *tgt, const char *fst,
unsigned long flags, const void *data)
{
return __nolibc_syscall5(__NR_mount, src, tgt, fst, flags, data);
}
static __attribute__((unused))
int mount(const char *src, const char *tgt,
const char *fst, unsigned long flags,
const void *data)
{
return __sysret(_sys_mount(src, tgt, fst, flags, data));
}
#endif /* _NOLIBC_SYS_MOUNT_H */
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Prctl definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_PRCTL_H
#define _NOLIBC_SYS_PRCTL_H
#include "../sys.h"
#include <linux/prctl.h>
/*
* int prctl(int option, unsigned long arg2, unsigned long arg3,
* unsigned long arg4, unsigned long arg5);
*/
static __attribute__((unused))
int _sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
return __nolibc_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5);
}
static __attribute__((unused))
int prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
return __sysret(_sys_prctl(option, arg2, arg3, arg4, arg5));
}
#endif /* _NOLIBC_SYS_PRCTL_H */
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* ptrace for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
* Copyright (C) 2025 Intel Corporation
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_PTRACE_H
#define _NOLIBC_SYS_PTRACE_H
#include "../sys.h"
#include <linux/ptrace.h>
/*
* long ptrace(int op, pid_t pid, void *addr, void *data);
*/
static __attribute__((unused))
long _sys_ptrace(int op, pid_t pid, void *addr, void *data)
{
return __nolibc_syscall4(__NR_ptrace, op, pid, addr, data);
}
static __attribute__((unused))
ssize_t ptrace(int op, pid_t pid, void *addr, void *data)
{
return __sysret(_sys_ptrace(op, pid, addr, data));
}
#endif /* _NOLIBC_SYS_PTRACE_H */
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* random definitions for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_RANDOM_H
#define _NOLIBC_SYS_RANDOM_H
#include "../arch.h"
#include "../sys.h"
#include <linux/random.h>
/*
* ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
*/
static __attribute__((unused))
ssize_t _sys_getrandom(void *buf, size_t buflen, unsigned int flags)
{
return __nolibc_syscall3(__NR_getrandom, buf, buflen, flags);
}
static __attribute__((unused))
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)
{
return __sysret(_sys_getrandom(buf, buflen, flags));
}
#endif /* _NOLIBC_SYS_RANDOM_H */
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Reboot definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_REBOOT_H
#define _NOLIBC_SYS_REBOOT_H
#include "../sys.h"
#include <linux/reboot.h>
/*
* int reboot(int cmd);
* <cmd> is among LINUX_REBOOT_CMD_*
*/
static __attribute__((unused))
ssize_t _sys_reboot(int magic1, int magic2, int cmd, void *arg)
{
return __nolibc_syscall4(__NR_reboot, magic1, magic2, cmd, arg);
}
static __attribute__((unused))
int reboot(int cmd)
{
return __sysret(_sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL));
}
#endif /* _NOLIBC_SYS_REBOOT_H */
@@ -0,0 +1,53 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Resource definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_RESOURCE_H
#define _NOLIBC_SYS_RESOURCE_H
#include "../sys.h"
#include <linux/resource.h>
/*
* int getrlimit(int resource, struct rlimit *rlim);
* int setrlimit(int resource, const struct rlimit *rlim);
*/
static __attribute__((unused))
int _sys_prlimit64(pid_t pid, int resource,
const struct rlimit64 *new_limit, struct rlimit64 *old_limit)
{
return __nolibc_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit);
}
static __attribute__((unused))
int getrlimit(int resource, struct rlimit *rlim)
{
struct rlimit64 rlim64;
int ret;
ret = __sysret(_sys_prlimit64(0, resource, NULL, &rlim64));
rlim->rlim_cur = rlim64.rlim_cur;
rlim->rlim_max = rlim64.rlim_max;
return ret;
}
static __attribute__((unused))
int setrlimit(int resource, const struct rlimit *rlim)
{
struct rlimit64 rlim64 = {
.rlim_cur = rlim->rlim_cur,
.rlim_max = rlim->rlim_max,
};
return __sysret(_sys_prlimit64(0, resource, &rlim64, NULL));
}
#endif /* _NOLIBC_SYS_RESOURCE_H */
@@ -0,0 +1,94 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_SELECT_H
#define _NOLIBC_SYS_SELECT_H
#include <linux/time.h>
#include <linux/unistd.h>
/* commonly an fd_set represents 256 FDs */
#ifndef FD_SETSIZE
#define FD_SETSIZE 256
#endif
#define FD_SETIDXMASK (8 * sizeof(unsigned long))
#define FD_SETBITMASK (8 * sizeof(unsigned long)-1)
/* for select() */
typedef struct {
unsigned long fds[(FD_SETSIZE + FD_SETBITMASK) / FD_SETIDXMASK];
} fd_set;
#define FD_CLR(fd, set) do { \
fd_set *__set = (set); \
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] &= \
~(1U << (__fd & FD_SETBITMASK)); \
} while (0)
#define FD_SET(fd, set) do { \
fd_set *__set = (set); \
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] |= \
1 << (__fd & FD_SETBITMASK); \
} while (0)
#define FD_ISSET(fd, set) ({ \
fd_set *__set = (set); \
int __fd = (fd); \
int __r = 0; \
if (__fd >= 0) \
__r = !!(__set->fds[__fd / FD_SETIDXMASK] & \
1U << (__fd & FD_SETBITMASK)); \
__r; \
})
#define FD_ZERO(set) do { \
fd_set *__set = (set); \
int __idx; \
int __size = (FD_SETSIZE+FD_SETBITMASK) / FD_SETIDXMASK;\
for (__idx = 0; __idx < __size; __idx++) \
__set->fds[__idx] = 0; \
} while (0)
/*
* int select(int nfds, fd_set *read_fds, fd_set *write_fds,
* fd_set *except_fds, struct timeval *timeout);
*/
static __attribute__((unused))
int _sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
{
#if defined(__NR_pselect6_time64)
struct __kernel_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = (uint32_t)timeout->tv_usec * 1000;
}
return __nolibc_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds,
timeout ? &t : NULL, NULL);
#else
struct __kernel_old_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
t.tv_nsec = (uint32_t)timeout->tv_usec * 1000;
}
return __nolibc_syscall6(__NR_pselect6, nfds, rfds, wfds, efds,
timeout ? &t : NULL, NULL);
#endif
}
static __attribute__((unused))
int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
{
return __sysret(_sys_select(nfds, rfds, wfds, efds, timeout));
}
#endif /* _NOLIBC_SYS_SELECT_H */
@@ -0,0 +1,91 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* stat definition for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_STAT_H
#define _NOLIBC_SYS_STAT_H
#include "../arch.h"
#include "../types.h"
#include "../sys.h"
#include "../sys/sysmacros.h"
/*
* int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf);
* int stat(const char *path, struct stat *buf);
* int fstatat(int fd, const char *path, struct stat *buf, int flag);
* int fstat(int fildes, struct stat *buf);
* int lstat(const char *path, struct stat *buf);
*/
static __attribute__((unused))
int _sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
{
#ifdef __NR_statx
return __nolibc_syscall5(__NR_statx, fd, path, flags, mask, buf);
#else
return __nolibc_enosys(__func__, fd, path, flags, mask, buf);
#endif
}
static __attribute__((unused))
int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
{
return __sysret(_sys_statx(fd, path, flags, mask, buf));
}
static __attribute__((unused))
int fstatat(int fd, const char *path, struct stat *buf, int flag)
{
struct statx statx;
long ret;
ret = __sysret(_sys_statx(fd, path, flag | AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx));
if (ret == -1)
return ret;
buf->st_dev = makedev(statx.stx_dev_major, statx.stx_dev_minor);
buf->st_ino = statx.stx_ino;
buf->st_mode = statx.stx_mode;
buf->st_nlink = statx.stx_nlink;
buf->st_uid = statx.stx_uid;
buf->st_gid = statx.stx_gid;
buf->st_rdev = makedev(statx.stx_rdev_major, statx.stx_rdev_minor);
buf->st_size = statx.stx_size;
buf->st_blksize = statx.stx_blksize;
buf->st_blocks = statx.stx_blocks;
buf->st_atim.tv_sec = statx.stx_atime.tv_sec;
buf->st_atim.tv_nsec = statx.stx_atime.tv_nsec;
buf->st_mtim.tv_sec = statx.stx_mtime.tv_sec;
buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec;
buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec;
buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec;
return 0;
}
static __attribute__((unused))
int stat(const char *path, struct stat *buf)
{
return fstatat(AT_FDCWD, path, buf, 0);
}
static __attribute__((unused))
int fstat(int fildes, struct stat *buf)
{
return fstatat(fildes, "", buf, AT_EMPTY_PATH);
}
static __attribute__((unused))
int lstat(const char *path, struct stat *buf)
{
return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
}
#endif /* _NOLIBC_SYS_STAT_H */
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* syscall() definition for NOLIBC
* Copyright (C) 2024 Thomas Weißschuh <linux@weissschuh.net>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_SYSCALL_H
#define _NOLIBC_SYS_SYSCALL_H
#define ___nolibc_syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N
#define __nolibc_syscall_narg(...) ___nolibc_syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define __nolibc_syscall(N, ...) __nolibc_syscall##N(__VA_ARGS__)
#define __nolibc_syscall_n(N, ...) __nolibc_syscall(N, __VA_ARGS__)
#define _syscall(...) __nolibc_syscall_n(__nolibc_syscall_narg(__VA_ARGS__), ##__VA_ARGS__)
#define syscall(...) __sysret(_syscall(__VA_ARGS__))
#endif /* _NOLIBC_SYS_SYSCALL_H */
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Sysmacro definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_SYSMACROS_H
#define _NOLIBC_SYS_SYSMACROS_H
#include "../std.h"
static __inline__ dev_t __nolibc_makedev(unsigned int maj, unsigned int min)
{
return (((dev_t)maj & ~0xfff) << 32) | ((maj & 0xfff) << 8) |
(((dev_t)min & ~0xff) << 12) | (min & 0xff);
}
#define makedev(maj, min) __nolibc_makedev(maj, min)
static __inline__ unsigned int __nolibc_major(dev_t dev)
{
return ((dev >> 32) & ~0xfff) | ((dev >> 8) & 0xfff);
}
#define major(dev) __nolibc_major(dev)
static __inline__ unsigned int __nolibc_minor(dev_t dev)
{
return ((dev >> 12) & ~0xff) | (dev & 0xff);
}
#define minor(dev) __nolibc_minor(dev)
#endif /* _NOLIBC_SYS_SYSMACROS_H */
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* time definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_TIME_H
#define _NOLIBC_SYS_TIME_H
#include "../arch.h"
#include "../sys.h"
static int _sys_clock_gettime(clockid_t clockid, struct timespec *tp);
/*
* int gettimeofday(struct timeval *tv, struct timezone *tz);
*/
static __attribute__((unused))
int _sys_gettimeofday(struct timeval *tv, struct timezone *tz)
{
(void) tz; /* Non-NULL tz is undefined behaviour */
struct timespec tp;
int ret;
ret = _sys_clock_gettime(CLOCK_REALTIME, &tp);
if (!ret && tv) {
tv->tv_sec = tp.tv_sec;
tv->tv_usec = (uint32_t)tp.tv_nsec / 1000;
}
return ret;
}
static __attribute__((unused))
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
return __sysret(_sys_gettimeofday(tv, tz));
}
#endif /* _NOLIBC_SYS_TIME_H */
@@ -0,0 +1,71 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* timerfd definitions for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_TIMERFD_H
#define _NOLIBC_SYS_TIMERFD_H
#include "../sys.h"
#include "../time.h"
#include <linux/timerfd.h>
static __attribute__((unused))
int _sys_timerfd_create(int clockid, int flags)
{
return __nolibc_syscall2(__NR_timerfd_create, clockid, flags);
}
static __attribute__((unused))
int timerfd_create(int clockid, int flags)
{
return __sysret(_sys_timerfd_create(clockid, flags));
}
static __attribute__((unused))
int _sys_timerfd_gettime(int fd, struct itimerspec *curr_value)
{
#if defined(__NR_timerfd_gettime64)
__nolibc_assert_time64_type(curr_value->it_value.tv_sec);
return __nolibc_syscall2(__NR_timerfd_gettime64, fd, curr_value);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall2(__NR_timerfd_gettime, fd, curr_value);
#endif
}
static __attribute__((unused))
int timerfd_gettime(int fd, struct itimerspec *curr_value)
{
return __sysret(_sys_timerfd_gettime(fd, curr_value));
}
static __attribute__((unused))
int _sys_timerfd_settime(int fd, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
#if defined(__NR_timerfd_settime64)
__nolibc_assert_time64_type(new_value->it_value.tv_sec);
return __nolibc_syscall4(__NR_timerfd_settime64, fd, flags, new_value, old_value);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value);
#endif
}
static __attribute__((unused))
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
return __sysret(_sys_timerfd_settime(fd, flags, new_value, old_value));
}
#endif /* _NOLIBC_SYS_TIMERFD_H */
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* sys/types.h shim for NOLIBC
* Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de>
*/
#include "../types.h"
@@ -0,0 +1,49 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* uio for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
* Copyright (C) 2025 Intel Corporation
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_UIO_H
#define _NOLIBC_SYS_UIO_H
#include "../sys.h"
#include <linux/uio.h>
/*
* ssize_t readv(int fd, const struct iovec *iovec, int count);
*/
static __attribute__((unused))
ssize_t _sys_readv(int fd, const struct iovec *iovec, int count)
{
return __nolibc_syscall3(__NR_readv, fd, iovec, count);
}
static __attribute__((unused))
ssize_t readv(int fd, const struct iovec *iovec, int count)
{
return __sysret(_sys_readv(fd, iovec, count));
}
/*
* ssize_t writev(int fd, const struct iovec *iovec, int count);
*/
static __attribute__((unused))
ssize_t _sys_writev(int fd, const struct iovec *iovec, int count)
{
return __nolibc_syscall3(__NR_writev, fd, iovec, count);
}
static __attribute__((unused))
ssize_t writev(int fd, const struct iovec *iovec, int count)
{
return __sysret(_sys_writev(fd, iovec, count));
}
#endif /* _NOLIBC_SYS_UIO_H */
@@ -0,0 +1,42 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Utsname definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_UTSNAME_H
#define _NOLIBC_SYS_UTSNAME_H
#include "../sys.h"
#include <linux/utsname.h>
/*
* int uname(struct utsname *buf);
*/
struct utsname {
char sysname[65];
char nodename[65];
char release[65];
char version[65];
char machine[65];
char domainname[65];
};
static __attribute__((unused))
int _sys_uname(struct utsname *buf)
{
return __nolibc_syscall1(__NR_uname, buf);
}
static __attribute__((unused))
int uname(struct utsname *buf)
{
return __sysret(_sys_uname(buf));
}
#endif /* _NOLIBC_SYS_UTSNAME_H */
+105
View File
@@ -0,0 +1,105 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* wait definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "../nolibc.h"
#ifndef _NOLIBC_SYS_WAIT_H
#define _NOLIBC_SYS_WAIT_H
#include "../arch.h"
#include "../std.h"
#include "../types.h"
/*
* pid_t wait(int *status);
* pid_t waitpid(pid_t pid, int *status, int options);
* int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
*/
static __attribute__((unused))
int _sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusage *rusage)
{
return __nolibc_syscall5(__NR_waitid, which, pid, infop, options, rusage);
}
static __attribute__((unused))
int waitid(int which, pid_t pid, siginfo_t *infop, int options)
{
return __sysret(_sys_waitid(which, pid, infop, options, NULL));
}
static __attribute__((unused))
pid_t waitpid(pid_t pid, int *status, int options)
{
int idtype, ret;
siginfo_t info;
pid_t id;
if (pid == INT_MIN) {
SET_ERRNO(ESRCH);
return -1;
} else if (pid < -1) {
idtype = P_PGID;
id = -pid;
} else if (pid == -1) {
idtype = P_ALL;
id = 0;
} else if (pid == 0) {
idtype = P_PGID;
id = 0;
} else {
idtype = P_PID;
id = pid;
}
options |= WEXITED;
ret = waitid(idtype, id, &info, options);
if (ret)
return -1;
switch (info.si_code) {
case 0:
if (status)
*status = 0;
break;
case CLD_EXITED:
if (status)
*status = (info.si_status & 0xff) << 8;
break;
case CLD_KILLED:
if (status)
*status = info.si_status & 0x7f;
break;
case CLD_DUMPED:
if (status)
*status = (info.si_status & 0x7f) | 0x80;
break;
case CLD_STOPPED:
case CLD_TRAPPED:
if (status)
*status = (info.si_status << 8) + 0x7f;
break;
case CLD_CONTINUED:
if (status)
*status = 0xffff;
break;
default:
return -1;
}
return info.si_pid;
}
static __attribute__((unused))
pid_t wait(int *status)
{
return waitpid(-1, status, 0);
}
#endif /* _NOLIBC_SYS_WAIT_H */
+205
View File
@@ -0,0 +1,205 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* time function definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_TIME_H
#define _NOLIBC_TIME_H
#include "std.h"
#include "arch.h"
#include "types.h"
#include "sys.h"
#include <linux/signal.h>
#include <linux/time.h>
#define __nolibc_assert_time64_type(t) \
__nolibc_static_assert(sizeof(t) == 8)
#define __nolibc_assert_native_time64() \
__nolibc_assert_time64_type(__kernel_old_time_t)
/*
* int clock_getres(clockid_t clockid, struct timespec *res);
* int clock_gettime(clockid_t clockid, struct timespec *tp);
* int clock_settime(clockid_t clockid, const struct timespec *tp);
* int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp,
* struct timespec *rmtp)
*/
static __attribute__((unused))
int _sys_clock_getres(clockid_t clockid, struct timespec *res)
{
#if defined(__NR_clock_getres_time64)
__nolibc_assert_time64_type(res->tv_sec);
return __nolibc_syscall2(__NR_clock_getres_time64, clockid, res);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall2(__NR_clock_getres, clockid, res);
#endif
}
static __attribute__((unused))
int clock_getres(clockid_t clockid, struct timespec *res)
{
return __sysret(_sys_clock_getres(clockid, res));
}
static __attribute__((unused))
int _sys_clock_gettime(clockid_t clockid, struct timespec *tp)
{
#if defined(__NR_clock_gettime64)
__nolibc_assert_time64_type(tp->tv_sec);
return __nolibc_syscall2(__NR_clock_gettime64, clockid, tp);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall2(__NR_clock_gettime, clockid, tp);
#endif
}
static __attribute__((unused))
int clock_gettime(clockid_t clockid, struct timespec *tp)
{
return __sysret(_sys_clock_gettime(clockid, tp));
}
static __attribute__((unused))
int _sys_clock_settime(clockid_t clockid, struct timespec *tp)
{
#if defined(__NR_clock_settime64)
__nolibc_assert_time64_type(tp->tv_sec);
return __nolibc_syscall2(__NR_clock_settime64, clockid, tp);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall2(__NR_clock_settime, clockid, tp);
#endif
}
static __attribute__((unused))
int clock_settime(clockid_t clockid, struct timespec *tp)
{
return __sysret(_sys_clock_settime(clockid, tp));
}
static __attribute__((unused))
int _sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
#if defined(__NR_clock_nanosleep_time64)
__nolibc_assert_time64_type(rqtp->tv_sec);
return __nolibc_syscall4(__NR_clock_nanosleep_time64, clockid, flags, rqtp, rmtp);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp);
#endif
}
static __attribute__((unused))
int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
/* Directly return a positive error number */
return -_sys_clock_nanosleep(clockid, flags, rqtp, rmtp);
}
static __inline__
double difftime(time_t time1, time_t time2)
{
return time1 - time2;
}
static __inline__
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
return __sysret(_sys_clock_nanosleep(CLOCK_REALTIME, 0, rqtp, rmtp));
}
static __attribute__((unused))
time_t time(time_t *tptr)
{
struct timeval tv;
/* note, cannot fail here */
_sys_gettimeofday(&tv, NULL);
if (tptr)
*tptr = tv.tv_sec;
return tv.tv_sec;
}
/*
* int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
* int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
* int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
*/
static __attribute__((unused))
int _sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
return __nolibc_syscall3(__NR_timer_create, clockid, evp, timerid);
}
static __attribute__((unused))
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
return __sysret(_sys_timer_create(clockid, evp, timerid));
}
static __attribute__((unused))
int _sys_timer_delete(timer_t timerid)
{
return __nolibc_syscall1(__NR_timer_delete, timerid);
}
static __attribute__((unused))
int timer_delete(timer_t timerid)
{
return __sysret(_sys_timer_delete(timerid));
}
static __attribute__((unused))
int _sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value)
{
#if defined(__NR_timer_gettime64)
__nolibc_assert_time64_type(curr_value->it_value.tv_sec);
return __nolibc_syscall2(__NR_timer_gettime64, timerid, curr_value);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall2(__NR_timer_gettime, timerid, curr_value);
#endif
}
static __attribute__((unused))
int timer_gettime(timer_t timerid, struct itimerspec *curr_value)
{
return __sysret(_sys_timer_gettime(timerid, curr_value));
}
static __attribute__((unused))
int _sys_timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
#if defined(__NR_timer_settime64)
__nolibc_assert_time64_type(new_value->it_value.tv_sec);
return __nolibc_syscall4(__NR_timer_settime64, timerid, flags, new_value, old_value);
#else
__nolibc_assert_native_time64();
return __nolibc_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value);
#endif
}
static __attribute__((unused))
int timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value, struct itimerspec *old_value)
{
return __sysret(_sys_timer_settime(timerid, flags, new_value, old_value));
}
#endif /* _NOLIBC_TIME_H */
+166
View File
@@ -0,0 +1,166 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* Special types used by various syscalls for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_TYPES_H
#define _NOLIBC_TYPES_H
#include "std.h"
#include <linux/mman.h>
#include <linux/stat.h>
#include <linux/time_types.h>
#include <linux/wait.h>
struct timespec {
time_t tv_sec;
int64_t tv_nsec;
};
#define _STRUCT_TIMESPEC
/* Never use with system calls */
struct timeval {
time_t tv_sec;
int64_t tv_usec;
};
#define timeval __nolibc_kernel_timeval
#include <linux/time.h>
#undef timeval
/* Only the generic macros and types may be defined here. The arch-specific
* ones such as the O_RDONLY and related macros used by fcntl() and open()
* must not be defined here.
*/
/* stat flags (WARNING, octal here). We need to check for an existing
* definition because linux/stat.h may omit to define those if it finds
* that any glibc header was already included.
*/
#if !defined(S_IFMT)
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFBLK 0060000
#define S_IFREG 0100000
#define S_IFIFO 0010000
#define S_IFLNK 0120000
#define S_IFSOCK 0140000
#define S_IFMT 0170000
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
#endif
/* dirent types */
#define DT_UNKNOWN 0x0
#define DT_FIFO 0x1
#define DT_CHR 0x2
#define DT_DIR 0x4
#define DT_BLK 0x6
#define DT_REG 0x8
#define DT_LNK 0xa
#define DT_SOCK 0xc
/* PATH_MAX and MAXPATHLEN are often used and found with plenty of different
* values.
*/
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN (PATH_MAX)
#endif
/* flags for mmap */
#ifndef MAP_FAILED
#define MAP_FAILED ((void *)-1)
#endif
/* whence values for lseek() */
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
/* flags for reboot */
#define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART
#define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT
#define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON
#define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF
#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
#define RB_SW_SUSPEND LINUX_REBOOT_CMD_SW_SUSPEND
#define RB_KEXEC LINUX_REBOOT_CMD_KEXEC
/* Macros used on waitpid()'s return status */
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WIFEXITED(status) (((status) & 0x7f) == 0)
#define WTERMSIG(status) ((status) & 0x7f)
#define WIFSIGNALED(status) ((status) - 1 < 0xff)
/* standard exit() codes */
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
/* for getdents64() */
struct linux_dirent64 {
uint64_t d_ino;
int64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
/* The format of the struct as returned by the libc to the application, which
* significantly differs from the format returned by the stat() syscall flavours.
*/
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
union { time_t st_atime; struct timespec st_atim; }; /* time of last access */
union { time_t st_mtime; struct timespec st_mtim; }; /* time of last modification */
union { time_t st_ctime; struct timespec st_ctim; }; /* time of last status change */
};
typedef __kernel_clockid_t clockid_t;
typedef int timer_t;
#ifndef container_of
#define container_of(PTR, TYPE, FIELD) ({ \
__typeof__(((TYPE *)0)->FIELD) *__FIELD_PTR = (PTR); \
(TYPE *)((char *) __FIELD_PTR - offsetof(TYPE, FIELD)); \
})
#endif
#endif /* _NOLIBC_TYPES_H */
+114
View File
@@ -0,0 +1,114 @@
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/*
* unistd function definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*/
/* make sure to include all global symbols */
#include "nolibc.h"
#ifndef _NOLIBC_UNISTD_H
#define _NOLIBC_UNISTD_H
#include "std.h"
#include "arch.h"
#include "types.h"
#include "sys.h"
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#define F_OK 0
#define X_OK 1
#define W_OK 2
#define R_OK 4
/*
* int access(const char *path, int amode);
* int faccessat(int fd, const char *path, int amode, int flag);
*/
static __attribute__((unused))
int _sys_faccessat(int fd, const char *path, int amode, int flag)
{
return __nolibc_syscall4(__NR_faccessat, fd, path, amode, flag);
}
static __attribute__((unused))
int faccessat(int fd, const char *path, int amode, int flag)
{
return __sysret(_sys_faccessat(fd, path, amode, flag));
}
static __attribute__((unused))
int access(const char *path, int amode)
{
return faccessat(AT_FDCWD, path, amode, 0);
}
#if !defined(_sys_ftruncate64) && defined(__NR_ftruncate64)
static __attribute__((unused))
int _sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
{
return __nolibc_syscall3(__NR_ftruncate64, fd, length0, length1);
}
#define _sys_ftruncate64 _sys_ftruncate64
#endif
static __attribute__((unused))
int _sys_ftruncate(int fd, off_t length)
{
#if defined(_sys_ftruncate64)
return _sys_ftruncate64(fd, __NOLIBC_LLARGPART(length, 0), __NOLIBC_LLARGPART(length, 1));
#else
return __nolibc_syscall2(__NR_ftruncate, fd, length);
#endif
}
static __attribute__((unused))
int ftruncate(int fd, off_t length)
{
return __sysret(_sys_ftruncate(fd, length));
}
static __attribute__((unused))
int msleep(unsigned int msecs)
{
struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 };
if (_sys_select(0, NULL, NULL, NULL, &my_timeval) < 0)
return (my_timeval.tv_sec * 1000) +
(my_timeval.tv_usec / 1000) +
!!(my_timeval.tv_usec % 1000);
else
return 0;
}
static __attribute__((unused))
unsigned int sleep(unsigned int seconds)
{
struct timeval my_timeval = { seconds, 0 };
if (_sys_select(0, NULL, NULL, NULL, &my_timeval) < 0)
return my_timeval.tv_sec + !!my_timeval.tv_usec;
else
return 0;
}
static __attribute__((unused))
int usleep(unsigned int usecs)
{
struct timeval my_timeval = { usecs / 1000000, usecs % 1000000 };
return _sys_select(0, NULL, NULL, NULL, &my_timeval);
}
static __attribute__((unused))
int tcsetpgrp(int fd, pid_t pid)
{
return ioctl(fd, TIOCSPGRP, &pid);
}
#endif /* _NOLIBC_UNISTD_H */