aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/elf.h26
-rw-r--r--include/fmt.h125
-rw-r--r--include/syscall.h56
3 files changed, 207 insertions, 0 deletions
diff --git a/include/elf.h b/include/elf.h
new file mode 100644
index 0000000..7e279fe
--- /dev/null
+++ b/include/elf.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2020 Johannes Stoelp
+
+#pragma once
+
+#include <bits/stdint-uintn.h>
+#include <stdint.h>
+
+enum eAuxvTag {
+ AT_NULL = 0, /* ignored */
+ AT_IGNORE = 1, /* ignored */
+ AT_EXECFD = 2, /* val */
+ AT_PHDR = 3, /* ptr */
+ AT_PHENT = 4, /* val */
+ AT_PHNUM = 5, /* val */
+ AT_PAGESZ = 6, /* val */
+ AT_BASE = 7, /* ptr */
+ AT_FLAGS = 8, /* val */
+ AT_ENTRY = 9, /* ptr */
+ AT_NOTELF = 10, /* val */
+ AT_UID = 11, /* val */
+ AT_EUID = 12, /* val */
+ AT_GID = 13, /* val */
+ AT_EGID = 14, /* val */
+
+ AT_MAX_CNT,
+};
diff --git a/include/fmt.h b/include/fmt.h
new file mode 100644
index 0000000..c74ac4c
--- /dev/null
+++ b/include/fmt.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2020 Johannes Stoelp
+
+#pragma once
+
+#include <stdarg.h>
+
+#define ALLOW_UNUSED __attribute__((unused))
+
+ALLOW_UNUSED
+static const char* num2dec(char* buf, unsigned long len, unsigned long long num) {
+ char* pbuf = buf + len - 1;
+ *pbuf = '\0';
+
+ if (num == 0) {
+ *(--pbuf) = '0';
+ }
+
+ while (num > 0 && pbuf != buf) {
+ char d = (num % 10) + '0';
+ *(--pbuf) = d;
+ num /= 10;
+ }
+ return pbuf;
+}
+
+ALLOW_UNUSED
+static const char* num2hex(char* buf, unsigned long len, unsigned long long num) {
+ char* pbuf = buf + len - 1;
+ *pbuf = '\0';
+
+ if (num == 0) {
+ *(--pbuf) = '0';
+ }
+
+ while (num > 0 && pbuf != buf) {
+ char d = (num & 0xf);
+ *(--pbuf) = d + (d > 9 ? 'a' - 10 : '0');
+ num >>= 4;
+ }
+ return pbuf;
+}
+
+ALLOW_UNUSED
+static int dynld_vsnprintf(char* buf, unsigned long len, const char* fmt, va_list ap) {
+ unsigned i = 0;
+
+#define put(c) \
+ { \
+ char _c = (c); \
+ if (i < len) { \
+ buf[i] = _c; \
+ } \
+ ++i; \
+ }
+
+#define puts(s) \
+ while (*s) { \
+ put(*s++); \
+ }
+
+ char scratch[16];
+ int l_cnt = 0;
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ put(*fmt++);
+ continue;
+ }
+
+ l_cnt = 0;
+
+ continue_fmt:
+ switch (*(++fmt /* constume '%' */)) {
+ case 'l':
+ ++l_cnt;
+ goto continue_fmt;
+ case 'd': {
+ long val = l_cnt > 0 ? va_arg(ap, long) : va_arg(ap, int);
+ if (val < 0) {
+ val *= -1;
+ put('-');
+ }
+ const char* ptr = num2dec(scratch, sizeof(scratch), val);
+ puts(ptr);
+ } break;
+ case 'x': {
+ unsigned long val = l_cnt > 0 ? va_arg(ap, unsigned long) : va_arg(ap, unsigned);
+ const char* ptr = num2hex(scratch, sizeof(scratch), val);
+ puts(ptr);
+ } break;
+ case 's': {
+ const char* ptr = va_arg(ap, const char*);
+ puts(ptr);
+ } break;
+ case 'p': {
+ const void* val = va_arg(ap, const void*);
+ const char* ptr = num2hex(scratch, sizeof(scratch), (unsigned long long)val);
+ put('0');
+ put('x');
+ puts(ptr);
+ } break;
+ default:
+ put(*fmt);
+ break;
+ }
+ ++fmt;
+ }
+
+#undef puts
+#undef put
+
+ if (buf) {
+ i < len ? (buf[i] = '\0') : (buf[len - 1] = '\0');
+ }
+ return i;
+}
+
+ALLOW_UNUSED
+static int dynld_snprintf(char* buf, unsigned long len, const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = dynld_vsnprintf(buf, len, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/include/syscall.h b/include/syscall.h
new file mode 100644
index 0000000..0460ede
--- /dev/null
+++ b/include/syscall.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2020 Johannes Stoelp
+
+#pragma once
+
+#if !defined(__linux__) || !defined(__x86_64__)
+# error "Only supported on linux(x86_64)!"
+#endif
+
+// Inline ASM
+// Syntax:
+// asm asm-qualifiers (AssemblerTemplate : OutputOperands : InputOperands : Clobbers)
+//
+// Output operand constraints:
+// = | operand (variable) is written to by this instruction
+// + | operand (variable) is written to / read from by this instruction
+//
+// Input/Output operand constraints:
+// r | allocate general purpose register
+//
+// Machine specific constraints (x86_64):
+// a | a register (eg rax)
+// d | d register (eg rdx)
+// D | di register (eg rdi)
+// S | si register (eg rsi)
+//
+// Local register variables:
+// In case a specific register is required which can not be specified via a
+// machine specific constraint.
+// ```c
+// register long r12 asm ("r12") = 42;
+// asm("nop" : : "r"(r10));
+// ```
+//
+// Reference:
+// 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
+//
+// Reference:
+// syscall(2)
+
+#define argcast(A) ((long)(A))
+#define syscall3(n,a1,a2,a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3))
+
+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");
+ return ret;
+}