aboutsummaryrefslogtreecommitdiff
path: root/lib/libelf
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-01 09:51:44 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-01 09:51:44 +1100
commitaaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f (patch)
treedfffc0d8f3d21f6736b7f09219c95e2370052d8a /lib/libelf
downloadSLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.zip
SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.gz
SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.bz2
Initial import of slof-JX-1.7.0-4
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'lib/libelf')
-rw-r--r--lib/libelf/Makefile47
-rw-r--r--lib/libelf/elf.c234
-rw-r--r--lib/libelf/libelf.code21
-rw-r--r--lib/libelf/libelf.in12
4 files changed, 314 insertions, 0 deletions
diff --git a/lib/libelf/Makefile b/lib/libelf/Makefile
new file mode 100644
index 0000000..82ef0bb
--- /dev/null
+++ b/lib/libelf/Makefile
@@ -0,0 +1,47 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS= -nostdlib
+
+TARGET = ../libelf.a
+
+all: $(TARGET)
+
+SRCS = elf.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/lib/libelf/elf.c b/lib/libelf/elf.c
new file mode 100644
index 0000000..359f628
--- /dev/null
+++ b/lib/libelf/elf.c
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/* this is elf.fs rewritten in C */
+
+#include <string.h>
+#include <cpu.h>
+#include <libelf.h>
+
+struct ehdr {
+ unsigned int ei_ident;
+ unsigned char ei_class;
+ unsigned char ei_data;
+ unsigned char ei_version;
+ unsigned char ei_pad[9];
+ unsigned short e_type;
+ unsigned short e_machine;
+ unsigned int e_version;
+ unsigned int e_entry;
+ unsigned int e_phoff;
+ unsigned int e_shoff;
+ unsigned int e_flags;
+ unsigned short e_ehsize;
+ unsigned short e_phentsize;
+ unsigned short e_phnum;
+ unsigned short e_shentsize;
+ unsigned short e_shnum;
+ unsigned short e_shstrndx;
+};
+
+struct phdr {
+ unsigned int p_type;
+ unsigned int p_offset;
+ unsigned int p_vaddr;
+ unsigned int p_paddr;
+ unsigned int p_filesz;
+ unsigned int p_memsz;
+ unsigned int p_flags;
+ unsigned int p_align;
+};
+
+struct ehdr64 {
+ unsigned int ei_ident;
+ unsigned char ei_class;
+ unsigned char ei_data;
+ unsigned char ei_version;
+ unsigned char ei_pad[9];
+ unsigned short e_type;
+ unsigned short e_machine;
+ unsigned int e_version;
+ unsigned long e_entry;
+ unsigned long e_phoff;
+ unsigned long e_shoff;
+ unsigned int e_flags;
+ unsigned short e_ehsize;
+ unsigned short e_phentsize;
+ unsigned short e_phnum;
+ unsigned short e_shentsize;
+ unsigned short e_shnum;
+ unsigned short e_shstrndx;
+};
+
+struct phdr64 {
+ unsigned int p_type;
+ unsigned int p_flags;
+ unsigned long p_offset;
+ unsigned long p_vaddr;
+ unsigned long p_paddr;
+ unsigned long p_filesz;
+ unsigned long p_memsz;
+ unsigned long p_align;
+};
+
+#define VOID(x) (void *)((unsigned long)x)
+
+static void
+load_segment(unsigned long *file_addr, struct phdr *phdr)
+{
+ unsigned long src = phdr->p_offset + (unsigned long) file_addr;
+ /* copy into storage */
+ memmove(VOID(phdr->p_vaddr), VOID(src), phdr->p_filesz);
+
+ /* clear bss */
+ memset(VOID(phdr->p_vaddr + phdr->p_filesz), 0,
+ phdr->p_memsz - phdr->p_filesz);
+
+ if (phdr->p_memsz) {
+ flush_cache(VOID(phdr->p_vaddr), phdr->p_memsz);
+ }
+}
+
+static unsigned int
+load_segments(unsigned long *file_addr)
+{
+ struct ehdr *ehdr = (struct ehdr *) file_addr;
+ /* Calculate program header address */
+ struct phdr *phdr =
+ (struct phdr *) (((unsigned char *) file_addr) + ehdr->e_phoff);
+ int i;
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr->p_type == 1) {
+ /* copy segment */
+ load_segment(file_addr, phdr);
+ }
+ /* step to next header */
+ phdr =
+ (struct phdr *) (((unsigned char *) phdr) +
+ ehdr->e_phentsize);
+ }
+ return ehdr->e_entry;
+}
+
+static void
+load_segment64(unsigned long *file_addr, struct phdr64 *phdr64)
+{
+ unsigned long src = phdr64->p_offset + (unsigned long) file_addr;
+ /* copy into storage */
+ memmove(VOID(phdr64->p_vaddr), VOID(src), phdr64->p_filesz);
+
+ /* clear bss */
+ memset(VOID(phdr64->p_vaddr + phdr64->p_filesz), 0,
+ phdr64->p_memsz - phdr64->p_filesz);
+
+ if (phdr64->p_memsz) {
+ flush_cache(VOID(phdr64->p_vaddr), phdr64->p_memsz);
+ }
+}
+
+static unsigned long
+load_segments64(unsigned long *file_addr)
+{
+ struct ehdr64 *ehdr64 = (struct ehdr64 *) file_addr;
+ /* Calculate program header address */
+ struct phdr64 *phdr64 =
+ (struct phdr64 *) (((unsigned char *) file_addr) + ehdr64->e_phoff);
+ int i;
+ /* loop e_phnum times */
+ for (i = 0; i <= ehdr64->e_phnum; i++) {
+ /* PT_LOAD ? */
+ if (phdr64->p_type == 1) {
+ /* copy segment */
+ load_segment64(file_addr, phdr64);
+ }
+ /* step to next header */
+ phdr64 =
+ (struct phdr64 *) (((unsigned char *) phdr64) +
+ ehdr64->e_phentsize);
+ }
+ return ehdr64->e_entry;
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x) (x)
+#else
+#define cpu_to_be32(x) bswap_32(x)
+#endif
+
+/**
+ * elf_check_file tests if the file at file_addr is
+ * a correct endian, ELF PPC executable
+ * @param file_addr pointer to the start of the ELF file
+ * @return the class (1 for 32 bit, 2 for 64 bit)
+ * -1 if it is not an ELF file
+ * -2 if it has the wrong endianess
+ * -3 if it is not an ELF executable
+ * -4 if it is not for PPC
+ */
+static int
+elf_check_file(unsigned long *file_addr)
+{
+ struct ehdr *ehdr = (struct ehdr *) file_addr;
+ /* check if it is an ELF image at all */
+ if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
+ return -1;
+
+ /* endian check */
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (ehdr->ei_data != 2)
+ /* not a big endian image */
+#else
+ if (ehdr->ei_data == 2)
+ /* not a little endian image */
+#endif
+ return -2;
+
+ /* check if it is an ELF executable */
+ if (ehdr->e_type != 2)
+ return -3;
+
+ /* check if it is a PPC ELF executable */
+ if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
+ return -4;
+
+ return ehdr->ei_class;
+}
+
+/**
+ * load_elf_file tries to load the ELF file specified in file_addr
+ *
+ * it first checks if the file is a PPC ELF executable and then loads
+ * the segments depending if it is a 64bit or 32 bit ELF file
+ *
+ * @param file_addr pointer to the start of the elf file
+ * @param entry pointer where the ELF loader will store
+ * the entry point
+ * @return 1 for a 32 bit file
+ * 2 for a 64 bit file
+ * anything else means an error during load
+ */
+int
+load_elf_file(unsigned long *file_addr, unsigned long *entry)
+{
+ int type = elf_check_file(file_addr);
+ switch (type) {
+ case 1:
+ *entry = load_segments(file_addr);
+ break;
+ case 2:
+ *entry = load_segments64(file_addr);
+ break;
+ }
+ return type;
+}
diff --git a/lib/libelf/libelf.code b/lib/libelf/libelf.code
new file mode 100644
index 0000000..6e019fc
--- /dev/null
+++ b/lib/libelf/libelf.code
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+int load_elf_file(unsigned long *file_addr, unsigned long *entry);
+
+PRIM(LOADELF)
+ void *file_addr = TOS.a;
+ int type;
+ unsigned long entry;
+ type = load_elf_file(file_addr, &entry);
+ TOS.u = entry;
+ PUSH; TOS.n = type;
+MIRP
diff --git a/lib/libelf/libelf.in b/lib/libelf/libelf.in
new file mode 100644
index 0000000..1fea40c
--- /dev/null
+++ b/lib/libelf/libelf.in
@@ -0,0 +1,12 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+cod(LOADELF)