From 1d2a6f21294f8390b683e4e097cb49210ed832d1 Mon Sep 17 00:00:00 2001 From: johannst Date: Fri, 26 Mar 2021 23:17:46 +0100 Subject: Added dyn allocator + syscall wrappers + minor fixes. --- lib/Makefile | 6 +++- lib/include/alloc.h | 6 ++++ lib/include/auxv.h | 2 +- lib/include/common.h | 18 +++++------ lib/include/syscall.h | 33 +++++++++++++------ lib/include/syscalls.h | 23 +++++++++++++ lib/src/alloc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/fmt.c | 6 ++-- lib/src/syscalls.c | 22 +++++++++++++ 9 files changed, 179 insertions(+), 24 deletions(-) create mode 100644 lib/include/alloc.h create mode 100644 lib/include/syscalls.h create mode 100644 lib/src/alloc.c create mode 100644 lib/src/syscalls.c (limited to 'lib') 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 - -#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 // size_t +#include // 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 +#include + +#include + +// 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 // __NR_* +#include +#include + +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(); +} -- cgit v1.2.3 From 9b4b10a31954c00813a7cbf9411d30bc84eccea8 Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 17 Apr 2021 23:38:23 +0200 Subject: add memset --- lib/Makefile | 1 + lib/include/common.h | 15 +++++++++------ lib/src/common.c | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 lib/src/common.c (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 62ecde8..5f8a1a9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,6 +9,7 @@ HDR+=include/syscall.h HDR+=include/syscalls.h DEP+=src/alloc.o +DEP+=src/common.o DEP+=src/fmt.o DEP+=src/io.o DEP+=src/syscalls.o diff --git a/lib/include/common.h b/lib/include/common.h index 631c25f..1e48097 100644 --- a/lib/include/common.h +++ b/lib/include/common.h @@ -5,10 +5,13 @@ #include "io.h" #include "syscalls.h" -#define ERROR_ON(cond, fmt, ...) \ - do { \ - if ((cond)) { \ - efmt("%s:%d " fmt, __FILE__, __LINE__ __VA_OPT__(, ) __VA_ARGS__); \ - _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); diff --git a/lib/src/common.c b/lib/src/common.c new file mode 100644 index 0000000..2d122f5 --- /dev/null +++ b/lib/src/common.c @@ -0,0 +1,18 @@ +// Copyright (c) 2021 Johannes Stoelp + +#include + +#if !defined(__linux__) || !defined(__x86_64__) +# error "Only supported on linux(x86_64)!" +#endif + +void* memset(void* s, int c, size_t n) { + asm volatile( + "cld" + "\n" + "rep stosb" + : "+D"(s), "+c"(n) + : "a"(c) + : "memory"); + return s; +} -- cgit v1.2.3 From 26088bf37ef85681cf2158fdff82233b1b0c9bfd Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 17 Apr 2021 23:41:17 +0200 Subject: added close,access,write,pread,mmap,munmap syscalls + syscall ret handler --- lib/include/syscall.h | 27 +++++++++++++++++++++++---- lib/include/syscalls.h | 25 +++++++++++++++++++++---- lib/src/syscalls.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 88 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/include/syscall.h b/lib/include/syscall.h index c9314d2..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) @@ -54,10 +55,12 @@ // 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)) +#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; @@ -76,3 +79,19 @@ static inline long _syscall3(long n, long a1, long a2, long a3) { 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 index 34b6b37..7808e98 100644 --- a/lib/include/syscalls.h +++ b/lib/include/syscalls.h @@ -5,6 +5,8 @@ #include // size_t #include // ssize_t, off_t, ... +extern int dynld_errno; + // Syscall definitions taken from corresponding man pages, eg // open(2) // read(2) @@ -12,12 +14,27 @@ #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); -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -off_t lseek(int fd, off_t offset, int whence); +// 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); diff --git a/lib/src/syscalls.c b/lib/src/syscalls.c index d6ac1a5..074fced 100644 --- a/lib/src/syscalls.c +++ b/lib/src/syscalls.c @@ -4,16 +4,56 @@ #include #include +// Storage for `dynld_errno`. +int dynld_errno; + +// Convert return value to errno/ret. +static long syscall_ret(unsigned long ret) { + if (ret > (unsigned long)-4096ul) { + dynld_errno = -ret; + return -1; + } + return ret; +} + int open(const char* path, int flags) { - return syscall2(__NR_open, path, flags); + long ret = syscall2(__NR_open, path, flags); + return syscall_ret(ret); +} + +int close(int fd) { + long ret = syscall1(__NR_close, fd); + return syscall_ret(ret); +} + +int access(const char* path, int mode) { + long ret = syscall2(__NR_access, path, mode); + return syscall_ret(ret); +} + +ssize_t write(int fd, const void* buf, size_t count) { + long ret = syscall3(__NR_write, fd, buf, count); + return syscall_ret(ret); } ssize_t read(int fd, void* buf, size_t count) { - return syscall3(__NR_read, fd, buf, count); + long ret = syscall3(__NR_read, fd, buf, count); + return syscall_ret(ret); +} + +ssize_t pread(int fd, void* buf, size_t count, off_t offset) { + long ret = syscall4(__NR_read, fd, buf, count, offset); + return syscall_ret(ret); +} + +void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + long ret = syscall6(__NR_mmap, addr, length, prot, flags, fd, offset); + return (void*)syscall_ret(ret); } -off_t lseek(int fd, off_t offset, int whence) { - return syscall3(__NR_lseek, fd, offset, whence); +int munmap(void* addr, size_t length) { + long ret = syscall2(__NR_munmap, addr, length); + return syscall_ret(ret); } void _exit(int status) { -- cgit v1.2.3 From 1bcaa7aceefad99c7bda9cb7bf6fcc5b48b53a75 Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 17 Apr 2021 23:41:52 +0200 Subject: fmt: add support for %c --- lib/src/fmt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/src/fmt.c b/lib/src/fmt.c index b0840de..56d95ed 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 = (char)(num % 10) + '0'; + char d = (char)(num % 10) + '0'; *(--pbuf) = d; num /= 10; } @@ -81,6 +81,10 @@ int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) { const char* ptr = num2hex(scratch, sizeof(scratch), val); puts(ptr); } break; + case 'c': { + char c = va_arg(ap, int); // By C standard, value passed to varg smaller than `sizeof(int)` will be converted to int. + put(c); + } break; case 's': { const char* ptr = va_arg(ap, const char*); puts(ptr); -- cgit v1.2.3 From b3f93e87f773c0e9099f256c78c1485fd7ce1dce Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 17 Apr 2021 23:42:18 +0200 Subject: io: make use of write syscall wrapper --- lib/src/io.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/src/io.c b/lib/src/io.c index b5e0dc5..5194042 100644 --- a/lib/src/io.c +++ b/lib/src/io.c @@ -1,10 +1,9 @@ // Copyright (c) 2020 Johannes Stoelp -#include #include +#include #include - -#include +#include // `pfmt` uses fixed-size buffer on the stack for formating the message // (for simplicity and since we don't impl buffered I/O). @@ -21,14 +20,14 @@ static int vdfmt(int fd, const char* fmt, va_list ap) { int ret = vfmt(buf, sizeof(buf), fmt, ap); if (ret > MAX_PRINTF_LEN - 1) { - syscall3(__NR_write, fd, buf, MAX_PRINTF_LEN - 1); + write(fd, buf, MAX_PRINTF_LEN - 1); static const char warn[] = "\npfmt: Message truncated, max length can be configured by defining MAX_PRINTF_LEN\n"; - syscall3(__NR_write, FD_STDERR, warn, sizeof(warn)); + write(FD_STDERR, warn, sizeof(warn)); return MAX_PRINTF_LEN - 1; } - syscall3(__NR_write, fd, buf, ret); + write(fd, buf, ret); return ret; } -- cgit v1.2.3 From 0358652ff40546877c63fee8ca272db76b94a37d Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 17 Apr 2021 23:43:01 +0200 Subject: elf: add ehdr, sym, reloc --- lib/include/elf.h | 114 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 104 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/include/elf.h b/lib/include/elf.h index a0fe6f7..4856c79 100644 --- a/lib/include/elf.h +++ b/lib/include/elf.h @@ -4,6 +4,51 @@ #include +/// ---------- +/// 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 /// -------------- @@ -39,16 +84,16 @@ 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_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 */ @@ -73,3 +118,52 @@ 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_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_JUMP_SLOT 7 /* Address affected by relocation: `offset` (+ base) */ -- cgit v1.2.3 From 3155439c1a96f1964aaee799b008331d0b362db3 Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 19 Apr 2021 21:50:29 +0200 Subject: added tests for fmt() char, long nums --- lib/src/fmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/src/fmt.c b/lib/src/fmt.c index 56d95ed..24ddd98 100644 --- a/lib/src/fmt.c +++ b/lib/src/fmt.c @@ -51,7 +51,7 @@ int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) { put(*s++); \ } - char scratch[16]; + char scratch[32]; int l_cnt = 0; while (*fmt) { -- cgit v1.2.3 From 1df4dfdcdbbaef7e5b32c5c0bfadec02b3ccd6f0 Mon Sep 17 00:00:00 2001 From: johannst Date: Tue, 20 Apr 2021 22:05:13 +0200 Subject: added memcpy + tests for memcpy/memset --- lib/include/common.h | 2 ++ lib/src/common.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'lib') diff --git a/lib/include/common.h b/lib/include/common.h index 1e48097..d006d71 100644 --- a/lib/include/common.h +++ b/lib/include/common.h @@ -15,3 +15,5 @@ void* memset(void* s, int c, size_t n); +void* memcpy(void* d, const void* s, size_t n); + diff --git a/lib/src/common.c b/lib/src/common.c index 2d122f5..dd806bf 100644 --- a/lib/src/common.c +++ b/lib/src/common.c @@ -16,3 +16,23 @@ void* memset(void* s, int c, size_t n) { : "memory"); return s; } + +void* memcpy(void* d, const void* s, size_t n) { + // When `d` points into `[s, s+n[` we would override `s` while copying into `d`. + // |------------|--------| + // s d s+n + // -> We don't support. + // + // When `d` points into `]s-n, s[` it is destructive for `s` but all data + // from `s` are copied into `d`. The user gets what he asks for. + // -> Supported. + ERROR_ON(s <= d && d < (void*)((unsigned char*)s + n), "memcpy: Unsupported overlap!"); + asm volatile( + "cld" + "\n" + "rep movsb" + : "+D"(d), "+S"(s), "+c"(n) + : + : "memory"); + return d; +} -- cgit v1.2.3 From 85230524414b6d27664bf77c8584bfeced6c71cb Mon Sep 17 00:00:00 2001 From: johannst Date: Wed, 21 Apr 2021 23:41:59 +0200 Subject: add support to resolve all relocations in PLT & RELA tables; add global variable as example to libgreet.so --- lib/include/elf.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/include/elf.h b/lib/include/elf.h index 4856c79..f0a0940 100644 --- a/lib/include/elf.h +++ b/lib/include/elf.h @@ -141,11 +141,12 @@ typedef struct { // 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. */ +#define SHN_UNDEF 0 /* Undefined section. */ +#define SHN_ABS 0xff1 /* Indicates an absolute value. */ /// ----------------- /// Relocations Entry @@ -166,4 +167,6 @@ typedef struct { #define ELF64_R_TYPE(i) ((i)&0xffffffffL) // x86_64 relocation types. +#define R_X86_64_COPY 5 /* Copy content from sym addr to relocation address */ +#define R_X86_64_GLOB_DAT 6 /* Address affected by relocation: `offset` (+ base) */ #define R_X86_64_JUMP_SLOT 7 /* Address affected by relocation: `offset` (+ base) */ -- cgit v1.2.3 From 05f740db6fe966d32256d4ed3b897f7b3e051fff Mon Sep 17 00:00:00 2001 From: johannst Date: Sun, 25 Apr 2021 23:38:36 +0200 Subject: added support for R_X86_64_64/R_X86_64_RELATIVE relocations + added init/fini --- lib/include/elf.h | 64 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/include/elf.h b/lib/include/elf.h index f0a0940..7a2e597 100644 --- a/lib/include/elf.h +++ b/lib/include/elf.h @@ -84,32 +84,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; @@ -167,6 +171,8 @@ typedef struct { #define ELF64_R_TYPE(i) ((i)&0xffffffffL) // x86_64 relocation types. -#define R_X86_64_COPY 5 /* Copy content from sym addr to relocation address */ -#define R_X86_64_GLOB_DAT 6 /* Address affected by relocation: `offset` (+ base) */ -#define R_X86_64_JUMP_SLOT 7 /* Address affected by relocation: `offset` (+ base) */ +#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` */ -- cgit v1.2.3 From fc137e7d0263a0fe908ca1a150e34a9c8b9902d4 Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 26 Apr 2021 22:47:53 +0200 Subject: add check for PT_TLS phdr --- lib/include/elf.h | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/include/elf.h b/lib/include/elf.h index 7a2e597..0317859 100644 --- a/lib/include/elf.h +++ b/lib/include/elf.h @@ -60,6 +60,7 @@ typedef struct { #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 -- cgit v1.2.3