elfboot: initial version
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.o
|
||||
*.elf
|
||||
|
||||
28
elfboot/Makefile
Normal file
28
elfboot/Makefile
Normal 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
84
elfboot/elfboot.c
Normal 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
23
elfboot/head.S
Normal 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
37
elfboot/raw.lds
Normal 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
9
elfboot/test.h
Normal 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
41
elfboot/test_main.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user