/* * piehello.c -- stage 19: "hello" as a static PIE, built with the stock * `musl-gcc -static-pie` (no special flags). The file's addresses start * at 0; the kernel loads it at a random base and tells us where through * the auxiliary vector. musl's start-up code (rcrt1.o) then fixes up the * program's own pointers before main runs. * * Exit code = number of failed checks. `piehello where` prints the load * address of main (tests/static_pie.rs runs it twice: different bases). */ #define _GNU_SOURCE #include #include #include #include #include static int fails; #define CHECK(cond, what) \ do { \ if (!(cond)) { \ fails++; \ printf("piehello: FAIL %s\n", what); \ } \ } while (0) /* Pointers in data: these need fixing up (relocating) at start-up. */ static const char *greeting = "hello from a static PIE"; static int (*say)(const char *) = puts; extern char _start[]; extern const Elf64_Ehdr __ehdr_start; /* the linker's name for our ELF header */ int main(int argc, char **argv) { if (argc > 1 && strcmp(argv[1], "where") == 0) { printf("%p\n", (void *)main); return 0; } say(greeting); unsigned long phdr = getauxval(AT_PHDR), entry = getauxval(AT_ENTRY); CHECK(getauxval(AT_BASE) == 0, "AT_BASE is 0 (no dynamic loader)"); CHECK(entry == (unsigned long)_start, "AT_ENTRY is where _start is"); CHECK(getauxval(AT_PHENT) == sizeof(Elf64_Phdr), "AT_PHENT"); /* Our ELF header is loaded too, at the load bias (the file's lowest * address is 0), and the program headers follow it, where AT_PHDR says. */ unsigned long bias = (unsigned long)&__ehdr_start; CHECK(phdr == bias + __ehdr_start.e_phoff, "AT_PHDR points at the program headers"); const Elf64_Phdr *ph = (const Elf64_Phdr *)phdr; int has_tls = 0, has_relro = 0, has_interp = 0; for (unsigned long i = 0; i < getauxval(AT_PHNUM); i++) { has_tls |= ph[i].p_type == PT_TLS; has_relro |= ph[i].p_type == PT_GNU_RELRO; has_interp |= ph[i].p_type == PT_INTERP; } CHECK(bias != 0 && bias % 4096 == 0, "a page-aligned, non-zero load bias"); CHECK(bias >= 0x8000000000UL, "loaded in Rustbelt's user space"); CHECK(has_relro && !has_interp, "PT_GNU_RELRO, no PT_INTERP"); (void)has_tls; /* The relocated pointers point into the loaded image. */ CHECK((unsigned long)greeting > bias, "relocated string pointer"); /* RELRO: musl made it read-only after relocating; mprotect worked. */ printf("argv[0] = %s, %d argument(s), bias %#lx\n", argv[0], argc, bias); return fails; }