diff --git a/Makefile b/Makefile index 62c82eb14aedee2fef964cd9fb823e50ff3357cc..ff17e1d2166b9e4026ff91454318ec1adeb3d22c 100644 --- a/Makefile +++ b/Makefile @@ -258,6 +258,7 @@ PERL = perl PYTHON = python CHECK = sparse + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void $(CF) NOSTDINC_FLAGS = @@ -596,14 +597,43 @@ leanos-kernel := $(patsubst %/, %/built-in.o, $(kernel-y)) leanos-init := $(patsubst %/, %/built-in.o, $(init-y)) leanos-libs := $(patsubst %/, %/lib.a, $(libs-y)) -leanos-deps := $(leanos-init) $(leanos-core) $(leanos-kernel) $(leanos-libs) + +# Externally visible symbols (used by link-leanos.sh) +export KBUILD_LEANOS_INIT := $(leanos-init) +export KBUILD_LEANOS_MAIN := $(leanos-core) $(leanos-kernel) $(leanos-libs) +export KBUILD_LDS := arch/$(SRCARCH)/kernel/leanos.lds +export LDFLAGS_leanos + + +leanos-deps := $(KBUILD_LDS) $(KBUILD_LEANOS_INIT) $(KBUILD_LEANOS_MAIN) quiet_cmd_leanos = LD $@ cmd_leanos = $(CC) $(LDFLAGS) -o $@ \ -Wl,--start-group $(leanos-deps) -Wl,--end-group -leanos: $(leanos-deps) FORCE - +$(call if_changed,leanos) + + +PHONY += leanos_prereq +leanos_prereq: $(leanos-deps) FORCE + +ifdef CONFIG_TRIM_UNUSED_KSYMS + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \ + "$(MAKE) -f $(srctree)/Makefile leanos" +endif + +# standalone target for easier testing +include/generated/autoksyms.h: FORCE + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh true + +# Final link of vmlinux with optional arch pass after final link + cmd_link-leanos = \ + $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_leanos); + + +leanos: leanos_prereq + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-leanos.sh + + # Build samples along the rest of the kernel ifdef CONFIG_SAMPLES @@ -797,17 +827,20 @@ clean: rm-dirs := $(CLEAN_DIRS) clean: rm-files := $(CLEAN_FILES) clean-dirs := $(addprefix _clean_, . $(leanos-dirs)) +leanosclean: + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-leanos.sh clean + PHONY += $(clean-dirs) clean archclean $(clean-dirs): $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) -clean: $(clean-dirs) +clean: $(clean-dirs) leanosclean $(call cmd,rmdirs) $(call cmd,rmfiles) @find . $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '*.ko.*' \ - -o -name '.*.d' -o -name '.*.tmp' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ -o -name modules.builtin -o -name '.tmp_*.o.*' \ -o -name '*.gcno' \) -type f -print | xargs rm -f diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index d91ba92498f984fa9ac95c7165e31f4ffcb32975..48692145a056402dc1b4dc5c68fafe0d049dbba1 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -7,5 +7,7 @@ obj-y += init.o obj-y += page.o obj-y += bootmem.o obj-y += mm.o +obj-y += elf.o +obj-y += module.o #libs-y += lib/ diff --git a/arch/sparc/kernel/elf.c b/arch/sparc/kernel/elf.c new file mode 100644 index 0000000000000000000000000000000000000000..f886290d2255cebca2129fbcf91739a79ab0823e --- /dev/null +++ b/arch/sparc/kernel/elf.c @@ -0,0 +1,50 @@ +#include <kernel/elf.h> + + + + + + +/** + * @brief check if the ELF file can be used by us + */ + +int elf_header_check(Elf_Ehdr *ehdr) +{ + if (ehdr->e_shentsize != sizeof(Elf_Shdr)) + return -1; + + if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0)) + return -1; + + if (!(ehdr->e_ident[EI_MAG1] == ELFMAG1)) + return -1; + + if (!(ehdr->e_ident[EI_MAG2] == ELFMAG2)) + return -1; + + if (!(ehdr->e_ident[EI_MAG3] == ELFMAG3)) + return -1; + + if (!(ehdr->e_ident[EI_CLASS] == ELFCLASS32)) + if (!(ehdr->e_ident[EI_CLASS] == ELFCLASS64)) + return -1; + + if (!elf_check_endian(ehdr)) + return -1; + + if (!(ehdr->e_ident[EI_VERSION] == EV_CURRENT)) + return -1; + + /* .o files only */ + if (!(ehdr->e_type == ET_REL)) + return -1; + + if(!elf_check_arch(ehdr)) + return -1; + + if (!(ehdr->e_version == EV_CURRENT)) + return -1; + + return 0; +} diff --git a/arch/sparc/kernel/leanos.lds b/arch/sparc/kernel/leanos.lds new file mode 100644 index 0000000000000000000000000000000000000000..bb8f380f01c3b9c38636470e3116845d7a19191c --- /dev/null +++ b/arch/sparc/kernel/leanos.lds @@ -0,0 +1 @@ +OUTPUT_FORMAT("elf32-sparc") diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c new file mode 100644 index 0000000000000000000000000000000000000000..7189813918a83b317bbd214e92f2ee2ad4ae270d --- /dev/null +++ b/arch/sparc/kernel/module.c @@ -0,0 +1,102 @@ +#include <kernel/module.h> +#include <kernel/printk.h> +#include <kernel/err.h> + + +/** + * @brief apply relocation + addend + * + * @param m an ELF module + * @param rel an ELF relocation entry + * @param sym the address of the target symbol + * + * return 0 on success + */ + +int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym) +{ + Elf_Addr rsym; + + uint8_t *loc8; + uint32_t *loc32; + + struct module_section *text; + + + + if (!m) + return -EINVAL; + + if (!rel) + return -EINVAL; + + if (!sym) + return -EINVAL; + + + + text = find_mod_sec(m, ".text"); + + loc8 = (uint8_t *) (text->addr + rel->r_offset); + loc32 = (uint32_t *) loc8; + + + /* the symbol address it is referring to */ + rsym = sym + rel->r_addend; + + + /* SPARC relocations are annoying, these are just the most common ones, + * add as needed + * http://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html + */ + + switch (ELF_R_TYPE(rel->r_info) & 0xff) { + case R_SPARC_DISP32: /* S + A - P */ + pr_debug("\tREL type R_SPARC_DISP32\n"); + rsym -= (Elf_Addr) loc8; + (*loc32) = rsym; + break; + + case R_SPARC_32: /* S + A */ + case R_SPARC_UA32: /* L + A */ + pr_debug("\tREL type R_SPARC_(UA)32\n"); + loc8[0] = rsym >> 24; + loc8[1] = rsym >> 16; + loc8[2] = rsym >> 8; + loc8[3] = rsym >> 0; + break; + + case R_SPARC_WDISP30: /* (S + A - P) >> 2 */ + pr_debug("\tREL type R_SPARC_WDISP30\n"); + rsym -= (Elf_Addr) loc8; + (*loc32) = ((*loc32) & ~(((1 << 30)) - 1)) | + ((rsym >> 2) & ((1 << 30) - 1)); + break; + + case R_SPARC_WDISP22: + pr_debug("\tREL type R_SPARC_WDISP22\n"); + rsym -= (Elf_Addr) loc8; + (*loc32) = ((*loc32) & ~(((1 << 22)) - 1)) | + ((rsym >> 2) & ((1 << 22) - 1)); + break; + + case R_SPARC_HI22: + pr_debug("\tREL type R_SPARC_HI22\n"); + (*loc32) = ((*loc32) & ~(((1 << 22)) - 1)) | + ((rsym >> 10) & ((1 << 22) - 1)); + break; + + case R_SPARC_LO10: + pr_debug("\tREL type R_SPARC_LO10\n"); + (*loc32) = ((*loc32) & ~(((1 << 10)) - 1)) | + (rsym & ((1 << 10) - 1)); + break; + + default: + pr_err("\tUnsupported relocation type: %x\n", + (ELF_R_TYPE(rel->r_info) & 0xff)); + return -ENOEXEC; + } + + return 0; +} diff --git a/include/kernel/elf.h b/include/kernel/elf.h new file mode 100644 index 0000000000000000000000000000000000000000..d51bde0380432fa61da4628f13cebaae41a5a5ec --- /dev/null +++ b/include/kernel/elf.h @@ -0,0 +1,568 @@ +#ifndef _KERNEL_ELF_H_ +#define _KERNEL_ELF_H_ + + +#include <stdint.h> +#include <stddef.h> + +/* some ELF constants&stuff ripped from include/uapi/linux/elf.h */ + + +/* 32-bit base types */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit base types */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + + +__extension__ +typedef struct elf32_dyn { + Elf32_Sword d_tag; /* dynamic array tag */ + union{ + Elf32_Sword d_val; + Elf32_Addr d_ptr; /* program virtual address */ + }; +} Elf32_Dyn; + +__extension__ +typedef struct elf64_dyn { + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + }; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define ELF64_R_SYM(x) ((x) >> 32) +#define ELF64_R_TYPE(x) ((x) & 0xffffffff) + +/* Dynamic Array Tags */ +#define DT_NULL 0 /* end of _DYNAMIC array */ +#define DT_NEEDED 1 /* str tbl offset of needed librart */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string tbl offset of shared obj */ +#define DT_RPATH 15 /* str tbl offset of lib search path */ +#define DT_SYMBOLIC 16 /* start symbol search in shared obj */ +#define DT_REL 17 /* address of reloc tbl with addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* used for debugging */ +#define DT_TEXTREL 22 /* allow reloc mod to unwritable seg */ +#define DT_JMPREL 23 /* addr of PLT's relocation entries */ +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + + +/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONLFAT 0x00002000 + +/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */ +#define DT_NUM (DT_JMPREL+1) + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + + + +typedef struct elf32_rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + + +/* relocs as needed */ +#define R_AMD64_NONE 0 +#define R_AMD64_RELATIVE 8 + + + + +typedef struct elf32_sym{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym { + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + + + + + + + + + + + + + + +/* + * Note Definitions + */ +typedef struct { + Elf32_Word namesz; + Elf32_Word descsz; + Elf32_Word type; +} Elf32_Note; + +typedef struct { + Elf64_Half namesz; + Elf64_Half descsz; + Elf64_Half type; +} Elf64_Note; + + + + + +/** + * e_ident[] identification indexes + */ + +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI ID */ +#define EI_ABIVERSION 8 /* ABI version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* size of e_ident[] */ + +/* e_ident[] magic numbers */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file classes */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASS32 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] Operating System/ABI */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + + +/* e_version */ +#define EV_NONE 0 +#define EV_CURRENT 1 +#define EV_NUM 2 /* number of versions */ + +/* e_type */ +#define ET_NONE 0 +#define ET_REL 1 /* relocatable */ +#define ET_EXEC 2 /* executable */ +#define ET_DYN 3 /* shared object*/ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 - unused? */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_PPC 20 /* PowerPC */ +#define EM_ARM 40 /* ARM AArch32 */ +#define EM_ALPHA 41 /* DEC ALPHA */ +#define EM_SH 42 /* Hitachi/Renesas Super-H */ +#define EM_SPARCV9 43 /* SPARC version 9 */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_AMD64 62 /* AMD64 architecture */ +#define EM_VAX 75 /* DEC VAX */ +#define EM_AARCH64 183 /* ARM AArch64 */ + + +/* ELF32 Header */ +typedef struct elf32_hdr{ + unsigned char e_ident[EI_NIDENT]; /* ELF identifier */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine type */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* entry point */ + Elf32_Off e_phoff; /* program header offset */ + Elf32_Off e_shoff; /* section header offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program headers */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section headers */ + Elf32_Half e_shstrndx; /* string table index */ +} Elf32_Ehdr; + +/* ELF64 Header */ +typedef struct elf64_hdr{ + unsigned char e_ident[EI_NIDENT]; /* ELF identifier */ + Elf64_Half e_type; /* object file type */ + Elf64_Half e_machine; /* machine type */ + Elf64_Word e_version; /* object file version */ + Elf64_Addr e_entry; /* entry point */ + Elf64_Off e_phoff; /* program header offset */ + Elf64_Off e_shoff; /* section header offset */ + Elf64_Word e_flags; /* processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* program header entry size */ + Elf64_Half e_phnum; /* number of program headers */ + Elf64_Half e_shentsize; /* section header entry size */ + Elf64_Half e_shnum; /* number of section headers */ + Elf64_Half e_shstrndx; /* string table index */ +} Elf64_Ehdr; + + +/* ELF32 Program Header */ +typedef struct elf32_phdr{ + Elf32_Word p_type; /* entry type */ + Elf32_Off p_flags; /* flags */ + Elf32_Addr p_offset; /* file offset */ + Elf32_Addr p_vaddr; /* virtual address */ + Elf32_Word p_paddr; /* physical address */ + Elf32_Word p_filesz; /* size in file */ + Elf32_Word p_memsz; /* size in memory */ + Elf32_Word p_align; /* alignment, file & memory */ +} Elf32_Phdr; + +/* ELF64 Program Header */ +typedef struct elf64_phdr { + Elf64_Word p_type; /* entry type */ + Elf64_Word p_flags; /* flags */ + Elf64_Off p_offset; /* file offset */ + Elf64_Addr p_vaddr; /* virtual address */ + Elf64_Addr p_paddr; /* physical address */ + Elf64_Xword p_filesz; /* size in file */ + Elf64_Xword p_memsz; /* size in memory */ + Elf64_Xword p_align; /* alignment, file & memory */ +} Elf64_Phdr; + + +/* Program entry types */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_TLS 7 /* thread local storage */ +#define PT_LOOS 0x60000000 /* reserved range for OS */ +#define PT_HIOS 0x6fffffff /* specific segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + + +/* ELF32 Section Header */ +typedef struct elf32_shdr { + Elf32_Word sh_name; /* section name index */ + Elf32_Word sh_type; /* section type */ + Elf32_Word sh_flags; /* section flags */ + Elf32_Addr sh_addr; /* (virtual) address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* link to other section header */ + Elf32_Word sh_info; /* misc info */ + Elf32_Word sh_addralign; /* memory address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +/* ELF64 Section Header */ +typedef struct elf64_shdr { + Elf64_Word sh_name; /* section name */ + Elf64_Word sh_type; /* section type */ + Elf64_Xword sh_flags; /* section flags */ + Elf64_Addr sh_addr; /* (virtual) address */ + Elf64_Off sh_offset; /* file offset */ + Elf64_Xword sh_size; /* section size */ + Elf64_Word sh_link; /* link to other section header */ + Elf64_Word sh_info; /* misc info */ + Elf64_Xword sh_addralign; /* memory address alignment */ + Elf64_Xword sh_entsize; /* section entry size */ +} Elf64_Shdr; + + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_TEXT ".text" /* code */ + + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_TLS 0x400 /* thread local storage */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor + * specific section attributes */ + + +/* Sparc ELF relocation types */ +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + + + + +/* end of ELF stuff */ + + + +/* begin configurable section */ + +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Dyn Elf_Dyn; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; +typedef Elf32_Off Elf_Off; +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Sym Elf_Sym; + +#define ELF_R_SYM(x) ELF32_R_SYM(x) +#define ELF_R_TYPE(x) ELF32_R_TYPE(x) + + + +/** + * NOTE: no free configuration, limited to 32bit ELF, SPARCv8, big endian, + * because I am lazy :) + */ +#if 1 +#define ELF_ENDIAN ELFDATA2MSB +#define EM_MACHINE EM_SPARC +#else +#define ELF_ENDIAN ELFDATA2LSB +#define EM_MACHINE EM_AMD64 +#endif + + +#define elf_check_arch(x) ((x)->e_machine == EM_MACHINE) +#define elf_check_endian(x) ((x)->e_ident[EI_DATA] == ELF_ENDIAN) + + +/* implemented in arch code */ +int elf_header_check(Elf_Ehdr *ehdr); + + +#endif /* _KERNEL_ELF_H_ */ diff --git a/include/kernel/ksym.h b/include/kernel/ksym.h new file mode 100644 index 0000000000000000000000000000000000000000..bcb8e7398f1f74b1e7bce95f4cea95deb17ef401 --- /dev/null +++ b/include/kernel/ksym.h @@ -0,0 +1,15 @@ +#ifndef _KERNEL_KSYM_H_ +#define _KERNEL_KSYM_H_ + + + +struct ksym { + char *name; + void *addr; +}; + +extern struct ksym __ksyms[]; + +void *lookup_symbol(const char *name); + +#endif /* _KERNEL_KSYM_H_ */ diff --git a/include/kernel/module.h b/include/kernel/module.h new file mode 100644 index 0000000000000000000000000000000000000000..c2d7ff629d4cbc8a93b7b0766aea87f00ecb4407 --- /dev/null +++ b/include/kernel/module.h @@ -0,0 +1,50 @@ +#ifndef _KERNEL_MODULE_H_ +#define _KERNEL_MODULE_H_ + + +#include <kernel/elf.h> + + +struct module_section { + char *name; + unsigned long addr; + size_t size; +}; + + +struct elf_module { + + unsigned long pa; + unsigned long va; + + + unsigned int align; + + Elf_Ehdr *ehdr; /* coincides with start of module image */ + Elf_Shdr *shdr; + Elf_Dyn *dyn; + + size_t size; + size_t dyn_size; + size_t sh_size; + size_t str_size; + + char *dyn_str; /* dynamic symbols string tab */ + char *sh_str; /* section header string tab */ + char *str; /* stringtab */ + + struct module_section *sec; + size_t num_sec; +}; + + + +/* implemented in architecture code */ +int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym); + + + +struct module_section *find_mod_sec(const struct elf_module *m, + const char *name); + +#endif /* _KERNEL_MODULE_H_ */ diff --git a/init/Kconfig b/init/Kconfig index 0c6330919084c7337816283c4327555e4101b2cd..5cd3ad80058f6e9d30e90633f538e6ab30631121 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -10,6 +10,16 @@ config KERNELVERSION menu "General Setup" +config KALLSYMS + bool "Generate a kernel symbol table" + default y + help + Create a kernel image symbol lookup table for use in loadable modules. + Note: If disabled, modules can still export symbols for other modules + to use, but no kernel functions will be resolvable. + If unsure, say Y. + + config CROSS_PLATFORM_TARGET bool "Cross-compile for different platform" default y @@ -34,6 +44,7 @@ config TARGET_COMPILER_BOOT_CODE endmenu # "General Setup" + menuconfig MODULES bool "Enable loadable module support" option modules diff --git a/init/main.c b/init/main.c index 0cf06ba4b8122c9a652f6788c8cb2e8998a19395..6004c42a810378a4d7d26df48dc490a35e1cc91b 100644 --- a/init/main.c +++ b/init/main.c @@ -6,6 +6,14 @@ #include <kernel/init.h> +#include <kernel/module.h> /* module_load */ + +#include <kernel/ksym.h> /* lookup_symbol */ + +#include <kernel/printk.h> + + +int module_load(struct elf_module *m, void *p); static void kernel_init(void) { @@ -17,8 +25,18 @@ static void kernel_init(void) int main(void) { + + struct elf_module m; + kernel_init(); + printk("%s at %p\n", "printk", lookup_symbol("printk")); + printk("%s at %p\n", "printf", lookup_symbol("printf")); + + + module_load(&m, (char *) 0xA0000000); + /* load -binary kernel/test.ko 0xA0000000 */ + return 0; } diff --git a/kernel/Makefile b/kernel/Makefile index fdb120a68f61faa27947be87b621445c16df00de..a0d25eacf0a7bf304ba1e64229a2171bc484e981 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,2 +1,5 @@ +obj-y += ksym.o obj-y += printk.o obj-y += bitmap.o +obj-y += module.o +obj-m += testmodule.o diff --git a/kernel/ksym.c b/kernel/ksym.c new file mode 100644 index 0000000000000000000000000000000000000000..c5a60d1626270e43e3989df1e7842e9e5e724f24 --- /dev/null +++ b/kernel/ksym.c @@ -0,0 +1,22 @@ +#include <string.h> + +#include <kernel/ksym.h> + + + +/* global kernel symbol table, filled at compile time */ +struct ksym __ksyms[] __attribute__((weak)) = {{NULL, NULL}}; + + +void *lookup_symbol(const char *name) +{ + struct ksym *s = &__ksyms[0]; + + while (s->name) { + if(!strcmp(s->name, name)) + return s->addr; + s++; + } + + return NULL; +} diff --git a/kernel/module.c b/kernel/module.c new file mode 100644 index 0000000000000000000000000000000000000000..96c95d9202552485da2f7cc28061f29015668a90 --- /dev/null +++ b/kernel/module.c @@ -0,0 +1,936 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <kernel/printk.h> +#include <kernel/err.h> +#include <kernel/module.h> +#include <kernel/ksym.h> + + +/* XXX quick and dirty malloc() standin */ +#include <page.h> +void *malloc(size_t size) { + return page_alloc(); +} + + +/** + * @brief find section headers marked ALLOC by index + * + * @param offset a offset into the table (to locate multiple identical types) + * + * @return section index or 0 if not found + */ + +static unsigned int find_shdr_alloc(const struct elf_module *m, + const unsigned int offset) +{ + size_t i; + + + for (i = offset; i < m->ehdr->e_shnum; i++) { + if ((m->shdr[i].sh_flags & SHF_ALLOC)) + return i; + } + + return 0; +} + + + +/** + * @brief get number of sections marked ALLOC with size > 0 + * + * @return number of ALLOC sections + */ + +static unsigned int get_num_alloc_sections(const struct elf_module *m) +{ + size_t i; + size_t cnt = 0; + + + for (i = 0; i < m->ehdr->e_shnum; i++) { + if ((m->shdr[i].sh_flags & SHF_ALLOC)) + if (m->shdr[i].sh_size) + cnt++; + } + + return cnt; +} + + +/** + * @brief get the number of entries in a dynamic section + * + * @return the number of entries in a dynamic section + */ + +static unsigned int get_num_dyn_entries(const struct elf_module *m) +{ + return m->dyn_size / sizeof(Elf_Dyn); +} + +/** + * @brief find a dynamic entry by tag + * + * @param offset a offset into the table (to locate multiple identical types) + * + * @return NULL if entry not found, pointer to entry otherwise + * + */ +__attribute__((unused)) +static Elf_Dyn *find_dyn(const struct elf_module *m, + const typeof(m->dyn->d_tag) d_tag, + const unsigned int offset) +{ + size_t i; + + + for (i = offset; i < get_num_dyn_entries(m); i++) + if (d_tag == m->dyn[i].d_tag) + return &m->dyn[i]; + + return NULL; +} + + +/** + * @brief return a section header by index + * + * @return NULL if entry not found, pointer to entry otherwise + * + */ + +static Elf_Shdr *get_sec(const struct elf_module *m, unsigned int idx) +{ + if (idx < m->ehdr->e_shnum) + return &m->shdr[idx]; + + return NULL; +} + + +/** + * @brief find find an elf section by type + * + * @param offset a offset into the table (to locate multiple identical types) + * + * @return section index or 0 if not found + * + */ + +static unsigned int find_sec_type(const struct elf_module *m, + const typeof(m->shdr->sh_type) sh_type, + const unsigned int offset) +{ + size_t i; + + + for (i = offset; i < m->ehdr->e_shnum; i++) { + if (sh_type == m->shdr[i].sh_type) + return i; + } + + return 0; +} + + + +/** + * @brief find an elf section by name + * + * @return section index or 0 if not found + */ + +static unsigned int find_sec(const struct elf_module *m, const char *name) +{ + size_t i; + + + for (i = 1; i < m->ehdr->e_shnum; i++) { + if (!strcmp(m->sh_str + m->shdr[i].sh_name, name)) + return i; + } + + return 0; +} + +/** + * @brief get an entry in the .shstrtab + * + * @return pointer to the start of the string or NULL if not found + */ + +static char *get_shstrtab_str(const struct elf_module *m, unsigned int idx) +{ + if (idx < m->sh_size) + return (m->sh_str + m->shdr[idx].sh_name); + + return NULL; +} + +/** + * @brief get an entry in the .strtab + * + * @return pointer to the start of the string or NULL if not found + */ + +__attribute__((unused)) +static char *get_strtab_str(const struct elf_module *m, unsigned int idx) +{ + if (idx < m->str_size) + return (m->str + idx); + + return NULL; +} + + +/** + * @brief get the name of a symbol in .symtab with a given index + * + * @return pointer to the start of the string or NULL if not found + */ + +static char *get_symbol_str(const struct elf_module *m, unsigned int idx) +{ + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + symtab = &m->shdr[find_sec(m, ".symtab")]; + + //symbols = (Elf_Sym *) (m->pa + symtab->sh_offset); + symbols = (Elf_Sym *) ((unsigned long) m->ehdr + symtab->sh_offset); + + if (idx < symtab->sh_size / symtab->sh_entsize) + return m->str + symbols[idx].st_name; + + return NULL; +} + + + +/** + * @brief find module section by name + * + * @return module section structure pointer or NULL if not found + */ + +struct module_section *find_mod_sec(const struct elf_module *m, + const char *name) + +{ + size_t i; + + + for (i = 0; i < m->num_sec; i++) { + if (!strcmp(m->sec[i].name, name)) + return &m->sec[i]; + } + + + return NULL; +} + + +/** + * @brief dump the name of all elf sections + */ + +void dump_sections(const struct elf_module *m) +{ + size_t i; + + + printk("\nSECTIONS:\n" + "============================\n" + "\t[NUM]\t[NAME]\t\t\t[TYPE]\t\t[SIZE]\t[ENTSZ]\t[FLAGS]\n"); + + + for (i = 0; i < m->ehdr->e_shnum; i++) { + + printk("\t%d\t%-20s", i, m->sh_str + m->shdr[i].sh_name); + + switch (m->shdr[i].sh_type) { + case SHT_NULL: + printk("%-10s", "\tNULL"); break; + case SHT_PROGBITS: + printk("%-10s", "\tPROGBITS"); + break; + case SHT_SYMTAB: + printk("%-10s", "\tSYMTAB"); break; + case SHT_STRTAB: + printk("%-10s", "\tSTRTAB"); break; + case SHT_RELA : + printk("%-10s", "\tRELA"); break; + case SHT_HASH : + printk("%-10s", "\tHASH"); break; + case SHT_DYNAMIC: + printk("%-10s", "\tDYNAMIC"); break; + case SHT_NOTE : + printk("%-10s", "\tNOTE"); break; + case SHT_NOBITS: + printk("%-10s", "\tNOBITS"); break; + case SHT_REL : + printk("%-10s", "\tREL"); break; + case SHT_SHLIB : + printk("%-10s", "\tSHLIB"); break; + case SHT_DYNSYM: + printk("%-10s", "\tDYNSYM"); break; + case SHT_NUM : + printk("%-10s", "\tNUM"); break; + default: + printk("%-10s", "\tOTHER"); break; + } + + printk("\t%ld\t%ld\t", m->shdr[i].sh_size, m->shdr[i].sh_entsize); + + if (m->shdr[i].sh_flags & SHF_WRITE) + printk("WRITE "); + if (m->shdr[i].sh_flags & SHF_ALLOC) + printk("ALLOC "); + if (m->shdr[i].sh_flags & SHF_EXECINSTR) + printk("EXECINSTR "); + if (m->shdr[i].sh_flags & SHF_TLS) + printk("TLS "); + if (m->shdr[i].sh_flags & SHF_MASKPROC) + printk("MASKPROC "); + + printk("\n"); + + } + +} + + +/** + * @brief get the type of a symbol + * + * @return 1 if symbol has been found, 0 otherwise + */ + +static unsigned long get_symbol_type(const struct elf_module *m, + const char *name) + +{ + unsigned int i; + unsigned int idx; + size_t sym_cnt; + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + idx = find_sec(m, ".symtab"); + + if (!idx) { + printf("WARN: no .symtab section found\n"); + return -1; + } + + symtab = &m->shdr[idx]; + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + printk("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) ((unsigned long) m->ehdr + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if(!strcmp(get_symbol_str(m, i), name)) { + return ELF_ST_TYPE(symbols[i].st_info); + } + } + + return 0; +} + + + +/** + * @brief get the value of a symbol + * + * @return 1 if symbol has been found, 0 otherwise + */ + +static unsigned long get_symbol_value(const struct elf_module *m, + const char *name, unsigned long *value) + +{ + unsigned int i; + unsigned int idx; + size_t sym_cnt; + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + idx = find_sec(m, ".symtab"); + + if (!idx) { + printf("WARN: no .symtab section found\n"); + return -1; + } + + symtab = &m->shdr[idx]; + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + printf("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) ((unsigned long) m->ehdr + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if(!strcmp(get_symbol_str(m, i), name)) { + (*value) = symbols[i].st_value; + return 1; + } + } + + return 0; +} + +/** + * @brief dump the contents of .symtab + */ + +static int dump_symtab(struct elf_module *m) +{ + Elf_Shdr *symtab; + Elf_Sym *symbols; + + size_t sym_cnt; + unsigned int idx; + unsigned int i; + + + + idx = find_sec(m, ".symtab"); + + if (!idx) { + printf("WARN: no .symtab section found\n"); + return -1; + } + + symtab = &m->shdr[idx]; + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + printf("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) ((unsigned long) m->ehdr + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + + printf("\n.symtab contains %d entries\n" + "============================\n" + "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\n", sym_cnt); + + + for (i = 0; i < sym_cnt; i++) { + + printf("\t%d\t%016lx\t%4ld", + i, + symbols[i].st_value, + symbols[i].st_size); + + switch (ELF_ST_TYPE(symbols[i].st_info)) { + case STT_NOTYPE : + printf("\tNOTYPE "); break; + case STT_OBJECT : + printf("\tOBJECT "); break; + case STT_FUNC : + printf("\tFUNC "); break; + case STT_SECTION : + printf("\tSECTION"); break; + case STT_FILE : + printf("\tFILE "); break; + case STT_COMMON : + printf("\tCOMMON "); break; + case STT_TLS : + printf("\tTLS "); break; + default: + printf("\tUNKNOWN"); break; + } + + printf("\t%-10s\n", get_symbol_str(m, i)); + + } + + return 0; +} + + + + +/** + * @brief dump the contents of strtab + */ + +__attribute__((unused)) +static void dump_strtab(const struct elf_module *m) +{ + size_t i; + + + if (!m->str) + return; + + + printf("\n.strtab:\n" + "============================\n" + "\t[OFF]\t[STR]\n"); + + while(i < m->sh_size) { + printf("\t[%d]\t%s\n", i, m->str + i); + i += strlen(m->str + i) + 1; + } + + printf("\n\n"); +} + + +/** + * @brief locate and set the ".shstrtab" section + * + * @return 0 if section header string table was not found, 1 otherwise + * + */ + +static int set_shstrtab(struct elf_module *m) +{ + size_t i; + + for (i = 0; i < m->ehdr->e_shnum; i++) { + + if (m->shdr[i].sh_type != SHT_STRTAB) + continue; + + /* section name index is not within table boundary, skip */ + if (m->shdr[i].sh_size < m->shdr[i].sh_name) + continue; + + m->sh_str = (((char *) m->ehdr) + m->shdr[i].sh_offset); + m->sh_size = m->shdr[i].sh_size; + + /* it's a string section and the size is ok, + * now make sure it is the right one */ + if (!strcmp(m->sh_str + m->shdr[i].sh_name, ".shstrtab")) + return 1; + } + + m->sh_str = NULL; + m->sh_size = 0; + + return 0; +} + +/** + * @brief locate and set the ".dynstr" section + * + * @return 0 if section header string table was not found, 1 otherwise + * + */ + +static int set_dynstr(struct elf_module *m) +{ + unsigned int idx; + + + idx = find_sec(m, ".dynstr"); + + if (idx) { + m->dyn_str = (((char *) m->ehdr) + m->shdr[idx].sh_offset); + m->dyn_size = m->shdr[idx].sh_size; + return 1; + } + + m->dyn_str = NULL; + m->dyn_size = 0; + + return 0; +} + + +/** + * @brief locate and set the ".strtab" section + * + * @return 0 if string table was not found, 1 otherwise + * + */ + +static int set_strtab(struct elf_module *m) +{ + unsigned int idx; + + + idx = find_sec(m, ".strtab"); + + if (idx) { + m->str = (((char *) m->ehdr) + m->shdr[idx].sh_offset); + m->str_size = m->shdr[idx].sh_size; + return 1; + } + + m->str = NULL; + m->str_size = 0; + + return 0; +} + + +/** + * @brief setup the module structure + * + * @return -1 on error + */ + +static int setup_module(struct elf_module *m) +{ + /* initialise module configuration */ + m->pa = 0; + m->va = 0; + // XXX + //m->size = 0; + m->align = sizeof(void *); + m->dyn = NULL; + m->dyn_size = 0; + + m->sec = NULL; + + /* set section headers */ + if (m->ehdr->e_shoff) { + m->shdr = (Elf_Shdr *) (((char *) m->ehdr) + m->ehdr->e_shoff); + } else { + m->shdr = NULL; + printf("ERR: no section header found\n"); + return -1; + } + + /* locate and set section header string table */ + if (!set_shstrtab(m)) + return -1; + + /* locate and set dynamic string table */ + if (!set_dynstr(m)) { + printf("WARN: no dynamic string table found\n"); + } + + /* locate and set string table */ + if (!set_strtab(m)) + return -1; + + /* set up for relocatable object */ + if (m->ehdr->e_type == ET_REL) { + printf("TODO\n"); + + m->align = 0x200000; /* PC */ +#if 0 + int i; + m->size = 0; + for (i = 0; i < m->ehdr->e_shnum; i++) { + if ((m->shdr[i].sh_flags & SHF_ALLOC)) { + printf("Alloc section: %s, size %ld\n", + m->sh_str + m->shdr[i].sh_name, + m->shdr[i].sh_size); + + m->size += m->shdr[i].sh_size; + + if (m->shdr[idx].sh_addralign > m->align) + + m->align = m->shdr[idx].sh_addralign; + + } + } +#endif + } + + return 0; +} + + + +static int module_load_mem(struct elf_module *m) +{ + unsigned int idx = 0; + unsigned long va_load; + unsigned long pa_load; + + char *src; + + Elf_Shdr *sec; + + struct module_section *s; + + void *mem; + + + mem = malloc(m->size); + + if (!mem) + return -ENOMEM; + + /* exec info */ + m->va = (unsigned long) mem; + m->pa = (unsigned long) mem; + + + printf("\n\nLoading module run-time sections\n"); + + va_load = m->va; + pa_load = m->pa; + + m->num_sec = get_num_alloc_sections(m); + m->sec = (struct module_section *) + malloc(sizeof(struct module_section) * m->num_sec); + + if (!m->sec) + return -1; + + + s = m->sec; + + while (1) { + + idx = find_shdr_alloc(m, idx + 1); + if (!idx) + break; + + sec = get_sec(m, idx); + + + if (!sec->sh_size) /* don't need those */ + continue; + + s->size = sec->sh_size; + + src = get_shstrtab_str(m, idx); + s->name = malloc(strlen(src)); + + if (!s->name) + return -1; + + strcpy(s->name, src); + + + if (sec->sh_type & SHT_NOBITS) { + printf("\tZero segment %10s at %p size %ld\n", + s->name, (char *) va_load, + sec->sh_size); + + bzero((void *) va_load, s->size); + } else { + printf("\tCopy segment %10s from %p to %p size %ld\n", + s->name, + (char *) m->ehdr + sec->sh_offset, + (char *) va_load, + sec->sh_size); + + memcpy((void *) va_load, + (char *) m->ehdr + sec->sh_offset, + sec->sh_size); + } + + s->addr = va_load; + va_load = s->addr + s->size; + + s++; + + if (s > &m->sec[m->num_sec]) { + printf("Error out of section memory\n"); + return -1; + } + } + + return 0; +} + + +static int module_relocate(struct elf_module *m) +{ + unsigned int idx = 0; + + size_t i; + size_t rel_cnt; + + Elf_Shdr *sec; + + + + /* no dynamic linkage, so it's either self-contained or bugged, we'll + * assume the former, so cross your fingers and hope for the best + */ + if (m->ehdr->e_type != ET_REL) + if (m->ehdr->e_type != ET_DYN) + return 0; + + + /* we only need RELA type relocations */ + + while (1) { + + idx = find_sec_type(m, SHT_RELA, idx + 1); + + if (!idx) + break; + + sec = get_sec(m, idx); + + printk("\nSection Header info: %ld\n", sec->sh_info); + + if (sec) { + + Elf_Rela *relatab; + + rel_cnt = sec->sh_size / sec->sh_entsize; + + printk("Found %d RELA entries\n", rel_cnt); + /* relocation table in memory */ + relatab = (Elf_Rela *) ((long)m->ehdr + sec->sh_offset); + + for (i = 0; i < rel_cnt; i++) { + + int reladdr; + unsigned int symsec = ELF_R_SYM(relatab[i].r_info); + char *symstr = get_symbol_str(m, symsec); + struct module_section *s; + struct module_section *text = find_mod_sec(m, ".text"); + + printf("OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n\n", + relatab[i].r_offset, + relatab[i].r_info, + relatab[i].r_addend, + sec->sh_link, + symsec, + symstr); + + + + if (strlen(symstr)) { + Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr); + + if (!sym) { + + unsigned long symval; + printf("\tNot found in library, resolving in module\n"); + + + if (!(get_symbol_type(m, symstr) & STT_FUNC)) { + printf("\tERROR, unresolved symbol %s\n", symstr); + return -1; + } + if (!get_symbol_value(m, symstr, &symval)) { + printf("\tERROR, unresolved symbol %s\n", symstr); + return -1; + } + + sym = (text->addr + symval); + + } + + printf("\tSymbol %s at %lx\n", symstr, sym); + + apply_relocate_add(m, &relatab[i], sym); + + } else { /* no string, symtab entry is probably a section, try to identify it */ + + char *secstr = get_shstrtab_str(m, symsec); + + s = find_mod_sec(m, secstr); + + if (!s) { + printf("Error cannot locate section %s for symbol\n", secstr); + continue; + } + /* target address to insert at location */ + reladdr = (long) s->addr; + printf("\tRelative symbol address: %x, entry at %08lx\n", reladdr, s->addr); + + apply_relocate_add(m, &relatab[i], reladdr); + } + + printf("\n"); + + + } + printf("\n"); + } + } + + + return 0; +} + + + + + +typedef void (*entrypoint_t)(void); +void go(entrypoint_t ep) +{ + ep(); + printk("done\n"); +} + + +int module_load(struct elf_module *m, void *p) +{ + unsigned long symval; + entrypoint_t ep; + + + /* the ELF binary starts with the ELF header */ + m->ehdr = (Elf_Ehdr *) p; + + printk("Checking ELF header\n"); + + if (elf_header_check(m->ehdr)) + return -1; + + printk("Setting up module configuration\n"); + + if (setup_module(m)) + return -1; + + + dump_sections(m); + + if (module_load_mem(m)) + return -1; + + dump_symtab(m); + + if (module_relocate(m)) + return -1; + +#if 1 + //uintptr_t epaddr = (uintptr_t) (m->va); + if (!get_symbol_value(m, "_module_init", &symval)) { + printf("module init not found\n"); + return -1; + + } + + ep = (entrypoint_t) (m->va + symval); + + printf("Binary entrypoint is %lx; invoking %p\n", m->ehdr->e_entry, ep); + + go(ep); +#endif + + return 0; +} + + + + diff --git a/kernel/testmodule.c b/kernel/testmodule.c new file mode 100644 index 0000000000000000000000000000000000000000..362018baf2465d04eb87e9cd7336c7b00310f1ff --- /dev/null +++ b/kernel/testmodule.c @@ -0,0 +1,23 @@ +/** + * @file kernel/test.c + */ + +#include <page.h> + +#include <kernel/printk.h> + + +void _module_init(void); + +void _module_init(void) +{ + int i; + + printk("moopmoop\n"); + + for (i = 0; i < 10; i++) + printk("the cow says: %d\n", i); + + printk("allocating: %p\n", page_alloc()); + +} diff --git a/scripts/gen_ksym.awk b/scripts/gen_ksym.awk new file mode 100755 index 0000000000000000000000000000000000000000..0f56712f2624d0525f0a2545bf35d7cbaf505424 --- /dev/null +++ b/scripts/gen_ksym.awk @@ -0,0 +1,4 @@ +#!/usr/bin/awk -f +BEGIN{ print "#include <stddef.h>\n #include \"include/kernel/ksym.h\""; print "struct ksym __ksyms[]={" } +{ if(NF==3){print "{\"" $3 "\", (void*) 0x" $1 "},"}} +END{print "{NULL,NULL} };"} diff --git a/scripts/link-leanos.sh b/scripts/link-leanos.sh new file mode 100755 index 0000000000000000000000000000000000000000..af6aa7aa455416fefb4393725fe406b12f8905f5 --- /dev/null +++ b/scripts/link-leanos.sh @@ -0,0 +1,293 @@ +#!/bin/sh +# +# link leanos +# +# leanos is linked from the objects selected by $(KBUILD_LEANOS_INIT) and +# $(KBUILD_LEANOS_MAIN). Most are built-in.o files from top-level directories +# in the kernel tree, others are specified in arch/$(ARCH)/Makefile. +# Ordering when linking is important, and $(KBUILD_LEANOS_INIT) must be first. +# +# leanos +# ^ +# | +# +-< $(KBUILD_LEANOS_INIT) +# | +--< init/version.o + more +# | +# +--< $(KBUILD_LEANOS_MAIN) +# | +--< drivers/built-in.o mm/built-in.o + more +# | +# +-< ${kallsymso} (see description in KALLSYMS section) +# +# leanos version (uname -v) cannot be updated during normal +# descending-into-subdirs phase since we do not yet know if we need to +# update leanos. +# Therefore this step is delayed until just before final link of leanos. +# +# System.map is generated to document addresses of all kernel symbols + +# Error out on error +set -e + +# Nice output in kbuild format +# Will be supressed by "make -s" +info() +{ + if [ "${quiet}" != "silent_" ]; then + printf " %-7s %s\n" ${1} ${2} + fi +} + +# Thin archive build here makes a final archive with +# symbol table and indexes from leanos objects, which can be +# used as input to linker. +# +# Traditional incremental style of link does not require this step +# +# built-in.o output file +# +archive_builtin() +{ + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + info AR built-in.o + rm -f built-in.o; + ${AR} rcsT${KBUILD_ARFLAGS} built-in.o \ + ${KBUILD_LEANOS_INIT} \ + ${KBUILD_LEANOS_MAIN} + fi +} + +# Link of leanos.o used for section mismatch analysis +# ${1} output file +modpost_link() +{ + local objects + + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="--whole-archive built-in.o" + else + objects="${KBUILD_LEANOS_INIT} \ + --start-group \ + ${KBUILD_LEANOS_MAIN} \ + --end-group" + fi + ${LD} ${LDFLAGS} -r -o ${1} ${objects} +} + +# Link of leanos +# ${1} - optional extra .o files +# ${2} - output file +leanos_link() +{ + local lds="${objtree}/${KBUILD_LDS}" + local objects + + + # since we link against the BCC libc at this time, we'll just + # call $CC instead of LD + ${CC} ${LDFLAGS} ${LDFLAGS_leanos} -o ${2} \ + ${KBUILD_LEANOS_INIT} ${KBUILD_LEANOS_MAIN} ${1} + +# if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then +# objects="--whole-archive built-in.o ${1}" +# else +# objects="${KBUILD_LEANOS_INIT} \ +# --start-group \ +# ${KBUILD_LEANOS_MAIN} \ +# --end-group \ +# ${1}" +# fi +# +# ${LD} ${LDFLAGS} ${LDFLAGS_leanos} -o ${2} \ +# -T ${lds} ${objects} + +} + + +# Create ${2} .o file with all symbols from the ${1} object file +kallsyms() +{ + info KSYM ${2} + local kallsymopt; + + + if [ -n "${CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX}" ]; then + kallsymopt="${kallsymopt} --symbol-prefix=_" + fi + + if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then + kallsymopt="${kallsymopt} --all-symbols" + fi + + if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then + kallsymopt="${kallsymopt} --absolute-percpu" + fi + + if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then + kallsymopt="${kallsymopt} --base-relative" + fi + + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + + local afile="`basename ${2} .o`.c" + + ${NM} -n ${1} | scripts/gen_ksym.awk > ${afile} + #${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile} + ${CC} ${aflags} -c -o ${2} ${afile} +} + +# Create map file with all symbols from ${1} +# See mksymap for additional details +mksysmap() +{ + ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} +} + +sortextable() +{ + ${objtree}/scripts/sortextable ${1} +} + +# Delete output files in case of error +cleanup() +{ + rm -f .old_version + rm -f .tmp_System.map + rm -f .tmp_kallsyms* + rm -f .tmp_version + rm -f .tmp_leanos* + rm -f built-in.o + rm -f System.map + rm -f leanos + rm -f leanos.o +} + +on_exit() +{ + if [ $? -ne 0 ]; then + cleanup + fi +} +trap on_exit EXIT + +on_signals() +{ + exit 1 +} +trap on_signals HUP INT QUIT TERM + +# +# +# Use "make V=1" to debug this script +case "${KBUILD_VERBOSE}" in +*1*) + set -x + ;; +esac + +if [ "$1" = "clean" ]; then + cleanup + exit 0 +fi + +# We need access to CONFIG_ symbols +case "${KCONFIG_CONFIG}" in +*/*) + . "${KCONFIG_CONFIG}" + ;; +*) + # Force using a file from the current directory + . "./${KCONFIG_CONFIG}" +esac + +archive_builtin + +#link leanos.o +info LD leanos.o +modpost_link leanos.o + +# modpost leanos.o to check for section mismatches +${MAKE} -f "${srctree}/scripts/Makefile.modpost" leanos.o + +# Update version +info GEN .version +if [ ! -r .version ]; then + rm -f .version; + echo 1 >.version; +else + mv .version .old_version; + expr 0$(cat .old_version) + 1 >.version; +fi; + +# final build of init/ +${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" + +kallsymso="" +kallsyms_leanos="" +if [ -n "${CONFIG_KALLSYMS}" ]; then + + # kallsyms support + # Generate section listing all symbols and add it into leanos + # It's a three step process: + # 1) Link .tmp_leanos1 so it has all symbols and sections, + # but __kallsyms is empty. + # Running kallsyms on that gives us .tmp_kallsyms1.o with + # the right size + # 2) Link .tmp_leanos2 so it now has a __kallsyms section of + # the right size, but due to the added section, some + # addresses have shifted. + # From here, we generate a correct .tmp_kallsyms2.o + # 2a) We may use an extra pass as this has been necessary to + # woraround some alignment related bugs. + # KALLSYMS_EXTRA_PASS=1 is used to trigger this. + # 3) The correct ${kallsymso} is linked into the final leanos. + # + # a) Verify that the System.map from leanos matches the map from + # ${kallsymso}. + + kallsymso=.tmp_kallsyms2.o + kallsyms_leanos=.tmp_leanos2 + + # step 1 + leanos_link "" .tmp_leanos1 + kallsyms .tmp_leanos1 .tmp_kallsyms1.o + + # step 2 + leanos_link .tmp_kallsyms1.o .tmp_leanos2 + kallsyms .tmp_leanos2 .tmp_kallsyms2.o + + # step 2a + if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then + kallsymso=.tmp_kallsyms3.o + kallsyms_leanos=.tmp_leanos3 + + leanos_link .tmp_kallsyms2.o .tmp_leanos3 + + kallsyms .tmp_leanos3 .tmp_kallsyms3.o + fi +fi + +info LD leanos +leanos_link "${kallsymso}" leanos + +if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then + info SORTEX leanos + sortextable leanos +fi + +info SYSMAP System.map +mksysmap leanos System.map + +# step a (see comment above) +if [ -n "${CONFIG_KALLSYMS}" ]; then + mksysmap ${kallsyms_leanos} .tmp_System.map + + if ! cmp -s System.map .tmp_System.map; then + echo >&2 Inconsistent kallsyms data + echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround + exit 1 + fi +fi + +# We made a new kernel - delete old version file +rm -f .old_version diff --git a/scripts/mksysmap b/scripts/mksysmap new file mode 100755 index 0000000000000000000000000000000000000000..a35acc0d0b827fa056348a76d074d5ef0a3dae93 --- /dev/null +++ b/scripts/mksysmap @@ -0,0 +1,44 @@ +#!/bin/sh -x +# Based on the vmlinux file create the System.map file +# System.map is used by module-init tools and some debugging +# tools to retrieve the actual addresses of symbols in the kernel. +# +# Usage +# mksysmap vmlinux System.map + + +##### +# Generate System.map (actual filename passed as second argument) + +# $NM produces the following output: +# f0081e80 T alloc_vfsmnt + +# The second row specify the type of the symbol: +# A = Absolute +# B = Uninitialised data (.bss) +# C = Common symbol +# D = Initialised data +# G = Initialised data for small objects +# I = Indirect reference to another symbol +# N = Debugging symbol +# R = Read only +# S = Uninitialised data for small objects +# T = Text code symbol +# U = Undefined symbol +# V = Weak symbol +# W = Weak symbol +# Corresponding small letters are local symbols + +# For System.map filter away: +# a - local absolute symbols +# U - undefined global symbols +# N - debugging symbols +# w - local weak symbols + +# readprofile starts reading symbols when _stext is found, and +# continue until it finds a symbol which is not either of 'T', 't', +# 'W' or 'w'. __crc_ are 'A' and placed in the middle +# so we just ignore them to let readprofile continue to work. +# (At least sparc64 has __crc_ in the middle). + +$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( .L\)' > $2