summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2010-01-24 02:59:22 +0000
committergonzo <gonzo@FreeBSD.org>2010-01-24 02:59:22 +0000
commitd184a1dc591e220ab469cf09ad53989e6d347422 (patch)
tree2ef8b97f66a86a0cffa295fb4ee6dafdbeb095a9
parent6bfde02405eb8939b3afcbdae9de37471c7bb79e (diff)
downloadFreeBSD-src-d184a1dc591e220ab469cf09ad53989e6d347422.zip
FreeBSD-src-d184a1dc591e220ab469cf09ad53989e6d347422.tar.gz
- Copy symbol-related tables (.symtab and .strtab) to the end of
relocated kernel. We use magic number to signal kernel that symbol data is present.
-rw-r--r--sys/mips/include/elf.h5
-rw-r--r--sys/mips/mips/elf_trampoline.c60
2 files changed, 64 insertions, 1 deletions
diff --git a/sys/mips/include/elf.h b/sys/mips/include/elf.h
index de12b5b..2d6ca3e 100644
--- a/sys/mips/include/elf.h
+++ b/sys/mips/include/elf.h
@@ -256,4 +256,9 @@ __ElfType(Auxinfo);
#define ET_DYN_LOAD_ADDR 0x0120000
+/*
+ * Constant to mark start of symtab/strtab saved by trampoline
+ */
+#define SYMTAB_MAGIC 0x64656267
+
#endif /* !_MACHINE_ELF_H_ */
diff --git a/sys/mips/mips/elf_trampoline.c b/sys/mips/mips/elf_trampoline.c
index d98b846..5bd100c 100644
--- a/sys/mips/mips/elf_trampoline.c
+++ b/sys/mips/mips/elf_trampoline.c
@@ -96,12 +96,17 @@ load_kernel(void * kstart)
#ifdef __mips_n64
Elf64_Ehdr *eh;
Elf64_Phdr phdr[64] /* XXX */;
+ Elf64_Phdr shdr[64] /* XXX */;
#else
Elf32_Ehdr *eh;
Elf32_Phdr phdr[64] /* XXX */;
+ Elf32_Shdr shdr[64] /* XXX */;
#endif
- int i;
+ int i, j;
void *entry_point;
+ vm_offset_t lastaddr = 0;
+ int symtabindex = -1;
+ int symstrindex = -1;
#ifdef __mips_n64
eh = (Elf64_Ehdr *)kstart;
@@ -112,6 +117,27 @@ load_kernel(void * kstart)
memcpy(phdr, (void *)(kstart + eh->e_phoff ),
eh->e_phnum * sizeof(phdr[0]));
+ memcpy(shdr, (void *)(kstart + eh->e_shoff),
+ sizeof(*shdr) * eh->e_shnum);
+
+ if (eh->e_shnum * eh->e_shentsize != 0 && eh->e_shoff != 0) {
+ for (i = 0; i < eh->e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ /*
+ * XXX: check if .symtab is in PT_LOAD?
+ */
+ if (shdr[i].sh_offset != 0 &&
+ shdr[i].sh_size != 0) {
+ symtabindex = i;
+ symstrindex = shdr[i].sh_link;
+ }
+ }
+ }
+ }
+
+ /*
+ * Copy loadable segments
+ */
for (i = 0; i < eh->e_phnum; i++) {
volatile char c;
@@ -120,12 +146,44 @@ load_kernel(void * kstart)
memcpy((void *)(phdr[i].p_vaddr),
(void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz);
+
/* Clean space from oversized segments, eg: bss. */
if (phdr[i].p_filesz < phdr[i].p_memsz)
bzero((void *)(phdr[i].p_vaddr + phdr[i].p_filesz),
phdr[i].p_memsz - phdr[i].p_filesz);
+
+ if (lastaddr < phdr[i].p_vaddr + phdr[i].p_memsz)
+ lastaddr = phdr[i].p_vaddr + phdr[i].p_memsz;
}
+ /* Now grab the symbol tables. */
+ if (symtabindex >= 0 && symstrindex >= 0) {
+ *(Elf_Size *)lastaddr = SYMTAB_MAGIC;
+ lastaddr += sizeof(Elf_Size);
+ *(Elf_Size *)lastaddr = shdr[symtabindex].sh_size +
+ shdr[symstrindex].sh_size + 2*sizeof(Elf_Size);
+ lastaddr += sizeof(Elf_Size);
+ /* .symtab size */
+ *(Elf_Size *)lastaddr = shdr[symtabindex].sh_size;
+ lastaddr += sizeof(shdr[symtabindex].sh_size);
+ /* .symtab data */
+ memcpy((void*)lastaddr,
+ shdr[symtabindex].sh_offset + kstart,
+ shdr[symtabindex].sh_size);
+ lastaddr += shdr[symtabindex].sh_size;
+
+ /* .strtab size */
+ *(Elf_Size *)lastaddr = shdr[symstrindex].sh_size;
+ lastaddr += sizeof(shdr[symstrindex].sh_size);
+
+ /* .strtab data */
+ memcpy((void*)lastaddr,
+ shdr[symstrindex].sh_offset + kstart,
+ shdr[symstrindex].sh_size);
+ } else
+ /* Do not take any chances */
+ *(Elf_Size *)lastaddr = 0;
+
return entry_point;
}
OpenPOWER on IntegriCloud