aboutsummaryrefslogtreecommitdiff
path: root/lib/include
diff options
context:
space:
mode:
Diffstat (limited to 'lib/include')
-rw-r--r--lib/include/alloc.h6
-rw-r--r--lib/include/auxv.h2
-rw-r--r--lib/include/common.h21
-rw-r--r--lib/include/elf.h156
-rw-r--r--lib/include/syscall.h58
-rw-r--r--lib/include/syscalls.h40
6 files changed, 235 insertions, 48 deletions
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..d006d71 100644
--- a/lib/include/common.h
+++ b/lib/include/common.h
@@ -3,14 +3,17 @@
#pragma once
#include "io.h"
-#include "syscall.h"
+#include "syscalls.h"
-#include <asm/unistd.h>
-
-#define ERROR_ON(cond, ...) \
- do { \
- if ((cond)) { \
- efmt(__VA_ARGS__); \
- syscall1(__NR_exit, 1); \
- } \
+#define ERROR_ON(cond, fmt, ...) \
+ do { \
+ if ((cond)) { \
+ efmt("%s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
+ _exit(1); \
+ } \
} while (0)
+
+
+void* memset(void* s, int c, size_t n);
+void* memcpy(void* d, const void* s, size_t n);
+
diff --git a/lib/include/elf.h b/lib/include/elf.h
index a0fe6f7..0317859 100644
--- a/lib/include/elf.h
+++ b/lib/include/elf.h
@@ -4,6 +4,51 @@
#include <stdint.h>
+/// ----------
+/// ELF Header
+/// ----------
+
+// Index into `ident`.
+#define EI_MAG0 0
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_OSABI 7
+
+// indent[EI_CLASS]
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+// indent[EI_CLASS]
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+// indent[EI_OSABI]
+#define ELFOSABI_SYSV 0
+
+// Objec file `type`.
+#define ET_NONE 0
+#define ET_DYN 3
+
+typedef struct {
+ uint8_t ident[16]; // ELF identification.
+ uint16_t type; // Object file type.
+ uint16_t machine; // Machine type.
+ uint32_t version; // Object file version.
+ uint64_t entry; // Entrypoint address.
+ uint64_t phoff; // Program header file offset.
+ uint64_t shoff; // Section header file offset.
+ uint32_t flags; // Processor specific flags.
+ uint16_t ehsize; // ELF header size.
+ uint16_t phentsize; // Program header entry size.
+ uint16_t phnum; // Number of program header entries.
+ uint16_t shentsize; // Section header entry size.
+ uint16_t shnum; // Number of section header entries.
+ uint16_t shstrndx; // Section name string table index.
+} Elf64Ehdr;
+
/// --------------
/// Program Header
/// --------------
@@ -15,6 +60,7 @@
#define PT_NOTE 4 /* Location of auxiliary information */
#define PT_SHLIB 5 /* Reserved, but unspecified semantic */
#define PT_PHDR 6 /* Location & size of program headers itself */
+#define PT_TLS 7 /* Thread local storage */
#define PT_GNU_EH_FRAME 0x6474e550 /* [x86-64] stack unwinding tables */
#define PT_LOPROC 0x70000000
@@ -39,32 +85,36 @@ typedef struct {
/// Dynamic Section
/// ---------------
-#define DT_NULL 0 /* [ignored] Marks end of dynamic section */
-#define DT_NEEDED 1 /* [val] Name of needed library */
-#define DT_PLTRELSZ 2 /* [val] Size in bytes of PLT relocs */
-#define DT_PLTGOT 3 /* [ptr] Processor defined value */
-#define DT_HASH 4 /* [ptr] Address of symbol hash table */
-#define DT_STRTAB 5 /* [ptr] Address of string table */
-#define DT_SYMTAB 6 /* [ptr] Address of symbol table */
-#define DT_RELA 7 /* [ptr] Address of Rela relocs */
-#define DT_RELASZ 8 /* [val] Total size of Rela relocs */
-#define DT_RELAENT 9 /* [val] Size of one Rela reloc */
-#define DT_STRSZ 10 /* [val] Size of string table */
-#define DT_SYMENT 11 /* [val] Size of one symbol table entry */
-#define DT_INIT 12 /* [ptr] Address of init function */
-#define DT_FINI 13 /* [ptr] Address of termination function */
-#define DT_SONAME 14 /* [val] Name of shared object */
-#define DT_RPATH 15 /* [val] Library search path (deprecated) */
-#define DT_SYMBOLIC 16 /* [ignored] Start symbol search here */
-#define DT_REL 17 /* [ptr] Address of Rel relocs */
-#define DT_RELSZ 18 /* [val] Total size of Rel relocs */
-#define DT_RELENT 19 /* [val] Size of one Rel reloc */
-#define DT_PLTREL 20 /* [val] Type of reloc in PLT */
-#define DT_DEBUG 21 /* [ptr] For debugging; unspecified */
-#define DT_TEXTREL 22 /* [ignored] Reloc might modify .text */
-#define DT_JMPREL 23 /* [ptr] Address of PLT relocs */
-#define DT_BIND_NOW 24 /* [ignored] Process relocations of object */
-#define DT_MAX_CNT 25
+#define DT_NULL 0 /* [ignored] Marks end of dynamic section */
+#define DT_NEEDED 1 /* [val] Name of needed library */
+#define DT_PLTRELSZ 2 /* [val] Size in bytes of PLT relocs */
+#define DT_PLTGOT 3 /* [ptr] Processor defined value */
+#define DT_HASH 4 /* [ptr] Address of symbol hash table */
+#define DT_STRTAB 5 /* [ptr] Address of string table */
+#define DT_SYMTAB 6 /* [ptr] Address of symbol table */
+#define DT_RELA 7 /* [ptr] Address of Rela relocs */
+#define DT_RELASZ 8 /* [val] Total size of Rela relocs */
+#define DT_RELAENT 9 /* [val] Size of one Rela reloc */
+#define DT_STRSZ 10 /* [val] Size of string table */
+#define DT_SYMENT 11 /* [val] Size of one symbol table entry */
+#define DT_INIT 12 /* [ptr] Address of init function */
+#define DT_FINI 13 /* [ptr] Address of termination function */
+#define DT_SONAME 14 /* [val] Name of shared object */
+#define DT_RPATH 15 /* [val] Library search path (deprecated) */
+#define DT_SYMBOLIC 16 /* [ignored] Start symbol search here */
+#define DT_REL 17 /* [ptr] Address of Rel relocs */
+#define DT_RELSZ 18 /* [val] Total size of Rel relocs */
+#define DT_RELENT 19 /* [val] Size of one Rel reloc */
+#define DT_PLTREL 20 /* [val] Type of reloc in PLT */
+#define DT_DEBUG 21 /* [ptr] For debugging; unspecified */
+#define DT_TEXTREL 22 /* [ignored] Reloc might modify .text */
+#define DT_JMPREL 23 /* [ptr] Address of PLT relocs */
+#define DT_BIND_NOW 24 /* [ignored] Process relocations of object */
+#define DT_INIT_ARRAY 25 /* [ptr] Address of array of initialization functions */
+#define DT_FINI_ARRAY 26 /* [ptr] Address of array of termination functions */
+#define DT_INIT_ARRAYSZ 27 /* [val] Size in bytes of the initialization array */
+#define DT_FINI_ARRAYSZ 28 /* [val] Size in bytes of the termination array */
+#define DT_MAX_CNT 29
typedef struct {
uint64_t tag;
@@ -73,3 +123,57 @@ typedef struct {
void* ptr;
};
} Elf64Dyn;
+
+/// ------------
+/// Symbol Entry
+/// ------------
+
+typedef struct {
+ uint32_t name; // Symbol name (index into string table).
+ uint8_t info; // Symbol Binding bits[7..4] + Symbol Type bits[3..0].
+ uint8_t other; // Reserved.
+ uint16_t shndx; // Section table index.
+ uint64_t value; //
+ uint64_t size; //
+} Elf64Sym;
+
+#define ELF64_ST_BIND(i) ((i) >> 4)
+#define ELF64_ST_TYPE(i) ((i)&0xf)
+
+// Symbold Bindings.
+#define STB_GLOBAL 1 /* Global symbol, visible to all object files. */
+#define STB_WEAK 2 /* Global scope, but with lower precedence than global symbols. */
+
+// Symbol Types.
+#define STT_NOTYPE 0 /* No type. */
+#define STT_OBJECT 1 /* Data Object. */
+#define STT_FUNC 2 /* Function entry point. */
+
+// Special Section Indicies.
+#define SHN_UNDEF 0 /* Undefined section. */
+#define SHN_ABS 0xff1 /* Indicates an absolute value. */
+
+/// -----------------
+/// Relocations Entry
+/// -----------------
+
+typedef struct {
+ uint64_t offset; // Virtual address of the storage unit affected by the relocation.
+ uint64_t info; // Symbol table index + relocation type.
+} Elf64Rel;
+
+typedef struct {
+ uint64_t offset; // Virtual address of the storage unit affected by the relocation.
+ uint64_t info; // Symbol table index + relocation type.
+ int64_t addend; // Constant value used to compute the relocation value.
+} Elf64Rela;
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i)&0xffffffffL)
+
+// x86_64 relocation types.
+#define R_X86_64_64 1 /* Absolute 64bit address, address affected by relocation: `base + offset` */
+#define R_X86_64_COPY 5 /* Copy content from sym addr to relocation address: `base + offset` */
+#define R_X86_64_GLOB_DAT 6 /* Address affected by relocation: `base + offset` */
+#define R_X86_64_JUMP_SLOT 7 /* Address affected by relocation: `base + offset` */
+#define R_X86_64_RELATIVE 8 /* Relative address *`base + offset` = `base + addend` */
diff --git a/lib/include/syscall.h b/lib/include/syscall.h
index 4947155..10dc545 100644
--- a/lib/include/syscall.h
+++ b/lib/include/syscall.h
@@ -19,6 +19,7 @@
//
// Machine specific constraints (x86_64):
// a | a register (eg rax)
+// c | c register (eg rcx)
// d | d register (eg rdx)
// D | di register (eg rdi)
// S | si register (eg rsi)
@@ -35,29 +36,62 @@
// 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 syscall3(n, a1, a2, a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3))
+#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))
+#define syscall4(n, a1, a2, a3, a4) _syscall4(n, argcast(a1), argcast(a2), argcast(a3), argcast(a4))
+#define syscall6(n, a1, a2, a3, a4, a5, a6) _syscall6(n, argcast(a1), argcast(a2), argcast(a3), argcast(a4), argcast(a5), argcast(a6))
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;
+}
+
+static inline long _syscall4(long n, long a1, long a2, long a3, long a4) {
+ long ret;
+ register long r10 asm("r10") = a4;
+ asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10) : "rcx", "r11", "memory");
+ return ret;
+}
+
+static inline long _syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) {
+ long ret;
+ register long r10 asm("r10") = a4;
+ register long r8 asm("r8") = a5;
+ register long r9 asm("r9") = a6;
+ asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory");
return ret;
}
diff --git a/lib/include/syscalls.h b/lib/include/syscalls.h
new file mode 100644
index 0000000..7808e98
--- /dev/null
+++ b/lib/include/syscalls.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2021 Johannes Stoelp
+
+#pragma once
+
+#include <stddef.h> // size_t
+#include <sys/types.h> // ssize_t, off_t, ...
+
+extern int dynld_errno;
+
+// Syscall definitions taken from corresponding man pages, eg
+// open(2)
+// read(2)
+// ...
+
+#define O_RDONLY 00
+int open(const char* path, int flags);
+int close(int fd);
+
+#define F_OK 0
+#define R_OK 4
+int access(const char* path, int mode);
+
+ssize_t write(int fd, const void* buf, size_t count);
+ssize_t read(int fd, void* buf, size_t count);
+ssize_t pread(int fd, void* buf, size_t count, off_t offset);
+
+// mmap - prot:
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+// mmap - flags:
+#define MAP_PRIVATE 0x2
+#define MAP_ANONYMOUS 0x20
+#define MAP_FIXED 0x10
+// mmap - ret:
+#define MAP_FAILED ((void*)-1)
+void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
+int munmap(void* addr, size_t length);
+
+void _exit(int status);