From 42462d5e56ba7966b3f5941e1b77136054fba3f4 Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Mon, 5 Jan 2026 17:12:25 -0500 Subject: [PATCH 1/8] Add note to assembly to quiet GNU tools complaining about executable stack. --- library/syscall.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/syscall.S b/library/syscall.S index b4676eec..35511446 100644 --- a/library/syscall.S +++ b/library/syscall.S @@ -27,3 +27,8 @@ syscall: addl $4,%esp leave ret + +# This is a GNU peculiarity which indicates that +# the stack does not need to be executable in this module. +.section .note.GNU-stack,"",@progbits + From e7eeccd7e5870c1dc040e15b5c514251f134b457 Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Mon, 5 Jan 2026 17:13:05 -0500 Subject: [PATCH 2/8] Use explicit linker script for userspace programs, to avoid unexpected behaviors from platform linking scripts. --- Makefile.config | 5 +++-- kernel/Makefile | 4 ++-- user/Makefile | 2 +- user/basekernel.user.ldscript | 21 +++++++++++++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 user/basekernel.user.ldscript diff --git a/Makefile.config b/Makefile.config index fea0f5c2..afd5bd5a 100644 --- a/Makefile.config +++ b/Makefile.config @@ -4,8 +4,8 @@ KERNEL_CCFLAGS=-Wall -c -ffreestanding -fno-pie -g -std=gnu99 # which is likely to work on native linux-x86. # CC=gcc -m32 -LD=ld -melf_i386 -#LD=ld -arch i386 +LD=ld +KERNEL_LD=ld -melf_i386 AR=ar OBJCOPY=objcopy ISOGEN=genisoimage @@ -15,6 +15,7 @@ ISOGEN=genisoimage # add cross/bin to your path, and uncomment these lines: #CC=i686-elf-gcc #LD=i686-elf-ld +#KERNEL_LD=i686-elf-ld #AR=i686-elf-ar #OBJCOPY=i686-elf-objcopy diff --git a/kernel/Makefile b/kernel/Makefile index c73677a3..82c1ccee 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,10 +12,10 @@ bootblock: bootblock.elf ${OBJCOPY} -O binary $< $@ kernel.elf: ${KERNEL_OBJECTS} - ${LD} ${KERNEL_LDFLAGS} -Ttext 0x10000 ${KERNEL_OBJECTS} -o $@ + ${KERNEL_LD} ${KERNEL_LDFLAGS} -Ttext 0x10000 ${KERNEL_OBJECTS} -o $@ bootblock.elf: bootblock.o - ${LD} ${KERNEL_LDFLAGS} -Ttext 0 $< -o $@ + ${KERNEL_LD} ${KERNEL_LDFLAGS} -Ttext 0 $< -o $@ %.o: %.c ${CC} ${KERNEL_CCFLAGS} -I ../include $< -o $@ diff --git a/user/Makefile b/user/Makefile index a2a55e20..2e224502 100644 --- a/user/Makefile +++ b/user/Makefile @@ -9,7 +9,7 @@ all: $(USER_PROGRAMS) ${CC} ${KERNEL_CCFLAGS} -I ../include $< -o $@ %.exe: %.o ../library/user-start.o ../library/baselib.a - ${LD} ${KERNEL_LDFLAGS} -Ttext 0x80000000 ../library/user-start.o $< ../library/baselib.a -o $@ + ${LD} -T basekernel.user.ldscript $< ../library/baselib.a -o $@ -Map . clean: rm -rf *.exe *.o diff --git a/user/basekernel.user.ldscript b/user/basekernel.user.ldscript new file mode 100644 index 00000000..3e8ed6c6 --- /dev/null +++ b/user/basekernel.user.ldscript @@ -0,0 +1,21 @@ +/* Linker script for userspace programs in basekernel */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +STARTUP(../library/user-start.o) + +ENTRY(_start) + +MEMORY { +RAM (rwx) : ORIGIN = 0x8000000, LENGTH = 2M +} + +SECTIONS { +.text : ALIGN(4096) { *(.text) } > RAM +.rodata : ALIGN(4096) { *(.rodata) } > RAM +.data : ALIGN(4096) { *(.data) } > RAM +.bss : ALIGN(4096) { *(.bss) } > RAM +.note : { *(.note) } > RAM +/DISCARD/ : { *(*) } +} From dc4d00f692af897e96ab98edcfc96aa38b3c7e36 Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Mon, 5 Jan 2026 17:29:31 -0500 Subject: [PATCH 3/8] Remove linker -Map argument used inconsistently. --- user/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/Makefile b/user/Makefile index 2e224502..16eb7714 100644 --- a/user/Makefile +++ b/user/Makefile @@ -9,7 +9,7 @@ all: $(USER_PROGRAMS) ${CC} ${KERNEL_CCFLAGS} -I ../include $< -o $@ %.exe: %.o ../library/user-start.o ../library/baselib.a - ${LD} -T basekernel.user.ldscript $< ../library/baselib.a -o $@ -Map . + ${LD} -T basekernel.user.ldscript $< ../library/baselib.a -o $@ clean: rm -rf *.exe *.o From 84d753707519bd5667b1a9056021f4b79787114e Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Mon, 5 Jan 2026 17:42:26 -0500 Subject: [PATCH 4/8] Missing zero, how embarrassing! --- user/basekernel.user.ldscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/basekernel.user.ldscript b/user/basekernel.user.ldscript index 3e8ed6c6..2e0218dc 100644 --- a/user/basekernel.user.ldscript +++ b/user/basekernel.user.ldscript @@ -8,7 +8,7 @@ STARTUP(../library/user-start.o) ENTRY(_start) MEMORY { -RAM (rwx) : ORIGIN = 0x8000000, LENGTH = 2M +RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 2M } SECTIONS { From d92998bdfd9d4b4b892023cd4de715fe41962e8a Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Tue, 6 Jan 2026 09:59:39 -0500 Subject: [PATCH 5/8] Update linker command line and scripts to generate executables that cleanly start at 0x8000000. --- user/Makefile | 2 +- user/basekernel.user.ldscript | 55 ++++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/user/Makefile b/user/Makefile index 16eb7714..573d9920 100644 --- a/user/Makefile +++ b/user/Makefile @@ -9,7 +9,7 @@ all: $(USER_PROGRAMS) ${CC} ${KERNEL_CCFLAGS} -I ../include $< -o $@ %.exe: %.o ../library/user-start.o ../library/baselib.a - ${LD} -T basekernel.user.ldscript $< ../library/baselib.a -o $@ + ${LD} -z max-page-size=4096 -T basekernel.user.ldscript $< ../library/baselib.a -o $@ -Map $@.map clean: rm -rf *.exe *.o diff --git a/user/basekernel.user.ldscript b/user/basekernel.user.ldscript index 2e0218dc..20229578 100644 --- a/user/basekernel.user.ldscript +++ b/user/basekernel.user.ldscript @@ -1,21 +1,54 @@ /* Linker script for userspace programs in basekernel */ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_FORMAT("elf32-i386") OUTPUT_ARCH(i386) +/* The first module in every program is the startup code of the standard library. */ STARTUP(../library/user-start.o) +/* The entry point for execution is the symbol _start found in user-start.o */ ENTRY(_start) -MEMORY { -RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 2M -} - SECTIONS { -.text : ALIGN(4096) { *(.text) } > RAM -.rodata : ALIGN(4096) { *(.rodata) } > RAM -.data : ALIGN(4096) { *(.data) } > RAM -.bss : ALIGN(4096) { *(.bss) } > RAM -.note : { *(.note) } > RAM -/DISCARD/ : { *(*) } + +/* User programs begin at 0x80000000, the top 2MB of memory. */ +. = 0x80000000; + +/* The text section contains executable code (rx) */ +.text : { *(.text) } + +/* The rodata section contains constants, strings, etc. */ +.rodata : ALIGN(CONSTANT(MAXPAGESIZE)) { *(.rodata) } + +/* The data section contains initialized values. */ +.data : ALIGN(CONSTANT(MAXPAGESIZE)) { *(.data) } + +/* The bss section describes uninitialized data. */ +/* This takes no space in the executable, but is allocated at runtime. */ +.bss : { *(.bss) } + +/* Any other miscellanous sections produced by the compiler follow here. */ } + +/* +Note there are some subtle issues about alignment here. + +The GNU linker on Linux defines COMMONPAGESIZE to be typical 4KB pages +and MAXPAGESIZE to be less-common 2MB superpages. These are controlled +by -z common-page-size and -z max-page-size on the command line, and +can be used (but not set) in this file. + +The linker attempts to page-align items in the executable +file on disk, so as to facilitate demand-paging at runtime. +It uses MAXPAGESIZE to do this by default, and so we if don't take +certain steps, the text section will be pushed to 2MB into the file, +and all of a sudden, we have huge executable files. +So, we set -z max-page-size=4096 on the command line. + +Next, we want sections with different permissions to be +4KB page-aligned, so that the kernel can made code (RX), +rodata (R), and data (RW) by apply the proper page protections. +So, the start of the rodata and data sections are aligned +to the start of the next page. +*/ + From 3e01bdee3bbf3c0595341dd6a7e6c24ab39c9ac5 Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Tue, 6 Jan 2026 11:27:20 -0500 Subject: [PATCH 6/8] Rework ELF loader to work correctly with multiple loadable segments that each may be partially initialized. --- kernel/elf.c | 134 +++++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 57 deletions(-) diff --git a/kernel/elf.c b/kernel/elf.c index c848efb4..5c591e26 100644 --- a/kernel/elf.c +++ b/kernel/elf.c @@ -52,7 +52,21 @@ struct elf_program { uint32_t align; }; +#define ELF_PROGRAM_TYPE_NULL 0 #define ELF_PROGRAM_TYPE_LOADABLE 1 +#define ELF_PROGRAM_TYPE_DYNAMIC 2 +#define ELF_PROGRAM_TYPE_INTERPRETER 3 +#define ELF_PROGRAM_TYPE_NOTE 4 +#define ELF_PROGRAM_TYPE_SHARED_LIBRARY 5 +#define ELF_PROGRAM_TYPE_PROGRAM_HEADER 6 +#define ELF_PROGRAM_TYPE_THREAD_LOCAL 7 +#define ELF_PROGRAM_TYPE_GNU_EH_FRAME 0x6474e550 +#define ELF_PROGRAM_TYPE_GNU_STACK 0x6474e551 +#define ELF_PROGRAM_TYPE_GNU_RELRO 0x6474e552 + +#define ELF_PROGRAM_FLAGS_EXEC 1 +#define ELF_PROGRAM_FLAGS_WRITE 2 +#define ELF_PROGRAM_FLAGS_READ 4 struct elf_section { uint32_t name; @@ -88,7 +102,6 @@ struct elf_section { #define ELF_SECTION_FLAGS_GROUP 512 #define ELF_SECTION_FLAGS_TLS 1024 - /* Ensure that the current process has address space up to this value. */ static int elf_ensure_address_space( struct process *p, uint32_t addr ) @@ -109,74 +122,81 @@ static int elf_ensure_address_space( struct process *p, uint32_t addr ) /* Return zero on success. */ } - + +/* Load an ELF executable into user space. */ + int elf_load(struct process *p, struct fs_dirent *d, addr_t * entry) { struct elf_header header; struct elf_program program; - struct elf_section section; int i; uint32_t actual; + /* Load the overall ELF header from the beginning of the file. */ actual = fs_dirent_read(d, (char *) &header, sizeof(header), 0); - if(actual != sizeof(header)) - goto noload; - - if(strncmp(header.ident, "\177ELF", 4) || header.machine != ELF_HEADER_MACHINE_I386 || header.version != ELF_HEADER_VERSION) - goto noexec; - - actual = fs_dirent_read(d, (char *) &program, sizeof(program), header.program_offset); - if(actual != sizeof(program)) - goto noload; - - //printf("elf: text %x bytes from offset %x at address %x length %x\n",program.file_size,program.offset,program.vaddr,program.memory_size); - - if(program.type != ELF_PROGRAM_TYPE_LOADABLE || program.vaddr < PROCESS_ENTRY_POINT || program.memory_size > 0x8000000 || program.memory_size != program.file_size) - goto noexec; - - process_data_size_set(p, program.memory_size); - - actual = fs_dirent_read(d, (char *) program.vaddr, program.memory_size, program.offset); - if(actual != program.memory_size) - goto mustdie; - - for(i = 0; i < header.shnum; i++) { - actual = fs_dirent_read(d, (char *) §ion, sizeof(section), header.section_offset + i * header.shentsize); - if(actual != sizeof(section)) - goto mustdie; - - if(section.type == ELF_SECTION_TYPE_BSS) { - /* For BSS, just clear that address space to zero. */ - actual = elf_ensure_address_space(p,section.address+section.size); - if(actual!=0) goto nomem; - memset((void *) section.address, section.size, 0); - } else if(section.type == ELF_SECTION_TYPE_PROGRAM && section.address!=0) { - /* For other loadable section types (usually data), load from file. */ - actual = elf_ensure_address_space(p,section.address+section.size); - if(actual!=0) goto nomem; - actual = fs_dirent_read(d,(char*)section.address,section.size,section.offset); - if(actual != section.size) goto mustdie; - } else { - /* skip all other section types */ - } + if(actual != sizeof(header)) { + printf("elf: unable to load elf header.\n"); + return KERROR_NOT_EXECUTABLE; } - *entry = header.entry; - return 0; + /* Bail out if the header doesnt not have the expected values. */ + if(strncmp(header.ident, "\177ELF", 4) || header.machine != ELF_HEADER_MACHINE_I386 || header.version != ELF_HEADER_VERSION) { + printf("elf: not a valid i386 executable file.\n"); + return KERROR_NOT_EXECUTABLE; + } + + /* An elf file contains a sequence of "program headers" that correspond to loadable segments. */ + for(i = 0; i < header.phnum; i++) { - noload: - printf("elf: failed to load correctly!\n"); - return KERROR_NOT_FOUND; + /* Load in the segment header itself. */ + actual = fs_dirent_read(d, (char *) &program, sizeof(program), header.program_offset + i * header.phentsize); + if(actual != sizeof(program)) { + printf("elf: unable to load segment header %d.\n",i); + return KERROR_NOT_EXECUTABLE; + } - noexec: - printf("elf: not a valid i386 ELF executable\n"); - return KERROR_NOT_EXECUTABLE; + /* Safe to skip segments that are not loadable or zero size: */ + if(program.type != ELF_PROGRAM_TYPE_LOADABLE || program.memory_size==0 ) { + continue; + } - nomem: - printf("elf: failed to allocate memory\n"); - return KERROR_OUT_OF_MEMORY; + /* Each segment must be within the expected userspace range. */ + if(program.vaddr < PROCESS_ENTRY_POINT || program.memory_size > 0x8000000) { + printf("elf: segment %d is invalid: vaddr %x size %x lies outside of user address space.\n",i,program.vaddr,program.memory_size); + return KERROR_NOT_EXECUTABLE; + } - mustdie: - printf("elf: did not load correctly\n"); - return KERROR_EXECUTION_FAILED; + /* Check for unexpected segment configuration. */ + if(program.file_size > program.memory_size) { + printf("elf: segment %d has unexpected file size %x smaller than memory size %x.\n",program.file_size,program.memory_size); + return KERROR_NOT_EXECUTABLE; + } + + + /* Expand the user address space if needed for this segment. */ + if(elf_ensure_address_space(p,program.vaddr + program.memory_size)!=0) { + printf("elf: unable to allocate memory for segment %d vaddr %x size %x\n",i,program.vaddr,program.memory_size); + return KERROR_OUT_OF_MEMORY; + } + + /* If some (or all) of this segment is on disk, load it in. */ + if(program.file_size>0) { + actual = fs_dirent_read(d, (char *) program.vaddr, program.file_size, program.offset); + if(actual != program.file_size) { + printf("elf: unable to load segment %d from disk.\n"); + return KERROR_NOT_EXECUTABLE; + } + } + + /* If the remainder (or all) of this segment is BSS, initialize it. */ + if(program.memory_size>program.file_size) { + memset( (char*) (program.vaddr+program.file_size), program.memory_size-program.file_size, 0 ); + } + + /* XXX Set page table bits here. */ + } + + /* Capture the program entry point for the caller to use. */ + *entry = header.entry; + return 0; } From fcfa0980019e88212395199e48de9d855ba75038 Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Tue, 6 Jan 2026 11:31:33 -0500 Subject: [PATCH 7/8] Align bss section independently, so that it is not combined with prior sections. --- user/basekernel.user.ldscript | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/user/basekernel.user.ldscript b/user/basekernel.user.ldscript index 20229578..5eaf35ef 100644 --- a/user/basekernel.user.ldscript +++ b/user/basekernel.user.ldscript @@ -25,7 +25,7 @@ SECTIONS { /* The bss section describes uninitialized data. */ /* This takes no space in the executable, but is allocated at runtime. */ -.bss : { *(.bss) } +.bss : ALIGN(CONSTANT(MAXPAGESIZE)) { *(.bss) } /* Any other miscellanous sections produced by the compiler follow here. */ } @@ -49,6 +49,8 @@ Next, we want sections with different permissions to be 4KB page-aligned, so that the kernel can made code (RX), rodata (R), and data (RW) by apply the proper page protections. So, the start of the rodata and data sections are aligned -to the start of the next page. +to the start of the next page. Each must be separately +aligned, so that if one is eliminated, those following +are not combined with the text segment. */ From a9ea785c7a2c8bd079ffa8c4076c0695ce5853df Mon Sep 17 00:00:00 2001 From: Douglas Thain Date: Wed, 7 Jan 2026 13:52:13 -0500 Subject: [PATCH 8/8] Separate elf definition in elf.h and process loader in loader.[ch] --- kernel/Makefile | 2 +- kernel/elf.h | 99 ++++++++++++++++++++++++++++++++++---- kernel/{elf.c => loader.c} | 99 ++------------------------------------ kernel/loader.h | 23 +++++++++ kernel/syscall_handler.c | 8 +-- 5 files changed, 122 insertions(+), 109 deletions(-) rename kernel/{elf.c => loader.c} (57%) create mode 100644 kernel/loader.h diff --git a/kernel/Makefile b/kernel/Makefile index 82c1ccee..870be7f2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,6 +1,6 @@ include ../Makefile.config -KERNEL_OBJECTS=kernelcore.o main.o console.o page.o keyboard.o mouse.o event_queue.o clock.o interrupt.o kmalloc.o pic.o ata.o cdromfs.o string.o bitmap.o graphics.o font.o syscall_handler.o process.o mutex.o list.o pagetable.o rtc.o kshell.o fs.o hash_set.o diskfs.o serial.o elf.o device.o kobject.o pipe.o bcache.o printf.o is_valid.o window.o +KERNEL_OBJECTS=kernelcore.o main.o console.o page.o keyboard.o mouse.o event_queue.o clock.o interrupt.o kmalloc.o pic.o ata.o cdromfs.o string.o bitmap.o graphics.o font.o syscall_handler.o process.o mutex.o list.o pagetable.o rtc.o kshell.o fs.o hash_set.o diskfs.o serial.o loader.o device.o kobject.o pipe.o bcache.o printf.o is_valid.o window.o basekernel.img: bootblock kernel cat bootblock kernel /dev/zero | head -c 1474560 > basekernel.img diff --git a/kernel/elf.h b/kernel/elf.h index 8fd47b5d..3365c060 100644 --- a/kernel/elf.h +++ b/kernel/elf.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2015-2019 The University of Notre Dame +Copyright (C) 2015-2025 The University of Notre Dame This software is distributed under the GNU General Public License. See the file LICENSE for details. */ @@ -8,16 +8,95 @@ See the file LICENSE for details. #define ELF_H #include "kernel/types.h" -#include "process.h" -#include "fs.h" -/* -elf_load opens the given filename, and if it contains a valid -ELF executable, allocates space in the current process' pagetable, -loads the text, data, and bss into memory, and updates the -entry point value in the current process structure. -*/ +struct elf_header { + char ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t program_offset; + uint32_t section_offset; + uint32_t flags; + uint16_t header_size; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +#define ELF_HEADER_TYPE_NONE 0 +#define ELF_HEADER_TYPE_OBJECT 1 +#define ELF_HEADER_TYPE_EXECUTABLE 2 +#define ELF_HEADER_TYPE_DYNAMIC 3 +#define ELF_HEADER_TYPE_CORE 4 + +#define ELF_HEADER_MACHINE_I386 3 +#define ELF_HEADER_MACHINE_ARM 40 +#define ELF_HEADER_MACHINE_X86_64 62 + +#define ELF_HEADER_VERSION 1 + +struct elf_program { + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t file_size; + uint32_t memory_size; + uint32_t flags; + uint32_t align; +}; + +#define ELF_PROGRAM_TYPE_NULL 0 +#define ELF_PROGRAM_TYPE_LOADABLE 1 +#define ELF_PROGRAM_TYPE_DYNAMIC 2 +#define ELF_PROGRAM_TYPE_INTERPRETER 3 +#define ELF_PROGRAM_TYPE_NOTE 4 +#define ELF_PROGRAM_TYPE_SHARED_LIBRARY 5 +#define ELF_PROGRAM_TYPE_PROGRAM_HEADER 6 +#define ELF_PROGRAM_TYPE_THREAD_LOCAL 7 +#define ELF_PROGRAM_TYPE_GNU_EH_FRAME 0x6474e550 +#define ELF_PROGRAM_TYPE_GNU_STACK 0x6474e551 +#define ELF_PROGRAM_TYPE_GNU_RELRO 0x6474e552 + +#define ELF_PROGRAM_FLAGS_EXEC 1 +#define ELF_PROGRAM_FLAGS_WRITE 2 +#define ELF_PROGRAM_FLAGS_READ 4 + +struct elf_section { + uint32_t name; + uint32_t type; + uint32_t flags; + uint32_t address; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t info; + uint32_t alignment; + uint32_t entry_size; +}; + +#define ELF_SECTION_TYPE_NULL 0 +#define ELF_SECTION_TYPE_PROGRAM 1 +#define ELF_SECTION_TYPE_SYMBOL_TABLE 2 +#define ELF_SECTION_TYPE_STRING_TABLE 3 +#define ELF_SECTION_TYPE_RELA 4 +#define ELF_SECTION_TYPE_HASH 5 +#define ELF_SECTION_TYPE_DYNAMIC 6 +#define ELF_SECTION_TYPE_NOTE 7 +#define ELF_SECTION_TYPE_BSS 8 -int elf_load(struct process *p, struct fs_dirent *d, addr_t * entry); +#define ELF_SECTION_FLAGS_WRITE 1 +#define ELF_SECTION_FLAGS_MEMORY 2 +#define ELF_SECTION_FLAGS_EXEC 8 +#define ELF_SECTION_FLAGS_MERGE 16 +#define ELF_SECTION_FLAGS_STRINGS 32 +#define ELF_SECTION_FLAGS_INFO_LINK 64 +#define ELF_SECTION_FLAGS_LINK_ORDER 128 +#define ELF_SECTION_FLAGS_NONSTANDARD 256 +#define ELF_SECTION_FLAGS_GROUP 512 +#define ELF_SECTION_FLAGS_TLS 1024 #endif diff --git a/kernel/elf.c b/kernel/loader.c similarity index 57% rename from kernel/elf.c rename to kernel/loader.c index 5c591e26..53e21134 100644 --- a/kernel/elf.c +++ b/kernel/loader.c @@ -1,9 +1,10 @@ /* -Copyright (C) 2015-2019 The University of Notre Dame +Copyright (C) 2015-2025 The University of Notre Dame This software is distributed under the GNU General Public License. See the file LICENSE for details. */ +#include "loader.h" #include "elf.h" #include "fs.h" #include "string.h" @@ -12,99 +13,9 @@ See the file LICENSE for details. #include "kernel/syscall.h" #include "memorylayout.h" -struct elf_header { - char ident[16]; - uint16_t type; - uint16_t machine; - uint32_t version; - uint32_t entry; - uint32_t program_offset; - uint32_t section_offset; - uint32_t flags; - uint16_t header_size; - uint16_t phentsize; - uint16_t phnum; - uint16_t shentsize; - uint16_t shnum; - uint16_t shstrndx; -}; - -#define ELF_HEADER_TYPE_NONE 0 -#define ELF_HEADER_TYPE_OBJECT 1 -#define ELF_HEADER_TYPE_EXECUTABLE 2 -#define ELF_HEADER_TYPE_DYNAMIC 3 -#define ELF_HEADER_TYPE_CORE 4 - -#define ELF_HEADER_MACHINE_I386 3 -#define ELF_HEADER_MACHINE_ARM 40 -#define ELF_HEADER_MACHINE_X86_64 62 - -#define ELF_HEADER_VERSION 1 - -struct elf_program { - uint32_t type; - uint32_t offset; - uint32_t vaddr; - uint32_t paddr; - uint32_t file_size; - uint32_t memory_size; - uint32_t flags; - uint32_t align; -}; - -#define ELF_PROGRAM_TYPE_NULL 0 -#define ELF_PROGRAM_TYPE_LOADABLE 1 -#define ELF_PROGRAM_TYPE_DYNAMIC 2 -#define ELF_PROGRAM_TYPE_INTERPRETER 3 -#define ELF_PROGRAM_TYPE_NOTE 4 -#define ELF_PROGRAM_TYPE_SHARED_LIBRARY 5 -#define ELF_PROGRAM_TYPE_PROGRAM_HEADER 6 -#define ELF_PROGRAM_TYPE_THREAD_LOCAL 7 -#define ELF_PROGRAM_TYPE_GNU_EH_FRAME 0x6474e550 -#define ELF_PROGRAM_TYPE_GNU_STACK 0x6474e551 -#define ELF_PROGRAM_TYPE_GNU_RELRO 0x6474e552 - -#define ELF_PROGRAM_FLAGS_EXEC 1 -#define ELF_PROGRAM_FLAGS_WRITE 2 -#define ELF_PROGRAM_FLAGS_READ 4 - -struct elf_section { - uint32_t name; - uint32_t type; - uint32_t flags; - uint32_t address; - uint32_t offset; - uint32_t size; - uint32_t link; - uint32_t info; - uint32_t alignment; - uint32_t entry_size; -}; - -#define ELF_SECTION_TYPE_NULL 0 -#define ELF_SECTION_TYPE_PROGRAM 1 -#define ELF_SECTION_TYPE_SYMBOL_TABLE 2 -#define ELF_SECTION_TYPE_STRING_TABLE 3 -#define ELF_SECTION_TYPE_RELA 4 -#define ELF_SECTION_TYPE_HASH 5 -#define ELF_SECTION_TYPE_DYNAMIC 6 -#define ELF_SECTION_TYPE_NOTE 7 -#define ELF_SECTION_TYPE_BSS 8 - -#define ELF_SECTION_FLAGS_WRITE 1 -#define ELF_SECTION_FLAGS_MEMORY 2 -#define ELF_SECTION_FLAGS_EXEC 8 -#define ELF_SECTION_FLAGS_MERGE 16 -#define ELF_SECTION_FLAGS_STRINGS 32 -#define ELF_SECTION_FLAGS_INFO_LINK 64 -#define ELF_SECTION_FLAGS_LINK_ORDER 128 -#define ELF_SECTION_FLAGS_NONSTANDARD 256 -#define ELF_SECTION_FLAGS_GROUP 512 -#define ELF_SECTION_FLAGS_TLS 1024 - /* Ensure that the current process has address space up to this value. */ -static int elf_ensure_address_space( struct process *p, uint32_t addr ) +static int loader_ensure_address_space( struct process *p, uint32_t addr ) { /* Size of user data area, ignoring start addr */ uint32_t limit = addr - PROCESS_ENTRY_POINT; @@ -125,7 +36,7 @@ static int elf_ensure_address_space( struct process *p, uint32_t addr ) /* Load an ELF executable into user space. */ -int elf_load(struct process *p, struct fs_dirent *d, addr_t * entry) +int loader_load_process(struct process *p, struct fs_dirent *d, addr_t * entry) { struct elf_header header; struct elf_program program; @@ -174,7 +85,7 @@ int elf_load(struct process *p, struct fs_dirent *d, addr_t * entry) /* Expand the user address space if needed for this segment. */ - if(elf_ensure_address_space(p,program.vaddr + program.memory_size)!=0) { + if(loader_ensure_address_space(p,program.vaddr + program.memory_size)!=0) { printf("elf: unable to allocate memory for segment %d vaddr %x size %x\n",i,program.vaddr,program.memory_size); return KERROR_OUT_OF_MEMORY; } diff --git a/kernel/loader.h b/kernel/loader.h new file mode 100644 index 00000000..45d5cd08 --- /dev/null +++ b/kernel/loader.h @@ -0,0 +1,23 @@ +/* +Copyright (C) 2015-2025 The University of Notre Dame +This software is distributed under the GNU General Public License. +See the file LICENSE for details. +*/ + +#ifndef LOADER_H +#define LOADER_H + +#include "process.h" +#include "fs.h" + +/* +loader_load_process reads the given file object, +and if it contains a valid ELF executable, loads +the segments of the executable into the process +address space, returning the executable entry point +in the argument "entry". +*/ + +int loader_load_process(struct process *p, struct fs_dirent *d, addr_t * entry); + +#endif diff --git a/kernel/syscall_handler.c b/kernel/syscall_handler.c index f1bda5e6..ee6793eb 100644 --- a/kernel/syscall_handler.c +++ b/kernel/syscall_handler.c @@ -21,7 +21,7 @@ See the file LICENSE for details. #include "pagetable.h" #include "clock.h" #include "rtc.h" -#include "elf.h" +#include "loader.h" #include "kmalloc.h" #include "page.h" #include "ata.h" @@ -119,7 +119,7 @@ int sys_process_run( int fd, int argc, const char **argv) /* Attempt to load the program image. */ addr_t entry; - int r = elf_load(p, k->data.file, &entry); + int r = loader_load_process(p, k->data.file, &entry); if(r >= 0) { /* If load succeeded, reset stack and pass arguments */ process_stack_reset(p, PAGE_SIZE); @@ -168,7 +168,7 @@ int sys_process_wrun( int fd, int argc, const char **argv, int *fds, int fd_len) /* Attempt to load the program image. */ addr_t entry; - int r = elf_load(p, k->data.file, &entry); + int r = loader_load_process(p, k->data.file, &entry); if(r >= 0) { /* If load succeeded, reset stack and pass arguments */ process_stack_reset(p, PAGE_SIZE); @@ -207,7 +207,7 @@ int sys_process_exec( int fd, int argc, const char **argv) char **copy_argv = argv_copy(argc, argv); /* Attempt to load the program image into this process. */ - int r = elf_load(current, k->data.file, &entry); + int r = loader_load_process(current, k->data.file, &entry); /* On failure, return only if our address space is not corrupted. */ if(r < 0) {