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