summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/elf/elf64.h22
-rw-r--r--api/loader/efi/shim.h2
-rwxr-xr-xdebug.sh1
-rw-r--r--efi.mk2
-rwxr-xr-ximage.sh4
-rw-r--r--lib/elf.c106
-rw-r--r--lib/elf.h17
-rw-r--r--loader/main_efi.c3
-rw-r--r--shim/Makefile6
-rw-r--r--shim/entry.c6
10 files changed, 160 insertions, 9 deletions
diff --git a/api/elf/elf64.h b/api/elf/elf64.h
index 4473d15..d975c35 100644
--- a/api/elf/elf64.h
+++ b/api/elf/elf64.h
@@ -18,6 +18,9 @@ typedef struct Elf64_Shdr Elf64_Shdr;
typedef struct Elf64_Sym Elf64_Sym;
typedef struct Elf64_Dyn Elf64_Dyn;
+typedef struct Elf64_Rel Elf64_Rel;
+typedef struct Elf64_Rela Elf64_Rela;
+
#define EM_X86_64 62
struct Elf64_Ehdr
@@ -84,3 +87,22 @@ struct Elf64_Dyn
};
};
+#define ELF64_R_SYM(info) ((info)>>32)
+#define ELF64_R_TYPE(info) ((Elf64_Word)(info))
+#define ELF64_R_INFO(sym, type) (((Elf64_Xword)(sym)<<32)+(Elf64_Xword)(type))
+
+#define R_AMD64_RELATIVE 8
+
+struct Elf64_Rel
+{
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+};
+
+struct Elf64_Rela
+{
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+ Elf64_Sxword r_addend;
+};
+
diff --git a/api/loader/efi/shim.h b/api/loader/efi/shim.h
index 3486c34..9421cc3 100644
--- a/api/loader/efi/shim.h
+++ b/api/loader/efi/shim.h
@@ -13,8 +13,6 @@
#define OsVendorMemoryType(t) ((EFI_MEMORY_TYPE)(0x80000000|t))
#define SystemMemoryType OsVendorMemoryType(1)
-struct efi_loader_image;
-
struct efi_loader_image
{
CHAR16 *path;
diff --git a/debug.sh b/debug.sh
index 1d606af..eacdc94 100755
--- a/debug.sh
+++ b/debug.sh
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
make -C loader &&
+make -C shim &&
make -C kernel &&
./image.sh &&
diff --git a/efi.mk b/efi.mk
index 72bd136..4067e44 100644
--- a/efi.mk
+++ b/efi.mk
@@ -22,7 +22,7 @@ CPPFLAGS += -I$(EFIAPIDIR) -I$(EFIAPIDIR)/protocol -I$(EFIAPIDIR)/$(GNUEFIARCH)
-DGNU_EFI_USE_MS_ABI -DEFI_CALL_WRAPPER -DEFI_DEBUG
CFLAGS += -fPIC -fshort-wchar -maccumulate-outgoing-args -mno-avx -mno-sse \
- -mno-mmx
+ -mno-mmx -funsigned-char -Wno-pointer-sign
OBJCOPY.efi = $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \
-j .dynsm -j .rel -j .rela -j .reloc \
diff --git a/image.sh b/image.sh
index 7d32df4..a14f635 100755
--- a/image.sh
+++ b/image.sh
@@ -2,6 +2,7 @@
imagefile=uefi.img
loaderfile=loader/loader.efi
+shimfile=shim/efi.os
kernelfile=kernel/kernel.os
if [[ ! -f ${imagefile} ]]; then
@@ -14,5 +15,6 @@ mmd -i ${imagefile} -Do ::EFI/BOOT
mcopy -i ${imagefile} -Do ${loaderfile} ::EFI/BOOT/BOOTX64.EFI
mmd -i ${imagefile} -Do ::adasoft
mmd -i ${imagefile} -Do ::adasoft/sophia
-mcopy -i ${imagefile} ${kernelfile} -Do ::adasoft/sophia
+mcopy -i ${imagefile} -Do ${shimfile} -Do ::adasoft/sophia
+mcopy -i ${imagefile} -Do ${kernelfile} -Do ::adasoft/sophia
diff --git a/lib/elf.c b/lib/elf.c
new file mode 100644
index 0000000..551a5a5
--- /dev/null
+++ b/lib/elf.c
@@ -0,0 +1,106 @@
+#include "elf.h"
+
+bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine)
+{
+ if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
+ ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
+ ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
+ ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
+ ehdr->e_machine != machine ||
+ ehdr->e_type != type)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs)
+{
+ size_t size = 0;
+
+ for (int i = 0; i < ehdr->e_phnum; i++)
+ {
+ if (phdrs[i].p_type != PT_LOAD)
+ {
+ continue;
+ }
+
+ if (phdrs[i].p_paddr + phdrs[i].p_memsz > size)
+ {
+ size = phdrs[i].p_paddr + phdrs[i].p_memsz;
+ if (phdrs[i].p_align > 1)
+ {
+ size = (size + phdrs[i].p_align - 1) &
+ ~(phdrs[i].p_align - 1);
+ }
+ }
+ }
+
+ return size;
+}
+
+void elf64_reloc(Elf64_Ehdr *ehdr)
+{
+ // locate the dynamic segment
+ Elf64_Phdr *phdrs = (Elf64_Phdr *)(ehdr->e_phoff + (uintptr_t)ehdr);
+ Elf64_Dyn *dyn = NULL;
+ Elf64_Rela *rela = NULL;
+ size_t rela_size;
+ int rela_count;
+
+ for (int i = 0; i < ehdr->e_phnum; i++)
+ {
+ if (phdrs[i].p_type != PT_DYNAMIC) continue;
+
+ dyn = (Elf64_Dyn *)(phdrs[i].p_offset + (uintptr_t)ehdr);
+ }
+
+ // parse the dynamic segment
+ while (dyn->d_tag != DT_NULL)
+ {
+ switch (dyn->d_tag)
+ {
+ case DT_RELA:
+ rela = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)ehdr);
+ break;
+ case DT_RELASZ:
+ rela_size = dyn->d_val;
+ break;
+ case DT_RELAENT:
+ rela_count = rela_size / dyn->d_val;
+ break;
+ default:
+ break;
+ }
+ dyn++;
+ }
+
+ // perform the actual relocations
+
+ for (int i; i < rela_count; i++)
+ {
+ union
+ {
+ Elf_Byte word8;
+ Elf64_Half word16;
+ Elf64_Word word32;
+ Elf64_Xword word64;
+ }
+ *reloc_ptr = NULL;
+
+ switch (ELF64_R_TYPE(rela[i].r_info))
+ {
+ case R_AMD64_RELATIVE:
+ reloc_ptr = (void *)(rela[i].r_offset + (uintptr_t)ehdr);
+ reloc_ptr->word64 = (rela[i].r_addend + (uintptr_t)ehdr);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
diff --git a/lib/elf.h b/lib/elf.h
new file mode 100644
index 0000000..3edb0a1
--- /dev/null
+++ b/lib/elf.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <elf/elf64.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __x86_64__
+# define elf_validate elf64_validate
+# define elf_size elf64_size
+# define elf_reloc elf64_reloc
+#endif
+
+bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine);
+size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdr);
+void elf64_reloc(Elf64_Ehdr *ehdr);
+
diff --git a/loader/main_efi.c b/loader/main_efi.c
index 7edb44d..4c9c9a0 100644
--- a/loader/main_efi.c
+++ b/loader/main_efi.c
@@ -145,7 +145,8 @@ EFI_STATUS open_image(struct efi_loader_image *image)
&ehdr_size,
&ehdr))))
{
- if (elf_validate(&ehdr, ET_EXEC, EM_X86_64))
+ if (elf_validate(&ehdr, ET_EXEC, EM_X86_64) ||
+ elf_validate(&ehdr, ET_DYN, EM_X86_64))
{
phdrs_size = ehdr.e_phentsize * ehdr.e_phnum;
phdrs = AllocatePool(phdrs_size);
diff --git a/shim/Makefile b/shim/Makefile
index 51ec96c..42007b8 100644
--- a/shim/Makefile
+++ b/shim/Makefile
@@ -15,11 +15,11 @@ CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden \
LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name))
LDSCRIPT := shim.ld
-LDFLAGS += -z max-page-size=4096 --export-dynamic
+LDFLAGS += -z max-page-size=4096 --export-dynamic -pic --no-dynamic-linker
LOADLIBES := -lgcc
-OBJS := entry.o memcmp.o memcpy.o memmove.o memset.o
-$(OBJS): CFLAGS += -fPIC -fPIE
+OBJS := entry.o elf.o memcmp.o memcpy.o memmove.o memset.o
+$(OBJS): CFLAGS += -fPIC
DEPS := $(patsubst %.o,%.d,$(OBJS))
diff --git a/shim/entry.c b/shim/entry.c
index 303f582..a4d00c7 100644
--- a/shim/entry.c
+++ b/shim/entry.c
@@ -49,7 +49,11 @@ EFI_STATUS efi_shim_entry(struct efi_loader_image *image,
* 3. exit boot services
* 5. ???????????
*/
-
+
+ void *image_base = (void *)image->buffer_base;
+
+ elf_reloc(image_base);
+
EFI_STATUS status;
if (!image)