* Moved most code of the heavy elf.cpp into several smaller source files.
* Some style cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30808 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -65,16 +65,26 @@ SEARCH on [ FGristFiles kernel_vsprintf.c ]
|
|||||||
SEARCH on [ FGristFiles KMessage.cpp ]
|
SEARCH on [ FGristFiles KMessage.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src system kernel messaging ] ;
|
= [ FDirName $(HAIKU_TOP) src system kernel messaging ] ;
|
||||||
|
|
||||||
Objects
|
|
||||||
runtime_loader.cpp
|
local sources =
|
||||||
|
add_ons.cpp
|
||||||
elf.cpp
|
elf.cpp
|
||||||
|
elf_haiku_version.cpp
|
||||||
|
elf_load_image.cpp
|
||||||
|
elf_symbol_lookup.cpp
|
||||||
|
elf_versioning.cpp
|
||||||
|
errors.cpp
|
||||||
export.cpp
|
export.cpp
|
||||||
heap.cpp
|
heap.cpp
|
||||||
|
images.cpp
|
||||||
|
runtime_loader.cpp
|
||||||
utility.cpp
|
utility.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
|
Objects $(sources) ;
|
||||||
|
|
||||||
Ld runtime_loader :
|
Ld runtime_loader :
|
||||||
[ FGristFiles runtime_loader.o elf.o export.o heap.o utility.o ]
|
[ FGristFiles $(sources:S=$(SUFOBJ)) ]
|
||||||
libruntime_loader.a
|
libruntime_loader.a
|
||||||
libruntime_loader_$(TARGET_ARCH).a
|
libruntime_loader_$(TARGET_ARCH).a
|
||||||
$(TARGET_STATIC_LIBSUPC++)
|
$(TARGET_STATIC_LIBSUPC++)
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "add_ons.h"
|
||||||
|
|
||||||
|
#include <util/kernel_cpp.h>
|
||||||
|
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<RuntimeLoaderAddOn> AddOnList;
|
||||||
|
|
||||||
|
|
||||||
|
static status_t register_defined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie);
|
||||||
|
static void unregister_defined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie);
|
||||||
|
static status_t register_undefined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie);
|
||||||
|
static void unregister_undefined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie);
|
||||||
|
|
||||||
|
|
||||||
|
static AddOnList sAddOns;
|
||||||
|
|
||||||
|
static runtime_loader_add_on_export sRuntimeLoaderAddOnExport = {
|
||||||
|
register_defined_symbol_patcher,
|
||||||
|
unregister_defined_symbol_patcher,
|
||||||
|
register_undefined_symbol_patcher,
|
||||||
|
unregister_undefined_symbol_patcher
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - add-on support functions
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
register_defined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie)
|
||||||
|
{
|
||||||
|
RuntimeLoaderSymbolPatcher* patcher
|
||||||
|
= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
|
||||||
|
if (patcher == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
patcher->next = image->defined_symbol_patchers;
|
||||||
|
image->defined_symbol_patchers = patcher;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
unregister_defined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie)
|
||||||
|
{
|
||||||
|
RuntimeLoaderSymbolPatcher** patcher = &image->defined_symbol_patchers;
|
||||||
|
while (*patcher != NULL) {
|
||||||
|
if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
|
||||||
|
RuntimeLoaderSymbolPatcher* toDelete = *patcher;
|
||||||
|
*patcher = (*patcher)->next;
|
||||||
|
delete toDelete;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
patcher = &(*patcher)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
register_undefined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie)
|
||||||
|
{
|
||||||
|
RuntimeLoaderSymbolPatcher* patcher
|
||||||
|
= new(mynothrow) RuntimeLoaderSymbolPatcher(_patcher, cookie);
|
||||||
|
if (patcher == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
patcher->next = image->undefined_symbol_patchers;
|
||||||
|
image->undefined_symbol_patchers = patcher;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
unregister_undefined_symbol_patcher(struct image_t* image,
|
||||||
|
runtime_loader_symbol_patcher* _patcher, void* cookie)
|
||||||
|
{
|
||||||
|
RuntimeLoaderSymbolPatcher** patcher = &image->undefined_symbol_patchers;
|
||||||
|
while (*patcher != NULL) {
|
||||||
|
if ((*patcher)->patcher == _patcher && (*patcher)->cookie == cookie) {
|
||||||
|
RuntimeLoaderSymbolPatcher* toDelete = *patcher;
|
||||||
|
*patcher = (*patcher)->next;
|
||||||
|
delete toDelete;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
patcher = &(*patcher)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
init_add_ons()
|
||||||
|
{
|
||||||
|
// invoke static constructors
|
||||||
|
new(&sAddOns) AddOnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
add_add_on(image_t* image, runtime_loader_add_on* addOnStruct)
|
||||||
|
{
|
||||||
|
RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image,
|
||||||
|
addOnStruct);
|
||||||
|
if (addOn == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
sAddOns.Add(addOn);
|
||||||
|
addOnStruct->init(&gRuntimeLoader, &sRuntimeLoaderAddOnExport);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
image_event(image_t* image, uint32 event)
|
||||||
|
{
|
||||||
|
AddOnList::Iterator it = sAddOns.GetIterator();
|
||||||
|
while (RuntimeLoaderAddOn* addOn = it.Next()) {
|
||||||
|
void (*function)(image_t* image) = NULL;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case IMAGE_EVENT_LOADED:
|
||||||
|
function = addOn->addOn->image_loaded;
|
||||||
|
break;
|
||||||
|
case IMAGE_EVENT_RELOCATED:
|
||||||
|
function = addOn->addOn->image_relocated;
|
||||||
|
break;
|
||||||
|
case IMAGE_EVENT_INITIALIZED:
|
||||||
|
function = addOn->addOn->image_initialized;
|
||||||
|
break;
|
||||||
|
case IMAGE_EVENT_UNINITIALIZING:
|
||||||
|
function = addOn->addOn->image_uninitializing;
|
||||||
|
break;
|
||||||
|
case IMAGE_EVENT_UNLOADING:
|
||||||
|
function = addOn->addOn->image_unloading;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function != NULL)
|
||||||
|
function(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ADD_ONS_H
|
||||||
|
#define ADD_ONS_H
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
#include <runtime_loader.h>
|
||||||
|
|
||||||
|
|
||||||
|
// image events
|
||||||
|
enum {
|
||||||
|
IMAGE_EVENT_LOADED,
|
||||||
|
IMAGE_EVENT_RELOCATED,
|
||||||
|
IMAGE_EVENT_INITIALIZED,
|
||||||
|
IMAGE_EVENT_UNINITIALIZING,
|
||||||
|
IMAGE_EVENT_UNLOADING
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct RuntimeLoaderAddOn
|
||||||
|
: public DoublyLinkedListLinkImpl<RuntimeLoaderAddOn> {
|
||||||
|
image_t* image;
|
||||||
|
runtime_loader_add_on* addOn;
|
||||||
|
|
||||||
|
RuntimeLoaderAddOn(image_t* image, runtime_loader_add_on* addOn)
|
||||||
|
:
|
||||||
|
image(image),
|
||||||
|
addOn(addOn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct RuntimeLoaderSymbolPatcher {
|
||||||
|
RuntimeLoaderSymbolPatcher* next;
|
||||||
|
runtime_loader_symbol_patcher* patcher;
|
||||||
|
void* cookie;
|
||||||
|
|
||||||
|
RuntimeLoaderSymbolPatcher(runtime_loader_symbol_patcher* patcher,
|
||||||
|
void* cookie)
|
||||||
|
:
|
||||||
|
patcher(patcher),
|
||||||
|
cookie(cookie)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void init_add_ons();
|
||||||
|
status_t add_add_on(image_t* image, runtime_loader_add_on* addOnStruct);
|
||||||
|
void image_event(image_t* image, uint32 event);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ADD_ONS_H
|
||||||
+70
-2215
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "elf_haiku_version.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <image_defs.h>
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
|
#include "elf_symbol_lookup.h"
|
||||||
|
|
||||||
|
|
||||||
|
// interim Haiku API versions
|
||||||
|
#define HAIKU_VERSION_PRE_GLUE_CODE 0x00000010
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
analyze_object_gcc_version(int fd, image_t* image, Elf32_Ehdr& eheader,
|
||||||
|
int32 sheaderSize, char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
if (sheaderSize > (int)bufferSize) {
|
||||||
|
FATAL("Cannot handle section headers bigger than %lu\n", bufferSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read section headers
|
||||||
|
ssize_t length = _kern_read(fd, eheader.e_shoff, buffer, sheaderSize);
|
||||||
|
if (length != sheaderSize) {
|
||||||
|
FATAL("Could not read section headers: %s\n", strerror(length));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the string section
|
||||||
|
Elf32_Shdr* sectionHeader
|
||||||
|
= (Elf32_Shdr*)(buffer + eheader.e_shstrndx * eheader.e_shentsize);
|
||||||
|
|
||||||
|
if (sheaderSize + sectionHeader->sh_size > bufferSize) {
|
||||||
|
FATAL("Buffer not big enough for section string section\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sectionStrings = buffer + bufferSize - sectionHeader->sh_size;
|
||||||
|
length = _kern_read(fd, sectionHeader->sh_offset, sectionStrings,
|
||||||
|
sectionHeader->sh_size);
|
||||||
|
if (length != (int)sectionHeader->sh_size) {
|
||||||
|
FATAL("Could not read section string section: %s\n", strerror(length));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the .comment section
|
||||||
|
off_t commentOffset = 0;
|
||||||
|
size_t commentSize = 0;
|
||||||
|
for (uint32 i = 0; i < eheader.e_shnum; i++) {
|
||||||
|
sectionHeader = (Elf32_Shdr*)(buffer + i * eheader.e_shentsize);
|
||||||
|
const char* sectionName = sectionStrings + sectionHeader->sh_name;
|
||||||
|
if (sectionHeader->sh_name != 0
|
||||||
|
&& strcmp(sectionName, ".comment") == 0) {
|
||||||
|
commentOffset = sectionHeader->sh_offset;
|
||||||
|
commentSize = sectionHeader->sh_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commentSize == 0) {
|
||||||
|
FATAL("Could not find .comment section\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read a part of the comment section
|
||||||
|
if (commentSize > 512)
|
||||||
|
commentSize = 512;
|
||||||
|
|
||||||
|
length = _kern_read(fd, commentOffset, buffer, commentSize);
|
||||||
|
if (length != (int)commentSize) {
|
||||||
|
FATAL("Could not read .comment section: %s\n", strerror(length));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the common prefix of the strings in the .comment section
|
||||||
|
static const char* kGCCVersionPrefix = "GCC: (GNU) ";
|
||||||
|
size_t gccVersionPrefixLen = strlen(kGCCVersionPrefix);
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
int gccMajor = 0;
|
||||||
|
int gccMiddle = 0;
|
||||||
|
int gccMinor = 0;
|
||||||
|
bool isHaiku = true;
|
||||||
|
|
||||||
|
// Read up to 10 comments. The first three or four are usually from the
|
||||||
|
// glue code.
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
// skip '\0'
|
||||||
|
while (index < commentSize && buffer[index] == '\0')
|
||||||
|
index++;
|
||||||
|
char* stringStart = buffer + index;
|
||||||
|
|
||||||
|
// find string end
|
||||||
|
while (index < commentSize && buffer[index] != '\0')
|
||||||
|
index++;
|
||||||
|
|
||||||
|
// ignore the entry at the end of the buffer
|
||||||
|
if (index == commentSize)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// We have to analyze string like these:
|
||||||
|
// GCC: (GNU) 2.9-beos-991026
|
||||||
|
// GCC: (GNU) 2.95.3-haiku-080322
|
||||||
|
// GCC: (GNU) 4.1.2
|
||||||
|
|
||||||
|
// skip the common prefix
|
||||||
|
if (strncmp(stringStart, kGCCVersionPrefix, gccVersionPrefixLen) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// the rest is the GCC version
|
||||||
|
char* gccVersion = stringStart + gccVersionPrefixLen;
|
||||||
|
char* gccPlatform = strchr(gccVersion, '-');
|
||||||
|
char* patchLevel = NULL;
|
||||||
|
if (gccPlatform != NULL) {
|
||||||
|
*gccPlatform = '\0';
|
||||||
|
gccPlatform++;
|
||||||
|
patchLevel = strchr(gccPlatform, '-');
|
||||||
|
if (patchLevel != NULL) {
|
||||||
|
*patchLevel = '\0';
|
||||||
|
patchLevel++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// split the gcc version into major, middle, and minor
|
||||||
|
int version[3] = { 0, 0, 0 };
|
||||||
|
|
||||||
|
for (int k = 0; gccVersion != NULL && k < 3; k++) {
|
||||||
|
char* dot = strchr(gccVersion, '.');
|
||||||
|
if (dot) {
|
||||||
|
*dot = '\0';
|
||||||
|
dot++;
|
||||||
|
}
|
||||||
|
version[k] = atoi(gccVersion);
|
||||||
|
gccVersion = dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// got any version?
|
||||||
|
if (version[0] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Select the gcc version with the smallest major, but the greatest
|
||||||
|
// middle/minor. This should usually ignore the glue code version as
|
||||||
|
// well as cases where e.g. in a gcc 2 program a single C file has
|
||||||
|
// been compiled with gcc 4.
|
||||||
|
if (gccMajor == 0 || gccMajor > version[0]
|
||||||
|
|| (gccMajor == version[0]
|
||||||
|
&& (gccMiddle < version[1]
|
||||||
|
|| (gccMiddle == version[1] && gccMinor < version[2])))) {
|
||||||
|
gccMajor = version[0];
|
||||||
|
gccMiddle = version[1];
|
||||||
|
gccMinor = version[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gccMajor == 2 && gccPlatform != NULL
|
||||||
|
&& strcmp(gccPlatform, "haiku")) {
|
||||||
|
isHaiku = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gccMajor == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (gccMajor == 2) {
|
||||||
|
if (gccMiddle < 95)
|
||||||
|
image->abi = B_HAIKU_ABI_GCC_2_ANCIENT;
|
||||||
|
else if (isHaiku)
|
||||||
|
image->abi = B_HAIKU_ABI_GCC_2_HAIKU;
|
||||||
|
else
|
||||||
|
image->abi = B_HAIKU_ABI_GCC_2_BEOS;
|
||||||
|
} else
|
||||||
|
image->abi = gccMajor << 16;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
analyze_image_haiku_version_and_abi(int fd, image_t* image, Elf32_Ehdr& eheader,
|
||||||
|
int32 sheaderSize, char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
// Haiku API version
|
||||||
|
struct Elf32_Sym* symbol = find_symbol(image,
|
||||||
|
SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME,
|
||||||
|
B_SYMBOL_TYPE_DATA));
|
||||||
|
if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
|
||||||
|
&& symbol->st_value > 0
|
||||||
|
&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
|
||||||
|
&& symbol->st_size >= sizeof(uint32)) {
|
||||||
|
image->api_version
|
||||||
|
= *(uint32*)(symbol->st_value + image->regions[0].delta);
|
||||||
|
} else
|
||||||
|
image->api_version = 0;
|
||||||
|
|
||||||
|
// Haiku ABI
|
||||||
|
symbol = find_symbol(image,
|
||||||
|
SymbolLookupInfo(B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME,
|
||||||
|
B_SYMBOL_TYPE_DATA));
|
||||||
|
if (symbol != NULL && symbol->st_shndx != SHN_UNDEF
|
||||||
|
&& symbol->st_value > 0
|
||||||
|
&& ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT
|
||||||
|
&& symbol->st_size >= sizeof(uint32)) {
|
||||||
|
image->abi = *(uint32*)(symbol->st_value + image->regions[0].delta);
|
||||||
|
} else
|
||||||
|
image->abi = 0;
|
||||||
|
|
||||||
|
if (image->abi == 0) {
|
||||||
|
// No ABI version in the shared object, i.e. it has been built before
|
||||||
|
// that was introduced in Haiku. We have to try and analyze the gcc
|
||||||
|
// version.
|
||||||
|
if (!analyze_object_gcc_version(fd, image, eheader, sheaderSize,
|
||||||
|
buffer, bufferSize)) {
|
||||||
|
FATAL("Failed to get gcc version for %s\n", image->path);
|
||||||
|
// not really fatal, actually
|
||||||
|
|
||||||
|
// assume ancient BeOS
|
||||||
|
image->abi = B_HAIKU_ABI_GCC_2_ANCIENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// guess the API version, if we couldn't figure it out yet
|
||||||
|
if (image->api_version == 0) {
|
||||||
|
image->api_version = image->abi > B_HAIKU_ABI_GCC_2_BEOS
|
||||||
|
? HAIKU_VERSION_PRE_GLUE_CODE : B_HAIKU_VERSION_BEOS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ELF_HAIKU_VERSION_H
|
||||||
|
#define ELF_HAIKU_VERSION_H
|
||||||
|
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
void analyze_image_haiku_version_and_abi(int fd, image_t* image,
|
||||||
|
Elf32_Ehdr& eheader, int32 sheaderSize, char* buffer,
|
||||||
|
size_t bufferSize);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ELF_HAIKU_VERSION_H
|
||||||
@@ -0,0 +1,547 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||||
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "elf_load_image.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <syscalls.h>
|
||||||
|
|
||||||
|
#include "add_ons.h"
|
||||||
|
#include "elf_haiku_version.h"
|
||||||
|
#include "elf_symbol_lookup.h"
|
||||||
|
#include "elf_versioning.h"
|
||||||
|
#include "images.h"
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const char* sSearchPathSubDir = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
get_program_path()
|
||||||
|
{
|
||||||
|
return gProgramImage != NULL ? gProgramImage->path : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int32
|
||||||
|
count_regions(char const* buff, int phnum, int phentsize)
|
||||||
|
{
|
||||||
|
struct Elf32_Phdr* pheaders;
|
||||||
|
int32 count = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < phnum; i++) {
|
||||||
|
pheaders = (struct Elf32_Phdr*)(buff + i * phentsize);
|
||||||
|
|
||||||
|
switch (pheaders->p_type) {
|
||||||
|
case PT_NULL:
|
||||||
|
// NOP header
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
count += 1;
|
||||||
|
if (pheaders->p_memsz != pheaders->p_filesz) {
|
||||||
|
addr_t A = TO_PAGE_SIZE(pheaders->p_vaddr
|
||||||
|
+ pheaders->p_memsz);
|
||||||
|
addr_t B = TO_PAGE_SIZE(pheaders->p_vaddr
|
||||||
|
+ pheaders->p_filesz);
|
||||||
|
|
||||||
|
if (A != B)
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PT_DYNAMIC:
|
||||||
|
// will be handled at some other place
|
||||||
|
break;
|
||||||
|
case PT_INTERP:
|
||||||
|
// should check here for appropiate interpreter
|
||||||
|
break;
|
||||||
|
case PT_NOTE:
|
||||||
|
// unsupported
|
||||||
|
break;
|
||||||
|
case PT_SHLIB:
|
||||||
|
// undefined semantics
|
||||||
|
break;
|
||||||
|
case PT_PHDR:
|
||||||
|
// we don't use it
|
||||||
|
break;
|
||||||
|
case PT_STACK:
|
||||||
|
// we don't use it
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FATAL("unhandled pheader type in count 0x%lx\n",
|
||||||
|
pheaders->p_type);
|
||||||
|
return B_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
parse_program_headers(image_t* image, char* buff, int phnum, int phentsize)
|
||||||
|
{
|
||||||
|
struct Elf32_Phdr* pheader;
|
||||||
|
int regcount;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
regcount = 0;
|
||||||
|
for (i = 0; i < phnum; i++) {
|
||||||
|
pheader = (struct Elf32_Phdr*)(buff + i * phentsize);
|
||||||
|
|
||||||
|
switch (pheader->p_type) {
|
||||||
|
case PT_NULL:
|
||||||
|
/* NOP header */
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
if (pheader->p_memsz == pheader->p_filesz) {
|
||||||
|
/*
|
||||||
|
* everything in one area
|
||||||
|
*/
|
||||||
|
image->regions[regcount].start = pheader->p_vaddr;
|
||||||
|
image->regions[regcount].size = pheader->p_memsz;
|
||||||
|
image->regions[regcount].vmstart
|
||||||
|
= PAGE_BASE(pheader->p_vaddr);
|
||||||
|
image->regions[regcount].vmsize
|
||||||
|
= TO_PAGE_SIZE(pheader->p_memsz
|
||||||
|
+ PAGE_OFFSET(pheader->p_vaddr));
|
||||||
|
image->regions[regcount].fdstart = pheader->p_offset;
|
||||||
|
image->regions[regcount].fdsize = pheader->p_filesz;
|
||||||
|
image->regions[regcount].delta = 0;
|
||||||
|
image->regions[regcount].flags = 0;
|
||||||
|
if (pheader->p_flags & PF_WRITE) {
|
||||||
|
// this is a writable segment
|
||||||
|
image->regions[regcount].flags |= RFLAG_RW;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* may require splitting
|
||||||
|
*/
|
||||||
|
addr_t A = TO_PAGE_SIZE(pheader->p_vaddr
|
||||||
|
+ pheader->p_memsz);
|
||||||
|
addr_t B = TO_PAGE_SIZE(pheader->p_vaddr
|
||||||
|
+ pheader->p_filesz);
|
||||||
|
|
||||||
|
image->regions[regcount].start = pheader->p_vaddr;
|
||||||
|
image->regions[regcount].size = pheader->p_filesz;
|
||||||
|
image->regions[regcount].vmstart
|
||||||
|
= PAGE_BASE(pheader->p_vaddr);
|
||||||
|
image->regions[regcount].vmsize
|
||||||
|
= TO_PAGE_SIZE(pheader->p_filesz
|
||||||
|
+ PAGE_OFFSET(pheader->p_vaddr));
|
||||||
|
image->regions[regcount].fdstart = pheader->p_offset;
|
||||||
|
image->regions[regcount].fdsize = pheader->p_filesz;
|
||||||
|
image->regions[regcount].delta = 0;
|
||||||
|
image->regions[regcount].flags = 0;
|
||||||
|
if (pheader->p_flags & PF_WRITE) {
|
||||||
|
// this is a writable segment
|
||||||
|
image->regions[regcount].flags |= RFLAG_RW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (A != B) {
|
||||||
|
/*
|
||||||
|
* yeah, it requires splitting
|
||||||
|
*/
|
||||||
|
regcount += 1;
|
||||||
|
image->regions[regcount].start = pheader->p_vaddr;
|
||||||
|
image->regions[regcount].size
|
||||||
|
= pheader->p_memsz - pheader->p_filesz;
|
||||||
|
image->regions[regcount].vmstart
|
||||||
|
= image->regions[regcount-1].vmstart
|
||||||
|
+ image->regions[regcount-1].vmsize;
|
||||||
|
image->regions[regcount].vmsize
|
||||||
|
= TO_PAGE_SIZE(pheader->p_memsz
|
||||||
|
+ PAGE_OFFSET(pheader->p_vaddr))
|
||||||
|
- image->regions[regcount-1].vmsize;
|
||||||
|
image->regions[regcount].fdstart = 0;
|
||||||
|
image->regions[regcount].fdsize = 0;
|
||||||
|
image->regions[regcount].delta = 0;
|
||||||
|
image->regions[regcount].flags = RFLAG_ANON;
|
||||||
|
if (pheader->p_flags & PF_WRITE) {
|
||||||
|
// this is a writable segment
|
||||||
|
image->regions[regcount].flags |= RFLAG_RW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
regcount += 1;
|
||||||
|
break;
|
||||||
|
case PT_DYNAMIC:
|
||||||
|
image->dynamic_ptr = pheader->p_vaddr;
|
||||||
|
break;
|
||||||
|
case PT_INTERP:
|
||||||
|
// should check here for appropiate interpreter
|
||||||
|
break;
|
||||||
|
case PT_NOTE:
|
||||||
|
// unsupported
|
||||||
|
break;
|
||||||
|
case PT_SHLIB:
|
||||||
|
// undefined semantics
|
||||||
|
break;
|
||||||
|
case PT_PHDR:
|
||||||
|
// we don't use it
|
||||||
|
break;
|
||||||
|
case PT_STACK:
|
||||||
|
// we don't use it
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FATAL("unhandled pheader type in parse 0x%lx\n",
|
||||||
|
pheader->p_type);
|
||||||
|
return B_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
assert_dynamic_loadable(image_t* image)
|
||||||
|
{
|
||||||
|
uint32 i;
|
||||||
|
|
||||||
|
if (!image->dynamic_ptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (i = 0; i < image->num_regions; i++) {
|
||||||
|
if (image->dynamic_ptr >= image->regions[i].start
|
||||||
|
&& image->dynamic_ptr
|
||||||
|
< image->regions[i].start + image->regions[i].size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_dynamic_segment(image_t* image)
|
||||||
|
{
|
||||||
|
struct Elf32_Dyn* d;
|
||||||
|
int i;
|
||||||
|
int sonameOffset = -1;
|
||||||
|
|
||||||
|
image->symhash = 0;
|
||||||
|
image->syms = 0;
|
||||||
|
image->strtab = 0;
|
||||||
|
|
||||||
|
d = (struct Elf32_Dyn*)image->dynamic_ptr;
|
||||||
|
if (!d)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (i = 0; d[i].d_tag != DT_NULL; i++) {
|
||||||
|
switch (d[i].d_tag) {
|
||||||
|
case DT_NEEDED:
|
||||||
|
image->num_needed += 1;
|
||||||
|
break;
|
||||||
|
case DT_HASH:
|
||||||
|
image->symhash
|
||||||
|
= (uint32*)(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_STRTAB:
|
||||||
|
image->strtab
|
||||||
|
= (char*)(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_SYMTAB:
|
||||||
|
image->syms = (struct Elf32_Sym*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_REL:
|
||||||
|
image->rel = (struct Elf32_Rel*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_RELSZ:
|
||||||
|
image->rel_len = d[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_RELA:
|
||||||
|
image->rela = (struct Elf32_Rela*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_RELASZ:
|
||||||
|
image->rela_len = d[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
// TK: procedure linkage table
|
||||||
|
case DT_JMPREL:
|
||||||
|
image->pltrel = (struct Elf32_Rel*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_PLTRELSZ:
|
||||||
|
image->pltrel_len = d[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_INIT:
|
||||||
|
image->init_routine
|
||||||
|
= (d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_FINI:
|
||||||
|
image->term_routine
|
||||||
|
= (d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_SONAME:
|
||||||
|
sonameOffset = d[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_VERSYM:
|
||||||
|
image->symbol_versions = (Elf32_Versym*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_VERDEF:
|
||||||
|
image->version_definitions = (Elf32_Verdef*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_VERDEFNUM:
|
||||||
|
image->num_version_definitions = d[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_VERNEED:
|
||||||
|
image->needed_versions = (Elf32_Verneed*)
|
||||||
|
(d[i].d_un.d_ptr + image->regions[0].delta);
|
||||||
|
break;
|
||||||
|
case DT_VERNEEDNUM:
|
||||||
|
image->num_needed_versions = d[i].d_un.d_val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets make sure we found all the required sections
|
||||||
|
if (!image->symhash || !image->syms || !image->strtab)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (sonameOffset >= 0)
|
||||||
|
strlcpy(image->name, STRING(image, sonameOffset), sizeof(image->name));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
parse_elf_header(struct Elf32_Ehdr* eheader, int32* _pheaderSize,
|
||||||
|
int32* _sheaderSize)
|
||||||
|
{
|
||||||
|
if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
|
||||||
|
return B_NOT_AN_EXECUTABLE;
|
||||||
|
|
||||||
|
if (eheader->e_ident[4] != ELFCLASS32)
|
||||||
|
return B_NOT_AN_EXECUTABLE;
|
||||||
|
|
||||||
|
if (eheader->e_phoff == 0)
|
||||||
|
return B_NOT_AN_EXECUTABLE;
|
||||||
|
|
||||||
|
if (eheader->e_phentsize < sizeof(struct Elf32_Phdr))
|
||||||
|
return B_NOT_AN_EXECUTABLE;
|
||||||
|
|
||||||
|
*_pheaderSize = eheader->e_phentsize * eheader->e_phnum;
|
||||||
|
*_sheaderSize = eheader->e_shentsize * eheader->e_shnum;
|
||||||
|
|
||||||
|
if (*_pheaderSize <= 0 || *_sheaderSize <= 0)
|
||||||
|
return B_NOT_AN_EXECUTABLE;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
load_image(char const* name, image_type type, const char* rpath,
|
||||||
|
image_t** _image)
|
||||||
|
{
|
||||||
|
int32 pheaderSize, sheaderSize;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
ssize_t length;
|
||||||
|
char pheaderBuffer[4096];
|
||||||
|
int32 numRegions;
|
||||||
|
image_t* found;
|
||||||
|
image_t* image;
|
||||||
|
status_t status;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
struct Elf32_Ehdr eheader;
|
||||||
|
|
||||||
|
// Have we already loaded that image? Don't check for add-ons -- we always
|
||||||
|
// reload them.
|
||||||
|
if (type != B_ADD_ON_IMAGE) {
|
||||||
|
found = find_loaded_image_by_name(name, APP_OR_LIBRARY_TYPE);
|
||||||
|
|
||||||
|
if (found == NULL && type != B_APP_IMAGE) {
|
||||||
|
// Special case for add-ons that link against the application
|
||||||
|
// executable, with the executable not having a soname set.
|
||||||
|
if (const char* lastSlash = strrchr(name, '/')) {
|
||||||
|
if (strcmp(gProgramImage->name, lastSlash + 1) == 0)
|
||||||
|
found = gProgramImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
atomic_add(&found->ref_count, 1);
|
||||||
|
*_image = found;
|
||||||
|
KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
|
||||||
|
"already loaded", name, type, rpath);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
|
||||||
|
rpath);
|
||||||
|
|
||||||
|
strlcpy(path, name, sizeof(path));
|
||||||
|
|
||||||
|
// find and open the file
|
||||||
|
fd = open_executable(path, type, rpath, get_program_path(),
|
||||||
|
sSearchPathSubDir);
|
||||||
|
if (fd < 0) {
|
||||||
|
FATAL("cannot open file %s\n", name);
|
||||||
|
KTRACE("rld: load_container(\"%s\"): failed to open file", name);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize the image path
|
||||||
|
status = _kern_normalize_path(path, true, path);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
|
// Test again if this image has been registered already - this time,
|
||||||
|
// we can check the full path, not just its name as noted.
|
||||||
|
// You could end up loading an image twice with symbolic links, else.
|
||||||
|
if (type != B_ADD_ON_IMAGE) {
|
||||||
|
found = find_loaded_image_by_name(path, APP_OR_LIBRARY_TYPE);
|
||||||
|
if (found) {
|
||||||
|
atomic_add(&found->ref_count, 1);
|
||||||
|
*_image = found;
|
||||||
|
_kern_close(fd);
|
||||||
|
KTRACE("rld: load_container(\"%s\"): already loaded after all",
|
||||||
|
name);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
length = _kern_read(fd, 0, &eheader, sizeof(eheader));
|
||||||
|
if (length != sizeof(eheader)) {
|
||||||
|
status = B_NOT_AN_EXECUTABLE;
|
||||||
|
FATAL("troubles reading ELF header\n");
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = parse_elf_header(&eheader, &pheaderSize, &sheaderSize);
|
||||||
|
if (status < B_OK) {
|
||||||
|
FATAL("incorrect ELF header\n");
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: what to do about this restriction??
|
||||||
|
if (pheaderSize > (int)sizeof(pheaderBuffer)) {
|
||||||
|
FATAL("Cannot handle program headers bigger than %lu\n",
|
||||||
|
sizeof(pheaderBuffer));
|
||||||
|
status = B_UNSUPPORTED;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = _kern_read(fd, eheader.e_phoff, pheaderBuffer, pheaderSize);
|
||||||
|
if (length != pheaderSize) {
|
||||||
|
FATAL("Could not read program headers: %s\n", strerror(length));
|
||||||
|
status = B_BAD_DATA;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
numRegions = count_regions(pheaderBuffer, eheader.e_phnum,
|
||||||
|
eheader.e_phentsize);
|
||||||
|
if (numRegions <= 0) {
|
||||||
|
FATAL("Troubles parsing Program headers, numRegions = %ld\n", numRegions);
|
||||||
|
status = B_BAD_DATA;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = create_image(name, path, numRegions);
|
||||||
|
if (image == NULL) {
|
||||||
|
FATAL("Failed to allocate image_t object\n");
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = parse_program_headers(image, pheaderBuffer, eheader.e_phnum,
|
||||||
|
eheader.e_phentsize);
|
||||||
|
if (status < B_OK)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
if (!assert_dynamic_loadable(image)) {
|
||||||
|
FATAL("Dynamic segment must be loadable (implementation restriction)\n");
|
||||||
|
status = B_UNSUPPORTED;
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = map_image(fd, path, image, type == B_APP_IMAGE);
|
||||||
|
if (status < B_OK) {
|
||||||
|
FATAL("Could not map image: %s\n", strerror(status));
|
||||||
|
status = B_ERROR;
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_dynamic_segment(image)) {
|
||||||
|
FATAL("Troubles handling dynamic section\n");
|
||||||
|
status = B_BAD_DATA;
|
||||||
|
goto err3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eheader.e_entry != 0)
|
||||||
|
image->entry_point = eheader.e_entry + image->regions[0].delta;
|
||||||
|
|
||||||
|
analyze_image_haiku_version_and_abi(fd, image, eheader, sheaderSize,
|
||||||
|
pheaderBuffer, sizeof(pheaderBuffer));
|
||||||
|
|
||||||
|
// If this is the executable image, we init the search path
|
||||||
|
// subdir, if the compiler version doesn't match ours.
|
||||||
|
if (type == B_APP_IMAGE) {
|
||||||
|
#if __GNUC__ == 2
|
||||||
|
if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_4)
|
||||||
|
sSearchPathSubDir = "gcc4";
|
||||||
|
#elif __GNUC__ == 4
|
||||||
|
if ((image->abi & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2)
|
||||||
|
sSearchPathSubDir = "gcc2";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// init gcc version dependent image flags
|
||||||
|
// symbol resolution strategy
|
||||||
|
if (image->abi == B_HAIKU_ABI_GCC_2_ANCIENT)
|
||||||
|
image->find_undefined_symbol = find_undefined_symbol_beos;
|
||||||
|
|
||||||
|
// init version infos
|
||||||
|
status = init_image_version_infos(image);
|
||||||
|
|
||||||
|
image->type = type;
|
||||||
|
register_image(image, fd, path);
|
||||||
|
image_event(image, IMAGE_EVENT_LOADED);
|
||||||
|
|
||||||
|
_kern_close(fd);
|
||||||
|
|
||||||
|
enqueue_loaded_image(image);
|
||||||
|
|
||||||
|
*_image = image;
|
||||||
|
|
||||||
|
KTRACE("rld: load_container(\"%s\"): done: id: %ld (ABI: %#lx)", name,
|
||||||
|
image->id, image->abi);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
err3:
|
||||||
|
unmap_image(image);
|
||||||
|
err2:
|
||||||
|
delete_image_struct(image);
|
||||||
|
err1:
|
||||||
|
_kern_close(fd);
|
||||||
|
|
||||||
|
KTRACE("rld: load_container(\"%s\"): failed: %s", name,
|
||||||
|
strerror(status));
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ELF_LOAD_IMAGE_H
|
||||||
|
#define ELF_LOAD_IMAGE_H
|
||||||
|
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
status_t parse_elf_header(struct Elf32_Ehdr* eheader, int32* _pheaderSize,
|
||||||
|
int32* _sheaderSize);
|
||||||
|
status_t load_image(char const* name, image_type type, const char* rpath,
|
||||||
|
image_t** _image);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ELF_LOAD_IMAGE_H
|
||||||
@@ -0,0 +1,472 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||||
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "elf_symbol_lookup.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "add_ons.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "images.h"
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
equals_image_name(image_t* image, const char* name)
|
||||||
|
{
|
||||||
|
const char* lastSlash = strrchr(name, '/');
|
||||||
|
return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! This function is called when we run BeOS images on Haiku.
|
||||||
|
It allows us to redirect functions to ensure compatibility.
|
||||||
|
*/
|
||||||
|
static const char*
|
||||||
|
beos_compatibility_map_symbol(const char* symbolName)
|
||||||
|
{
|
||||||
|
struct symbol_mapping {
|
||||||
|
const char* from;
|
||||||
|
const char* to;
|
||||||
|
};
|
||||||
|
static const struct symbol_mapping kMappings[] = {
|
||||||
|
// TODO: Improve this, and also use it for libnet.so compatibility!
|
||||||
|
// Allow an image to provide a function that will be invoked for every
|
||||||
|
// (transitively) depending image. The function can return a table to
|
||||||
|
// remap symbols (probably better address to address). All the tables
|
||||||
|
// for a single image would be combined into a hash table and an
|
||||||
|
// undefined symbol patcher using this hash table would be added.
|
||||||
|
{"fstat", "__be_fstat"},
|
||||||
|
{"lstat", "__be_lstat"},
|
||||||
|
{"stat", "__be_stat"},
|
||||||
|
};
|
||||||
|
const uint32 kMappingCount = sizeof(kMappings) / sizeof(kMappings[0]);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < kMappingCount; i++) {
|
||||||
|
if (!strcmp(symbolName, kMappings[i].from))
|
||||||
|
return kMappings[i].to;
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbolName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
elf_hash(const char* _name)
|
||||||
|
{
|
||||||
|
const uint8* name = (const uint8*)_name;
|
||||||
|
|
||||||
|
uint32 hash = 0;
|
||||||
|
uint32 temp;
|
||||||
|
|
||||||
|
while (*name) {
|
||||||
|
hash = (hash << 4) + *name++;
|
||||||
|
if ((temp = hash & 0xf0000000)) {
|
||||||
|
hash ^= temp >> 24;
|
||||||
|
}
|
||||||
|
hash &= ~temp;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
patch_defined_symbol(image_t* image, const char* name, void** symbol,
|
||||||
|
int32* type)
|
||||||
|
{
|
||||||
|
RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers;
|
||||||
|
while (patcher != NULL && *symbol != 0) {
|
||||||
|
image_t* inImage = image;
|
||||||
|
patcher->patcher(patcher->cookie, NULL, image, name, &inImage,
|
||||||
|
symbol, type);
|
||||||
|
patcher = patcher->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
patch_undefined_symbol(image_t* rootImage, image_t* image, const char* name,
|
||||||
|
image_t** foundInImage, void** symbol, int32* type)
|
||||||
|
{
|
||||||
|
if (*foundInImage != NULL)
|
||||||
|
patch_defined_symbol(*foundInImage, name, symbol, type);
|
||||||
|
|
||||||
|
RuntimeLoaderSymbolPatcher* patcher = image->undefined_symbol_patchers;
|
||||||
|
while (patcher != NULL) {
|
||||||
|
patcher->patcher(patcher->cookie, rootImage, image, name, foundInImage,
|
||||||
|
symbol, type);
|
||||||
|
patcher = patcher->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Elf32_Sym*
|
||||||
|
find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo)
|
||||||
|
{
|
||||||
|
if (image->dynamic_ptr == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Elf32_Sym* versionedSymbol = NULL;
|
||||||
|
uint32 versionedSymbolCount = 0;
|
||||||
|
|
||||||
|
uint32 bucket = lookupInfo.hash % HASHTABSIZE(image);
|
||||||
|
|
||||||
|
for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF;
|
||||||
|
i = HASHCHAINS(image)[i]) {
|
||||||
|
Elf32_Sym* symbol = &image->syms[i];
|
||||||
|
|
||||||
|
if (symbol->st_shndx != SHN_UNDEF
|
||||||
|
&& ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL)
|
||||||
|
|| (ELF32_ST_BIND(symbol->st_info) == STB_WEAK))
|
||||||
|
&& !strcmp(SYMNAME(image, symbol), lookupInfo.name)) {
|
||||||
|
|
||||||
|
// check if the type matches
|
||||||
|
uint32 type = ELF32_ST_TYPE(symbol->st_info);
|
||||||
|
if ((lookupInfo.type == B_SYMBOL_TYPE_TEXT && type != STT_FUNC)
|
||||||
|
|| (lookupInfo.type == B_SYMBOL_TYPE_DATA
|
||||||
|
&& type != STT_OBJECT)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the version
|
||||||
|
|
||||||
|
// Handle the simple cases -- the image doesn't have version
|
||||||
|
// information -- first.
|
||||||
|
if (image->symbol_versions == NULL) {
|
||||||
|
if (lookupInfo.version == NULL) {
|
||||||
|
// No specific symbol version was requested either, so the
|
||||||
|
// symbol is just fine.
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A specific version is requested. If it's the dependency
|
||||||
|
// referred to by the requested version, it's apparently an
|
||||||
|
// older version of the dependency and we're not happy.
|
||||||
|
if (equals_image_name(image, lookupInfo.version->file_name)) {
|
||||||
|
// TODO: That should actually be kind of fatal!
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is some other image. We accept the symbol.
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The image has version information. Let's see what we've got.
|
||||||
|
uint32 versionID = image->symbol_versions[i];
|
||||||
|
uint32 versionIndex = VER_NDX(versionID);
|
||||||
|
elf_version_info& version = image->versions[versionIndex];
|
||||||
|
|
||||||
|
// skip local versions
|
||||||
|
if (versionIndex == VER_NDX_LOCAL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (lookupInfo.version != NULL) {
|
||||||
|
// a specific version is requested
|
||||||
|
|
||||||
|
// compare the versions
|
||||||
|
if (version.hash == lookupInfo.version->hash
|
||||||
|
&& strcmp(version.name, lookupInfo.version->name) == 0) {
|
||||||
|
// versions match
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The versions don't match. We're still fine with the
|
||||||
|
// base version, if it is public and we're not looking for
|
||||||
|
// the default version.
|
||||||
|
if ((versionID & VER_NDX_FLAG_HIDDEN) == 0
|
||||||
|
&& versionIndex == VER_NDX_GLOBAL
|
||||||
|
&& (lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION)
|
||||||
|
== 0) {
|
||||||
|
// TODO: Revise the default version case! That's how
|
||||||
|
// FreeBSD implements it, but glibc doesn't handle it
|
||||||
|
// specially.
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No specific version requested, but the image has version
|
||||||
|
// information. This can happen in either of these cases:
|
||||||
|
//
|
||||||
|
// * The dependent object was linked against an older version
|
||||||
|
// of the now versioned dependency.
|
||||||
|
// * The symbol is looked up via find_image_symbol() or dlsym().
|
||||||
|
//
|
||||||
|
// In the first case we return the base version of the symbol
|
||||||
|
// (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't
|
||||||
|
// exist, the unique, non-hidden versioned symbol.
|
||||||
|
//
|
||||||
|
// In the second case we want to return the public default
|
||||||
|
// version of the symbol. The handling is pretty similar to the
|
||||||
|
// first case, with the exception that we treat VER_NDX_INITIAL
|
||||||
|
// as regular version.
|
||||||
|
|
||||||
|
// VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if
|
||||||
|
// we don't look for the default version.
|
||||||
|
if (versionIndex == VER_NDX_GLOBAL
|
||||||
|
|| ((lookupInfo.flags & LOOKUP_FLAG_DEFAULT_VERSION) == 0
|
||||||
|
&& versionIndex == VER_NDX_INITIAL)) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not hidden, remember the version -- we'll return it, if
|
||||||
|
// it is the only one.
|
||||||
|
if ((versionID & VER_NDX_FLAG_HIDDEN) == 0) {
|
||||||
|
versionedSymbolCount++;
|
||||||
|
versionedSymbol = symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return versionedSymbolCount == 1 ? versionedSymbol : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
|
||||||
|
void **_location)
|
||||||
|
{
|
||||||
|
// get the symbol in the image
|
||||||
|
Elf32_Sym* symbol = find_symbol(image, lookupInfo);
|
||||||
|
if (symbol == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
void* location = (void*)(symbol->st_value + image->regions[0].delta);
|
||||||
|
int32 symbolType = lookupInfo.type;
|
||||||
|
patch_defined_symbol(image, lookupInfo.name, &location, &symbolType);
|
||||||
|
|
||||||
|
if (_location != NULL)
|
||||||
|
*_location = location;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo,
|
||||||
|
image_t** _foundInImage, void** _location)
|
||||||
|
{
|
||||||
|
image_t* queue[count_loaded_images()];
|
||||||
|
uint32 count = 0;
|
||||||
|
uint32 index = 0;
|
||||||
|
queue[count++] = image;
|
||||||
|
image->flags |= RFLAG_VISITED;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
while (index < count) {
|
||||||
|
// pop next image
|
||||||
|
image = queue[index++];
|
||||||
|
|
||||||
|
if (find_symbol(image, lookupInfo, _location) == B_OK) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push needed images
|
||||||
|
for (uint32 i = 0; i < image->num_needed; i++) {
|
||||||
|
image_t* needed = image->needed[i];
|
||||||
|
if ((needed->flags & RFLAG_VISITED) == 0) {
|
||||||
|
queue[count++] = needed;
|
||||||
|
needed->flags |= RFLAG_VISITED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear visited flags
|
||||||
|
for (uint32 i = 0; i < count; i++)
|
||||||
|
queue[i]->flags &= ~RFLAG_VISITED;
|
||||||
|
|
||||||
|
return found ? B_OK : B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Elf32_Sym*
|
||||||
|
find_undefined_symbol_beos(image_t* rootImage, image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
|
||||||
|
{
|
||||||
|
// BeOS style symbol resolution: It is sufficient to check the direct
|
||||||
|
// dependencies. The linker would have complained, if the symbol wasn't
|
||||||
|
// there.
|
||||||
|
for (uint32 i = 0; i < image->num_needed; i++) {
|
||||||
|
if (image->needed[i]->dynamic_ptr) {
|
||||||
|
Elf32_Sym *symbol = find_symbol(image->needed[i],
|
||||||
|
lookupInfo);
|
||||||
|
if (symbol) {
|
||||||
|
*foundInImage = image->needed[i];
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Elf32_Sym*
|
||||||
|
find_undefined_symbol_global(image_t* rootImage, image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
|
||||||
|
{
|
||||||
|
// Global load order symbol resolution: All loaded images are searched for
|
||||||
|
// the symbol in the order they have been loaded. We skip add-on images and
|
||||||
|
// RTLD_LOCAL images though.
|
||||||
|
image_t* otherImage = get_loaded_images().head;
|
||||||
|
while (otherImage != NULL) {
|
||||||
|
if (otherImage == rootImage
|
||||||
|
|| (otherImage->type != B_ADD_ON_IMAGE
|
||||||
|
&& (otherImage->flags
|
||||||
|
& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) {
|
||||||
|
Elf32_Sym *symbol = find_symbol(otherImage, lookupInfo);
|
||||||
|
if (symbol) {
|
||||||
|
*foundInImage = otherImage;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otherImage = otherImage->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Elf32_Sym*
|
||||||
|
find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** foundInImage)
|
||||||
|
{
|
||||||
|
// TODO: How do we want to implement this one? Using global scope resolution
|
||||||
|
// might be undesired as it is now, since libraries could refer to symbols in
|
||||||
|
// the add-on, which would result in add-on symbols implicitely becoming used
|
||||||
|
// outside of the add-on. So the options would be to use the global scope but
|
||||||
|
// skip the add-on, or to do breadth-first resolution in the add-on dependency
|
||||||
|
// scope, also skipping the add-on itself. BeOS style resolution is safe, too,
|
||||||
|
// but we miss out features like undefined symbols and preloading.
|
||||||
|
return find_undefined_symbol_beos(rootImage, image, lookupInfo,
|
||||||
|
foundInImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
resolve_symbol(image_t* rootImage, image_t* image, struct Elf32_Sym* sym,
|
||||||
|
addr_t* symAddress)
|
||||||
|
{
|
||||||
|
switch (sym->st_shndx) {
|
||||||
|
case SHN_UNDEF:
|
||||||
|
{
|
||||||
|
struct Elf32_Sym* sharedSym;
|
||||||
|
image_t* sharedImage;
|
||||||
|
const char* symName = SYMNAME(image, sym);
|
||||||
|
|
||||||
|
// patch the symbol name
|
||||||
|
if (image->abi < B_HAIKU_ABI_GCC_2_HAIKU) {
|
||||||
|
// The image has been compiled with a BeOS compiler. This means
|
||||||
|
// we'll have to redirect some functions for compatibility.
|
||||||
|
symName = beos_compatibility_map_symbol(symName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the version info
|
||||||
|
const elf_version_info* versionInfo = NULL;
|
||||||
|
if (image->symbol_versions != NULL) {
|
||||||
|
uint32 index = sym - image->syms;
|
||||||
|
uint32 versionIndex = VER_NDX(image->symbol_versions[index]);
|
||||||
|
if (versionIndex >= VER_NDX_INITIAL)
|
||||||
|
versionInfo = image->versions + versionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 type = B_SYMBOL_TYPE_ANY;
|
||||||
|
if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC)
|
||||||
|
type = B_SYMBOL_TYPE_TEXT;
|
||||||
|
else if (ELF32_ST_TYPE(sym->st_info) == STT_OBJECT)
|
||||||
|
type = B_SYMBOL_TYPE_DATA;
|
||||||
|
|
||||||
|
// it's undefined, must be outside this image, try the other images
|
||||||
|
sharedSym = rootImage->find_undefined_symbol(rootImage, image,
|
||||||
|
SymbolLookupInfo(symName, type, versionInfo), &sharedImage);
|
||||||
|
void* location = NULL;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ERROR_NO_SYMBOL,
|
||||||
|
ERROR_WRONG_TYPE,
|
||||||
|
ERROR_NOT_EXPORTED,
|
||||||
|
ERROR_UNPATCHED
|
||||||
|
};
|
||||||
|
uint32 lookupError = ERROR_UNPATCHED;
|
||||||
|
|
||||||
|
if (sharedSym == NULL) {
|
||||||
|
// symbol not found at all
|
||||||
|
lookupError = ERROR_NO_SYMBOL;
|
||||||
|
sharedImage = NULL;
|
||||||
|
} else if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
|
||||||
|
&& ELF32_ST_TYPE(sym->st_info)
|
||||||
|
!= ELF32_ST_TYPE(sharedSym->st_info)) {
|
||||||
|
// symbol not of the requested type
|
||||||
|
lookupError = ERROR_WRONG_TYPE;
|
||||||
|
sharedImage = NULL;
|
||||||
|
} else if (ELF32_ST_BIND(sharedSym->st_info) != STB_GLOBAL
|
||||||
|
&& ELF32_ST_BIND(sharedSym->st_info) != STB_WEAK) {
|
||||||
|
// symbol not exported
|
||||||
|
lookupError = ERROR_NOT_EXPORTED;
|
||||||
|
sharedImage = NULL;
|
||||||
|
} else {
|
||||||
|
// symbol is fine, get its location
|
||||||
|
location = (void*)(sharedSym->st_value
|
||||||
|
+ sharedImage->regions[0].delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_undefined_symbol(rootImage, image, symName, &sharedImage,
|
||||||
|
&location, &type);
|
||||||
|
|
||||||
|
if (location == NULL) {
|
||||||
|
switch (lookupError) {
|
||||||
|
case ERROR_NO_SYMBOL:
|
||||||
|
FATAL("elf_resolve_symbol: could not resolve symbol "
|
||||||
|
"'%s'\n", symName);
|
||||||
|
break;
|
||||||
|
case ERROR_WRONG_TYPE:
|
||||||
|
FATAL("elf_resolve_symbol: found symbol '%s' in shared "
|
||||||
|
"image but wrong type\n", symName);
|
||||||
|
break;
|
||||||
|
case ERROR_NOT_EXPORTED:
|
||||||
|
FATAL("elf_resolve_symbol: found symbol '%s', but not "
|
||||||
|
"exported\n", symName);
|
||||||
|
break;
|
||||||
|
case ERROR_UNPATCHED:
|
||||||
|
FATAL("elf_resolve_symbol: found symbol '%s', but was "
|
||||||
|
"hidden by symbol patchers\n", symName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report_errors())
|
||||||
|
gErrorMessage.AddString("missing symbol", symName);
|
||||||
|
|
||||||
|
return B_MISSING_SYMBOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*symAddress = (addr_t)location;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SHN_ABS:
|
||||||
|
*symAddress = sym->st_value + image->regions[0].delta;
|
||||||
|
return B_NO_ERROR;
|
||||||
|
|
||||||
|
case SHN_COMMON:
|
||||||
|
// ToDo: finish this
|
||||||
|
FATAL("elf_resolve_symbol: COMMON symbol, finish me!\n");
|
||||||
|
return B_ERROR; //ERR_NOT_IMPLEMENTED_YET;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// standard symbol
|
||||||
|
*symAddress = sym->st_value + image->regions[0].delta;
|
||||||
|
return B_NO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ELF_SYMBOL_LOOKUP_H
|
||||||
|
#define ELF_SYMBOL_LOOKUP_H
|
||||||
|
|
||||||
|
#include <runtime_loader.h>
|
||||||
|
|
||||||
|
|
||||||
|
// values for SymbolLookupInfo::flags
|
||||||
|
#define LOOKUP_FLAG_DEFAULT_VERSION 0x01
|
||||||
|
|
||||||
|
|
||||||
|
uint32 elf_hash(const char* name);
|
||||||
|
|
||||||
|
|
||||||
|
struct SymbolLookupInfo {
|
||||||
|
const char* name;
|
||||||
|
int32 type;
|
||||||
|
uint32 hash;
|
||||||
|
uint32 flags;
|
||||||
|
const elf_version_info* version;
|
||||||
|
|
||||||
|
SymbolLookupInfo(const char* name, int32 type, uint32 hash,
|
||||||
|
const elf_version_info* version = NULL, uint32 flags = 0)
|
||||||
|
:
|
||||||
|
name(name),
|
||||||
|
type(type),
|
||||||
|
hash(hash),
|
||||||
|
flags(flags),
|
||||||
|
version(version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolLookupInfo(const char* name, int32 type,
|
||||||
|
const elf_version_info* version = NULL, uint32 flags = 0)
|
||||||
|
:
|
||||||
|
name(name),
|
||||||
|
type(type),
|
||||||
|
hash(elf_hash(name)),
|
||||||
|
flags(flags),
|
||||||
|
version(version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void patch_defined_symbol(image_t* image, const char* name,
|
||||||
|
void** symbol, int32* type);
|
||||||
|
void patch_undefined_symbol(image_t* rootImage, image_t* image,
|
||||||
|
const char* name, image_t** foundInImage, void** symbol,
|
||||||
|
int32* type);
|
||||||
|
|
||||||
|
Elf32_Sym* find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo);
|
||||||
|
status_t find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
|
||||||
|
void** _location);
|
||||||
|
status_t find_symbol_breadth_first(image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** _foundInImage,
|
||||||
|
void** _location);
|
||||||
|
Elf32_Sym* find_undefined_symbol_beos(image_t* rootImage, image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** foundInImage);
|
||||||
|
Elf32_Sym* find_undefined_symbol_global(image_t* rootImage, image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** foundInImage);
|
||||||
|
Elf32_Sym* find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
|
||||||
|
const SymbolLookupInfo& lookupInfo, image_t** foundInImage);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ELF_SYMBOL_LOOKUP_H
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "elf_versioning.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "images.h"
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
assert_defined_image_version(image_t* dependentImage, image_t* image,
|
||||||
|
const elf_version_info& neededVersion, bool weak)
|
||||||
|
{
|
||||||
|
// If the image doesn't have version definitions, we print a warning and
|
||||||
|
// succeed. Weird, but that's how glibc does it. Not unlikely we'll fail
|
||||||
|
// later when resolving versioned symbols.
|
||||||
|
if (image->version_definitions == NULL) {
|
||||||
|
FATAL("%s: No version information available (required by %s)\n",
|
||||||
|
image->name, dependentImage->name);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate through the defined versions to find the given one
|
||||||
|
Elf32_Verdef* definition = image->version_definitions;
|
||||||
|
for (uint32 i = 0; i < image->num_version_definitions; i++) {
|
||||||
|
uint32 versionIndex = VER_NDX(definition->vd_ndx);
|
||||||
|
elf_version_info& info = image->versions[versionIndex];
|
||||||
|
|
||||||
|
if (neededVersion.hash == info.hash
|
||||||
|
&& strcmp(neededVersion.name, info.name) == 0) {
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
definition = (Elf32_Verdef*)
|
||||||
|
((uint8*)definition + definition->vd_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// version not found -- fail, if not weak
|
||||||
|
if (!weak) {
|
||||||
|
FATAL("%s: version \"%s\" not found (required by %s)\n", image->name,
|
||||||
|
neededVersion.name, dependentImage->name);
|
||||||
|
return B_MISSING_SYMBOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_image_version_infos(image_t* image)
|
||||||
|
{
|
||||||
|
// First find out how many version infos we need -- i.e. get the greatest
|
||||||
|
// version index from the defined and needed versions (they use the same
|
||||||
|
// index namespace).
|
||||||
|
uint32 maxIndex = 0;
|
||||||
|
|
||||||
|
if (image->version_definitions != NULL) {
|
||||||
|
Elf32_Verdef* definition = image->version_definitions;
|
||||||
|
for (uint32 i = 0; i < image->num_version_definitions; i++) {
|
||||||
|
if (definition->vd_version != 1) {
|
||||||
|
FATAL("Unsupported version definition revision: %u\n",
|
||||||
|
definition->vd_version);
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 versionIndex = VER_NDX(definition->vd_ndx);
|
||||||
|
if (versionIndex > maxIndex)
|
||||||
|
maxIndex = versionIndex;
|
||||||
|
|
||||||
|
definition = (Elf32_Verdef*)
|
||||||
|
((uint8*)definition + definition->vd_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->needed_versions != NULL) {
|
||||||
|
Elf32_Verneed* needed = image->needed_versions;
|
||||||
|
for (uint32 i = 0; i < image->num_needed_versions; i++) {
|
||||||
|
if (needed->vn_version != 1) {
|
||||||
|
FATAL("Unsupported version needed revision: %u\n",
|
||||||
|
needed->vn_version);
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf32_Vernaux* vernaux
|
||||||
|
= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
|
||||||
|
for (uint32 k = 0; k < needed->vn_cnt; k++) {
|
||||||
|
uint32 versionIndex = VER_NDX(vernaux->vna_other);
|
||||||
|
if (versionIndex > maxIndex)
|
||||||
|
maxIndex = versionIndex;
|
||||||
|
|
||||||
|
vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxIndex == 0)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// allocate the version infos
|
||||||
|
image->versions
|
||||||
|
= (elf_version_info*)malloc(sizeof(elf_version_info) * (maxIndex + 1));
|
||||||
|
if (image->versions == NULL) {
|
||||||
|
FATAL("Memory shortage in init_image_version_infos()");
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
image->num_versions = maxIndex + 1;
|
||||||
|
|
||||||
|
// init the version infos
|
||||||
|
|
||||||
|
// version definitions
|
||||||
|
if (image->version_definitions != NULL) {
|
||||||
|
Elf32_Verdef* definition = image->version_definitions;
|
||||||
|
for (uint32 i = 0; i < image->num_version_definitions; i++) {
|
||||||
|
if (definition->vd_cnt > 0
|
||||||
|
&& (definition->vd_flags & VER_FLG_BASE) == 0) {
|
||||||
|
Elf32_Verdaux* verdaux
|
||||||
|
= (Elf32_Verdaux*)((uint8*)definition + definition->vd_aux);
|
||||||
|
|
||||||
|
uint32 versionIndex = VER_NDX(definition->vd_ndx);
|
||||||
|
elf_version_info& info = image->versions[versionIndex];
|
||||||
|
info.hash = definition->vd_hash;
|
||||||
|
info.name = STRING(image, verdaux->vda_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
definition = (Elf32_Verdef*)
|
||||||
|
((uint8*)definition + definition->vd_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// needed versions
|
||||||
|
if (image->needed_versions != NULL) {
|
||||||
|
Elf32_Verneed* needed = image->needed_versions;
|
||||||
|
for (uint32 i = 0; i < image->num_needed_versions; i++) {
|
||||||
|
const char* fileName = STRING(image, needed->vn_file);
|
||||||
|
|
||||||
|
Elf32_Vernaux* vernaux
|
||||||
|
= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
|
||||||
|
for (uint32 k = 0; k < needed->vn_cnt; k++) {
|
||||||
|
uint32 versionIndex = VER_NDX(vernaux->vna_other);
|
||||||
|
elf_version_info& info = image->versions[versionIndex];
|
||||||
|
info.hash = vernaux->vna_hash;
|
||||||
|
info.name = STRING(image, vernaux->vna_name);
|
||||||
|
info.file_name = fileName;
|
||||||
|
info.hidden = (vernaux->vna_other & VER_NDX_FLAG_HIDDEN) != 0;
|
||||||
|
|
||||||
|
vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
check_needed_image_versions(image_t* image)
|
||||||
|
{
|
||||||
|
if (image->needed_versions == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
Elf32_Verneed* needed = image->needed_versions;
|
||||||
|
for (uint32 i = 0; i < image->num_needed_versions; i++) {
|
||||||
|
const char* fileName = STRING(image, needed->vn_file);
|
||||||
|
image_t* dependency = find_loaded_image_by_name(fileName,
|
||||||
|
ALL_IMAGE_TYPES);
|
||||||
|
if (dependency == NULL) {
|
||||||
|
// This can't really happen, unless the object file is broken, since
|
||||||
|
// the file should also appear in DT_NEEDED.
|
||||||
|
FATAL("Version dependency \"%s\" not found", fileName);
|
||||||
|
return B_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf32_Vernaux* vernaux
|
||||||
|
= (Elf32_Vernaux*)((uint8*)needed + needed->vn_aux);
|
||||||
|
for (uint32 k = 0; k < needed->vn_cnt; k++) {
|
||||||
|
uint32 versionIndex = VER_NDX(vernaux->vna_other);
|
||||||
|
elf_version_info& info = image->versions[versionIndex];
|
||||||
|
|
||||||
|
status_t error = assert_defined_image_version(image, dependency,
|
||||||
|
info, (vernaux->vna_flags & VER_FLG_WEAK) != 0);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
vernaux = (Elf32_Vernaux*)((uint8*)vernaux + vernaux->vna_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
needed = (Elf32_Verneed*)((uint8*)needed + needed->vn_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ELF_VERSIONING_H
|
||||||
|
#define ELF_VERSIONING_H
|
||||||
|
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
status_t init_image_version_infos(image_t* image);
|
||||||
|
status_t check_needed_image_versions(image_t* image);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ELF_VERSIONING_H
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
|
||||||
|
KMessage gErrorMessage;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ERRORS_H
|
||||||
|
#define ERRORS_H
|
||||||
|
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern KMessage gErrorMessage;
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
report_errors()
|
||||||
|
{
|
||||||
|
return gProgramArgs->error_port >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ERRORS_H
|
||||||
@@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||||
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "images.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <syscalls.h>
|
||||||
|
#include <vm_defs.h>
|
||||||
|
|
||||||
|
#include "add_ons.h"
|
||||||
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define RLD_PROGRAM_BASE 0x00200000
|
||||||
|
/* keep in sync with app ldscript */
|
||||||
|
|
||||||
|
|
||||||
|
bool gInvalidImageIDs;
|
||||||
|
|
||||||
|
static image_queue_t sLoadedImages = {0, 0};
|
||||||
|
static image_queue_t sDisposableImages = {0, 0};
|
||||||
|
static uint32 sLoadedImageCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//! Remaps the image ID of \a image after fork.
|
||||||
|
static status_t
|
||||||
|
update_image_id(image_t* image)
|
||||||
|
{
|
||||||
|
int32 cookie = 0;
|
||||||
|
image_info info;
|
||||||
|
while (_kern_get_next_image_info(B_CURRENT_TEAM, &cookie, &info,
|
||||||
|
sizeof(image_info)) == B_OK) {
|
||||||
|
for (uint32 i = 0; i < image->num_regions; i++) {
|
||||||
|
if (image->regions[i].vmstart == (addr_t)info.text) {
|
||||||
|
image->id = info.id;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FATAL("Could not update image ID %ld after fork()!\n", image->id);
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
enqueue_image(image_queue_t* queue, image_t* image)
|
||||||
|
{
|
||||||
|
image->next = NULL;
|
||||||
|
|
||||||
|
image->prev = queue->tail;
|
||||||
|
if (queue->tail)
|
||||||
|
queue->tail->next = image;
|
||||||
|
|
||||||
|
queue->tail = image;
|
||||||
|
if (!queue->head)
|
||||||
|
queue->head = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
dequeue_image(image_queue_t* queue, image_t* image)
|
||||||
|
{
|
||||||
|
if (image->next)
|
||||||
|
image->next->prev = image->prev;
|
||||||
|
else
|
||||||
|
queue->tail = image->prev;
|
||||||
|
|
||||||
|
if (image->prev)
|
||||||
|
image->prev->next = image->next;
|
||||||
|
else
|
||||||
|
queue->head = image->next;
|
||||||
|
|
||||||
|
image->prev = NULL;
|
||||||
|
image->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static image_t*
|
||||||
|
find_image_in_queue(image_queue_t* queue, const char* name, bool isPath,
|
||||||
|
uint32 typeMask)
|
||||||
|
{
|
||||||
|
for (image_t* image = queue->head; image; image = image->next) {
|
||||||
|
const char* imageName = isPath ? image->path : image->name;
|
||||||
|
int length = isPath ? sizeof(image->path) : sizeof(image->name);
|
||||||
|
|
||||||
|
if (!strncmp(imageName, name, length)
|
||||||
|
&& (typeMask & IMAGE_TYPE_TO_MASK(image->type)) != 0) {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_image_flags_recursively(image_t* image, uint32 flagsToSet,
|
||||||
|
uint32 flagsToClear)
|
||||||
|
{
|
||||||
|
image_t* queue[sLoadedImageCount];
|
||||||
|
uint32 count = 0;
|
||||||
|
uint32 index = 0;
|
||||||
|
queue[count++] = image;
|
||||||
|
image->flags |= RFLAG_VISITED;
|
||||||
|
|
||||||
|
while (index < count) {
|
||||||
|
// pop next image
|
||||||
|
image = queue[index++];
|
||||||
|
|
||||||
|
// push dependencies
|
||||||
|
for (uint32 i = 0; i < image->num_needed; i++) {
|
||||||
|
image_t* needed = image->needed[i];
|
||||||
|
if ((needed->flags & RFLAG_VISITED) == 0) {
|
||||||
|
queue[count++] = needed;
|
||||||
|
needed->flags |= RFLAG_VISITED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update flags
|
||||||
|
for (uint32 i = 0; i < count; i++) {
|
||||||
|
queue[i]->flags = (queue[i]->flags | flagsToSet)
|
||||||
|
& ~(flagsToClear | RFLAG_VISITED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
topological_sort(image_t* image, uint32 slot, image_t** initList,
|
||||||
|
uint32 sortFlag)
|
||||||
|
{
|
||||||
|
uint32 i;
|
||||||
|
|
||||||
|
if (image->flags & sortFlag)
|
||||||
|
return slot;
|
||||||
|
|
||||||
|
image->flags |= sortFlag; /* make sure we don't visit this one */
|
||||||
|
for (i = 0; i < image->num_needed; i++)
|
||||||
|
slot = topological_sort(image->needed[i], slot, initList, sortFlag);
|
||||||
|
|
||||||
|
initList[slot] = image;
|
||||||
|
return slot + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
image_t*
|
||||||
|
create_image(const char* name, const char* path, int regionCount)
|
||||||
|
{
|
||||||
|
size_t allocSize = sizeof(image_t)
|
||||||
|
+ (regionCount - 1) * sizeof(elf_region_t);
|
||||||
|
|
||||||
|
image_t* image = (image_t*)malloc(allocSize);
|
||||||
|
if (image == NULL) {
|
||||||
|
FATAL("no memory for image %s\n", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(image, 0, allocSize);
|
||||||
|
|
||||||
|
strlcpy(image->path, path, sizeof(image->path));
|
||||||
|
|
||||||
|
// Make the last component of the supplied name the image name.
|
||||||
|
// If present, DT_SONAME will replace this name.
|
||||||
|
const char* lastSlash = strrchr(name, '/');
|
||||||
|
if (lastSlash != NULL)
|
||||||
|
strlcpy(image->name, lastSlash + 1, sizeof(image->name));
|
||||||
|
else
|
||||||
|
strlcpy(image->name, name, sizeof(image->name));
|
||||||
|
|
||||||
|
image->ref_count = 1;
|
||||||
|
image->num_regions = regionCount;
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_image_struct(image_t* image)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
size_t size = sizeof(image_t)
|
||||||
|
+ (image->num_regions - 1) * sizeof(elf_region_t);
|
||||||
|
memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
|
||||||
|
#endif
|
||||||
|
free(image->needed);
|
||||||
|
free(image->versions);
|
||||||
|
|
||||||
|
while (RuntimeLoaderSymbolPatcher* patcher
|
||||||
|
= image->defined_symbol_patchers) {
|
||||||
|
image->defined_symbol_patchers = patcher->next;
|
||||||
|
delete patcher;
|
||||||
|
}
|
||||||
|
while (RuntimeLoaderSymbolPatcher* patcher
|
||||||
|
= image->undefined_symbol_patchers) {
|
||||||
|
image->undefined_symbol_patchers = patcher->next;
|
||||||
|
delete patcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// overwrite images to make sure they aren't accidently reused anywhere
|
||||||
|
memset(image, 0xa5, size);
|
||||||
|
#endif
|
||||||
|
free(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_image(image_t* image)
|
||||||
|
{
|
||||||
|
if (image == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_kern_unregister_image(image->id);
|
||||||
|
// registered in load_container()
|
||||||
|
|
||||||
|
delete_image_struct(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
put_image(image_t* image)
|
||||||
|
{
|
||||||
|
// If all references to the image are gone, add it to the disposable list
|
||||||
|
// and remove all dependencies
|
||||||
|
|
||||||
|
if (atomic_add(&image->ref_count, -1) == 1) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
dequeue_image(&sLoadedImages, image);
|
||||||
|
enqueue_image(&sDisposableImages, image);
|
||||||
|
sLoadedImageCount--;
|
||||||
|
|
||||||
|
for (i = 0; i < image->num_needed; i++)
|
||||||
|
put_image(image->needed[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
map_image(int fd, char const* path, image_t* image, bool fixed)
|
||||||
|
{
|
||||||
|
// cut the file name from the path as base name for the created areas
|
||||||
|
const char* baseName = strrchr(path, '/');
|
||||||
|
if (baseName != NULL)
|
||||||
|
baseName++;
|
||||||
|
else
|
||||||
|
baseName = path;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < image->num_regions; i++) {
|
||||||
|
char regionName[B_OS_NAME_LENGTH];
|
||||||
|
addr_t loadAddress;
|
||||||
|
uint32 addressSpecifier;
|
||||||
|
|
||||||
|
// for BeOS compatibility: if we load an old BeOS executable, we
|
||||||
|
// have to relocate it, if possible - we recognize it because the
|
||||||
|
// vmstart is set to 0 (hopefully always)
|
||||||
|
if (fixed && image->regions[i].vmstart == 0)
|
||||||
|
fixed = false;
|
||||||
|
|
||||||
|
snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
|
||||||
|
baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
|
||||||
|
|
||||||
|
if (image->dynamic_ptr && !fixed) {
|
||||||
|
// relocatable image... we can afford to place wherever
|
||||||
|
if (i == 0) {
|
||||||
|
// but only the first segment gets a free ride
|
||||||
|
loadAddress = RLD_PROGRAM_BASE;
|
||||||
|
addressSpecifier = B_BASE_ADDRESS;
|
||||||
|
} else {
|
||||||
|
loadAddress = image->regions[i].vmstart
|
||||||
|
+ image->regions[i-1].delta;
|
||||||
|
addressSpecifier = B_EXACT_ADDRESS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not relocatable, put it where it asks or die trying
|
||||||
|
loadAddress = image->regions[i].vmstart;
|
||||||
|
addressSpecifier = B_EXACT_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->regions[i].flags & RFLAG_ANON) {
|
||||||
|
image->regions[i].id = _kern_create_area(regionName,
|
||||||
|
(void**)&loadAddress, addressSpecifier,
|
||||||
|
image->regions[i].vmsize, B_NO_LOCK,
|
||||||
|
B_READ_AREA | B_WRITE_AREA);
|
||||||
|
|
||||||
|
if (image->regions[i].id < 0)
|
||||||
|
return image->regions[i].id;
|
||||||
|
|
||||||
|
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
|
||||||
|
image->regions[i].vmstart = loadAddress;
|
||||||
|
} else {
|
||||||
|
image->regions[i].id = _kern_map_file(regionName,
|
||||||
|
(void**)&loadAddress, addressSpecifier,
|
||||||
|
image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
|
||||||
|
REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
|
||||||
|
|
||||||
|
if (image->regions[i].id < 0)
|
||||||
|
return image->regions[i].id;
|
||||||
|
|
||||||
|
TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
|
||||||
|
(void *)loadAddress, image->regions[i].vmsize,
|
||||||
|
image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
|
||||||
|
|
||||||
|
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
|
||||||
|
image->regions[i].vmstart = loadAddress;
|
||||||
|
|
||||||
|
// handle trailer bits in data segment
|
||||||
|
if (image->regions[i].flags & RFLAG_RW) {
|
||||||
|
addr_t startClearing;
|
||||||
|
addr_t toClear;
|
||||||
|
|
||||||
|
startClearing = image->regions[i].vmstart
|
||||||
|
+ PAGE_OFFSET(image->regions[i].start)
|
||||||
|
+ image->regions[i].size;
|
||||||
|
toClear = image->regions[i].vmsize
|
||||||
|
- PAGE_OFFSET(image->regions[i].start)
|
||||||
|
- image->regions[i].size;
|
||||||
|
|
||||||
|
TRACE(("cleared 0x%lx and the following 0x%lx bytes\n",
|
||||||
|
startClearing, toClear));
|
||||||
|
memset((void *)startClearing, 0, toClear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->dynamic_ptr)
|
||||||
|
image->dynamic_ptr += image->regions[0].delta;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
unmap_image(image_t* image)
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < image->num_regions; i++) {
|
||||||
|
_kern_delete_area(image->regions[i].id);
|
||||||
|
|
||||||
|
image->regions[i].id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! This function will change the protection of all read-only segments to really
|
||||||
|
be read-only.
|
||||||
|
The areas have to be read/write first, so that they can be relocated.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
remap_images()
|
||||||
|
{
|
||||||
|
for (image_t* image = sLoadedImages.head; image != NULL;
|
||||||
|
image = image->next) {
|
||||||
|
for (uint32 i = 0; i < image->num_regions; i++) {
|
||||||
|
if ((image->regions[i].flags & RFLAG_RW) == 0
|
||||||
|
&& (image->regions[i].flags & RFLAG_REMAPPED) == 0) {
|
||||||
|
// we only need to do this once, so we remember those we've already mapped
|
||||||
|
if (_kern_set_area_protection(image->regions[i].id,
|
||||||
|
B_READ_AREA | B_EXECUTE_AREA) == B_OK) {
|
||||||
|
image->regions[i].flags |= RFLAG_REMAPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
register_image(image_t* image, int fd, const char* path)
|
||||||
|
{
|
||||||
|
struct stat stat;
|
||||||
|
image_info info;
|
||||||
|
|
||||||
|
// TODO: set these correctly
|
||||||
|
info.id = 0;
|
||||||
|
info.type = image->type;
|
||||||
|
info.sequence = 0;
|
||||||
|
info.init_order = 0;
|
||||||
|
info.init_routine = (void (*)())image->init_routine;
|
||||||
|
info.term_routine = (void (*)())image->term_routine;
|
||||||
|
|
||||||
|
if (_kern_read_stat(fd, NULL, false, &stat, sizeof(struct stat)) == B_OK) {
|
||||||
|
info.device = stat.st_dev;
|
||||||
|
info.node = stat.st_ino;
|
||||||
|
} else {
|
||||||
|
info.device = -1;
|
||||||
|
info.node = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(info.name, path, sizeof(info.name));
|
||||||
|
info.text = (void *)image->regions[0].vmstart;
|
||||||
|
info.text_size = image->regions[0].vmsize;
|
||||||
|
info.data = (void *)image->regions[1].vmstart;
|
||||||
|
info.data_size = image->regions[1].vmsize;
|
||||||
|
info.api_version = image->api_version;
|
||||||
|
info.abi = image->abi;
|
||||||
|
image->id = _kern_register_image(&info, sizeof(image_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! After fork, we lazily rebuild the image IDs of all loaded images.
|
||||||
|
status_t
|
||||||
|
update_image_ids()
|
||||||
|
{
|
||||||
|
for (image_t* image = sLoadedImages.head; image; image = image->next) {
|
||||||
|
status_t status = update_image_id(image);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
for (image_t* image = sDisposableImages.head; image; image = image->next) {
|
||||||
|
status_t status = update_image_id(image);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
gInvalidImageIDs = false;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image_queue_t&
|
||||||
|
get_loaded_images()
|
||||||
|
{
|
||||||
|
return sLoadedImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image_queue_t&
|
||||||
|
get_disposable_images()
|
||||||
|
{
|
||||||
|
return sDisposableImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
count_loaded_images()
|
||||||
|
{
|
||||||
|
return sLoadedImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
enqueue_loaded_image(image_t* image)
|
||||||
|
{
|
||||||
|
enqueue_image(&sLoadedImages, image);
|
||||||
|
sLoadedImageCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dequeue_loaded_image(image_t* image)
|
||||||
|
{
|
||||||
|
dequeue_image(&sLoadedImages, image);
|
||||||
|
sLoadedImageCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dequeue_disposable_image(image_t* image)
|
||||||
|
{
|
||||||
|
dequeue_image(&sDisposableImages, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image_t*
|
||||||
|
find_loaded_image_by_name(char const* name, uint32 typeMask)
|
||||||
|
{
|
||||||
|
bool isPath = strchr(name, '/') != NULL;
|
||||||
|
return find_image_in_queue(&sLoadedImages, name, isPath, typeMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image_t*
|
||||||
|
find_loaded_image_by_id(image_id id, bool ignoreDisposable)
|
||||||
|
{
|
||||||
|
if (gInvalidImageIDs) {
|
||||||
|
// After fork, we lazily rebuild the image IDs of all loaded images
|
||||||
|
update_image_ids();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (image_t* image = sLoadedImages.head; image; image = image->next) {
|
||||||
|
if (image->id == id)
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreDisposable)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (image_t* image = sDisposableImages.head; image; image = image->next) {
|
||||||
|
if (image->id == id)
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
set_image_flags_recursively(image_t* image, uint32 flags)
|
||||||
|
{
|
||||||
|
update_image_flags_recursively(image, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_image_flags_recursively(image_t* image, uint32 flags)
|
||||||
|
{
|
||||||
|
update_image_flags_recursively(image, 0, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
get_sorted_image_list(image_t* image, image_t*** _list, uint32 sortFlag)
|
||||||
|
{
|
||||||
|
image_t** list;
|
||||||
|
|
||||||
|
list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t*));
|
||||||
|
if (list == NULL) {
|
||||||
|
FATAL("memory shortage in get_sorted_image_list()");
|
||||||
|
*_list = NULL;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(list, 0, sLoadedImageCount * sizeof(image_t*));
|
||||||
|
|
||||||
|
*_list = list;
|
||||||
|
return topological_sort(image, 0, list, sortFlag);
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||||
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
#ifndef IMAGES_H
|
||||||
|
#define IMAGES_H
|
||||||
|
|
||||||
|
#include <runtime_loader.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL
|
||||||
|
|
||||||
|
RFLAG_RW = 0x0010,
|
||||||
|
RFLAG_ANON = 0x0020,
|
||||||
|
|
||||||
|
RFLAG_TERMINATED = 0x0200,
|
||||||
|
RFLAG_INITIALIZED = 0x0400,
|
||||||
|
RFLAG_SYMBOLIC = 0x0800,
|
||||||
|
RFLAG_RELOCATED = 0x1000,
|
||||||
|
RFLAG_PROTECTED = 0x2000,
|
||||||
|
RFLAG_DEPENDENCIES_LOADED = 0x4000,
|
||||||
|
RFLAG_REMAPPED = 0x8000,
|
||||||
|
|
||||||
|
RFLAG_VISITED = 0x10000,
|
||||||
|
RFLAG_USE_FOR_RESOLVING = 0x20000
|
||||||
|
// temporarily set in the symbol resolution code
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define IMAGE_TYPE_TO_MASK(type) (1 << ((type) - 1))
|
||||||
|
#define ALL_IMAGE_TYPES (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
|
||||||
|
| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE) \
|
||||||
|
| IMAGE_TYPE_TO_MASK(B_ADD_ON_IMAGE) \
|
||||||
|
| IMAGE_TYPE_TO_MASK(B_SYSTEM_IMAGE))
|
||||||
|
#define APP_OR_LIBRARY_TYPE (IMAGE_TYPE_TO_MASK(B_APP_IMAGE) \
|
||||||
|
| IMAGE_TYPE_TO_MASK(B_LIBRARY_IMAGE))
|
||||||
|
|
||||||
|
|
||||||
|
extern bool gInvalidImageIDs;
|
||||||
|
|
||||||
|
|
||||||
|
image_t* create_image(const char* name, const char* path, int regionCount);
|
||||||
|
void delete_image_struct(image_t* image);
|
||||||
|
void delete_image(image_t* image);
|
||||||
|
void put_image(image_t* image);
|
||||||
|
|
||||||
|
status_t map_image(int fd, char const* path, image_t* image, bool fixed);
|
||||||
|
void unmap_image(image_t* image);
|
||||||
|
void remap_images();
|
||||||
|
|
||||||
|
void register_image(image_t* image, int fd, const char* path);
|
||||||
|
status_t update_image_ids();
|
||||||
|
|
||||||
|
image_queue_t& get_loaded_images();
|
||||||
|
image_queue_t& get_disposable_images();
|
||||||
|
uint32 count_loaded_images();
|
||||||
|
void enqueue_loaded_image(image_t* image);
|
||||||
|
void dequeue_loaded_image(image_t* image);
|
||||||
|
void dequeue_disposable_image(image_t* image);
|
||||||
|
|
||||||
|
image_t* find_loaded_image_by_name(char const* name, uint32 typeMask);
|
||||||
|
image_t* find_loaded_image_by_id(image_id id, bool ignoreDisposable);
|
||||||
|
|
||||||
|
void set_image_flags_recursively(image_t* image, uint32 flags);
|
||||||
|
void clear_image_flags_recursively(image_t* image, uint32 flags);
|
||||||
|
ssize_t get_sorted_image_list(image_t* image, image_t*** _list,
|
||||||
|
uint32 sortFlag);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // IMAGES_H
|
||||||
@@ -20,14 +20,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_RLD
|
|
||||||
#ifdef TRACE_RLD
|
|
||||||
# define TRACE(x) printf x
|
|
||||||
#else
|
|
||||||
# define TRACE(x) ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
struct user_space_program_args *gProgramArgs;
|
struct user_space_program_args *gProgramArgs;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,46 +5,74 @@
|
|||||||
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||||
* Distributed under the terms of the NewOS License.
|
* Distributed under the terms of the NewOS License.
|
||||||
*/
|
*/
|
||||||
#ifndef RUNTIME_LOADER_H
|
#ifndef RUNTIME_LOADER_PRIVATE_H
|
||||||
#define RUNTIME_LOADER_H
|
#define RUNTIME_LOADER_PRIVATE_H
|
||||||
|
|
||||||
|
|
||||||
#include <user_runtime.h>
|
#include <user_runtime.h>
|
||||||
#include <runtime_loader.h>
|
#include <runtime_loader.h>
|
||||||
|
|
||||||
|
#include "tracing_config.h"
|
||||||
|
|
||||||
extern struct user_space_program_args *gProgramArgs;
|
#include "utility.h"
|
||||||
|
|
||||||
|
|
||||||
|
//#define TRACE_RLD
|
||||||
|
#ifdef TRACE_RLD
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if RUNTIME_LOADER_TRACING
|
||||||
|
# define KTRACE(x...) ktrace_printf(x)
|
||||||
|
#else
|
||||||
|
# define KTRACE(x...)
|
||||||
|
#endif // RUNTIME_LOADER_TRACING
|
||||||
|
|
||||||
|
|
||||||
|
#define FATAL(x...) \
|
||||||
|
do { \
|
||||||
|
dprintf("runtime_loader: " x); \
|
||||||
|
if (!gProgramLoaded) \
|
||||||
|
printf("runtime_loader: " x); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
|
||||||
|
extern struct user_space_program_args* gProgramArgs;
|
||||||
extern struct rld_export gRuntimeLoader;
|
extern struct rld_export gRuntimeLoader;
|
||||||
extern char *(*gGetEnv)(const char *name);
|
extern char* (*gGetEnv)(const char* name);
|
||||||
|
extern bool gProgramLoaded;
|
||||||
|
extern image_t* gProgramImage;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int runtime_loader(void *arg);
|
int runtime_loader(void* arg);
|
||||||
int open_executable(char *name, image_type type, const char *rpath,
|
int open_executable(char* name, image_type type, const char* rpath,
|
||||||
const char *programPath, const char *compatibilitySubDir);
|
const char* programPath, const char* compatibilitySubDir);
|
||||||
status_t test_executable(const char *path, char *interpreter);
|
status_t test_executable(const char* path, char* interpreter);
|
||||||
|
|
||||||
void terminate_program(void);
|
void terminate_program(void);
|
||||||
image_id load_program(char const *path, void **entry);
|
image_id load_program(char const* path, void** entry);
|
||||||
image_id load_library(char const *path, uint32 flags, bool addOn,
|
image_id load_library(char const* path, uint32 flags, bool addOn,
|
||||||
void** _handle);
|
void** _handle);
|
||||||
status_t unload_library(void* handle, image_id imageID, bool addOn);
|
status_t unload_library(void* handle, image_id imageID, bool addOn);
|
||||||
status_t get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
|
status_t get_nth_symbol(image_id imageID, int32 num, char* nameBuffer,
|
||||||
int32 *_nameLength, int32 *_type, void **_location);
|
int32* _nameLength, int32* _type, void** _location);
|
||||||
status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
|
status_t get_symbol(image_id imageID, char const* symbolName, int32 symbolType,
|
||||||
bool recursive, image_id *_inImage, void **_location);
|
bool recursive, image_id* _inImage, void** _location);
|
||||||
status_t get_library_symbol(void* handle, void* caller, const char* symbolName,
|
status_t get_library_symbol(void* handle, void* caller, const char* symbolName,
|
||||||
void **_location);
|
void** _location);
|
||||||
status_t get_next_image_dependency(image_id id, uint32 *cookie,
|
status_t get_next_image_dependency(image_id id, uint32* cookie,
|
||||||
const char **_name);
|
const char** _name);
|
||||||
int resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
|
int resolve_symbol(image_t* rootImage, image_t* image, struct Elf32_Sym* sym,
|
||||||
addr_t *sym_addr);
|
addr_t* sym_addr);
|
||||||
|
|
||||||
|
|
||||||
status_t elf_verify_header(void *header, int32 length);
|
status_t elf_verify_header(void* header, int32 length);
|
||||||
void rldelf_init(void);
|
void rldelf_init(void);
|
||||||
void rldexport_init(void);
|
void rldexport_init(void);
|
||||||
status_t elf_reinit_after_fork(void);
|
status_t elf_reinit_after_fork(void);
|
||||||
@@ -52,10 +80,10 @@ status_t elf_reinit_after_fork(void);
|
|||||||
status_t heap_init(void);
|
status_t heap_init(void);
|
||||||
|
|
||||||
// arch dependent prototypes
|
// arch dependent prototypes
|
||||||
status_t arch_relocate_image(image_t *rootImage, image_t *image);
|
status_t arch_relocate_image(image_t* rootImage, image_t* image);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* RUNTIME_LOADER_H */
|
#endif /* RUNTIME_LOADER_PRIVATE_H */
|
||||||
|
|||||||
@@ -58,6 +58,21 @@ printf(const char *format, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
dprintf(const char *format, ...)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
va_list list;
|
||||||
|
va_start(list, format);
|
||||||
|
|
||||||
|
vsnprintf(buffer, sizeof(buffer), format, list);
|
||||||
|
_kern_debug_output(buffer);
|
||||||
|
|
||||||
|
va_end(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" uint32
|
extern "C" uint32
|
||||||
__swap_int32(uint32 value)
|
__swap_int32(uint32 value)
|
||||||
{
|
{
|
||||||
@@ -79,8 +94,41 @@ _get_thread_info(thread_id thread, thread_info *info, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
extern "C" status_t
|
||||||
snooze(bigtime_t timeout)
|
snooze(bigtime_t timeout)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Mini atoi(), so we don't have to include the libroot dependencies.
|
||||||
|
*/
|
||||||
|
extern "C" int
|
||||||
|
atoi(const char* num)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
while (*num >= '0' && *num <= '9') {
|
||||||
|
result = (result * 10) + (*num - '0');
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if RUNTIME_LOADER_TRACING
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
ktrace_printf(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
va_start(list, format);
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
vsnprintf(buffer, sizeof(buffer), format, list);
|
||||||
|
_kern_ktrace_output(buffer);
|
||||||
|
|
||||||
|
va_end(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // RUNTIME_LOADER_TRACING
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef UTILITY_H
|
||||||
|
#define UTILITY_H
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define PAGE_MASK (B_PAGE_SIZE - 1)
|
||||||
|
|
||||||
|
#define PAGE_OFFSET(x) ((x) & (PAGE_MASK))
|
||||||
|
#define PAGE_BASE(x) ((x) & ~(PAGE_MASK))
|
||||||
|
#define TO_PAGE_SIZE(x) ((x + (PAGE_MASK)) & ~(PAGE_MASK))
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void dprintf(const char *format, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UTILITY_H
|
||||||
Reference in New Issue
Block a user