From 32b756510fd216cc507a320ae1cd539fc4222609 Mon Sep 17 00:00:00 2001 From: Alessandro Di Federico Date: Sat, 30 Jan 2016 11:07:47 +0100 Subject: [PATCH] Prepare stack for the translated program * Create 3 constant global variables (`phdr_address`, `e_phentsize` and `e_phnum`) in the IR which will be used to populate the auxiliary vectors at run-time. * Update compile options for `support.c` to ignore useless warnings and enable debug information * Implement in `support.c` some functions required by QEMU run-time and other cleanups to make it compatible with programs translated from `_start`, not `root` * Implement in `support.c` the `prepare_stack` function, which initializes the base of the stack with environment variables, arguments and auxiliary vectors * Improve syscall support --- codegenerator.cpp | 43 ++++++++--- tests/Tests.cmake | 2 +- tests/support.c | 177 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 190 insertions(+), 32 deletions(-) diff --git a/codegenerator.cpp b/codegenerator.cpp index 742fc82b4..f50aef33c 100644 --- a/codegenerator.cpp +++ b/codegenerator.cpp @@ -80,11 +80,6 @@ CodeGenerator::CodeGenerator(std::string Input, BinaryHandle = std::move(BinaryOrErr.get()); - // Provide an abort declaration - TheModule->getOrInsertFunction("abort", - FunctionType::get(Type::getVoidTy(Context), - false)); - // We only support ELF for now auto *TheBinary = cast(BinaryHandle.getBinary()); @@ -148,6 +143,23 @@ void CodeGenerator::parseELF(object::ObjectFile *TheBinary, ElfHeaderHelper->setAlignment(1); ElfHeaderHelper->setSection(".elfheaderhelper"); + auto *RegisterType = Type::getIntNTy(Context, T::Is64Bits ? 64 : 32); + auto createConstGlobal = [this, &RegisterType] (const Twine &Name, + uint64_t Value) { + return new GlobalVariable(*TheModule, + RegisterType, + true, + GlobalValue::ExternalLinkage, + ConstantInt::get(RegisterType, Value), + Name); + }; + + // These values will be used to populate the auxiliary vectors + auto PhdrAddress = reinterpret_cast(TheELF.base() + + ElfHeader->e_phoff); + createConstGlobal("phdr_address", PhdrAddress); + createConstGlobal("e_phentsize", ElfHeader->e_phentsize); + createConstGlobal("e_phnum", ElfHeader->e_phnum); // Loop over the program headers looking for PT_LOAD segments, read them out // and create a global variable for each one of them (writable or read-only), @@ -521,6 +533,21 @@ bool CpuLoopExitPass::runOnModule(llvm::Module& M) { void CodeGenerator::translate(uint64_t VirtualAddress, std::string Name) { + // Declare useful functions + TheModule->getOrInsertFunction("abort", + FunctionType::get(Type::getVoidTy(Context), + false)); + auto *TargetSetBrkFunction = HelpersModule->getFunction("target_set_brk"); + TheModule->getOrInsertFunction("target_set_brk", + TargetSetBrkFunction->getFunctionType()); + Function *CpuLoop = HelpersModule->getFunction("cpu_loop"); + assert(CpuLoop != nullptr); + TheModule->getOrInsertFunction("cpu_loop", CpuLoop->getFunctionType()); + TheModule->getOrInsertFunction("syscall_init", + FunctionType::get(Type::getVoidTy(Context), + { }, + false)); + IRBuilder<> Builder(Context); if (VirtualAddress == 0) @@ -676,16 +703,11 @@ void CodeGenerator::translate(uint64_t VirtualAddress, std::tie(VirtualAddress, Entry) = JumpTargets.peek(); } // End translations loop - Function *CpuLoop = HelpersModule->getFunction("cpu_loop"); - assert(CpuLoop != nullptr); legacy::FunctionPassManager CpuLoopPM(TheModule.get()); CpuLoopPM.add(new LoopInfoWrapperPass()); CpuLoopPM.add(new CpuLoopFunctionPass()); CpuLoopPM.run(*CpuLoop); - // Force linking of cpu_loop - TheModule->getOrInsertFunction("cpu_loop", CpuLoop->getFunctionType()); - // CpuLoopFunctionPass expects a variable name exception_index to exist Variables.getByEnvOffset(ptc.exception_index, "exception_index"); @@ -711,6 +733,7 @@ void CodeGenerator::translate(uint64_t VirtualAddress, // syscall.c "print_syscall", "print_syscall_ret", + "do_ioctl_dm", // ARM cpu_loop "EmulateAll", "cpu_abort", diff --git a/tests/Tests.cmake b/tests/Tests.cmake index 9295a33b3..94cde3da2 100644 --- a/tests/Tests.cmake +++ b/tests/Tests.cmake @@ -150,7 +150,7 @@ foreach(ARCH ${SUPPORTED_ARCHITECTURES}) COMMAND sh -c "$ -g ll --entry $(${CMAKE_CURRENT_SOURCE_DIR}/tests/get-function-virtual-address ${BIN}/${TEST_NAME} root) --architecture ${ARCH} ${BIN}/${TEST_NAME} ${BIN}/${TEST_NAME}.ll") # Command-line to link support.c and the translated binaries - compile_executable("$(${CMAKE_CURRENT_SOURCE_DIR}/tests/li-csv-to-ld-options ${BIN}/${TEST_NAME}.ll.li.csv) ${BIN}/${TEST_NAME}${CMAKE_C_OUTPUT_EXTENSION} ${TEST_SRC}/support.c -DTARGET_${NORMALIZED_ARCH}" + compile_executable("$(${CMAKE_CURRENT_SOURCE_DIR}/tests/li-csv-to-ld-options ${BIN}/${TEST_NAME}.ll.li.csv) ${BIN}/${TEST_NAME}${CMAKE_C_OUTPUT_EXTENSION} ${TEST_SRC}/support.c -DTARGET_${NORMALIZED_ARCH} -lz -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -g" "${BIN}/${TEST_NAME}.translated" COMPILE_TRANSLATED) diff --git a/tests/support.c b/tests/support.c index 6e988f986..9772733c6 100644 --- a/tests/support.c +++ b/tests/support.c @@ -1,8 +1,12 @@ -#include -#include +#include +#include #include +#include +#include #include +#include #include +#include #if defined(TARGET_arm) @@ -17,6 +21,8 @@ target_reg *return_value = &r0; target_reg *first_argument = &r0; target_reg *second_argument = &r1; +#define SWAP(x) (htole32(x)) + #elif defined(TARGET_x86_64) typedef uint64_t target_reg; @@ -30,6 +36,8 @@ target_reg *return_value = &rax; target_reg *first_argument = &rdi; target_reg *second_argument = &rsi; +#define SWAP(x) (htole64(x)) + #elif defined(TARGET_mips) typedef uint32_t target_reg; @@ -44,6 +52,8 @@ target_reg *return_value = &v0; target_reg *first_argument = &a0; target_reg *second_argument = &a1; +#define SWAP(x) (htobe32(x)) + #endif void root(void); @@ -65,29 +75,154 @@ void itoa(unsigned i, char *b){ } while(i); } -int main(int argc, char *argv[]) { - char buffer[100]; - int size = strlen(argv[1]); - *first_argument = (target_reg) mmap((void *) 0x9000, - 0x3000, - PROT_READ | PROT_WRITE, MAP_FIXED - | MAP_ANONYMOUS | MAP_32BIT | MAP_PRIVATE, - -1, - 0); - memcpy((void *) *first_argument, argv[1], size); - *second_argument = size; +const unsigned align = sizeof(target_reg); +extern target_reg phdr_address; +extern target_reg e_phentsize; +extern target_reg e_phnum; - *stack = (target_reg) mmap((void *) 0x3000, - 0x3000, - PROT_READ | PROT_WRITE, MAP_FIXED - | MAP_ANONYMOUS | MAP_32BIT | MAP_PRIVATE, +void page_set_flags(target_reg start, target_reg end, int flags) { } +void tb_invalidate_phys_range(target_reg start, target_reg end) { } +uintptr_t qemu_real_host_page_size = 1 << 12; +uintptr_t qemu_real_host_page_mask = ~((1 << 12) - 1); +uintptr_t qemu_host_page_size = 1 << 12; +uintptr_t qemu_host_page_mask = ~((1 << 12) - 1); + + +target_reg prepare_stack(target_reg stack, int argc, char **argv) { + target_reg tmp; + target_reg platform_address; + target_reg random_address; + target_reg arg_area; + char **argp; + char **arge; + +#define MOVE(ptr, size) do { \ + (ptr) -= ((size) + align - 1) & ~(align - 1); \ + } while (0); + +#define PUSH(ptr, size, data) do { \ + MOVE(ptr, size); \ + memcpy((void *) (ptr), (data), size); \ + } while(0) + +#define PUSH_STR(ptr, data) do { \ + tmp = strlen(data) + 1; \ + PUSH(ptr, (tmp), (void *) (data)); \ + } while(0) + +#define PUSH_REG(ptr, data) do { \ + tmp = SWAP(data); \ + PUSH(ptr, align, (void *) &tmp); \ + } while (0); + +#define PUSH_AUX(ptr, key, value) do { \ + PUSH_REG(ptr, key); \ + PUSH_REG(ptr, (target_reg) (value)); \ + } while(0) + + // Reserve space for arguments and environment variables + arg_area = stack; + argp = argv; + + while (*++argp != NULL) + ; + while (*++argp != NULL) + ; + + arge = argp; + + while (*--argp != NULL) + MOVE(stack, strlen(*argp) + 1); + // Push the arguments + while (--argp != (argv - 1)) + MOVE(stack, strlen(*argp) + 1); + + PUSH_STR(stack, "revamb"); + platform_address = (target_reg) stack; + + // 1234567890123456 + PUSH_STR(stack, "4 I used a dice"); + random_address = (target_reg) stack; + + // Force 16 bytes alignment + stack &= ~15; + + PUSH_AUX(stack, AT_NULL, 0); + PUSH_AUX(stack, AT_PHDR, phdr_address); + PUSH_AUX(stack, AT_PHENT, e_phentsize); + PUSH_AUX(stack, AT_PHNUM, e_phnum); + PUSH_AUX(stack, AT_PAGESZ, 4096); + PUSH_AUX(stack, AT_BASE, 0); + PUSH_AUX(stack, AT_FLAGS, 0); + PUSH_AUX(stack, AT_ENTRY, &root); + PUSH_AUX(stack, AT_UID, getuid()); + PUSH_AUX(stack, AT_EUID, geteuid()); + PUSH_AUX(stack, AT_GID, getgid()); + PUSH_AUX(stack, AT_EGID, getegid()); + // PUSH_AUX(stack, AT_HWCAP, (abi_ulong) ELF_HWCAP); + // PUSH_AUX(stack, AT_HWCAP2, (abi_ulong) ELF_HWCAP2); + PUSH_AUX(stack, AT_CLKTCK, sysconf(_SC_CLK_TCK)); + PUSH_AUX(stack, AT_RANDOM, random_address); + PUSH_AUX(stack, AT_PLATFORM, platform_address); + + PUSH_REG(stack, 0); + + // Copy arguments and environment variables, and store their address + argp = arge; + + // First push environment variables + while (*--argp != NULL) { + PUSH_STR(arg_area, *argp); + PUSH_REG(stack, arg_area); + } + + // Push the separator + PUSH_REG(stack, 0); + + // Push the arguments + while (--argp != (argv - 1)) { + PUSH_STR(arg_area, *argp); + PUSH_REG(stack, arg_area); + } + + PUSH_REG(stack, argc); + +#undef PUSH_AUX +#undef PUSH_REG +#undef PUSH +#undef PUSH_STR +#undef MOVE + + return stack; +} + +void target_set_brk(target_reg new_brk); +void syscall_init(void); + +void *g_malloc0_n(size_t n, size_t size) { + return calloc(n, size); +} + +int main(int argc, char *argv[]) { + *stack = (target_reg) mmap((void *) NULL, + 0x100000, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_32BIT | MAP_PRIVATE, -1, - 0) + 0x1000; + 0) + 0x100000 - 0x1000; + + *stack = prepare_stack(*stack, argc, argv); + + target_set_brk((target_reg) mmap((void *) NULL, + 0x1000, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_32BIT | MAP_PRIVATE, + -1, + 0) + 0x1000); + + syscall_init(); root(); - itoa(*return_value, buffer); - puts(buffer); - return 0; }