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.
This commit is contained in:
Alex Smith 2012-07-28 16:57:56 +01:00
parent bd8b78e6ee
commit 12b3e8a8a0
6 changed files with 194 additions and 23 deletions

View File

@ -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 ;

View File

@ -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) }
}

View File

@ -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
:
<src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o
<src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o
<src!system!libroot!posix!string!arch!$(TARGET_ARCH)>arch_string.o
;

View File

@ -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 <runtime_loader.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
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;
}

View File

@ -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();
}

View File

@ -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