summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/elf64.c196
-rw-r--r--lib/heap.c39
2 files changed, 204 insertions, 31 deletions
diff --git a/lib/elf64.c b/lib/elf64.c
index e880179..b5afc18 100644
--- a/lib/elf64.c
+++ b/lib/elf64.c
@@ -1,43 +1,130 @@
#include <stdbool.h>
+#include <libc/stdlib.h>
#include <lib/elf.h>
+#include <posix/unistd.h>
-bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine)
+static bool is_valid_ident(Elf_Byte const e_ident[EI_NIDENT])
{
- 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 (e_ident[EI_MAG1] == ELFMAG1
+ && e_ident[EI_MAG1] == ELFMAG1
+ && e_ident[EI_MAG2] == ELFMAG2
+ && e_ident[EI_MAG3] == ELFMAG3
+ && e_ident[EI_CLASS] == ELFCLASS64
+ && e_ident[EI_DATA] == ELFDATA2LSB
+ && e_ident[EI_VERSION] == EV_CURRENT);
+}
+
+bool elf64_validate(Elf64_Ehdr const *ehdr, unsigned type, unsigned machine)
+{
+ return (is_valid_ident(ehdr->e_ident)
+ && ehdr->e_type == type
+ && ehdr->e_machine == machine);
+}
+
+static ssize_t read_ehdr(int fd, Elf64_Ehdr *ehdr)
+{
+ ssize_t pos = lseek(fd, 0, SEEK_CUR);
+
+ ssize_t result;
+
+ if ((result = lseek(fd, 0, SEEK_SET)) == 0)
+ {
+ result = read(fd, ehdr, sizeof(*ehdr));
+ }
+
+ lseek(fd, pos, SEEK_SET);
+
+ return result;
+}
+
+static ssize_t read_phdr(int fd, Elf64_Ehdr *ehdr, int phdr_index, Elf64_Phdr *phdr)
+{
+ if (phdr_index > ehdr->e_phnum)
+ {
+ return -1;
+ }
+
+ ssize_t pos = lseek(fd, 0, SEEK_CUR);
+
+ ssize_t offset = ehdr->e_phoff + ehdr->e_phentsize * phdr_index;
+
+ ssize_t result;
+
+ if ((result = lseek(fd, offset, SEEK_SET)) == offset)
+ {
+ result = read(fd, phdr, ehdr->e_phentsize);
+ }
+
+ lseek(fd, pos, SEEK_SET);
+
+ return result;
+}
+
+static ssize_t read_phdrs(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr phdrs[ehdr->e_phnum])
+{
+ ssize_t result = 0;
+
+ for (int i = 0; result >= 0 && i < ehdr->e_phnum; i++)
+ {
+ result = read_phdr(fd, ehdr, i, &phdrs[i]);
+ }
+
+ return result;
+}
+
+bool elf64_validate_fd(int fd, unsigned type, unsigned machine)
+{
+ Elf64_Ehdr ehdr;
+ read_ehdr(fd, &ehdr);
+ return elf64_validate(&ehdr, type, machine);
+}
+
+static bool is_loadable(Elf64_Phdr const *phdr)
+{
+ return phdr != nullptr && phdr->p_type == PT_LOAD;
+}
+
+static size_t aligned_size(Elf64_Phdr const *phdr)
+{
+ size_t size = phdr->p_offset + phdr->p_memsz;
+ return (size + phdr->p_align - 1) & ~(phdr->p_align - 1);
+}
+
+static size_t segment_memsz(Elf64_Phdr const *phdr)
+{
+ return is_loadable(phdr) ? aligned_size(phdr) : 0;
+}
+
+size_t elf64_size(Elf64_Ehdr const *ehdr, Elf64_Phdr *phdrs)
+{
+ size_t size = 0;
+
+ for (int i = 0; i < ehdr->e_phnum; i++)
+ {
+ size_t size_next = segment_memsz(&phdrs[i]);
+ size = size_next > size ? size_next : size;
+ }
- return true;
+ return size;
}
-size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs)
+size_t elf64_size_fd(int fd)
{
- size_t size = 0;
+ size_t size = 0;
- for (int i = 0; i < ehdr->e_phnum; i++)
- {
- if (phdrs[i].p_type != PT_LOAD)
- {
- continue;
- }
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr phdr;
- size = phdrs[i].p_offset + phdrs[i].p_memsz;
- if (phdrs[i].p_align > 1)
- {
- size = (size + phdrs[i].p_align - 1) & ~(phdrs[i].p_align - 1);
- }
- }
+ ssize_t result = read_ehdr(fd, &ehdr);
- return size;
+ for (int i = 0; result >= 0 && i < ehdr.e_phnum; i++)
+ {
+ result = read_phdr(fd, &ehdr, i, &phdr);
+ size_t size_next = segment_memsz(&phdr);
+ size = size_next > size ? size_next : size;
+ }
+
+ return result > 0 ? size : 0;
}
static Elf64_Dyn *get_dynent(Elf64_Dyn *dyntab, unsigned long dt_type)
@@ -55,7 +142,7 @@ static Elf64_Dyn *get_dynent(Elf64_Dyn *dyntab, unsigned long dt_type)
return nullptr;
}
-void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type)
+void *elf64_dt_ptr(char *base, Elf64_Dyn *dyntab, unsigned long dt_type)
{
Elf64_Dyn *dynent = get_dynent(dyntab, dt_type);
@@ -64,7 +151,7 @@ void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type)
return nullptr;
}
- return dynent->d_ptr + (char *)base;
+ return dynent->d_ptr + base;
}
uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type)
@@ -79,3 +166,50 @@ uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type)
return dynent->d_val;
}
+static ssize_t load_segment(int fd, Elf64_Phdr *phdr, size_t buffer_size, char buffer[buffer_size])
+{
+ if (!is_loadable(phdr))
+ {
+ return 0;
+ }
+
+ ssize_t pos = lseek(fd, 0, SEEK_CUR);
+
+ ssize_t result;
+
+ if ((result = lseek(fd, phdr->p_offset, SEEK_SET)) >= 0)
+ {
+ result = read(fd, &buffer[phdr->p_offset], phdr->p_memsz);
+ }
+
+ lseek(fd, pos, SEEK_SET);
+
+ return result;
+}
+
+ssize_t elf64_load_segments(int fd, size_t buffer_size, char buffer[buffer_size])
+{
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)&buffer[0];
+
+ ssize_t result;
+
+ if ((result = read_ehdr(fd, ehdr)) < 0)
+ {
+ return result;
+ }
+
+ Elf64_Phdr *phdrs = (Elf64_Phdr *)&buffer[ehdr->e_phoff];
+
+ if ((result = read_phdrs(fd, ehdr, phdrs)) < 0)
+ {
+ return result;
+ }
+
+ for (int i = 0; result > 0 && i < ehdr->e_phnum; i++)
+ {
+ result = load_segment(fd, &phdrs[i], buffer_size, buffer);
+ }
+
+ return result;
+}
+
diff --git a/lib/heap.c b/lib/heap.c
new file mode 100644
index 0000000..8331a17
--- /dev/null
+++ b/lib/heap.c
@@ -0,0 +1,39 @@
+#include <string.h>
+#include <stdlib.h>
+
+struct heap_node
+{
+ struct heap_node *next;
+ size_t size;
+};
+
+struct heap_head
+{
+ struct heap_node *first;
+ size_t total_bytes;
+ size_t ready_bytes;
+};
+
+void *malloc(size_t size)
+{
+ (void)size;
+ return nullptr;
+}
+
+void *calloc(size_t count, size_t size)
+{
+ void *block = malloc(count * size);
+
+ if (block != nullptr)
+ {
+ memset(block, 0, count * size);
+ }
+
+ return block;
+}
+
+void free(void *block)
+{
+ (void)block;
+}
+