elfboot: initial version

This commit is contained in:
Taku Shimosawa
2011-09-22 18:56:55 +09:00
commit 1b054d6e1e
7 changed files with 225 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
*.elf

28
elfboot/Makefile Normal file
View File

@ -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

84
elfboot/elfboot.c Normal file
View File

@ -0,0 +1,84 @@
#include <elf.h>
#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;
}

23
elfboot/head.S Normal file
View File

@ -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

37
elfboot/raw.lds Normal file
View File

@ -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)
}
}

9
elfboot/test.h Normal file
View File

@ -0,0 +1,9 @@
#ifdef TEST
#include <stdio.h>
#include <stdlib.h>
#define dprintf printf
#else
#define dprintf(...)
#endif

41
elfboot/test_main.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/mman.h>
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;
}