From 12b3e8a8a01e04da03da98410425695880e96347 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sat, 28 Jul 2012 16:57:56 +0100 Subject: [PATCH] Support x86_64 in the runtime loader. * Added x86_64 linker script and relocation code. * Some 64-bit safety fixes to the heap code. * Added runtime_loader, libroot and bash to the x86_64 image. The boot script will be launched, but will panic shortly after because fork is broken. --- build/jam/Haiku64Image | 8 +- src/system/ldscripts/x86_64/runtime_loader.ld | 53 ++++++++++ src/system/runtime_loader/arch/x86_64/Jamfile | 14 +++ .../arch/x86_64/arch_relocate.cpp | 96 +++++++++++++++++++ src/system/runtime_loader/heap.cpp | 32 +++---- src/system/runtime_loader/images.cpp | 14 ++- 6 files changed, 194 insertions(+), 23 deletions(-) create mode 100644 src/system/ldscripts/x86_64/runtime_loader.ld create mode 100644 src/system/runtime_loader/arch/x86_64/Jamfile create mode 100644 src/system/runtime_loader/arch/x86_64/arch_relocate.cpp diff --git a/build/jam/Haiku64Image b/build/jam/Haiku64Image index 1b126d4b37..d887b46abd 100644 --- a/build/jam/Haiku64Image +++ b/build/jam/Haiku64Image @@ -19,7 +19,7 @@ if $(HAIKU_ATA_STACK) = 1 { IDE_ONLY = "" ; } -SYSTEM_BIN = ; +SYSTEM_BIN = bash ; SYSTEM_APPS = ; @@ -27,7 +27,7 @@ SYSTEM_PREFERENCES = ; SYSTEM_DEMOS = ; -SYSTEM_LIBS = ; +SYSTEM_LIBS = libroot.so ; PRIVATE_SYSTEM_LIBS = ; @@ -74,13 +74,13 @@ AddLibrariesToHaikuHybridImage system lib AddFilesToHaikuImage system servers : $(SYSTEM_SERVERS) ; # apps -#AddFilesToHaikuImage system : runtime_loader ; +AddFilesToHaikuImage system : runtime_loader ; AddFilesToHaikuImage system bin : $(SYSTEM_BIN) ; AddFilesToHaikuImage system apps : $(SYSTEM_APPS) ; AddFilesToHaikuImage system preferences : $(SYSTEM_PREFERENCES) ; AddFilesToHaikuImage system demos : $(SYSTEM_DEMOS) ; -#AddSymlinkToHaikuImage system bin : bash : sh ; +AddSymlinkToHaikuImage system bin : bash : sh ; #AddSymlinkToHaikuImage system bin : less : more ; #AddSymlinkToHaikuImage system bin : gzip : gunzip ; #AddSymlinkToHaikuImage system bin : gzip : zcat ; diff --git a/src/system/ldscripts/x86_64/runtime_loader.ld b/src/system/ldscripts/x86_64/runtime_loader.ld new file mode 100644 index 0000000000..a83a6de457 --- /dev/null +++ b/src/system/ldscripts/x86_64/runtime_loader.ld @@ -0,0 +1,53 @@ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) + +ENTRY(runtime_loader) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x00200000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rela.got : { *(.rela.got) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x90909090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .text.* .gnu.linkonce.t.*) } =0x90909090 + + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + + /* writable data */ + . = ALIGN (CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); + __data_start = .; + PROVIDE(_data_start = .); + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + PROVIDE (_ctor_list = .); + .ctors : { *(.ctors) } + PROVIDE (__ctor_end = .); + + + /* uninitialized data (in same segment as writable data) */ + PROVIDE (__bss_start = .); + .bss : { *(.bss) } + + . = ALIGN(0x1000); + PROVIDE (_end = .); + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/system/runtime_loader/arch/x86_64/Jamfile b/src/system/runtime_loader/arch/x86_64/Jamfile new file mode 100644 index 0000000000..a894a0c1b5 --- /dev/null +++ b/src/system/runtime_loader/arch/x86_64/Jamfile @@ -0,0 +1,14 @@ +SubDir HAIKU_TOP src system runtime_loader arch x86_64 ; + +UsePrivateHeaders runtime_loader ; +UsePrivateSystemHeaders ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; + +StaticLibrary libruntime_loader_$(TARGET_ARCH).a : + arch_relocate.cpp + : + atomic.o + thread.o + arch_string.o +; diff --git a/src/system/runtime_loader/arch/x86_64/arch_relocate.cpp b/src/system/runtime_loader/arch/x86_64/arch_relocate.cpp new file mode 100644 index 0000000000..7148c2e23f --- /dev/null +++ b/src/system/runtime_loader/arch/x86_64/arch_relocate.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + */ + + +#include "runtime_loader_private.h" + +#include + +#include +#include +#include + + +static status_t +relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel, + size_t relLength, SymbolLookupCache* cache) +{ + for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) { + int type = ELF64_R_TYPE(rel[i].r_info); + int symIndex = ELF64_R_SYM(rel[i].r_info); + Elf64_Addr symAddr = 0; + + // Resolve the symbol, if any. + if (symIndex != 0) { + Elf64_Sym* sym = SYMBOL(image, symIndex); + + status_t status = resolve_symbol(rootImage, image, sym, cache, + &symAddr); + if (status != B_OK) { + TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n", + SYMNAME(image, sym), status)); + printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n", + SYMNAME(image, sym), status); + return status; + } + } + + // Address of the relocation. + Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset; + + // Calculate the relocation value. + Elf64_Addr relocValue; + switch(type) { + case R_X86_64_NONE: + continue; + case R_X86_64_64: + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + relocValue = symAddr + rel[i].r_addend; + break; + case R_X86_64_PC32: + relocValue = symAddr + rel[i].r_addend - rel[i].r_offset; + break; + case R_X86_64_RELATIVE: + relocValue = image->regions[0].delta + rel[i].r_addend; + break; + default: + TRACE(("unhandled relocation type %d\n", type)); + return B_BAD_DATA; + } + + *(Elf64_Addr *)relocAddr = relocValue; + } + + return B_OK; +} + + +status_t +arch_relocate_image(image_t* rootImage, image_t* image, + SymbolLookupCache* cache) +{ + status_t status; + + // No REL on x86_64. + + // Perform RELA relocations. + if (image->rela) { + status = relocate_rela(rootImage, image, image->rela, image->rela_len, + cache); + if (status != B_OK) + return status; + } + + // PLT relocations (they are RELA on x86_64). + if (image->pltrel) { + status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel, + image->pltrel_len, cache); + if (status != B_OK) + return status; + } + + return B_OK; +} diff --git a/src/system/runtime_loader/heap.cpp b/src/system/runtime_loader/heap.cpp index 03346a978e..02dc286b02 100644 --- a/src/system/runtime_loader/heap.cpp +++ b/src/system/runtime_loader/heap.cpp @@ -35,11 +35,11 @@ static const size_t kInitialHeapSize = 65536; struct free_chunk { - uint32 size; + size_t size; free_chunk *next; - uint32 Size() const; - free_chunk *Split(uint32 splitSize); + size_t Size() const; + free_chunk *Split(size_t splitSize); bool IsTouching(free_chunk *link); free_chunk *Join(free_chunk *link); void Remove(free_chunk *previous = NULL); @@ -50,7 +50,7 @@ struct free_chunk { }; -static uint32 sAvailable; +static size_t sAvailable; static free_chunk sFreeAnchor; @@ -58,10 +58,10 @@ static free_chunk sFreeAnchor; * in this chunk. */ -uint32 +size_t free_chunk::Size() const { - return size - sizeof(uint32); + return size - sizeof(size_t); } @@ -70,13 +70,13 @@ free_chunk::Size() const */ free_chunk * -free_chunk::Split(uint32 splitSize) +free_chunk::Split(size_t splitSize) { - free_chunk *chunk = (free_chunk *)((uint8 *)this + sizeof(uint32) + splitSize); - chunk->size = size - splitSize - sizeof(uint32); + free_chunk *chunk = (free_chunk *)((uint8 *)this + sizeof(size_t) + splitSize); + chunk->size = size - splitSize - sizeof(size_t); chunk->next = next; - size = splitSize + sizeof(uint32); + size = splitSize + sizeof(size_t); return chunk; } @@ -167,7 +167,7 @@ free_chunk::AllocatedAddress() const free_chunk * free_chunk::SetToAllocated(void *allocated) { - return (free_chunk *)((uint8 *)allocated - sizeof(uint32)); + return (free_chunk *)((uint8 *)allocated - sizeof(size_t)); } @@ -183,7 +183,7 @@ add_area(size_t size) if (area < B_OK) return area; - sAvailable += size - sizeof(uint32); + sAvailable += size - sizeof(size_t); // declare the whole heap as one chunk, and add it // to the free list @@ -198,7 +198,7 @@ add_area(size_t size) static status_t -grow_heap(uint32 bytes) +grow_heap(size_t bytes) { // align the area size to an 32768 bytes boundary bytes = (bytes + 32767) & ~32767; @@ -295,10 +295,10 @@ restart: goto restart; } - if (chunk->Size() > size + sizeof(free_chunk) + 4) { + if (chunk->Size() > size + sizeof(free_chunk) + sizeof(size_t)) { // if this chunk is bigger than the requested size, // we split it to form two chunks (with a minimal - // size of 4 allocatable bytes). + // size of sizeof(size_t) allocatable bytes). free_chunk *freeChunk = chunk->Split(size); last->next = freeChunk; @@ -312,7 +312,7 @@ restart: last->next = chunk->next; } - sAvailable -= size + sizeof(uint32); + sAvailable -= size + sizeof(size_t); return chunk->AllocatedAddress(); } diff --git a/src/system/runtime_loader/images.cpp b/src/system/runtime_loader/images.cpp index 0f504a9335..6c6c460285 100644 --- a/src/system/runtime_loader/images.cpp +++ b/src/system/runtime_loader/images.cpp @@ -23,8 +23,16 @@ #include "runtime_loader_private.h" -#define RLD_PROGRAM_BASE 0x00200000 - /* keep in sync with app ldscript */ +// keep in sync with app ldscript +#ifdef __x86_64__ + // runtime_loader potentially occupies 0x200000 - 0x600000 due to large + // page segment alignment. +# define RLD_PROGRAM_BASE 0x600000 +# define MAX_PAGE_SIZE 0x200000 +#else +# define RLD_PROGRAM_BASE 0x200000 +# define MAX_PAGE_SIZE B_PAGE_SIZE +#endif bool gInvalidImageIDs; @@ -319,7 +327,7 @@ map_image(int fd, char const* path, image_t* image, bool fixed) // Check whether the segments have an unreasonable amount of unused space // inbetween. - if (reservedSize > length + 8 * 1024) + if (reservedSize > length + MAX_PAGE_SIZE * 2) return B_BAD_DATA; // reserve that space and allocate the areas from that one