mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Initial crt0 implementation
Builds but cannot link, missing a lot of symbols
This commit is contained in:
parent
7e9abe6e90
commit
6d79de7d71
@ -59,11 +59,14 @@ endif
|
||||
|
||||
ifdef B_INIT
|
||||
|
||||
# -lc -lm is hardcoded in this variable, disable it
|
||||
TARGET_LDLIBS :=
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskinit
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
crt0 \
|
||||
libbase \
|
||||
libcompat \
|
||||
libpolicy \
|
||||
libxz \
|
||||
libinit-rs
|
||||
@ -87,7 +90,6 @@ include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskboot
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libcompat \
|
||||
liblzma \
|
||||
liblz4 \
|
||||
libbz2 \
|
||||
@ -163,6 +165,7 @@ include $(BUILD_STATIC_LIBRARY)
|
||||
include src/Android-rs.mk
|
||||
include src/base/Android.mk
|
||||
include src/external/Android.mk
|
||||
include src/crt0/Android.mk
|
||||
|
||||
ifdef B_BB
|
||||
|
||||
|
@ -4,10 +4,20 @@ APP_CFLAGS := -Wall -Oz -fomit-frame-pointer -flto
|
||||
APP_LDFLAGS := -flto
|
||||
APP_CPPFLAGS := -std=c++20
|
||||
APP_STL := none
|
||||
APP_PLATFORM := android-23
|
||||
APP_PLATFORM := android-26
|
||||
APP_THIN_ARCHIVE := true
|
||||
APP_STRIP_MODE := none
|
||||
|
||||
# magiskinit uses crt0
|
||||
ifdef B_INIT
|
||||
|
||||
# Disable all security and debugging features
|
||||
APP_CFLAGS += -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -U_FORTIFY_SOURCE
|
||||
# Override output folder to make sure all dependencies are rebuilt with new CFLAGS
|
||||
NDK_APP_OUT := ./obj/init
|
||||
|
||||
endif
|
||||
|
||||
# Busybox should use stock libc.a
|
||||
ifdef B_BB
|
||||
APP_PLATFORM := android-26
|
||||
|
@ -22,18 +22,3 @@ LOCAL_SRC_FILES := \
|
||||
base-rs.cpp \
|
||||
../external/cxx-rs/src/cxx.cc
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# All static executables should link with libcompat
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libcompat
|
||||
LOCAL_SRC_FILES := compat/compat.cpp
|
||||
# Fix static variables' ctor/dtor when using LTO
|
||||
# See: https://github.com/android/ndk/issues/1461
|
||||
LOCAL_EXPORT_LDFLAGS := -static -T src/lto_fix.lds -Wl,--wrap=rename -Wl,--wrap=renameat
|
||||
# For some reason, using the hacky libc.a with x86 will trigger stack protection violation
|
||||
# when mixing Rust and C++ code. Disable stack protector to bypass this issue.
|
||||
ifeq ($(TARGET_ARCH), x86)
|
||||
LOCAL_EXPORT_CFLAGS := -fno-stack-protector
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
@ -8,6 +8,10 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifndef __call_bypassing_fortify
|
||||
#define __call_bypassing_fortify(fn) (&fn)
|
||||
#endif
|
||||
|
||||
#undef vsnprintf
|
||||
static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
|
||||
constexpr int sz = 4096;
|
||||
|
14
native/src/crt0/Android.mk
Normal file
14
native/src/crt0/Android.mk
Normal file
@ -0,0 +1,14 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := crt0
|
||||
|
||||
# Manually link the compiler runtime library
|
||||
LOCAL_compiler_rt := $(shell $(TARGET_CC) -target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) --print-libgcc-file-name)
|
||||
|
||||
LOCAL_EXPORT_LDFLAGS := -static -nostartfiles -nodefaultlibs $(LOCAL_compiler_rt)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
nolibc.c
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
10
native/src/crt0/nolibc.c
Normal file
10
native/src/crt0/nolibc.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include "nolibc/crt.h"
|
||||
#include "nolibc/arch.h"
|
||||
|
||||
// errno
|
||||
|
||||
static int g_errno = 0;
|
||||
|
||||
int *__errno(void) {
|
||||
return &g_errno;
|
||||
}
|
159
native/src/crt0/nolibc/arch-aarch64.h
Normal file
159
native/src/crt0/nolibc/arch-aarch64.h
Normal file
@ -0,0 +1,159 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* AARCH64 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_AARCH64_H
|
||||
#define _NOLIBC_ARCH_AARCH64_H
|
||||
|
||||
/* Syscalls for AARCH64 :
|
||||
* - 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.
|
||||
*
|
||||
* On aarch64, select() is not implemented so we have to use pselect6().
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_PSELECT6
|
||||
|
||||
#define my_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 my_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 my_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 my_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 my_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 my_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 my_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; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((noreturn)) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */
|
||||
"and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */
|
||||
"bl _start_c\n" /* transfer to c runtime */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_AARCH64_H */
|
200
native/src/crt0/nolibc/arch-arm.h
Normal file
200
native/src/crt0/nolibc/arch-arm.h
Normal file
@ -0,0 +1,200 @@
|
||||
/* 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
|
||||
|
||||
/* 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 my_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 my_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 my_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 my_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 my_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 my_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 my_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; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((noreturn)) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"mov r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */
|
||||
"and ip, r0, #-8\n" /* sp must be 8-byte aligned in the callee */
|
||||
"mov sp, ip\n"
|
||||
"bl _start_c\n" /* transfer to c runtime */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_ARM_H */
|
179
native/src/crt0/nolibc/arch-i386.h
Normal file
179
native/src/crt0/nolibc/arch-i386.h
Normal file
@ -0,0 +1,179 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* i386 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_I386_H
|
||||
#define _NOLIBC_ARCH_I386_H
|
||||
|
||||
/* 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 my_syscall0(num) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_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 my_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 my_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 my_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 my_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 my_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; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* 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__((noreturn)) _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 */
|
||||
"and $-16, %esp\n" /* last pushed argument must be 16-byte aligned */
|
||||
"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 */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_I386_H */
|
177
native/src/crt0/nolibc/arch-x86_64.h
Normal file
177
native/src/crt0/nolibc/arch-x86_64.h
Normal file
@ -0,0 +1,177 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* x86_64 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_X86_64_H
|
||||
#define _NOLIBC_ARCH_X86_64_H
|
||||
|
||||
/* 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 my_syscall0(num) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r10") = (long)(arg4); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r10") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r8") = (long)(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 my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r10") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r8") = (long)(arg5); \
|
||||
register long _arg6 __asm__ ("r9") = (long)(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; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* 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__((noreturn)) _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 */
|
||||
"and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */
|
||||
"call _start_c\n" /* transfer to c runtime */
|
||||
"hlt\n" /* ensure it does not return */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_X86_64_H */
|
28
native/src/crt0/nolibc/arch.h
Normal file
28
native/src/crt0/nolibc/arch.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
/* Below comes the architecture-specific code. For each architecture, we have
|
||||
* the syscall declarations and the _start code definition. This is the only
|
||||
* global part. On all architectures the kernel puts everything in the stack
|
||||
* before jumping to _start just above us, without any return address (_start
|
||||
* is not a function but an entry point). So at the stack pointer we find argc.
|
||||
* Then argv[] begins, and ends at the first NULL. Then we have envp which
|
||||
* starts and ends with a NULL as well. So envp=argv+argc+1.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_H
|
||||
#define _NOLIBC_ARCH_H
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#include "arch-x86_64.h"
|
||||
#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
|
||||
#include "arch-i386.h"
|
||||
#elif defined(__ARM_EABI__)
|
||||
#include "arch-arm.h"
|
||||
#elif defined(__aarch64__)
|
||||
#include "arch-aarch64.h"
|
||||
#endif
|
||||
|
||||
#endif /* _NOLIBC_ARCH_H */
|
78
native/src/crt0/nolibc/crt.h
Normal file
78
native/src/crt0/nolibc/crt.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* 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
|
||||
|
||||
char **environ;
|
||||
const unsigned long *_auxv;
|
||||
void _exit(int);
|
||||
|
||||
typedef void init_func_t(int, char*[], char*[]);
|
||||
typedef void fini_func_t(void);
|
||||
|
||||
extern init_func_t *__preinit_array_start[];
|
||||
extern init_func_t *__preinit_array_end[];
|
||||
extern init_func_t *__init_array_start[];
|
||||
extern init_func_t *__init_array_end[];
|
||||
extern fini_func_t *__fini_array_start[];
|
||||
extern fini_func_t *__fini_array_end[];
|
||||
|
||||
static void call_array(init_func_t **start, init_func_t **end, int argc, char *argv[], char *envp[]) {
|
||||
unsigned long count = end - start;
|
||||
while (count-- > 0) {
|
||||
init_func_t* function = *start++;
|
||||
(*function)(argc, argv, envp);
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((used)) _start_c(long *sp)
|
||||
{
|
||||
long argc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
const unsigned long *auxv;
|
||||
/* silence potential warning: conflicting types for 'main' */
|
||||
int _nolibc_main(int, char **, char **) __asm__ ("main");
|
||||
|
||||
/*
|
||||
* 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++;)
|
||||
;
|
||||
_auxv = auxv;
|
||||
|
||||
/* call preinit and init */
|
||||
call_array(__preinit_array_start, __preinit_array_end, argc, argv, envp);
|
||||
call_array(__init_array_start, __init_array_end, argc, argv, envp);
|
||||
|
||||
/* go to application */
|
||||
_exit(_nolibc_main(argc, argv, envp));
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
Loading…
x
Reference in New Issue
Block a user