Skip to content
Snippets Groups Projects
Commit e46e0521 authored by Armin Luntzer's avatar Armin Luntzer
Browse files

* add basic module loading system and symbol resolver

* adapt symbol table generation from linux (scripts/mksysmap,
* scripts/link-vmlinux.sh ->  scripts/link-leanos.sh, etc.)
parent 4488b24b
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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/
#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;
}
OUTPUT_FORMAT("elf32-sparc")
#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;
}
#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_ */
#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_ */
#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_ */
......@@ -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
......
......@@ -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;
}
......
obj-y += ksym.o
obj-y += printk.o
obj-y += bitmap.o
obj-y += module.o
obj-m += testmodule.o
#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;
}
#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;
}
/**
* @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());
}
#!/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} };"}
#!/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
#!/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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment