├── lib ├── empty │ ├── empty.c │ └── lib.mk └── lku │ ├── crt0_arm.S │ ├── crt0_riscv.S │ ├── lib.mk │ └── liblk.c ├── apps └── hello │ ├── testfile │ ├── app.mk │ └── hello.c ├── makefile.lk ├── sys ├── project │ ├── qemu-arm-usertest.mk │ └── qemu-riscv-usertest.mk └── lib │ └── lkuser │ ├── rules.mk │ ├── include │ ├── lib │ │ └── lkuser.h │ └── sys │ │ ├── lkuser_syscalls.h │ │ └── _syscalls.h │ ├── lkuser_priv.h │ ├── thread.h │ ├── thread.cpp │ ├── proc.h │ ├── proc.cpp │ ├── user.cpp │ └── syscalls.cpp ├── .gitignore ├── .gitmodules ├── lk_inc.mk ├── arch ├── arm │ ├── arch.mk │ ├── linker.ld │ └── armelf.xe └── riscv │ ├── arch.mk │ ├── linker.ld │ ├── elf64lriscv.xce │ └── elf64lriscv.xe ├── .github └── workflows │ ├── notify-irc.yml │ └── github-ci.yml ├── make ├── lib.mk └── app.mk └── makefile /lib/empty/empty.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/hello/testfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /makefile.lk: -------------------------------------------------------------------------------- 1 | lk/makefile -------------------------------------------------------------------------------- /sys/project/qemu-arm-usertest.mk: -------------------------------------------------------------------------------- 1 | MODULES += \ 2 | lib/lkuser 3 | 4 | include project/qemu-virt-arm32-test.mk 5 | 6 | -------------------------------------------------------------------------------- /sys/project/qemu-riscv-usertest.mk: -------------------------------------------------------------------------------- 1 | MODULES += \ 2 | lib/lkuser 3 | 4 | include project/qemu-virt-riscv64-supervisor-test.mk 5 | 6 | -------------------------------------------------------------------------------- /lib/lku/crt0_arm.S: -------------------------------------------------------------------------------- 1 | .section .text.startup 2 | .arm 3 | .globl _start 4 | _start: 5 | // nothing to do so just branch into C code 6 | b _start_c 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | install-* 3 | *.swp 4 | *~ 5 | tags 6 | TAGS 7 | local.mk 8 | *.orig 9 | cscope.* 10 | doit 11 | t 12 | tagit 13 | compile_commands.json 14 | .clangd 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lk"] 2 | path = lk 3 | url = https://github.com/littlekernel/lk.git 4 | [submodule "newlib"] 5 | path = newlib 6 | url = https://github.com/littlekernel/newlib.git 7 | -------------------------------------------------------------------------------- /lib/lku/crt0_riscv.S: -------------------------------------------------------------------------------- 1 | .section .text.startup 2 | 3 | .globl _start 4 | _start: 5 | .option push 6 | .option norelax 7 | la gp, __global_pointer$ 8 | .option pop 9 | 10 | j _start_c 11 | 12 | -------------------------------------------------------------------------------- /lib/empty/lib.mk: -------------------------------------------------------------------------------- 1 | LOCAL_DIR := $(GET_LOCAL_DIR) 2 | #$(warning LOCAL_DIR $(LOCAL_DIR)) 3 | 4 | LIB_NAME := empty 5 | LIB_BUILDDIR := $(call TOBUILDDIR, $(LOCAL_DIR)) 6 | LIB := $(LIB_BUILDDIR)/$(LIB_NAME).a 7 | 8 | #$(warning LIB_NAME = $(LIB_NAME)) 9 | #$(warning LIB_BUILDDIR = $(LIB_BUILDDIR)) 10 | #$(warning LIB = $(LIB)) 11 | 12 | LIB_CFLAGS := 13 | LIB_SRCS := $(LOCAL_DIR)/empty.c 14 | 15 | include make/lib.mk 16 | -------------------------------------------------------------------------------- /lib/lku/lib.mk: -------------------------------------------------------------------------------- 1 | LOCAL_DIR := $(GET_LOCAL_DIR) 2 | #$(warning LOCAL_DIR $(LOCAL_DIR)) 3 | 4 | LIB_NAME := lku 5 | LIB_BUILDDIR := $(call TOBUILDDIR, $(LOCAL_DIR)) 6 | LIB := $(LIB_BUILDDIR)/$(LIB_NAME).a 7 | 8 | #$(warning LIB_NAME = $(LIB_NAME)) 9 | #$(warning LIB_BUILDDIR = $(LIB_BUILDDIR)) 10 | #$(warning LIB = $(LIB)) 11 | 12 | LIB_CFLAGS := 13 | LIB_SRCS := $(LOCAL_DIR)/liblk.c 14 | LIB_SRCS += $(LOCAL_DIR)/crt0_$(ARCH).S 15 | 16 | include make/lib.mk 17 | -------------------------------------------------------------------------------- /sys/lib/lkuser/rules.mk: -------------------------------------------------------------------------------- 1 | LOCAL_DIR := $(GET_LOCAL_DIR) 2 | 3 | MODULE := $(LOCAL_DIR) 4 | 5 | GLOBAL_INCLUDES += $(LOCAL_DIR)/include 6 | 7 | MODULE_SRCS += $(LOCAL_DIR)/user.cpp 8 | MODULE_SRCS += $(LOCAL_DIR)/proc.cpp 9 | MODULE_SRCS += $(LOCAL_DIR)/syscalls.cpp 10 | MODULE_SRCS += $(LOCAL_DIR)/thread.cpp 11 | 12 | MODULE_DEPS += lib/bio 13 | MODULE_DEPS += lib/elf 14 | MODULE_DEPS += lib/fs 15 | 16 | MODULE_COMPILEFLAGS += -Wno-invalid-offsetof 17 | 18 | include make/module.mk 19 | -------------------------------------------------------------------------------- /apps/hello/app.mk: -------------------------------------------------------------------------------- 1 | LOCAL_DIR := $(GET_LOCAL_DIR) 2 | #$(warning LOCAL_DIR $(LOCAL_DIR)) 3 | 4 | APP_NAME := hello 5 | APP_BUILDDIR := $(call TOBUILDDIR, $(LOCAL_DIR)) 6 | APP := $(APP_BUILDDIR)/$(APP_NAME) 7 | 8 | APP_LIBS := $(call TOBUILDDIR, lib/empty/empty.a) 9 | APP_LIBS += $(call TOBUILDDIR, lib/lku/lku.a) 10 | 11 | #$(warning APP_NAME = $(APP_NAME)) 12 | #$(warning APP_BUILDDIR = $(APP_BUILDDIR)) 13 | #$(warning APP = $(APP)) 14 | 15 | APP_CFLAGS := 16 | APP_SRCS := $(LOCAL_DIR)/hello.c 17 | 18 | FS_LIST += $(LOCAL_DIR)/testfile:data/testfile 19 | 20 | $(LOCAL_DIR)/testfile: 21 | 22 | include make/app.mk 23 | -------------------------------------------------------------------------------- /lk_inc.mk: -------------------------------------------------------------------------------- 1 | # copy this and makefile to your external root directory and customize 2 | # according to how you want to use a split repository 3 | 4 | # the top level directory that all paths are relative to 5 | LKMAKEROOT := . 6 | 7 | # paths relative to LKMAKEROOT where additional modules should be searched 8 | LKINC := sys 9 | 10 | # the path relative to LKMAKEROOT where the main lk repository lives 11 | LKROOT := lk 12 | 13 | # set the directory relative to LKMAKEROOT where output will go 14 | BUILDROOT ?= . 15 | 16 | # set the default project if no args are passed 17 | DEFAULT_PROJECT ?= qemu-arm-usertest 18 | 19 | #TOOLCHAIN_PREFIX := 20 | -------------------------------------------------------------------------------- /arch/arm/arch.mk: -------------------------------------------------------------------------------- 1 | # arch stuff 2 | TOOLCHAIN_PREFIX ?= arm-eabi- 3 | #ARCH_LINKER_SCRIPT := arch/arm/linker.ld 4 | #ARCH_LINKER_SCRIPT := arch/arm/armelf.xe 5 | 6 | ARCH_COMPILEFLAGS := -mthumb -march=armv7-a -mfpu=neon -mfloat-abi=hard -DARCH_ARM=1 7 | ARCH_CFLAGS := 8 | ARCH_CPPFLAGS := 9 | ARCH_ASMFLAGS := 10 | ARCH_LDFLAGS := -z max-page-size=4096 -Ttext-segment=0x01000000 11 | 12 | # newlib path stuff 13 | NEWLIB_INC_DIR := $(NEWLIB_INSTALL_DIR)/arm-eabi/include 14 | NEWLIB_ARCH_TARGET := arm-eabi 15 | 16 | # libc revision we want 17 | LIBC := $(NEWLIB_INSTALL_DIR)/arm-eabi/lib/thumb/v7-a+simd/hard/libc.a 18 | LIBM := $(NEWLIB_INSTALL_DIR)/arm-eabi/lib/thumb/v7-a+simd/hard/libm.a 19 | #CRT0 := $(NEWLIB_INSTALL_DIR)/arm-eabi/lib/thumb/v7-a+simd/hard/crt0.o 20 | 21 | 22 | -------------------------------------------------------------------------------- /arch/riscv/arch.mk: -------------------------------------------------------------------------------- 1 | # arch stuff 2 | TOOLCHAIN_PREFIX ?= riscv64-elf- 3 | #ARCH_LINKER_SCRIPT := arch/riscv/linker.ld 4 | #ARCH_LINKER_SCRIPT := arch/riscv/elf64lriscv.xe 5 | 6 | ARCH_COMPILEFLAGS := -DARCH_RISCV=1 7 | ARCH_CFLAGS := -march=rv64imafdc -mabi=lp64d -mcmodel=medany 8 | ARCH_CPPFLAGS := 9 | ARCH_ASMFLAGS := 10 | ARCH_LDFLAGS := -Ttext-segment=0x01000000 11 | 12 | # newlib path stuff 13 | NEWLIB_INC_DIR := $(NEWLIB_INSTALL_DIR)/riscv64-elf/include 14 | NEWLIB_ARCH_TARGET := riscv64-elf 15 | 16 | # libc revision we want 17 | MULTILIB := rv64imafdc/lp64d/medany 18 | LIBC := $(NEWLIB_INSTALL_DIR)/riscv64-elf/lib/$(MULTILIB)/libc.a 19 | LIBM := $(NEWLIB_INSTALL_DIR)/riscv64-elf/lib/$(MULTILIB)/libm.a 20 | #CRT0 := $(NEWLIB_INSTALL_DIR)/riscv64-elf/lib/$(MULTILIB)/crt0.o 21 | 22 | 23 | -------------------------------------------------------------------------------- /sys/lib/lkuser/include/lib/lkuser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #pragma once 24 | 25 | -------------------------------------------------------------------------------- /.github/workflows/notify-irc.yml: -------------------------------------------------------------------------------- 1 | name: "Push Notification" 2 | on: [push, pull_request, create] 3 | 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: irc push 9 | uses: rectalogic/notify-irc@v1 10 | if: github.event_name == 'push' 11 | with: 12 | server: "irc.libera.chat" 13 | channel: "#lk" 14 | nickname: lk-github 15 | notice: false 16 | message: | 17 | ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }} 18 | ${{ join(github.event.commits.*.message) }} 19 | - name: irc pull request 20 | uses: rectalogic/notify-irc@v1 21 | if: github.event_name == 'pull_request' 22 | with: 23 | server: "irc.libera.chat" 24 | channel: "#lk" 25 | nickname: lk-github 26 | notice: false 27 | message: | 28 | ${{ github.actor }} opened PR ${{ github.event.html_url }} 29 | - name: irc tag created 30 | uses: rectalogic/notify-irc@v1 31 | if: github.event_name == 'create' && github.event.ref_type == 'tag' 32 | with: 33 | server: "irc.libera.chat" 34 | channel: "#lk" 35 | nickname: lk-github 36 | notice: false 37 | message: | 38 | ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }} 39 | -------------------------------------------------------------------------------- /sys/lib/lkuser/include/sys/lkuser_syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #pragma once 24 | 25 | /* for direct function pointer based syscalls, simply define them as a 26 | * structure with a list of function pointers. 27 | */ 28 | #define LK_SYSCALL_DEF(n, ret, name, args...) \ 29 | ret (*name)(args); 30 | 31 | struct lkuser_syscall_table { 32 | #include "_syscalls.h" 33 | }; 34 | 35 | #undef LK_SYSCALL_DEF 36 | 37 | -------------------------------------------------------------------------------- /apps/hello/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | extern void foo(void); 10 | 11 | volatile int bss_var; 12 | volatile int data_var = 9; 13 | 14 | // test that floating point is working 15 | __attribute__((noinline)) 16 | double fadd(double a, double b) { 17 | return a + b; 18 | } 19 | 20 | void call_atexit(void) { 21 | printf("at exit here!\n"); 22 | } 23 | 24 | int main(void) 25 | { 26 | //foo(); 27 | printf("Hello, World!\n"); 28 | printf("printing something from bss %d (should be 0)\n", bss_var); 29 | printf("printing something from data %d (should be 9)\n", data_var); 30 | 31 | printf("sleeping..."); 32 | fflush(stdout); 33 | sleep(1); 34 | printf("done\n"); 35 | 36 | char *buf; 37 | 38 | buf = malloc(4096); 39 | 40 | printf("enter something\n"); 41 | fgets(buf, 4096, stdin); 42 | printf("line '%s'\n", buf); 43 | 44 | free(buf); 45 | 46 | printf("printing some floating point %f (should be .1234)\n", 0.1234); 47 | printf("more float printing %f (should be .2464)\n", fadd(0.1234, 0.123)); 48 | 49 | buf = malloc(4096); 50 | char *buf2 = malloc(4096); 51 | printf("malloced two buffers %p %p\n", buf, buf2); 52 | 53 | printf("copying some data (%p to %p)\n", buf, buf2); 54 | memcpy(buf2, buf, 4096); 55 | 56 | free(buf); 57 | free(buf2); 58 | 59 | printf("buffers are freed\n"); 60 | 61 | printf("registering atexit call\n"); 62 | atexit(call_atexit); 63 | 64 | printf("exiting main\n"); 65 | return 99; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /sys/lib/lkuser/lkuser_priv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "proc.h" 36 | #include "thread.h" 37 | 38 | /* defined in syscalls.c */ 39 | extern const lkuser_syscall_table lkuser_syscalls; 40 | 41 | /* one of the syscalls */ 42 | void sys_exit(int retcode) __NO_RETURN; 43 | -------------------------------------------------------------------------------- /sys/lib/lkuser/include/sys/_syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /* included from other files to define a syscall api */ 25 | LK_SYSCALL_DEF(0, void, exit, int retcode) 26 | LK_SYSCALL_DEF(1, int, open, const char *name, int flags, int mode) 27 | LK_SYSCALL_DEF(2, int, close, int file) 28 | LK_SYSCALL_DEF(3, int, write, int file, const char *ptr, int len) 29 | LK_SYSCALL_DEF(4, int, read, int file, char *ptr, int len) 30 | LK_SYSCALL_DEF(5, int, lseek, int file, long pos, int whence) 31 | LK_SYSCALL_DEF(6, void *, sbrk, long incr) 32 | LK_SYSCALL_DEF(7, int, sleep_sec, unsigned long useconds) 33 | LK_SYSCALL_DEF(8, int, sleep_usec, unsigned long useconds) 34 | 35 | -------------------------------------------------------------------------------- /make/lib.mk: -------------------------------------------------------------------------------- 1 | # shared make file for different applications 2 | 3 | _LIB_CSRCS := $(filter %.c,$(LIB_SRCS)) 4 | _LIB_CPPSRCS := $(filter %.cpp,$(LIB_SRCS)) 5 | _LIB_ASMSRCS := $(filter %.S,$(LIB_SRCS)) 6 | 7 | #$(warning _LIB_CSRCS = $(_LIB_CSRCS)) 8 | #$(warning _LIB_CPPSRCS = $(_LIB_CPPSRCS)) 9 | #$(warning _LIB_ASMSRCS = $(_LIB_ASMSRCS)) 10 | 11 | _LIB_COBJS := $(call TOBUILDDIR,$(patsubst %.c,%.o,$(_LIB_CSRCS))) 12 | _LIB_CPPOBJS := $(call TOBUILDDIR,$(patsubst %.cpp,%.o,$(_LIB_CPPSRCS))) 13 | _LIB_ASMOBJS := $(call TOBUILDDIR,$(patsubst %.S,%.o,$(_LIB_ASMSRCS))) 14 | 15 | #$(warning _LIB_COBJS = $(_LIB_COBJS)) 16 | #$(warning _LIB_CPPOBJS = $(_LIB_CPPOBJS)) 17 | #$(warning _LIB_ASMOBJS = $(_LIB_ASMOBJS)) 18 | 19 | _LIB_OBJS := $(_LIB_COBJS) $(_LIB_CPPOBJS) $(_LIB_ASMOBJS) $(_LIB_ARM_COBJS) $(_LIB_ARM_CPPOBJS) $(_LIB_ARM_ASMOBJS) 20 | 21 | #$(warning _LIB_OBJS = $(_LIB_OBJS)) 22 | 23 | # make sure libc is built (and headers are generated) before compiling anything 24 | $(_LIB_OBJS): $(LIBC) 25 | 26 | $(_LIB_COBJS): $(BUILDDIR)/%.o: %.c 27 | @$(MKDIR) 28 | @echo compiling $< 29 | $(NOECHO)$(ARCH_CC) $(GLOBAL_OPTFLAGS) $(LIB_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(LIB_COMPILEFLAGS) $(GLOBAL_CFLAGS) $(ARCH_CFLAGS) $(LIB_CFLAGS) $(THUMBCFLAGS) $(GLOBAL_INCLUDES) $(LIB_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ 30 | 31 | $(_LIB_ASMOBJS): $(BUILDDIR)/%.o: %.S 32 | @$(MKDIR) 33 | @echo compiling $< 34 | $(NOECHO)$(ARCH_CC) $(GLOBAL_OPTFLAGS) $(LIB_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(LIB_COMPILEFLAGS) $(GLOBAL_ASMFLAGS) $(ARCH_ASMFLAGS) $(LIB_ASMFLAGS) $(GLOBAL_INCLUDES) $(LIB_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ 35 | 36 | $(LIB): _LIB_OBJS := $(_LIB_OBJS) 37 | $(LIB): $(_LIB_OBJS) 38 | @$(MKDIR) 39 | @echo linking $@ 40 | $(NOECHO)$(ARCH_AR) -rcs $@ $(_LIB_OBJS) 41 | 42 | # add ourself to the build list 43 | LIBS += $(LIB) 44 | 45 | # add ourself to the list of files to add to the target fs 46 | FS_LIST += $(LIB):lib/$(notdir $(LIB)) 47 | 48 | # empty out various local variables 49 | _LIB_CSRCS := 50 | _LIB_CPPSRCS := 51 | _LIB_ASMSRCS := 52 | _LIB_COBJS := 53 | _LIB_CPPOBJS := 54 | _LIB_ASMOBJS := 55 | _LIB_OBJS := 56 | LIB_SRCS := 57 | LIB_OPTFLAGS := 58 | LIB_CFLAGS := 59 | LIB_COMPILEFLAGS := 60 | LIB_INCLUDES := 61 | LIB := 62 | 63 | -------------------------------------------------------------------------------- /sys/lib/lkuser/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2022 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace lkuser { 30 | 31 | class proc; 32 | 33 | class thread { 34 | private: 35 | explicit thread(proc *p); 36 | 37 | DISALLOW_COPY_ASSIGN_AND_MOVE(thread); 38 | public: 39 | ~thread(); 40 | 41 | // factory to build threads 42 | static thread *create(proc *p, vaddr_t entry); 43 | 44 | // accessors 45 | proc *get_proc() const { return proc_; } 46 | vaddr_t get_entry() const { return entry_; } 47 | void *get_stack() const { return user_stack_; } 48 | 49 | // operations on our thread 50 | void resume() { thread_resume(&lkthread); } 51 | void join() { thread_join(&lkthread, NULL, INFINITE_TIME); } 52 | 53 | // public for proc to maintain a list 54 | list_node node = LIST_INITIAL_CLEARED_VALUE; 55 | 56 | private: 57 | proc *proc_ = nullptr; 58 | vaddr_t entry_ {}; 59 | 60 | void *user_stack_ = nullptr; 61 | 62 | thread_t lkthread {}; 63 | }; 64 | 65 | static inline thread *get_lkuser_thread() { 66 | thread *t = (thread *)tls_get(TLS_ENTRY_LKUSER); 67 | DEBUG_ASSERT(t); 68 | return t; 69 | } 70 | 71 | } // namespace lkuser 72 | -------------------------------------------------------------------------------- /arch/riscv/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-littleriscv") 2 | /* 3 | * LK linker script for single segment binaries. 4 | */ 5 | PHDRS 6 | { 7 | code PT_LOAD FLAGS(5); /* PF_R|PF_X */ 8 | rodata PT_LOAD FLAGS(4); /* PF_R */ 9 | data PT_LOAD FLAGS(6); /* PF_R|PF_W */ 10 | } 11 | 12 | ENTRY(_start) 13 | SECTIONS 14 | { 15 | . = 0x1000000; /* 16MB offset, base of user address space */ 16 | 17 | /* text/read-only data */ 18 | .text : { 19 | *(.text .text*) 20 | *(.gnu.linkonce.t.*) 21 | } :code 22 | 23 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 24 | 25 | .rodata : { 26 | __rodata_start = .; 27 | *(.rodata .rodata.* .gnu.linkonce.r.*) 28 | } :rodata 29 | 30 | /* trick to force any extra sections to be emitted here */ 31 | . = .; 32 | 33 | __rodata_end = .; 34 | __rom_end = . ; 35 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 36 | __data_start_rom = .; 37 | 38 | .data : { 39 | __data_start = .; 40 | *(.data .data.* .gnu.linkonce.d.*) 41 | __ctor_list = .; 42 | KEEP(*(.ctors .init_array)) 43 | __ctor_end = .; 44 | __dtor_list = .; 45 | KEEP(*(.dtors .fini_array)) 46 | __dtor_end = .; 47 | *(.got*) 48 | *(.dynamic) 49 | } :data 50 | 51 | /* Try to put sdata and sbss near each other by putting sdata at the end of the data segment 52 | * and sbss at the start of the bss segment. This maximizes reach of things referenced off of 53 | * the global pointer. */ 54 | .sdata : { 55 | __global_pointer$ = . + (4K / 2); 56 | *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) 57 | *(.sdata .sdata.* .gnu.linkonce.s.*) 58 | } 59 | 60 | . = ALIGN(64 / 8); 61 | __data_end = .; 62 | __bss_start = .; 63 | 64 | .sbss : { 65 | *(.dynsbss) 66 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 67 | *(.scommon) 68 | } 69 | 70 | /* uninitialized data (in same segment as writable data) */ 71 | .bss : { 72 | /* regular bss */ 73 | *(.bss .bss.*) 74 | *(.gnu.linkonce.b.*) 75 | } 76 | 77 | . = ALIGN(64 / 8); 78 | __bss_end = .; 79 | 80 | /* Align the end to ensure anything after the kernel ends up on its own pages */ 81 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 82 | _end = .; 83 | 84 | .comment 0 : { *(.comment) } 85 | 86 | /* Strip unnecessary stuff */ 87 | /DISCARD/ : { *(.note .eh_frame) } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /make/app.mk: -------------------------------------------------------------------------------- 1 | # shared make file for different applications 2 | 3 | #$(warning APP_NAME = $(APP_NAME)) 4 | #$(warning APP_BUILDDIR = $(APP_BUILDDIR)) 5 | #$(warning APP = $(APP)) 6 | #$(warning APP_SRCS = $(APP_SRCS)) 7 | #$(warning APP_CFLAGS = $(APP_CFLAGS)) 8 | #$(warning APP_LIBS = $(APP_LIBS)) 9 | 10 | _APP_CSRCS := $(filter %.c,$(APP_SRCS)) 11 | _APP_CPPSRCS := $(filter %.cpp,$(APP_SRCS)) 12 | _APP_ASMSRCS := $(filter %.S,$(APP_SRCS)) 13 | 14 | #$(warning _APP_CSRCS = $(_APP_CSRCS)) 15 | #$(warning _APP_CPPSRCS = $(_APP_CPPSRCS)) 16 | #$(warning _APP_ASMSRCS = $(_APP_ASMSRCS)) 17 | 18 | _APP_COBJS := $(call TOBUILDDIR,$(patsubst %.c,%.o,$(_APP_CSRCS))) 19 | _APP_CPPOBJS := $(call TOBUILDDIR,$(patsubst %.cpp,%.o,$(_APP_CPPSRCS))) 20 | _APP_ASMOBJS := $(call TOBUILDDIR,$(patsubst %.S,%.o,$(_APP_ASMSRCS))) 21 | 22 | #$(warning _APP_COBJS = $(_APP_COBJS)) 23 | #$(warning _APP_CPPOBJS = $(_APP_CPPOBJS)) 24 | #$(warning _APP_ASMOBJS = $(_APP_ASMOBJS)) 25 | 26 | _APP_OBJS := $(_APP_COBJS) $(_APP_CPPOBJS) $(_APP_ASMOBJS) $(_APP_ARM_COBJS) $(_APP_ARM_CPPOBJS) $(_APP_ARM_ASMOBJS) 27 | 28 | #$(warning _APP_OBJS = $(_APP_OBJS)) 29 | 30 | # make sure libc is built (and headers are generated) before compiling anything 31 | $(_APP_OBJS): $(LIBC) 32 | 33 | $(_APP_COBJS): $(BUILDDIR)/%.o: %.c 34 | @$(MKDIR) 35 | @echo compiling $< 36 | $(NOECHO)$(ARCH_CC) $(GLOBAL_OPTFLAGS) $(APP_OPTFLAGS) $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(APP_COMPILEFLAGS) $(GLOBAL_CFLAGS) $(ARCH_CFLAGS) $(APP_CFLAGS) $(THUMBCFLAGS) $(GLOBAL_INCLUDES) $(APP_INCLUDES) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ 37 | 38 | $(APP): _APP_OBJS := $(_APP_OBJS) 39 | $(APP): APP_LIBS := $(APP_LIBS) 40 | $(APP): $(_APP_OBJS) $(ARCH_LINKER_SCRIPT) $(APP_LIBS) $(GLOBAL_LIBS) 41 | @$(MKDIR) 42 | @echo linking $@ 43 | $(NOECHO)$(ARCH_LD) $(GLOBAL_LDFLAGS) $(ARCH_LDFLAGS) $(CRT0) $(_APP_OBJS) $(EXTRA_OBJS) $(APP_LIBS) $(GLOBAL_LIBS) $(LIBGCC) -o $@ 44 | 45 | $(APP).lst: $(APP) 46 | @$(MKDIR) 47 | @echo generating $@ 48 | $(NOECHO)$(ARCH_OBJDUMP) -C -d -r $< > $@ 49 | 50 | $(APP).dump: $(APP) 51 | @$(MKDIR) 52 | @echo generating $@ 53 | $(NOECHO)$(ARCH_OBJDUMP) -C -x $< > $@ 54 | 55 | $(APP).strip: $(APP) 56 | @$(MKDIR) 57 | @echo generating $@ 58 | $(NOECHO)$(ARCH_STRIP) -d $< -o $@ 59 | 60 | # add ourself to the build list 61 | APPS += $(APP) 62 | APPS_EXTRADEPS += $(APP).lst $(APP).dump $(APP).strip 63 | 64 | # add ourself to the list of files to add to the target fs 65 | FS_LIST += $(APP).strip:bin/$(notdir $(APP)) 66 | 67 | # empty out various local variables 68 | _APP_CSRCS := 69 | _APP_CPPSRCS := 70 | _APP_ASMSRCS := 71 | _APP_COBJS := 72 | _APP_CPPOBJS := 73 | _APP_ASMOBJS := 74 | _APP_OBJS := 75 | APP_SRCS := 76 | APP_OPTFLAGS := 77 | APP_CFLAGS := 78 | APP_COMPILEFLAGS := 79 | APP_INCLUDES := 80 | APP_LIBS := 81 | APP := 82 | 83 | -------------------------------------------------------------------------------- /.github/workflows/github-ci.yml: -------------------------------------------------------------------------------- 1 | name: LKUSER CI 2 | 3 | # Brute force build a bunch of variants of LK userspace in parallel jobs. 4 | 5 | on: [ push, pull_request ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | toolchain-ver: [11.2.0] 14 | arch: 15 | - arm 16 | - riscv 17 | 18 | env: 19 | TOOLCHAIN_VER: ${{ matrix.toolchain-ver }} 20 | ARCH: ${{ matrix.arch }} 21 | steps: 22 | - name: banner 23 | shell: bash 24 | run: | 25 | printf "Building with %d processors\n" "$(nproc)" 26 | grep -oP '(?<=model name\t: ).*' /proc/cpuinfo|head -n1 27 | echo PROJECT = $PROJECT 28 | echo TOOLCHAIN_VER = $TOOLCHAIN_VER 29 | echo ARCH = $ARCH 30 | 31 | # check out the source 32 | - name: checkout source 33 | uses: actions/checkout@v3 34 | with: 35 | submodules: true 36 | 37 | # compute the toolchain prefix this project will need 38 | - name: compute toolchain 39 | shell: bash 40 | run: | 41 | TOOLCHAIN_PREFIX=$(make list-toolchain | grep TOOLCHAIN_PREFIX | tail -1 | cut -d ' ' -f 3) 42 | echo "TOOLCHAIN_PREFIX=${TOOLCHAIN_PREFIX}" >> $GITHUB_ENV 43 | echo "TOOLCHAIN=${TOOLCHAIN_PREFIX}${{ matrix.toolchain-ver }}-$(uname)-$(uname -m)" >> $GITHUB_ENV 44 | 45 | # maintain a directory archives/ in the repo 46 | # it will contain tarballs of various toolchains 47 | - name: cache 48 | uses: actions/cache@v2.1.1 49 | id: cache 50 | with: 51 | # A list of files, directories, and wildcard patterns to cache and restore 52 | path: archives 53 | # An explicit key for restoring and saving the cache 54 | key: archives-${{ env.TOOLCHAIN }} 55 | 56 | # download a toolchain from http://newos.org/toolchains 57 | - name: fetch/extract toolchain 58 | shell: bash 59 | run: | 60 | TOOLCHAIN_BASE_URL="http://newos.org/toolchains" 61 | TOOLCHAIN_SUFFIX="tar.xz" 62 | TOOLCHAIN_ADDRESS="$TOOLCHAIN_BASE_URL/$TOOLCHAIN.$TOOLCHAIN_SUFFIX" 63 | mkdir -p archives 64 | cd archives 65 | echo "Downloading toolchain $TOOLCHAIN from $TOOLCHAIN_ADDRESS" 66 | wget -v -N $TOOLCHAIN_ADDRESS || exit 1 67 | cd .. 68 | echo "Unpacking $TOOLCHAIN" 69 | tar xf archives/$TOOLCHAIN.$TOOLCHAIN_SUFFIX || exit 1 70 | echo "$GITHUB_WORKSPACE/$TOOLCHAIN/bin" >> $GITHUB_PATH 71 | 72 | # build it 73 | - name: build 74 | shell: bash 75 | run: | 76 | make -j $(nproc) 77 | 78 | # upload artifacts 79 | #- uses: actions/upload-artifact@v2 80 | # with: 81 | # name: build-dir 82 | # path: build-${{ matrix.project }}/lk.* 83 | 84 | # vim: ts=2 sw=2 expandtab 85 | -------------------------------------------------------------------------------- /arch/arm/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | ENTRY(_start) 5 | SECTIONS 6 | { 7 | . = 0x01000000; /* base of lk user space */ 8 | 9 | /* text/read-only data */ 10 | /* set the load address to physical MEMBASE */ 11 | .text : { 12 | *(.text.startup .text.startup*) 13 | *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) 14 | } 15 | 16 | .interp : { *(.interp) } 17 | .hash : { *(.hash) } 18 | .dynsym : { *(.dynsym) } 19 | .dynstr : { *(.dynstr) } 20 | .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } 21 | .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } 22 | .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } 23 | .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } 24 | .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } 25 | .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } 26 | .rel.got : { *(.rel.got) } 27 | .rela.got : { *(.rela.got) } 28 | .rel.ctors : { *(.rel.ctors) } 29 | .rela.ctors : { *(.rela.ctors) } 30 | .rel.dtors : { *(.rel.dtors) } 31 | .rela.dtors : { *(.rela.dtors) } 32 | .rel.init : { *(.rel.init) } 33 | .rela.init : { *(.rela.init) } 34 | .rel.fini : { *(.rel.fini) } 35 | .rela.fini : { *(.rela.fini) } 36 | .rel.bss : { *(.rel.bss) } 37 | .rela.bss : { *(.rela.bss) } 38 | .rel.plt : { *(.rel.plt) } 39 | .rela.plt : { *(.rela.plt) } 40 | .init : { *(.init) } =0x9090 41 | .plt : { *(.plt) } 42 | 43 | /* .ARM.exidx is sorted, so has to go in its own output section. */ 44 | __exidx_start = .; 45 | .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } 46 | __exidx_end = .; 47 | 48 | .rodata : ALIGN(4) { 49 | __rodata_start = .; 50 | __fault_handler_table_start = .; 51 | KEEP(*(.rodata.fault_handler_table)) 52 | __fault_handler_table_end = .; 53 | *(.rodata .rodata.* .gnu.linkonce.r.*) 54 | /*INCLUDE "arch/shared_rodata_sections.ld"*/ 55 | . = ALIGN(4); 56 | __rodata_end = .; 57 | } 58 | 59 | 60 | .data : ALIGN(4) { 61 | /* writable data */ 62 | __data_start_rom = .; 63 | /* in one segment binaries, the rom data address is on top of the ram data address */ 64 | __data_start = .; 65 | *(.data .data.* .gnu.linkonce.d.*) 66 | /*INCLUDE "arch/shared_data_sections.ld" */ 67 | } 68 | 69 | .ctors : ALIGN(4) { 70 | __ctor_list = .; 71 | KEEP(*(.ctors .init_array)) 72 | __ctor_end = .; 73 | } 74 | .dtors : ALIGN(4) { 75 | __dtor_list = .; 76 | KEEP(*(.dtors .fini_array)) 77 | __dtor_end = .; 78 | } 79 | .got : { *(.got.plt) *(.got) } 80 | .dynamic : { *(.dynamic) } 81 | 82 | __data_end = .; 83 | 84 | /* unintialized data (in same segment as writable data) */ 85 | .bss : ALIGN(4) { 86 | KEEP(*(.bss.prebss.*)) 87 | . = ALIGN(4); 88 | __bss_start = .; 89 | *(.bss .bss.*) 90 | *(.gnu.linkonce.b.*) 91 | *(COMMON) 92 | . = ALIGN(4); 93 | __bss_end = .; 94 | 95 | } 96 | 97 | _end = .; 98 | 99 | /* Strip unnecessary stuff */ 100 | /DISCARD/ : { *(.comment .note .eh_frame) } 101 | } 102 | -------------------------------------------------------------------------------- /sys/lib/lkuser/thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2022 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "thread.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "proc.h" 31 | 32 | #define LOCAL_TRACE 0 33 | 34 | namespace lkuser { 35 | 36 | thread::thread(proc *p) : proc_(p) {} 37 | thread::~thread() = default; 38 | 39 | int lkuser_start_routine(void *arg) { 40 | thread *t = (thread *)arg; 41 | 42 | /* set our per-thread pointer */ 43 | __tls_set(TLS_ENTRY_LKUSER, (uintptr_t)t); 44 | 45 | /* switch to user mode and start the thread */ 46 | arch_enter_uspace(t->get_entry(), 47 | (uintptr_t)t->get_stack() + PAGE_SIZE); 48 | 49 | __UNREACHABLE; 50 | } 51 | 52 | thread *thread::create(proc *p, vaddr_t entry) { 53 | thread *t; 54 | t = new thread(p); 55 | if (!t) { 56 | TRACEF("error allocating thread state\n"); 57 | return NULL; 58 | } 59 | 60 | t->entry_ = entry; 61 | 62 | // create the lk side of the thread 63 | thread_t *lkthread = thread_create_etc(&t->lkthread, "lkuser", lkuser_start_routine, t, LOW_PRIORITY, NULL, DEFAULT_STACK_SIZE); 64 | if (!lkthread) { 65 | TRACEF("error creating thread\n"); 66 | delete t; 67 | return nullptr; 68 | } 69 | DEBUG_ASSERT(lkthread == &t->lkthread); 70 | 71 | // set the address space for this thread 72 | t->lkthread.aspace = p->get_aspace(); 73 | 74 | // create a user stack for the new thread 75 | // TODO: move this logic elsewhere and/or generally make it a user space problem 76 | status_t err = vmm_alloc(p->get_aspace(), "lkuser_user_stack", PAGE_SIZE, &t->user_stack_, PAGE_SIZE_SHIFT, 77 | 0, ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_NO_EXECUTE); 78 | LTRACEF("vmm_alloc returns %d, stack at %p\n", err, t->user_stack_); 79 | DEBUG_ASSERT(err >= NO_ERROR); 80 | 81 | // add ourselves to the parent process 82 | err = p->add_thread(t); 83 | if (err < 0) { 84 | // XXX clean up the LK thread 85 | panic("failed addition of thread to process\n"); 86 | return nullptr; 87 | } 88 | 89 | return t; 90 | } 91 | 92 | } // namespace lkuser 93 | 94 | -------------------------------------------------------------------------------- /sys/lib/lkuser/proc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2022 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #pragma once 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace lkuser { 32 | 33 | class thread; 34 | 35 | class proc { 36 | private: 37 | proc(); 38 | 39 | DISALLOW_COPY_ASSIGN_AND_MOVE(proc); 40 | 41 | public: 42 | ~proc(); 43 | 44 | static proc *create(); 45 | void destroy(); 46 | 47 | status_t add_thread(thread *t); 48 | status_t wait(); // wait for process to exit 49 | void start(); 50 | void exit(int retcode); // must be called by a thread in the process 51 | 52 | // accessors 53 | vmm_aspace_t *get_aspace() const { return aspace_; } 54 | 55 | // state of the loader 56 | struct loader_state { 57 | elf_handle_t elf; 58 | vaddr_t entry; // entry point to the binary 59 | bool loaded; 60 | }; 61 | loader_state &get_loader_state() { return loader_; } 62 | const loader_state &get_loader_state() const { return loader_; } 63 | 64 | // process state 65 | enum state { 66 | PROC_STATE_INITIAL, 67 | PROC_STATE_RUNNING, 68 | PROC_STATE_DEAD, 69 | }; 70 | state get_state() const { return state_; } 71 | 72 | // sbrk state 73 | struct sbrk_state { 74 | uintptr_t last_sbrk; 75 | uintptr_t last_sbrk_top; 76 | }; 77 | sbrk_state &get_sbrk_state() { return sbrk_state_; } 78 | const sbrk_state &get_sbrk_state() const { return sbrk_state_; } 79 | 80 | // list node for the process list 81 | list_node node = LIST_INITIAL_CLEARED_VALUE; 82 | 83 | private: 84 | loader_state loader_ {}; 85 | 86 | // our address space 87 | vmm_aspace_t *aspace_ = nullptr; 88 | 89 | // list of threads 90 | list_node thread_list_ = LIST_INITIAL_VALUE(thread_list_); 91 | Mutex thread_list_lock_; 92 | 93 | int retcode_; 94 | state state_ = PROC_STATE_INITIAL; 95 | 96 | event_t exit_event_ = EVENT_INITIAL_VALUE(exit_event_, false, 0); 97 | 98 | // sbrk information 99 | sbrk_state sbrk_state_; 100 | }; 101 | 102 | void add_to_global_list(proc *p); 103 | 104 | } // namespace lkuser 105 | 106 | -------------------------------------------------------------------------------- /lib/lku/liblk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | extern int main(void); 8 | 9 | // TODO: implement __retarget_lock* routines from newlib 10 | 11 | #define SYSCALL_FUNCTION_PTR 0 12 | 13 | #if SYSCALL_FUNCTION_PTR 14 | 15 | /* direct function pointer version */ 16 | static const struct lkuser_syscall_table *lk_syscalls; 17 | 18 | #define LK_SYSCALL(func, args...) \ 19 | lk_syscalls->func(args) 20 | 21 | #elif ARCH_ARM 22 | 23 | #define LK_SYSCALL(func, args...) \ 24 | _lk_##func(args) 25 | 26 | /* build a function that uses the svc instruction to call into system mode */ 27 | #define LK_SYSCALL_DEF(n, ret, name, args...) \ 28 | __attribute__((naked)) ret _lk_##name(args) { \ 29 | \ 30 | asm volatile( \ 31 | "mov r12, #" #n ";" \ 32 | "svc #99;" \ 33 | "bx lr;" \ 34 | ::: "memory"); \ 35 | } 36 | 37 | #include 38 | 39 | #undef LK_SYSCALL_DEF 40 | 41 | #elif ARCH_RISCV 42 | 43 | #define LK_SYSCALL(func, args...) \ 44 | _lk_##func(args) 45 | 46 | /* build a function that uses the ecall instruction to call into supervisor mode */ 47 | #define LK_SYSCALL_DEF(n, ret, name, args...) \ 48 | __attribute__((naked)) ret _lk_##name(args) { \ 49 | \ 50 | asm volatile( \ 51 | "li t0, " #n ";" \ 52 | "ecall;" \ 53 | "ret;" \ 54 | ::: "memory"); \ 55 | } 56 | 57 | #include 58 | 59 | #undef LK_SYSCALL_DEF 60 | 61 | #else 62 | #error define syscall mechanism for this arch 63 | #endif 64 | 65 | // Called from startup assembly 66 | void _start_c(const struct lkuser_syscall_table *syscalls) 67 | { 68 | #if SYSCALL_FUNCTION_PTR 69 | lk_syscalls = syscalls; 70 | #endif 71 | 72 | // register to call the fini array on exit 73 | extern void __libc_fini_array(void); 74 | atexit(__libc_fini_array); 75 | 76 | // call the init array 77 | extern void __libc_init_array(void); 78 | __libc_init_array(); 79 | 80 | int ret = main(); 81 | 82 | exit(ret); 83 | } 84 | 85 | /* make libc happy */ 86 | void _init(void) {} 87 | void _fini(void) {} 88 | 89 | /* implement needed stuff to get it to compile */ 90 | 91 | int _fstat(int file, struct stat *st) 92 | { 93 | st->st_mode = S_IFCHR; 94 | return 0; 95 | } 96 | 97 | int _isatty(int file) { return 1; } 98 | 99 | void *_sbrk(ptrdiff_t incr) 100 | { 101 | return LK_SYSCALL(sbrk, incr); 102 | } 103 | 104 | int _open(const char *name, int flags, int mode) 105 | { 106 | return LK_SYSCALL(open, name, flags, mode); 107 | } 108 | 109 | int _close(int file) 110 | { 111 | return LK_SYSCALL(close, file); 112 | } 113 | 114 | int _read(int file, char *ptr, int len) 115 | { 116 | return LK_SYSCALL(read, file, ptr, len); 117 | } 118 | 119 | int _write(int file, const char *ptr, int len) 120 | { 121 | return LK_SYSCALL(write, file, ptr, len); 122 | } 123 | 124 | int _lseek(int file, _off_t pos, int whence) 125 | { 126 | return LK_SYSCALL(lseek, file, pos, whence); 127 | } 128 | 129 | void _exit(int arg) 130 | { 131 | LK_SYSCALL(exit, arg); 132 | 133 | __builtin_unreachable(); 134 | } 135 | 136 | int usleep(useconds_t useconds) 137 | { 138 | return LK_SYSCALL(sleep_usec, useconds); 139 | } 140 | 141 | int sleep(unsigned int seconds) 142 | { 143 | return LK_SYSCALL(sleep_sec, seconds); 144 | } 145 | 146 | int _kill (int pid, int sig) 147 | { 148 | // XXX sort this out 149 | LK_SYSCALL(exit, 0); 150 | 151 | __builtin_unreachable(); 152 | } 153 | 154 | pid_t _getpid (void) 155 | { 156 | return (pid_t)1; 157 | } 158 | -------------------------------------------------------------------------------- /sys/lib/lkuser/proc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2022 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "proc.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "thread.h" 31 | #include "lkuser_priv.h" 32 | 33 | #define LOCAL_TRACE 0 34 | 35 | namespace lkuser { 36 | 37 | // event to kick off a pass of the reaper thread 38 | event_t reap_event = EVENT_INITIAL_VALUE(reap_event, false, EVENT_FLAG_AUTOUNSIGNAL); 39 | 40 | // list of processes 41 | list_node proc_list = LIST_INITIAL_VALUE(proc_list); 42 | Mutex proc_list_lock; 43 | 44 | void add_to_global_list(proc *p) { 45 | AutoLock guard(proc_list_lock); 46 | list_add_head(&proc_list, &p->node); 47 | } 48 | 49 | proc::proc() = default; 50 | proc::~proc() = default; 51 | 52 | proc *proc::create() { 53 | proc *p = new proc; 54 | if (!p) { 55 | TRACEF("error allocating proc state\n"); 56 | return NULL; 57 | } 58 | 59 | /* create an address space for it */ 60 | if (vmm_create_aspace(&p->aspace_, "lkuser", 0) < 0) { 61 | TRACEF("error creating address space\n"); 62 | delete p; 63 | return NULL; 64 | } 65 | 66 | /* add the process to the process list */ 67 | add_to_global_list(p); 68 | 69 | return p; 70 | } 71 | 72 | status_t proc::add_thread(thread *t) { 73 | /* add the thread to the process */ 74 | { 75 | AutoLock guard(thread_list_lock_); 76 | list_add_head(&thread_list_, &t->node); 77 | } 78 | 79 | return NO_ERROR; 80 | } 81 | 82 | void proc::destroy() { 83 | // TODO: formalize the state machine more 84 | DEBUG_ASSERT(state_ == PROC_STATE_DEAD); 85 | 86 | // clean up all the threads 87 | thread *t; 88 | while ((t = list_remove_head_type(&thread_list_, thread, node))) { 89 | t->join(); 90 | 91 | delete t; 92 | } 93 | 94 | // free everything inside the address space 95 | vmm_free_aspace(aspace_); 96 | 97 | // no one should be waiting for to us 98 | event_destroy(&exit_event_); 99 | 100 | // free any resources in the elf handle 101 | elf_close_handle(&get_loader_state().elf); 102 | } 103 | 104 | status_t proc::wait() { 105 | return event_wait(&exit_event_); 106 | } 107 | 108 | void proc::start() { 109 | state_ = PROC_STATE_RUNNING; 110 | } 111 | 112 | void proc::exit(int retcode) { 113 | state_ = proc::PROC_STATE_DEAD; 114 | retcode = retcode; 115 | event_signal(&exit_event_, true); 116 | 117 | // TODO: only trigger the reaper when the last thread exits 118 | event_signal(&reap_event, true); 119 | } 120 | 121 | // reaper thread that cleans up dead processes 122 | static int reaper(void *arg) { 123 | for (;;) { 124 | event_wait(&reap_event); 125 | 126 | for (;;) { 127 | proc *found = NULL; 128 | { 129 | AutoLock guard(proc_list_lock); 130 | 131 | proc *temp; 132 | list_for_every_entry(&proc_list, temp, proc, node) { 133 | if (temp->get_state() == proc::PROC_STATE_DEAD) { 134 | list_delete(&temp->node); 135 | found = temp; 136 | break; 137 | } 138 | } 139 | } 140 | 141 | if (!found) { 142 | break; 143 | } 144 | 145 | TRACEF("going to reap process %p\n", found); 146 | 147 | found->destroy(); 148 | 149 | // delete the process 150 | delete found; 151 | } 152 | } 153 | 154 | return 0; 155 | } 156 | 157 | void lkuser_init(uint level) { 158 | thread_detach_and_resume(thread_create("reaper", &reaper, NULL, HIGH_PRIORITY, DEFAULT_STACK_SIZE)); 159 | } 160 | 161 | LK_INIT_HOOK(lkuser, lkuser_init, LK_INIT_LEVEL_THREADING); 162 | 163 | 164 | } // namespace lkuser 165 | 166 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # allow local overrides of particular things 2 | -include local.mk 3 | 4 | include lk/make/macros.mk 5 | NOECHO ?= @ 6 | # try to have the compiler output colorized error messages if available 7 | export GCC_COLORS ?= 1 8 | 9 | all: _all 10 | 11 | # a list of files added by various modules in the form of 12 | # : 13 | FS_LIST := 14 | 15 | APPS := 16 | APPS_EXTRADEPS := 17 | APP_RULES := $(shell find apps -name app.mk) 18 | $(warning APP_RULES = $(APP_RULES)) 19 | 20 | LIBS := 21 | LIBS_EXTRADEPS := 22 | LIB_RULES := $(shell find lib -name lib.mk) 23 | $(warning LIB_RULES = $(LIB_RULES)) 24 | 25 | CCACHE ?= 26 | ARCH ?= riscv 27 | 28 | BUILDDIR := build-$(ARCH) 29 | LK_TESTPROJECT := qemu-$(ARCH)-usertest 30 | 31 | # some newlib stuff 32 | NEWLIB_BUILD_DIR := build-newlib-$(ARCH) 33 | NEWLIB_INSTALL_DIR := install-newlib-$(ARCH) 34 | NEWLIB_INC_DIR := # arch.mk should set this 35 | NEWLIB_ARCH_TARGET := # arch.mk should set this 36 | LIBC := # arch.mk should set this and libm 37 | LIBM := 38 | 39 | include arch/$(ARCH)/arch.mk 40 | 41 | # compiler flags 42 | GLOBAL_COMPILEFLAGS := -g -fno-builtin -finline -O2 43 | GLOBAL_COMPILEFLAGS += -W -Wall -Wno-multichar -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Werror=return-type 44 | GLOBAL_CFLAGS := --std=gnu99 -Werror-implicit-function-declaration -Wstrict-prototypes -Wwrite-strings 45 | GLOBAL_CPPFLAGS := -fno-exceptions -fno-rtti -fno-threadsafe-statics 46 | GLOBAL_ASMFLAGS := -DASSEMBLY 47 | GLOBAL_LDFLAGS := 48 | GLOBAL_INCLUDES := -I$(NEWLIB_INC_DIR) -Isys/lib/lkuser/include 49 | GLOBAL_LIBS := $(LIBC) $(LIBM) 50 | 51 | GLOBAL_COMPILEFLAGS += -ffunction-sections -fdata-sections 52 | GLOBAL_LDFLAGS += --gc-sections 53 | 54 | ARCH_CC ?= $(CCACHE) $(TOOLCHAIN_PREFIX)gcc 55 | ARCH_LD ?= $(TOOLCHAIN_PREFIX)ld 56 | ARCH_AR ?= $(TOOLCHAIN_PREFIX)ar 57 | ARCH_OBJDUMP ?= $(TOOLCHAIN_PREFIX)objdump 58 | ARCH_OBJCOPY ?= $(TOOLCHAIN_PREFIX)objcopy 59 | ARCH_CPPFILT ?= $(TOOLCHAIN_PREFIX)c++filt 60 | ARCH_SIZE ?= $(TOOLCHAIN_PREFIX)size 61 | ARCH_NM ?= $(TOOLCHAIN_PREFIX)nm 62 | ARCH_STRIP ?= $(TOOLCHAIN_PREFIX)strip 63 | 64 | LIBGCC := $(shell $(ARCH_CC) $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(THUMBCFLAGS) -print-libgcc-file-name) 65 | $(info LIBGCC = $(LIBGCC)) 66 | 67 | include $(APP_RULES) 68 | $(warning APPS = $(APPS)) 69 | 70 | include $(LIB_RULES) 71 | $(warning LIBS = $(LIBS)) 72 | 73 | _all: lk apps libs 74 | 75 | lk: 76 | PROJECT=$(LK_TESTPROJECT) $(MAKE) -f makefile.lk 77 | 78 | apps: $(APPS) $(APPS_EXTRADEPS) 79 | 80 | libs: $(LIBS) $(LIBS_EXTRADEPS) 81 | 82 | clean-apps: 83 | rm -rf -- "."/"$(BUILDDIR)" 84 | 85 | clean: clean-apps 86 | PROJECT=$(LK_TESTPROJECT) $(MAKE) -f makefile.lk clean 87 | 88 | spotless: clean-apps clean-newlib 89 | $(MAKE) -f makefile.lk spotless 90 | 91 | configure-newlib $(NEWLIB_BUILD_DIR)/.stamp: 92 | mkdir -p $(NEWLIB_BUILD_DIR) 93 | cd $(NEWLIB_BUILD_DIR) && ../newlib/configure --target $(NEWLIB_ARCH_TARGET) \ 94 | --prefix=`pwd`/../$(NEWLIB_INSTALL_DIR) \ 95 | --disable-newlib-supplied-syscalls \ 96 | --enable-target-optspace 97 | $(MAKE) -C $(NEWLIB_BUILD_DIR) configure-host 98 | $(MAKE) -C $(NEWLIB_BUILD_DIR) configure-target 99 | touch $(NEWLIB_BUILD_DIR)/.stamp 100 | 101 | build-newlib $(NEWLIB_INSTALL_DIR)/.stamp: $(NEWLIB_BUILD_DIR)/.stamp 102 | mkdir -p $(NEWLIB_INSTALL_DIR) 103 | $(MAKE) -C $(NEWLIB_BUILD_DIR) 104 | $(MAKE) -C $(NEWLIB_BUILD_DIR) install MAKEFLAGS= 105 | touch $(NEWLIB_INSTALL_DIR)/.stamp 106 | 107 | $(LIBC) $(LIBM) $(CRT0): $(NEWLIB_INSTALL_DIR)/.stamp 108 | 109 | newlib: build-newlib 110 | 111 | clean-newlib: 112 | rm -rf -- ./"$(NEWLIB_BUILD_DIR)" ./"$(NEWLIB_INSTALL_DIR)" 113 | 114 | FS_LIST_LEFT := $(foreach F,$(FS_LIST),$(firstword $(subst :, ,$(F)))) 115 | FS_LIST_RIGHT := $(foreach F,$(FS_LIST),$(lastword $(subst :, ,$(F)))) 116 | FS_LIST_DIRS := $(filter-out .,$(sort $(patsubst %/,%,$(dir $(FS_LIST_RIGHT))))) 117 | 118 | $(info FS_LIST = $(FS_LIST)) 119 | $(info FS_LIST_LEFT = $(FS_LIST_LEFT)) 120 | $(info FS_LIST_RIGHT = $(FS_LIST_RIGHT)) 121 | $(info FS_LIST_DIRS = $(FS_LIST_DIRS)) 122 | 123 | # generate a directory within the build dir that holds all of the 124 | # files referenced in FS_LIST. 125 | ROOT_DIR := $(BUILDDIR)/root_dir 126 | $(ROOT_DIR).stamp: $(FS_LIST_LEFT) 127 | @$(MKDIR) 128 | @echo building root fs image in $(ROOT_DIR) 129 | $(NOECHO)if [ -d "$(ROOT_DIR)" ]; then \ 130 | rm -r -- "$(ROOT_DIR)";\ 131 | fi 132 | $(NOECHO)mkdir -p -- $(addprefix $(ROOT_DIR)/,$(FS_LIST_DIRS)) 133 | $(NOECHO)$(foreach F,$(FS_LIST),\ 134 | cp -- "$(firstword $(subst :, ,$(F)))" "$(addprefix $(ROOT_DIR)/,$(lastword $(subst :, ,$(F))))"; \ 135 | ) 136 | $(NOECHO)touch $(ROOT_DIR).stamp 137 | $(NOECHO)#du -a $(ROOT_DIR) 138 | 139 | # generate a FAT disk image with applications in it 140 | # copies the entire tree that is stored in $(ROOT_DIR) 141 | $(BUILDDIR)/root.fat: $(ROOT_DIR).stamp 142 | @$(MKDIR) 143 | @echo generating FAT image $@ 144 | $(NOECHO)dd if=/dev/zero of=$@.tmp bs=1048576 count=64 145 | $(NOECHO)mformat -i $@.tmp -m f8 -v lkuser 146 | $(NOECHO)mcopy -v -i $@.tmp -s "$(ROOT_DIR)"/* :: 147 | $(NOECHO)mv $@.tmp $@ 148 | $(NOECHO)#mdir -/ -i $@ :: 149 | 150 | fs: $(BUILDDIR)/root.fat 151 | 152 | list-toolchain: 153 | @echo TOOLCHAIN_PREFIX = ${TOOLCHAIN_PREFIX} 154 | 155 | test: _all fs 156 | ifeq ($(ARCH),arm) 157 | qemu-system-arm -m 512 -smp 1 -machine virt -cpu cortex-a15 -kernel build-$(LK_TESTPROJECT)/lk.elf -nographic -drive if=none,file=$(BUILDDIR)/root.fat,id=blk,format=raw -device virtio-blk-device,drive=blk 158 | else ifeq ($(ARCH),riscv) 159 | qemu-system-riscv64 -m 512 -smp 1 -machine virt -cpu rv64 -bios default -kernel build-$(LK_TESTPROJECT)/lk.elf -nographic -drive if=none,file=$(BUILDDIR)/root.fat,id=blk,format=raw -device virtio-blk-device,drive=blk 160 | endif 161 | 162 | .PHONY: all _all apps fs lk clean clean-apps spotless newlib build-newlib configure-newlib clean-newlib list-toolchain 163 | 164 | # vim: set noexpandtab ts=4 sw=4: 165 | -------------------------------------------------------------------------------- /sys/lib/lkuser/user.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "lkuser_priv.h" 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #define LOCAL_TRACE 0 44 | 45 | namespace lkuser { 46 | 47 | static ssize_t elf_read_hook_file(struct elf_handle *handle, void *buf, uint64_t offset, size_t len) { 48 | filehandle *fhandle = (filehandle *)handle->read_hook_arg; 49 | 50 | LTRACEF("handle %p, buf %p, offset %llu, len %#zx\n", handle, buf, offset, len); 51 | 52 | return fs_read_file(fhandle, buf, offset, len); 53 | } 54 | 55 | static status_t elf_mem_alloc(struct elf_handle *handle, void **ptr, size_t len, uint num, uint flags) { 56 | LTRACEF("handle %p, ptr %p [%p], size %#zx, num %u, flags %#x\n", handle, ptr, *ptr, len, num, flags); 57 | 58 | proc *p = (proc *)handle->mem_alloc_hook_arg; 59 | 60 | char name[16]; 61 | snprintf(name, sizeof(name), "lkuser%u", num); 62 | 63 | // round the allocations down and up to page boundaries 64 | uintptr_t va = (uintptr_t)*ptr; 65 | uintptr_t newva = ROUNDDOWN(va, PAGE_SIZE); 66 | ptrdiff_t aligndiff = va - newva; 67 | len += aligndiff; 68 | va = newva; 69 | 70 | // round the size up to the next boundary 71 | len = ROUNDUP(len, PAGE_SIZE); 72 | 73 | LTRACEF("aligned va %#lx size %#zx\n", va, len); 74 | 75 | void *vaptr = (void *)va; 76 | status_t err = vmm_alloc(p->get_aspace(), name, len, &vaptr, 0, VMM_FLAG_VALLOC_SPECIFIC, ARCH_MMU_FLAG_PERM_USER); 77 | LTRACEF("vmm_alloc returns %d, ptr %p\n", err, vaptr); 78 | 79 | *ptr = (void *)((uintptr_t)vaptr + aligndiff); 80 | LTRACEF("returning ptr %p\n", *ptr); 81 | 82 | return err; 83 | } 84 | 85 | static status_t lkuser_load_file(proc *proc, const char *file_name) { 86 | status_t err; 87 | 88 | LTRACE; 89 | 90 | /* switch to the address space we're loading into */ 91 | vmm_set_active_aspace(proc->get_aspace()); 92 | 93 | filehandle *handle; 94 | err = fs_open_file(file_name, &handle); 95 | if (err < 0) { 96 | TRACEF("failed to open file %s\n", file_name); 97 | return err; 98 | } 99 | 100 | proc::loader_state &ls = proc->get_loader_state(); 101 | 102 | /* create an elf handle */ 103 | err = elf_open_handle(&ls.elf, &elf_read_hook_file, handle, false); 104 | LTRACEF("elf_open_handle returns %d\n", err); 105 | if (err < 0) { 106 | TRACEF("failed to open elf handle\n"); 107 | goto err; 108 | } 109 | 110 | /* register a memory allocation callback */ 111 | ls.elf.mem_alloc_hook = &elf_mem_alloc; 112 | ls.elf.mem_alloc_hook_arg = proc; 113 | 114 | /* try to load the binary */ 115 | err = elf_load(&ls.elf); 116 | LTRACEF("elf_load returns %d\n", err); 117 | if (err < 0) { 118 | TRACEF("failed to load elf file\n"); 119 | goto err; 120 | } 121 | 122 | /* the binary loaded properly */ 123 | ls.entry = ls.elf.entry; 124 | ls.loaded = true; 125 | 126 | fs_close_file(handle); 127 | vmm_set_active_aspace(NULL); 128 | 129 | return NO_ERROR; 130 | 131 | err: 132 | if (handle) { 133 | fs_close_file(handle); 134 | } 135 | vmm_set_active_aspace(NULL); 136 | return err; 137 | } 138 | 139 | status_t lkuser_start_binary(proc *p, bool wait) { 140 | DEBUG_ASSERT(p); 141 | 142 | const auto ls = p->get_loader_state(); 143 | LTRACEF("proc %p, entry %#lx\n", p, ls.entry); 144 | 145 | if (!ls.loaded) { 146 | return ERR_NOT_READY; 147 | } 148 | 149 | thread *t = thread::create(p, ls.entry); 150 | if (!t) { 151 | // XXX free proc 152 | return ERR_NO_MEMORY; 153 | } 154 | 155 | /* we're ready to run now */ 156 | p->start(); 157 | 158 | /* resume */ 159 | LTRACEF("resuming main thread\n"); 160 | t->resume(); 161 | 162 | if (wait) { 163 | p->wait(); 164 | } 165 | 166 | return NO_ERROR; 167 | } 168 | 169 | } // namespace lkuser 170 | 171 | #if defined(WITH_LIB_CONSOLE) 172 | #include 173 | 174 | static int cmd_lkuser(int argc, const console_cmd_args *argv) { 175 | int rc = 0; 176 | 177 | if (argc < 2) { 178 | notenoughargs: 179 | printf("not enough arguments:\n"); 180 | usage: 181 | printf("%s load \n", argv[0].str); 182 | printf("%s run [&]\n", argv[0].str); 183 | return -1; 184 | } 185 | 186 | static lkuser::proc *proc; 187 | if (!strcmp(argv[1].str, "load")) { 188 | if (argc < 3) { 189 | goto notenoughargs; 190 | } 191 | if (!proc) { 192 | proc = lkuser::proc::create(); 193 | } 194 | status_t err; 195 | err = lkuser_load_file(proc, argv[2].str); 196 | printf("lkuser_load_file() returns %d, entry at %#lx\n", err, proc->get_loader_state().entry); 197 | } else if (!strcmp(argv[1].str, "run")) { 198 | if (!proc) { 199 | printf("no loaded binary\n"); 200 | return -1; 201 | } 202 | 203 | bool wait = true; 204 | if (argc > 2 && !strcmp(argv[2].str, "&")) { 205 | wait = false; 206 | } 207 | 208 | status_t err = lkuser_start_binary(proc, wait); 209 | printf("lkuser_start_binary() returns %d\n", err); 210 | proc = NULL; 211 | } else { 212 | printf("unrecognized subcommand\n"); 213 | goto usage; 214 | } 215 | 216 | return rc; 217 | } 218 | 219 | STATIC_COMMAND_START 220 | STATIC_COMMAND("lkuser", "user space routines", &cmd_lkuser) 221 | STATIC_COMMAND_END(lkuser); 222 | 223 | #endif 224 | 225 | -------------------------------------------------------------------------------- /sys/lib/lkuser/syscalls.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Travis Geiselbrecht 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files 6 | * (the "Software"), to deal in the Software without restriction, 7 | * including without limitation the rights to use, copy, modify, merge, 8 | * publish, distribute, sublicense, and/or sell copies of the Software, 9 | * and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "lkuser_priv.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "lkuser_priv.h" 38 | 39 | #define LOCAL_TRACE 0 40 | 41 | using namespace lkuser; 42 | 43 | void sys_exit(int retcode) { 44 | LTRACEF("retcode %d\n", retcode); 45 | 46 | auto *t = get_lkuser_thread(); 47 | DEBUG_ASSERT(t); 48 | 49 | // XXX check that we're the last thread in this process 50 | t->get_proc()->exit(retcode); 51 | 52 | thread_exit(retcode); 53 | } 54 | 55 | int sys_write(int file, const char *ptr, int len) { 56 | LTRACEF("file %d, ptr %p, len %d\n", file, ptr, len); 57 | 58 | if (file == 1 || file == 2) { 59 | for (int i = 0; i < len; i++) { 60 | fputc(ptr[i], stdout); 61 | } 62 | } 63 | 64 | return len; 65 | } 66 | 67 | int sys_open(const char *name, int flags, int mode) { 68 | LTRACEF("name '%s', flags 0x%x, mode 0x%x\n", name, flags, mode); 69 | 70 | return -1; 71 | } 72 | 73 | int sys_close(int file) { 74 | LTRACEF("file %d\n", file); 75 | 76 | return -1; 77 | } 78 | 79 | int sys_read(int file, char *ptr, int len) { 80 | LTRACEF("file %d, ptr %p, len %d\n", file, ptr, len); 81 | 82 | if (len <= 0) 83 | return 0; 84 | 85 | if (file == 0) { 86 | /* trying to read from stdin */ 87 | int c = getchar(); 88 | if (c >= 0) { 89 | /* translate \r -> \n */ 90 | if (c == '\r') c = '\n'; 91 | 92 | ptr[0] = c; 93 | return 1; 94 | } 95 | 96 | return 0; 97 | } else { 98 | /* bad file descriptor */ 99 | return -1; 100 | } 101 | } 102 | 103 | int sys_lseek(int file, long pos, int whence) { 104 | LTRACEF("file %d, pos %ld, whence %d\n", file, pos, whence); 105 | 106 | return -1; 107 | } 108 | 109 | void *sys_sbrk(long incr) { 110 | void *ptr; 111 | 112 | LTRACEF("incr %ld\n", incr); 113 | 114 | auto *t = get_lkuser_thread(); 115 | proc *p = t->get_proc(); 116 | auto ss = p->get_sbrk_state(); 117 | 118 | if (incr < 0) 119 | return NULL; 120 | 121 | if (incr == 0) 122 | return (void *)ss.last_sbrk; 123 | 124 | if (ss.last_sbrk != 0 && ss.last_sbrk + incr <= ss.last_sbrk_top) { 125 | LTRACEF("still have space in the last allocation: last_sbrk 0x%lx, last_sbrk_top 0x%lx\n", ss.last_sbrk, ss.last_sbrk_top); 126 | ptr = (void *)ss.last_sbrk; 127 | ss.last_sbrk += incr; 128 | return ptr; 129 | } 130 | 131 | #define HEAP_ALLOC_CHUNK_SIZE (PAGE_SIZE * 16) 132 | 133 | /* allocate a new chunk for the heap */ 134 | size_t alloc_size = ROUNDUP(incr, HEAP_ALLOC_CHUNK_SIZE); 135 | status_t err = vmm_alloc(t->get_proc()->get_aspace(), "heap", alloc_size, &ptr, PAGE_SIZE_SHIFT, 136 | 0, ARCH_MMU_FLAG_PERM_USER | ARCH_MMU_FLAG_PERM_NO_EXECUTE); 137 | 138 | ss.last_sbrk = (uintptr_t)ptr + incr; 139 | ss.last_sbrk_top = (uintptr_t)ptr + HEAP_ALLOC_CHUNK_SIZE; 140 | 141 | LTRACEF("vmm_alloc returns %d, ptr at %p, last_sbrk now 0x%lx, top 0x%lx\n", err, ptr, ss.last_sbrk, ss.last_sbrk_top); 142 | 143 | return (err >= 0) ? ptr : NULL; 144 | } 145 | 146 | int sys_sleep_sec(unsigned long seconds) { 147 | LTRACEF("seconds %lu\n", seconds); 148 | 149 | thread_sleep(seconds * 1000U); 150 | return 0; 151 | } 152 | 153 | int sys_sleep_usec(unsigned long useconds) { 154 | LTRACEF("useconds %lu\n", useconds); 155 | 156 | thread_sleep(useconds / 1000U); 157 | return 0; 158 | } 159 | 160 | int sys_invalid_syscall(void) { 161 | LTRACEF("invalid syscall\n"); 162 | return ERR_INVALID_ARGS; 163 | } 164 | 165 | const struct lkuser_syscall_table lkuser_syscalls = { 166 | .exit = &sys_exit, 167 | .open = &sys_open, 168 | .close = &sys_close, 169 | .write = &sys_write, 170 | .read = &sys_read, 171 | .lseek = &sys_lseek, 172 | .sbrk = &sys_sbrk, 173 | .sleep_sec = &sys_sleep_sec, 174 | .sleep_usec = &sys_sleep_usec, 175 | }; 176 | 177 | #if ARCH_ARM 178 | extern "C" 179 | void arm_syscall_handler(struct arm_fault_frame *frame) { 180 | /* re-enable interrupts to maintain kernel preemptiveness */ 181 | arch_enable_ints(); 182 | 183 | LTRACEF("arm syscall: r12 %u\n", frame->r[12]); 184 | 185 | /* build a function pointer to call the routine. 186 | * the args are jammed into the function independent of if the function 187 | * uses them or not, which is safe for simple arg passing. 188 | */ 189 | int64_t (*sfunc)(unsigned long a, unsigned long b, unsigned long c, unsigned long d); 190 | 191 | switch (frame->r[12]) { 192 | #define LK_SYSCALL_DEF(n, ret, name, args...) \ 193 | case n: sfunc = reinterpret_cast((uintptr_t)sys_##name); break; 194 | #include 195 | #undef LK_SYSCALL_DEF 196 | default: 197 | sfunc = reinterpret_cast((uintptr_t)sys_invalid_syscall); 198 | } 199 | 200 | LTRACEF("func %p\n", sfunc); 201 | 202 | /* call the routine */ 203 | uint64_t ret = sfunc(frame->r[0], frame->r[1], frame->r[2], frame->r[3]); 204 | 205 | /* unpack the 64bit return back into r0 and r1 */ 206 | frame->r[0] = ret & 0xffffffff; 207 | frame->r[1] = (ret >> 32) & 0xffffffff; 208 | } 209 | #endif 210 | #if ARCH_RISCV 211 | #include 212 | extern "C" 213 | void riscv_syscall_handler(struct riscv_short_iframe *frame) { 214 | /* re-enable interrupts to maintain kernel preemptiveness */ 215 | arch_enable_ints(); 216 | 217 | LTRACEF("riscv syscall: t0 %lu\n", frame->t0); 218 | 219 | /* build a function pointer to call the routine. 220 | * the args are jammed into the function independent of if the function 221 | * uses them or not, which is safe for simple arg passing. 222 | */ 223 | int64_t (*sfunc)(unsigned long a, unsigned long b, unsigned long c, unsigned long d); 224 | 225 | switch (frame->t0) { 226 | #define LK_SYSCALL_DEF(n, ret, name, args...) \ 227 | case n: sfunc = reinterpret_cast((uintptr_t)sys_##name); break; 228 | #include 229 | #undef LK_SYSCALL_DEF 230 | default: 231 | sfunc = reinterpret_cast((uintptr_t)sys_invalid_syscall); 232 | } 233 | 234 | LTRACEF("func %p\n", sfunc); 235 | 236 | /* call the routine */ 237 | uint64_t ret = sfunc(frame->a0, frame->a1, frame->a2, frame->a3); 238 | 239 | /* unpack the 64bit return back into a0 and a1 */ 240 | frame->a0 = ret & 0xffffffff; 241 | frame->a1 = (ret >> 32) & 0xffffffff; 242 | 243 | /* bump the PC forward over the ecall */ 244 | frame->epc += 4; 245 | 246 | arch_disable_ints(); 247 | } 248 | #endif 249 | 250 | 251 | -------------------------------------------------------------------------------- /arch/riscv/elf64lriscv.xce: -------------------------------------------------------------------------------- 1 | /* taken from gcc 10.2.0 */ 2 | 3 | /* Script for -z combreloc -z separate-code */ 4 | /* Copyright (C) 2014-2020 Free Software Foundation, Inc. 5 | Copying and distribution of this script, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. */ 8 | OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", 9 | "elf64-littleriscv") 10 | OUTPUT_ARCH(riscv) 11 | ENTRY(_start) 12 | SECTIONS 13 | { 14 | PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x1000000)); . = SEGMENT_START("text-segment", 0x1000000) + SIZEOF_HEADERS; 15 | .interp : { *(.interp) } 16 | .note.gnu.build-id : { *(.note.gnu.build-id) } 17 | .hash : { *(.hash) } 18 | .gnu.hash : { *(.gnu.hash) } 19 | .dynsym : { *(.dynsym) } 20 | .dynstr : { *(.dynstr) } 21 | .gnu.version : { *(.gnu.version) } 22 | .gnu.version_d : { *(.gnu.version_d) } 23 | .gnu.version_r : { *(.gnu.version_r) } 24 | .rela.dyn : 25 | { 26 | *(.rela.init) 27 | *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) 28 | *(.rela.fini) 29 | *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) 30 | *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) 31 | *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) 32 | *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) 33 | *(.rela.ctors) 34 | *(.rela.dtors) 35 | *(.rela.got) 36 | *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) 37 | *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) 38 | *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) 39 | *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) 40 | *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) 41 | PROVIDE_HIDDEN (__rela_iplt_start = .); 42 | *(.rela.iplt) 43 | PROVIDE_HIDDEN (__rela_iplt_end = .); 44 | } 45 | .rela.plt : 46 | { 47 | *(.rela.plt) 48 | } 49 | . = ALIGN(CONSTANT (MAXPAGESIZE)); 50 | .init : 51 | { 52 | KEEP (*(SORT_NONE(.init))) 53 | } 54 | .plt : { *(.plt) } 55 | .iplt : { *(.iplt) } 56 | .text : 57 | { 58 | *(.text.unlikely .text.*_unlikely .text.unlikely.*) 59 | *(.text.exit .text.exit.*) 60 | *(.text.startup .text.startup.*) 61 | *(.text.hot .text.hot.*) 62 | *(SORT(.text.sorted.*)) 63 | *(.text .stub .text.* .gnu.linkonce.t.*) 64 | /* .gnu.warning sections are handled specially by elf.em. */ 65 | *(.gnu.warning) 66 | } 67 | .fini : 68 | { 69 | KEEP (*(SORT_NONE(.fini))) 70 | } 71 | PROVIDE (__etext = .); 72 | PROVIDE (_etext = .); 73 | PROVIDE (etext = .); 74 | . = ALIGN(CONSTANT (MAXPAGESIZE)); 75 | /* Adjust the address for the rodata segment. We want to adjust up to 76 | the same address within the page on the next page up. */ 77 | . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); 78 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 79 | .rodata1 : { *(.rodata1) } 80 | .sdata2 : 81 | { 82 | *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) 83 | } 84 | .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } 85 | .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } 86 | .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } 87 | .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } 88 | .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } 89 | /* These sections are generated by the Sun/Oracle C++ compiler. */ 90 | .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } 91 | /* Adjust the address for the data segment. We want to adjust up to 92 | the same address within the page on the next page up. */ 93 | . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); 94 | /* Exception handling */ 95 | .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } 96 | .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } 97 | .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } 98 | .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } 99 | /* Thread Local Storage sections */ 100 | .tdata : 101 | { 102 | PROVIDE_HIDDEN (__tdata_start = .); 103 | *(.tdata .tdata.* .gnu.linkonce.td.*) 104 | } 105 | .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } 106 | .preinit_array : 107 | { 108 | PROVIDE_HIDDEN (__preinit_array_start = .); 109 | KEEP (*(.preinit_array)) 110 | PROVIDE_HIDDEN (__preinit_array_end = .); 111 | } 112 | .init_array : 113 | { 114 | PROVIDE_HIDDEN (__init_array_start = .); 115 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 116 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 117 | PROVIDE_HIDDEN (__init_array_end = .); 118 | } 119 | .fini_array : 120 | { 121 | PROVIDE_HIDDEN (__fini_array_start = .); 122 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 123 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 124 | PROVIDE_HIDDEN (__fini_array_end = .); 125 | } 126 | .ctors : 127 | { 128 | /* gcc uses crtbegin.o to find the start of 129 | the constructors, so we make sure it is 130 | first. Because this is a wildcard, it 131 | doesn't matter if the user does not 132 | actually link against crtbegin.o; the 133 | linker won't look for a file to match a 134 | wildcard. The wildcard also means that it 135 | doesn't matter which directory crtbegin.o 136 | is in. */ 137 | KEEP (*crtbegin.o(.ctors)) 138 | KEEP (*crtbegin?.o(.ctors)) 139 | /* We don't want to include the .ctor section from 140 | the crtend.o file until after the sorted ctors. 141 | The .ctor section from the crtend file contains the 142 | end of ctors marker and it must be last */ 143 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 144 | KEEP (*(SORT(.ctors.*))) 145 | KEEP (*(.ctors)) 146 | } 147 | .dtors : 148 | { 149 | KEEP (*crtbegin.o(.dtors)) 150 | KEEP (*crtbegin?.o(.dtors)) 151 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 152 | KEEP (*(SORT(.dtors.*))) 153 | KEEP (*(.dtors)) 154 | } 155 | .jcr : { KEEP (*(.jcr)) } 156 | .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } 157 | .dynamic : { *(.dynamic) } 158 | . = DATA_SEGMENT_RELRO_END (0, .); 159 | . = ALIGN(CONSTANT (MAXPAGESIZE)); /* TG: added for alignment */ 160 | .data : 161 | { 162 | __DATA_BEGIN__ = .; 163 | *(.data .data.* .gnu.linkonce.d.*) 164 | SORT(CONSTRUCTORS) 165 | } 166 | .data1 : { *(.data1) } 167 | .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } 168 | /* We want the small data sections together, so single-instruction offsets 169 | can access them all, and initialized data all before uninitialized, so 170 | we can shorten the on-disk segment size. */ 171 | .sdata : 172 | { 173 | __SDATA_BEGIN__ = .; 174 | *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) 175 | *(.sdata .sdata.* .gnu.linkonce.s.*) 176 | } 177 | _edata = .; PROVIDE (edata = .); 178 | . = .; 179 | __bss_start = .; 180 | .sbss : 181 | { 182 | *(.dynsbss) 183 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 184 | *(.scommon) 185 | } 186 | .bss : 187 | { 188 | *(.dynbss) 189 | *(.bss .bss.* .gnu.linkonce.b.*) 190 | *(COMMON) 191 | /* Align here to ensure that the .bss section occupies space up to 192 | _end. Align after .bss to ensure correct alignment even if the 193 | .bss section disappears because there are no input sections. 194 | FIXME: Why do we need it? When there is no .bss section, we do not 195 | pad the .data section. */ 196 | . = ALIGN(. != 0 ? 64 / 8 : 1); 197 | } 198 | . = ALIGN(64 / 8); 199 | . = SEGMENT_START("ldata-segment", .); 200 | . = ALIGN(64 / 8); 201 | __BSS_END__ = .; 202 | __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, 203 | MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); 204 | _end = .; PROVIDE (end = .); 205 | . = DATA_SEGMENT_END (.); 206 | /* Stabs debugging sections. */ 207 | .stab 0 : { *(.stab) } 208 | .stabstr 0 : { *(.stabstr) } 209 | .stab.excl 0 : { *(.stab.excl) } 210 | .stab.exclstr 0 : { *(.stab.exclstr) } 211 | .stab.index 0 : { *(.stab.index) } 212 | .stab.indexstr 0 : { *(.stab.indexstr) } 213 | .comment 0 : { *(.comment) } 214 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } 215 | /* DWARF debug sections. 216 | Symbols in the DWARF debugging sections are relative to the beginning 217 | of the section so we begin them at 0. */ 218 | /* DWARF 1 */ 219 | .debug 0 : { *(.debug) } 220 | .line 0 : { *(.line) } 221 | /* GNU DWARF 1 extensions */ 222 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 223 | .debug_sfnames 0 : { *(.debug_sfnames) } 224 | /* DWARF 1.1 and DWARF 2 */ 225 | .debug_aranges 0 : { *(.debug_aranges) } 226 | .debug_pubnames 0 : { *(.debug_pubnames) } 227 | /* DWARF 2 */ 228 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 229 | .debug_abbrev 0 : { *(.debug_abbrev) } 230 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } 231 | .debug_frame 0 : { *(.debug_frame) } 232 | .debug_str 0 : { *(.debug_str) } 233 | .debug_loc 0 : { *(.debug_loc) } 234 | .debug_macinfo 0 : { *(.debug_macinfo) } 235 | /* SGI/MIPS DWARF 2 extensions */ 236 | .debug_weaknames 0 : { *(.debug_weaknames) } 237 | .debug_funcnames 0 : { *(.debug_funcnames) } 238 | .debug_typenames 0 : { *(.debug_typenames) } 239 | .debug_varnames 0 : { *(.debug_varnames) } 240 | /* DWARF 3 */ 241 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 242 | .debug_ranges 0 : { *(.debug_ranges) } 243 | /* DWARF Extension. */ 244 | .debug_macro 0 : { *(.debug_macro) } 245 | .debug_addr 0 : { *(.debug_addr) } 246 | .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } 247 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 248 | } 249 | -------------------------------------------------------------------------------- /arch/riscv/elf64lriscv.xe: -------------------------------------------------------------------------------- 1 | /* taken from gcc 10.2.0 */ 2 | 3 | /* Script for -z separate-code */ 4 | /* Copyright (C) 2014-2020 Free Software Foundation, Inc. 5 | Copying and distribution of this script, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. */ 8 | OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", 9 | "elf64-littleriscv") 10 | OUTPUT_ARCH(riscv) 11 | ENTRY(_start) 12 | SECTIONS 13 | { 14 | PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x1000000)); . = SEGMENT_START("text-segment", 0x1000000) + SIZEOF_HEADERS; 15 | .interp : { *(.interp) } 16 | .note.gnu.build-id : { *(.note.gnu.build-id) } 17 | .hash : { *(.hash) } 18 | .gnu.hash : { *(.gnu.hash) } 19 | .dynsym : { *(.dynsym) } 20 | .dynstr : { *(.dynstr) } 21 | .gnu.version : { *(.gnu.version) } 22 | .gnu.version_d : { *(.gnu.version_d) } 23 | .gnu.version_r : { *(.gnu.version_r) } 24 | .rela.init : { *(.rela.init) } 25 | .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } 26 | .rela.fini : { *(.rela.fini) } 27 | .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } 28 | .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } 29 | .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } 30 | .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } 31 | .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } 32 | .rela.ctors : { *(.rela.ctors) } 33 | .rela.dtors : { *(.rela.dtors) } 34 | .rela.got : { *(.rela.got) } 35 | .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } 36 | .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } 37 | .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } 38 | .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } 39 | .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } 40 | .rela.iplt : 41 | { 42 | PROVIDE_HIDDEN (__rela_iplt_start = .); 43 | *(.rela.iplt) 44 | PROVIDE_HIDDEN (__rela_iplt_end = .); 45 | } 46 | .rela.plt : 47 | { 48 | *(.rela.plt) 49 | } 50 | . = ALIGN(CONSTANT (MAXPAGESIZE)); 51 | .init : 52 | { 53 | KEEP (*(SORT_NONE(.init))) 54 | } 55 | .plt : { *(.plt) } 56 | .iplt : { *(.iplt) } 57 | .text : 58 | { 59 | *(.text.unlikely .text.*_unlikely .text.unlikely.*) 60 | *(.text.exit .text.exit.*) 61 | *(.text.startup .text.startup.*) 62 | *(.text.hot .text.hot.*) 63 | *(SORT(.text.sorted.*)) 64 | *(.text .stub .text.* .gnu.linkonce.t.*) 65 | /* .gnu.warning sections are handled specially by elf.em. */ 66 | *(.gnu.warning) 67 | } 68 | .fini : 69 | { 70 | KEEP (*(SORT_NONE(.fini))) 71 | } 72 | PROVIDE (__etext = .); 73 | PROVIDE (_etext = .); 74 | PROVIDE (etext = .); 75 | . = ALIGN(CONSTANT (MAXPAGESIZE)); 76 | /* Adjust the address for the rodata segment. We want to adjust up to 77 | the same address within the page on the next page up. */ 78 | . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); 79 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 80 | .rodata1 : { *(.rodata1) } 81 | .sdata2 : 82 | { 83 | *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) 84 | } 85 | .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } 86 | .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } 87 | .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } 88 | .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } 89 | .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } 90 | /* These sections are generated by the Sun/Oracle C++ compiler. */ 91 | .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } 92 | /* Adjust the address for the data segment. We want to adjust up to 93 | the same address within the page on the next page up. */ 94 | . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); 95 | /* Exception handling */ 96 | .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } 97 | .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } 98 | .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } 99 | .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } 100 | /* Thread Local Storage sections */ 101 | .tdata : 102 | { 103 | PROVIDE_HIDDEN (__tdata_start = .); 104 | *(.tdata .tdata.* .gnu.linkonce.td.*) 105 | } 106 | .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } 107 | .preinit_array : 108 | { 109 | PROVIDE_HIDDEN (__preinit_array_start = .); 110 | KEEP (*(.preinit_array)) 111 | PROVIDE_HIDDEN (__preinit_array_end = .); 112 | } 113 | .init_array : 114 | { 115 | PROVIDE_HIDDEN (__init_array_start = .); 116 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 117 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 118 | PROVIDE_HIDDEN (__init_array_end = .); 119 | } 120 | .fini_array : 121 | { 122 | PROVIDE_HIDDEN (__fini_array_start = .); 123 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 124 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 125 | PROVIDE_HIDDEN (__fini_array_end = .); 126 | } 127 | .ctors : 128 | { 129 | /* gcc uses crtbegin.o to find the start of 130 | the constructors, so we make sure it is 131 | first. Because this is a wildcard, it 132 | doesn't matter if the user does not 133 | actually link against crtbegin.o; the 134 | linker won't look for a file to match a 135 | wildcard. The wildcard also means that it 136 | doesn't matter which directory crtbegin.o 137 | is in. */ 138 | KEEP (*crtbegin.o(.ctors)) 139 | KEEP (*crtbegin?.o(.ctors)) 140 | /* We don't want to include the .ctor section from 141 | the crtend.o file until after the sorted ctors. 142 | The .ctor section from the crtend file contains the 143 | end of ctors marker and it must be last */ 144 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 145 | KEEP (*(SORT(.ctors.*))) 146 | KEEP (*(.ctors)) 147 | } 148 | .dtors : 149 | { 150 | KEEP (*crtbegin.o(.dtors)) 151 | KEEP (*crtbegin?.o(.dtors)) 152 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 153 | KEEP (*(SORT(.dtors.*))) 154 | KEEP (*(.dtors)) 155 | } 156 | .jcr : { KEEP (*(.jcr)) } 157 | .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } 158 | .dynamic : { *(.dynamic) } 159 | . = DATA_SEGMENT_RELRO_END (0, .); 160 | . = ALIGN(CONSTANT (MAXPAGESIZE)); /* TG: added for alignment */ 161 | .data : 162 | { 163 | __DATA_BEGIN__ = .; 164 | *(.data .data.* .gnu.linkonce.d.*) 165 | SORT(CONSTRUCTORS) 166 | } 167 | .data1 : { *(.data1) } 168 | .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } 169 | /* We want the small data sections together, so single-instruction offsets 170 | can access them all, and initialized data all before uninitialized, so 171 | we can shorten the on-disk segment size. */ 172 | .sdata : 173 | { 174 | __SDATA_BEGIN__ = .; 175 | *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) 176 | *(.sdata .sdata.* .gnu.linkonce.s.*) 177 | } 178 | _edata = .; PROVIDE (edata = .); 179 | . = .; 180 | __bss_start = .; 181 | .sbss : 182 | { 183 | *(.dynsbss) 184 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 185 | *(.scommon) 186 | } 187 | .bss : 188 | { 189 | *(.dynbss) 190 | *(.bss .bss.* .gnu.linkonce.b.*) 191 | *(COMMON) 192 | /* Align here to ensure that the .bss section occupies space up to 193 | _end. Align after .bss to ensure correct alignment even if the 194 | .bss section disappears because there are no input sections. 195 | FIXME: Why do we need it? When there is no .bss section, we do not 196 | pad the .data section. */ 197 | . = ALIGN(. != 0 ? 64 / 8 : 1); 198 | } 199 | . = ALIGN(64 / 8); 200 | . = SEGMENT_START("ldata-segment", .); 201 | . = ALIGN(64 / 8); 202 | __BSS_END__ = .; 203 | __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, 204 | MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); 205 | _end = .; PROVIDE (end = .); 206 | . = DATA_SEGMENT_END (.); 207 | /* Stabs debugging sections. */ 208 | .stab 0 : { *(.stab) } 209 | .stabstr 0 : { *(.stabstr) } 210 | .stab.excl 0 : { *(.stab.excl) } 211 | .stab.exclstr 0 : { *(.stab.exclstr) } 212 | .stab.index 0 : { *(.stab.index) } 213 | .stab.indexstr 0 : { *(.stab.indexstr) } 214 | .comment 0 : { *(.comment) } 215 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } 216 | /* DWARF debug sections. 217 | Symbols in the DWARF debugging sections are relative to the beginning 218 | of the section so we begin them at 0. */ 219 | /* DWARF 1 */ 220 | .debug 0 : { *(.debug) } 221 | .line 0 : { *(.line) } 222 | /* GNU DWARF 1 extensions */ 223 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 224 | .debug_sfnames 0 : { *(.debug_sfnames) } 225 | /* DWARF 1.1 and DWARF 2 */ 226 | .debug_aranges 0 : { *(.debug_aranges) } 227 | .debug_pubnames 0 : { *(.debug_pubnames) } 228 | /* DWARF 2 */ 229 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 230 | .debug_abbrev 0 : { *(.debug_abbrev) } 231 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } 232 | .debug_frame 0 : { *(.debug_frame) } 233 | .debug_str 0 : { *(.debug_str) } 234 | .debug_loc 0 : { *(.debug_loc) } 235 | .debug_macinfo 0 : { *(.debug_macinfo) } 236 | /* SGI/MIPS DWARF 2 extensions */ 237 | .debug_weaknames 0 : { *(.debug_weaknames) } 238 | .debug_funcnames 0 : { *(.debug_funcnames) } 239 | .debug_typenames 0 : { *(.debug_typenames) } 240 | .debug_varnames 0 : { *(.debug_varnames) } 241 | /* DWARF 3 */ 242 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 243 | .debug_ranges 0 : { *(.debug_ranges) } 244 | /* DWARF Extension. */ 245 | .debug_macro 0 : { *(.debug_macro) } 246 | .debug_addr 0 : { *(.debug_addr) } 247 | .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } 248 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 249 | } 250 | -------------------------------------------------------------------------------- /arch/arm/armelf.xe: -------------------------------------------------------------------------------- 1 | /* Script for -z separate-code */ 2 | /* Copyright (C) 2014-2020 Free Software Foundation, Inc. 3 | Copying and distribution of this script, with or without modification, 4 | are permitted in any medium without royalty provided the copyright 5 | notice and this notice are preserved. */ 6 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", 7 | "elf32-littlearm") 8 | OUTPUT_ARCH(arm) 9 | ENTRY(_start) 10 | SEARCH_DIR("/home/geist/svn/toolchains/arm-eabi-10.2.0-Linux-x86_64/arm-eabi/lib"); 11 | SECTIONS 12 | { 13 | PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x1000000)); . = SEGMENT_START("text-segment", 0x1000000); 14 | .interp : { *(.interp) } 15 | .note.gnu.build-id : { *(.note.gnu.build-id) } 16 | .hash : { *(.hash) } 17 | .gnu.hash : { *(.gnu.hash) } 18 | .dynsym : { *(.dynsym) } 19 | .dynstr : { *(.dynstr) } 20 | .gnu.version : { *(.gnu.version) } 21 | .gnu.version_d : { *(.gnu.version_d) } 22 | .gnu.version_r : { *(.gnu.version_r) } 23 | .rel.init : { *(.rel.init) } 24 | .rela.init : { *(.rela.init) } 25 | .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } 26 | .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } 27 | .rel.fini : { *(.rel.fini) } 28 | .rela.fini : { *(.rela.fini) } 29 | .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } 30 | .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } 31 | .rel.data.rel.ro : { *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) } 32 | .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } 33 | .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } 34 | .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } 35 | .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } 36 | .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } 37 | .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } 38 | .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } 39 | .rel.ctors : { *(.rel.ctors) } 40 | .rela.ctors : { *(.rela.ctors) } 41 | .rel.dtors : { *(.rel.dtors) } 42 | .rela.dtors : { *(.rela.dtors) } 43 | .rel.got : { *(.rel.got) } 44 | .rela.got : { *(.rela.got) } 45 | .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } 46 | .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } 47 | .rel.iplt : 48 | { 49 | PROVIDE_HIDDEN (__rel_iplt_start = .); 50 | *(.rel.iplt) 51 | PROVIDE_HIDDEN (__rel_iplt_end = .); 52 | } 53 | .rela.iplt : 54 | { 55 | PROVIDE_HIDDEN (__rela_iplt_start = .); 56 | *(.rela.iplt) 57 | PROVIDE_HIDDEN (__rela_iplt_end = .); 58 | } 59 | .rel.plt : 60 | { 61 | *(.rel.plt) 62 | } 63 | .rela.plt : 64 | { 65 | *(.rela.plt) 66 | } 67 | . = ALIGN(CONSTANT (MAXPAGESIZE)); 68 | .init : 69 | { 70 | KEEP (*(SORT_NONE(.init))) 71 | } 72 | .plt : { *(.plt) } 73 | .iplt : { *(.iplt) } 74 | .text : 75 | { 76 | *(.text.unlikely .text.*_unlikely .text.unlikely.*) 77 | *(.text.exit .text.exit.*) 78 | *(.text.startup .text.startup.*) 79 | *(.text.hot .text.hot.*) 80 | *(SORT(.text.sorted.*)) 81 | *(.text .stub .text.* .gnu.linkonce.t.*) 82 | /* .gnu.warning sections are handled specially by elf.em. */ 83 | *(.gnu.warning) 84 | *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) 85 | } 86 | .fini : 87 | { 88 | KEEP (*(SORT_NONE(.fini))) 89 | } 90 | PROVIDE (__etext = .); 91 | PROVIDE (_etext = .); 92 | PROVIDE (etext = .); 93 | . = ALIGN(CONSTANT (MAXPAGESIZE)); 94 | /* Adjust the address for the rodata segment. We want to adjust up to 95 | the same address within the page on the next page up. */ 96 | . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); 97 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 98 | .rodata1 : { *(.rodata1) } 99 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } 100 | .ARM.exidx : 101 | { 102 | PROVIDE_HIDDEN (__exidx_start = .); 103 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 104 | PROVIDE_HIDDEN (__exidx_end = .); 105 | } 106 | .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } 107 | .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } 108 | .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } 109 | .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } 110 | /* These sections are generated by the Sun/Oracle C++ compiler. */ 111 | .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } 112 | /* Adjust the address for the data segment. We want to adjust up to 113 | the same address within the page on the next page up. */ 114 | . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); 115 | /* Exception handling */ 116 | .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } 117 | .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } 118 | .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } 119 | .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } 120 | /* Thread Local Storage sections */ 121 | .tdata : 122 | { 123 | PROVIDE_HIDDEN (__tdata_start = .); 124 | *(.tdata .tdata.* .gnu.linkonce.td.*) 125 | } 126 | .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } 127 | .preinit_array : 128 | { 129 | PROVIDE_HIDDEN (__preinit_array_start = .); 130 | KEEP (*(.preinit_array)) 131 | PROVIDE_HIDDEN (__preinit_array_end = .); 132 | } 133 | .init_array : 134 | { 135 | PROVIDE_HIDDEN (__init_array_start = .); 136 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 137 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 138 | PROVIDE_HIDDEN (__init_array_end = .); 139 | } 140 | .fini_array : 141 | { 142 | PROVIDE_HIDDEN (__fini_array_start = .); 143 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 144 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 145 | PROVIDE_HIDDEN (__fini_array_end = .); 146 | } 147 | .ctors : 148 | { 149 | /* gcc uses crtbegin.o to find the start of 150 | the constructors, so we make sure it is 151 | first. Because this is a wildcard, it 152 | doesn't matter if the user does not 153 | actually link against crtbegin.o; the 154 | linker won't look for a file to match a 155 | wildcard. The wildcard also means that it 156 | doesn't matter which directory crtbegin.o 157 | is in. */ 158 | KEEP (*crtbegin.o(.ctors)) 159 | KEEP (*crtbegin?.o(.ctors)) 160 | /* We don't want to include the .ctor section from 161 | the crtend.o file until after the sorted ctors. 162 | The .ctor section from the crtend file contains the 163 | end of ctors marker and it must be last */ 164 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 165 | KEEP (*(SORT(.ctors.*))) 166 | KEEP (*(.ctors)) 167 | } 168 | .dtors : 169 | { 170 | KEEP (*crtbegin.o(.dtors)) 171 | KEEP (*crtbegin?.o(.dtors)) 172 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 173 | KEEP (*(SORT(.dtors.*))) 174 | KEEP (*(.dtors)) 175 | } 176 | .jcr : { KEEP (*(.jcr)) } 177 | .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } 178 | .dynamic : { *(.dynamic) } 179 | . = ALIGN(CONSTANT (MAXPAGESIZE)); /* TG: added for alignment */ 180 | .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } 181 | .data : 182 | { 183 | __data_start = .; 184 | *(.data .data.* .gnu.linkonce.d.*) 185 | SORT(CONSTRUCTORS) 186 | } 187 | .data1 : { *(.data1) } 188 | _edata = .; PROVIDE (edata = .); 189 | . = .; 190 | __bss_start = .; 191 | __bss_start__ = .; 192 | .bss : 193 | { 194 | *(.dynbss) 195 | *(.bss .bss.* .gnu.linkonce.b.*) 196 | *(COMMON) 197 | /* Align here to ensure that the .bss section occupies space up to 198 | _end. Align after .bss to ensure correct alignment even if the 199 | .bss section disappears because there are no input sections. 200 | FIXME: Why do we need it? When there is no .bss section, we do not 201 | pad the .data section. */ 202 | . = ALIGN(. != 0 ? 32 / 8 : 1); 203 | } 204 | _bss_end__ = .; __bss_end__ = .; 205 | . = ALIGN(32 / 8); 206 | . = SEGMENT_START("ldata-segment", .); 207 | . = ALIGN(32 / 8); 208 | __end__ = .; 209 | _end = .; PROVIDE (end = .); 210 | .stack 0x80000 : 211 | { 212 | _stack = .; 213 | *(.stack) 214 | } 215 | /* Stabs debugging sections. */ 216 | .stab 0 : { *(.stab) } 217 | .stabstr 0 : { *(.stabstr) } 218 | .stab.excl 0 : { *(.stab.excl) } 219 | .stab.exclstr 0 : { *(.stab.exclstr) } 220 | .stab.index 0 : { *(.stab.index) } 221 | .stab.indexstr 0 : { *(.stab.indexstr) } 222 | .comment 0 : { *(.comment) } 223 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } 224 | /* DWARF debug sections. 225 | Symbols in the DWARF debugging sections are relative to the beginning 226 | of the section so we begin them at 0. */ 227 | /* DWARF 1 */ 228 | .debug 0 : { *(.debug) } 229 | .line 0 : { *(.line) } 230 | /* GNU DWARF 1 extensions */ 231 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 232 | .debug_sfnames 0 : { *(.debug_sfnames) } 233 | /* DWARF 1.1 and DWARF 2 */ 234 | .debug_aranges 0 : { *(.debug_aranges) } 235 | .debug_pubnames 0 : { *(.debug_pubnames) } 236 | /* DWARF 2 */ 237 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 238 | .debug_abbrev 0 : { *(.debug_abbrev) } 239 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } 240 | .debug_frame 0 : { *(.debug_frame) } 241 | .debug_str 0 : { *(.debug_str) } 242 | .debug_loc 0 : { *(.debug_loc) } 243 | .debug_macinfo 0 : { *(.debug_macinfo) } 244 | /* SGI/MIPS DWARF 2 extensions */ 245 | .debug_weaknames 0 : { *(.debug_weaknames) } 246 | .debug_funcnames 0 : { *(.debug_funcnames) } 247 | .debug_typenames 0 : { *(.debug_typenames) } 248 | .debug_varnames 0 : { *(.debug_varnames) } 249 | /* DWARF 3 */ 250 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 251 | .debug_ranges 0 : { *(.debug_ranges) } 252 | /* DWARF Extension. */ 253 | .debug_macro 0 : { *(.debug_macro) } 254 | .debug_addr 0 : { *(.debug_addr) } 255 | .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } 256 | .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } 257 | /* This section contains data that is not initialised during load 258 | *or* application reset. */ 259 | .noinit (NOLOAD) : 260 | { 261 | . = ALIGN(2); 262 | PROVIDE (__noinit_start = .); 263 | *(.noinit) 264 | . = ALIGN(2); 265 | PROVIDE (__noinit_end = .); 266 | } 267 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 268 | } 269 | --------------------------------------------------------------------------------