From 1b054d6e1e03e6550b8992b09edd2390445ab6a5 Mon Sep 17 00:00:00 2001 From: Taku Shimosawa Date: Thu, 22 Sep 2011 18:56:55 +0900 Subject: [PATCH] elfboot: initial version --- .gitignore | 3 ++ elfboot/Makefile | 28 +++++++++++++++ elfboot/elfboot.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ elfboot/head.S | 23 +++++++++++++ elfboot/raw.lds | 37 ++++++++++++++++++++ elfboot/test.h | 9 +++++ elfboot/test_main.c | 41 ++++++++++++++++++++++ 7 files changed, 225 insertions(+) create mode 100644 .gitignore create mode 100644 elfboot/Makefile create mode 100644 elfboot/elfboot.c create mode 100644 elfboot/head.S create mode 100644 elfboot/raw.lds create mode 100644 elfboot/test.h create mode 100644 elfboot/test_main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6481c8dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.elf + diff --git a/elfboot/Makefile b/elfboot/Makefile new file mode 100644 index 00000000..fba5f87a --- /dev/null +++ b/elfboot/Makefile @@ -0,0 +1,28 @@ +CFLAGS=-c -Wall -O +CFLAGS_TEST=-DTEST + +all: elfboot elfboot_test + +elfboot: elfboot.bin + cp $^ $@ + truncate -s $(shell expr '(' `stat -c '%s' $^` + 4095 ')' / 4096 '*' 4096) $@ + +elfboot.bin: elfboot.elf + objcopy -O binary $^ $@ + +elfboot.elf: head.o elfboot.raw.o raw.lds + ld $(LDFLAGS_RAW) -T raw.lds -o $@ $^ + +elfboot_test: elfboot.test.o test_main.o + gcc $(LDFLAGS) -o $@ $^ + +elfboot.raw.o: elfboot.c + gcc $(CFLAGS) -o $@ $^ +elfboot.test.o: elfboot.c + gcc $(CFLAGS) $(CFLAGS_TEST) -o $@ $^ + +clean: + $(RM) elfboot *.bin *.elf elfboot_test *.o + +disas: + objdump -b binary -m i386:x86-64 -D elfboot.bin diff --git a/elfboot/elfboot.c b/elfboot/elfboot.c new file mode 100644 index 00000000..3dba9bdd --- /dev/null +++ b/elfboot/elfboot.c @@ -0,0 +1,84 @@ +#include +#include "test.h" + +#ifdef TEST +static void *memcpy(void *dest, void *src, unsigned long len) +{ + dprintf("Copying %p to %p for %08ld bytes\n", src, dest, len); + + return dest; +} +static void *memset(void *dest, int v, unsigned long len) +{ + dprintf("Filling %p with %02x for %08ld bytes\n", dest, (unsigned char)v, len); + + return dest; +} +#else +static void *memcpy(void *dest, void *src, unsigned long len) +{ + char *d = dest, *s = src; + + for ( ; len ; len--) { + *(d++) = *(s++); + } + + return d; +} +static void *memset(void *dest, int v, unsigned long len) +{ + char *d = dest; + + for ( ; len ; len--) { + *(d++) = (char)v; + } + + return d; +} +#endif + +static void load_programs(unsigned char *image, Elf64_Phdr *hdrs, int nhdr) +{ + int i; + + for (i = 0; i < nhdr; i++) { + if (hdrs[i].p_type == PT_LOAD) { + dprintf("PT_LOAD : %lx: %lx - %lx (%lx)\n", + hdrs[i].p_vaddr, + hdrs[i].p_offset, hdrs[i].p_filesz, + hdrs[i].p_memsz); + + memcpy((void *)hdrs[i].p_vaddr, + image + hdrs[i].p_offset, + hdrs[i].p_filesz); + if (hdrs[i].p_filesz < hdrs[i].p_memsz) { + memset((void *)hdrs[i].p_vaddr + + hdrs[i].p_filesz, 0, + hdrs[i].p_memsz - hdrs[i].p_filesz); + } + } + } +} + + +/* + * Return value: If success, the entry point address. Otherwise, 0. + */ +unsigned long elfboot_main(unsigned char *image) +{ + Elf64_Ehdr *hdr; + + hdr = (Elf64_Ehdr *)image; + if (hdr->e_ident[0] != 0x7f || hdr->e_ident[1] != 'E' + || hdr->e_ident[2] != 'L' || hdr->e_ident[3] != 'F') { + return 0; + } + /* TODO: We may overlap. So copying should be more sophisticated */ + if (!hdr->e_phoff || hdr->e_phentsize != sizeof(Elf64_Phdr)) { + return 0; + } + load_programs(image, + (Elf64_Phdr *)(image + hdr->e_phoff), hdr->e_phnum); + return hdr->e_entry; +} + diff --git a/elfboot/head.S b/elfboot/head.S new file mode 100644 index 00000000..d4315127 --- /dev/null +++ b/elfboot/head.S @@ -0,0 +1,23 @@ +.text +.globl _start +_start: + leaq _stack_end(%rip), %rsp + /* preserve arguments */ + pushq %rdi + pushq %rsi + pushq %rdx + pushq %rcx + leaq _stack_end(%rip), %rdi + call elfboot_main + andq %rax, %rax + jz 1f + popq %rcx + popq %rdx + popq %rsi + popq %rdi + jmpq *%rax +1: + cli + hlt + jmp 1b + \ No newline at end of file diff --git a/elfboot/raw.lds b/elfboot/raw.lds new file mode 100644 index 00000000..798395a0 --- /dev/null +++ b/elfboot/raw.lds @@ -0,0 +1,37 @@ +ENTRY(_start) + +PHDRS +{ + text PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + . = SIZEOF_HEADERS; + . = ALIGN(4096); + .text : { + *(.text) + } :text + .data : { + *(.data) + *(.data.*) + } :data + .rodata : { + *(.rodata .rodata.*) + } :data + + . = ALIGN(8); + .bss : { + _bss_start = .; + *(.bss .bss.*) + _bss_end = .; + . = ALIGN(4096); + _stack_end = .; + } :data + + /DISCARD/ : { + *(.eh_frame) + *(.note.gnu.build-id) + } +} \ No newline at end of file diff --git a/elfboot/test.h b/elfboot/test.h new file mode 100644 index 00000000..5c3fd9c1 --- /dev/null +++ b/elfboot/test.h @@ -0,0 +1,9 @@ +#ifdef TEST +#include +#include + +#define dprintf printf +#else +#define dprintf(...) +#endif + diff --git a/elfboot/test_main.c b/elfboot/test_main.c new file mode 100644 index 00000000..474db271 --- /dev/null +++ b/elfboot/test_main.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include + +unsigned long elfboot_main(unsigned char *image); + +int main(int argc, char **argv) +{ + int fd; + struct stat st; + void *p; + + if (argc < 2) { + fprintf(stderr, "Usage : %s (elf)\n", argv[0]); + return 1; + } + fd = open(argv[1], O_RDONLY); + if (fd < 0){ + perror("open"); + return 1; + } + + fstat(fd, &st); + + p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (p == MAP_FAILED) { + perror("mmap"); + return 2; + } + + printf("read result : %lx\n", elfboot_main(p)); + + munmap(p, st.st_size); + close(fd); + + return 0; +}