From f9f2b6bb2d685556bc3346ca3f7e55f4c865fc16 Mon Sep 17 00:00:00 2001 From: johannst Date: Tue, 24 Nov 2020 21:23:08 +0100 Subject: add process init chapter Add chapter on process initialization. Add program to visualize data provided by the Linux Kernel as specified in the SysV ABI. Add utils for syscalls and printing + tests. --- include/elf.h | 26 ++++++++++++ include/fmt.h | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/syscall.h | 56 ++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 include/elf.h create mode 100644 include/fmt.h create mode 100644 include/syscall.h (limited to 'include') 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 +#include + +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 + +#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; +} -- cgit v1.2.3