aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohannst <johannes.stoelp@gmail.com>2021-03-26 23:17:46 +0100
committerjohannst <johannes.stoelp@gmail.com>2021-03-26 23:17:46 +0100
commit1d2a6f21294f8390b683e4e097cb49210ed832d1 (patch)
tree19f6854c3e1fa6a82ec4ed4bb57b2d3dadf979b8
parentcf97ecd5b52c2f7a8953fd1674742d46fd15418a (diff)
downloaddynld-1d2a6f21294f8390b683e4e097cb49210ed832d1.tar.gz
dynld-1d2a6f21294f8390b683e4e097cb49210ed832d1.zip
Added dyn allocator + syscall wrappers + minor fixes.
-rw-r--r--lib/Makefile6
-rw-r--r--lib/include/alloc.h6
-rw-r--r--lib/include/auxv.h2
-rw-r--r--lib/include/common.h18
-rw-r--r--lib/include/syscall.h33
-rw-r--r--lib/include/syscalls.h23
-rw-r--r--lib/src/alloc.c87
-rw-r--r--lib/src/fmt.c6
-rw-r--r--lib/src/syscalls.c22
9 files changed, 179 insertions, 24 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 29c103a..62ecde8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,13 +1,17 @@
# Copyright (c) 2020 Johannes Stoelp
+HDR+=include/alloc.h
HDR+=include/auxv.h
HDR+=include/elf.h
HDR+=include/fmt.h
HDR+=include/io.h
HDR+=include/syscall.h
+HDR+=include/syscalls.h
-DEP+=src/io.o
+DEP+=src/alloc.o
DEP+=src/fmt.o
+DEP+=src/io.o
+DEP+=src/syscalls.o
libcommon.a: $(HDR) $(DEP)
ar -crs $@ $(filter %.o, $^)
diff --git a/lib/include/alloc.h b/lib/include/alloc.h
new file mode 100644
index 0000000..baf8d3d
--- /dev/null
+++ b/lib/include/alloc.h
@@ -0,0 +1,6 @@
+// Copyright (c) 2021 Johannes Stoelp
+
+#pragma once
+
+void* alloc(unsigned size);
+void dealloc(void* ptr);
diff --git a/lib/include/auxv.h b/lib/include/auxv.h
index 42dac38..1ac953e 100644
--- a/lib/include/auxv.h
+++ b/lib/include/auxv.h
@@ -15,7 +15,7 @@
#define AT_EXECFD 2 /* [val] File descriptor of user program (in case Linux Kernel didn't mapped) */
#define AT_PHDR 3 /* [ptr] Address of Phdr of use program (in case Kernel mapped user program) */
#define AT_PHENT 4 /* [val] Size in bytes of one Phdr entry */
-#define AT_PHNUM 5 /* [val] Number of Phread entries */
+#define AT_PHNUM 5 /* [val] Number of Phdr entries */
#define AT_PAGESZ 6 /* [val] System page size */
#define AT_BASE 7 /* [ptr] `base address` interpreter was loaded to */
#define AT_FLAGS 8 /* [val] */
diff --git a/lib/include/common.h b/lib/include/common.h
index 5ea6050..631c25f 100644
--- a/lib/include/common.h
+++ b/lib/include/common.h
@@ -3,14 +3,12 @@
#pragma once
#include "io.h"
-#include "syscall.h"
-
-#include <asm/unistd.h>
-
-#define ERROR_ON(cond, ...) \
- do { \
- if ((cond)) { \
- efmt(__VA_ARGS__); \
- syscall1(__NR_exit, 1); \
- } \
+#include "syscalls.h"
+
+#define ERROR_ON(cond, fmt, ...) \
+ do { \
+ if ((cond)) { \
+ efmt("%s:%d " fmt, __FILE__, __LINE__ __VA_OPT__(, ) __VA_ARGS__); \
+ _exit(1); \
+ } \
} while (0)
diff --git a/lib/include/syscall.h b/lib/include/syscall.h
index 4947155..c9314d2 100644
--- a/lib/include/syscall.h
+++ b/lib/include/syscall.h
@@ -35,29 +35,44 @@
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
// https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints
// https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html
-
-// Linux syscall ABI
-// x86-64
-// #syscall: rax
-// ret : rax
-// instr : syscall
-// args : rdi rsi rdx r10 r8 r9
+//
+//
+// Linux syscall ABI - x86-64
+// #syscall: rax
+// ret : rax
+// instr : syscall
+// args : rdi rsi rdx r10 r8 r9
//
// Reference:
// syscall(2)
+//
+//
+// X86_64 `syscall` instruction additionally clobbers following registers:
+// rcx Store return address.
+// r11 Store RFLAGS.
+//
+// Reference:
+// https://www.felixcloutier.com/x86/syscall
#define argcast(A) ((long)(A))
#define syscall1(n, a1) _syscall1(n, argcast(a1))
+#define syscall2(n, a1, a2) _syscall2(n, argcast(a1), argcast(a2))
#define syscall3(n, a1, a2, a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3))
static inline long _syscall1(long n, long a1) {
long ret;
- asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "memory");
+ asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory");
+ return ret;
+}
+
+static inline long _syscall2(long n, long a1, long a2) {
+ long ret;
+ asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) : "rcx", "r11", "memory");
return ret;
}
static inline long _syscall3(long n, long a1, long a2, long a3) {
long ret;
- asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3) : "memory");
+ asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3) : "rcx", "r11", "memory");
return ret;
}
diff --git a/lib/include/syscalls.h b/lib/include/syscalls.h
new file mode 100644
index 0000000..34b6b37
--- /dev/null
+++ b/lib/include/syscalls.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2021 Johannes Stoelp
+
+#pragma once
+
+#include <stddef.h> // size_t
+#include <sys/types.h> // ssize_t, off_t, ...
+
+// Syscall definitions taken from corresponding man pages, eg
+// open(2)
+// read(2)
+// ...
+
+#define O_RDONLY 00
+int open(const char* path, int flags);
+
+ssize_t read(int fd, void* buf, size_t count);
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+off_t lseek(int fd, off_t offset, int whence);
+
+void _exit(int status);
diff --git a/lib/src/alloc.c b/lib/src/alloc.c
new file mode 100644
index 0000000..8b05d9e
--- /dev/null
+++ b/lib/src/alloc.c
@@ -0,0 +1,87 @@
+// Copyright (c) 2021 Johannes Stoelp
+
+#include <alloc.h>
+#include <common.h>
+
+#include <stdint.h>
+
+// Extremely simple and non-thread safe implementation of a dynamic
+// memory allocator. Which will greatly suffer under fragmentation as
+// we neither use splitting nor coalesce free blocks. It uses
+// first-fit and always traverses the block list from the beginning.
+//
+// Bottom line, this allocator can be optimized in so many ways but it
+// doesn't really matter for the purpose of this studies and therefore
+// the allocator is implemented in the most naive way.
+
+// Allocation block descriptor.
+struct BlockDescriptor {
+ unsigned mFree;
+ unsigned mSize;
+ struct BlockDescriptor* mNext;
+};
+
+// Global Allocator.
+
+// Size of available memory to the allocator.
+enum { MEMORY_SIZE = 1 * 1024 * 1024 };
+// Memory for the allocator (statically reserved in the `.bss` section).
+uint8_t gMemory[MEMORY_SIZE];
+
+// Top index into `gMemory` to indicate next free memory.
+unsigned gMemoryTop;
+
+// List of allocated blocks (free + used).
+struct BlockDescriptor* gHead;
+
+// Request free memory from `gMemory` and advance the `gMemoryTop` index.
+static void* brk(unsigned size) {
+ ERROR_ON(gMemoryTop + size >= MEMORY_SIZE, "Allocator OOM!");
+ const unsigned old_top = gMemoryTop;
+ gMemoryTop += size;
+ return (void*)(gMemory + old_top);
+}
+
+// Allocate memory chunk of `size` and return pointer to the chunk.
+void* alloc(unsigned size) {
+ struct BlockDescriptor* current = 0;
+
+ // Check if we have a free block in the list of allocated blocks
+ // that matches the requested size.
+ current = gHead;
+ while (current) {
+ if (current->mFree && current->mSize < size) {
+ current->mFree = 0;
+ return (void*)(current + 1);
+ };
+ current = current->mNext;
+ }
+
+ // Compute real allocation size: Payload + BlockDescriptor.
+ unsigned real_size = size + sizeof(struct BlockDescriptor);
+
+ // No free block found in the list of blocks, allocate new block.
+ current = brk(real_size);
+
+ // Initialize new block.
+ current->mFree = 0;
+ current->mSize = size;
+ current->mNext = 0;
+
+ // Insert new block at the beginning of the list of blocks.
+ if (gHead != 0) {
+ current->mNext = gHead;
+ }
+ gHead = current;
+
+ return (void*)(current + 1);
+}
+
+void dealloc(void* ptr) {
+ // Get descriptor block.
+ struct BlockDescriptor* current = (struct BlockDescriptor*)ptr - 1;
+
+ // Mark block as free.
+ ERROR_ON(current->mFree, "Tried to de-alloc free block!");
+ current->mFree = 1;
+}
diff --git a/lib/src/fmt.c b/lib/src/fmt.c
index be1ca3a..b0840de 100644
--- a/lib/src/fmt.c
+++ b/lib/src/fmt.c
@@ -11,7 +11,7 @@ static const char* num2dec(char* buf, unsigned long len, unsigned long long num)
}
while (num > 0 && pbuf != buf) {
- char d = (num % 10) + '0';
+ char d = (char)(num % 10) + '0';
*(--pbuf) = d;
num /= 10;
}
@@ -28,7 +28,7 @@ static const char* num2hex(char* buf, unsigned long len, unsigned long long num)
while (num > 0 && pbuf != buf) {
char d = (num & 0xf);
- *(--pbuf) = d + (d > 9 ? 'a' - 10 : '0');
+ *(--pbuf) = (char)(d + (d > 9 ? 'a' - 10 : '0'));
num >>= 4;
}
return pbuf;
@@ -73,7 +73,7 @@ int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) {
val *= -1;
put('-');
}
- const char* ptr = num2dec(scratch, sizeof(scratch), val);
+ const char* ptr = num2dec(scratch, sizeof(scratch), (unsigned long)val);
puts(ptr);
} break;
case 'x': {
diff --git a/lib/src/syscalls.c b/lib/src/syscalls.c
new file mode 100644
index 0000000..d6ac1a5
--- /dev/null
+++ b/lib/src/syscalls.c
@@ -0,0 +1,22 @@
+// Copyright (c) 2021 Johannes Stoelp
+
+#include <asm/unistd.h> // __NR_*
+#include <syscall.h>
+#include <syscalls.h>
+
+int open(const char* path, int flags) {
+ return syscall2(__NR_open, path, flags);
+}
+
+ssize_t read(int fd, void* buf, size_t count) {
+ return syscall3(__NR_read, fd, buf, count);
+}
+
+off_t lseek(int fd, off_t offset, int whence) {
+ return syscall3(__NR_lseek, fd, offset, whence);
+}
+
+void _exit(int status) {
+ syscall1(__NR_exit, status);
+ __builtin_unreachable();
+}