* 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:
parent
b327a1bc7d
commit
94830eb226
@ -65,16 +65,26 @@ SEARCH on [ FGristFiles kernel_vsprintf.c ]
|
||||
SEARCH on [ FGristFiles KMessage.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src system kernel messaging ] ;
|
||||
|
||||
Objects
|
||||
runtime_loader.cpp
|
||||
|
||||
local sources =
|
||||
add_ons.cpp
|
||||
elf.cpp
|
||||
elf_haiku_version.cpp
|
||||
elf_load_image.cpp
|
||||
elf_symbol_lookup.cpp
|
||||
elf_versioning.cpp
|
||||
errors.cpp
|
||||
export.cpp
|
||||
heap.cpp
|
||||
images.cpp
|
||||
runtime_loader.cpp
|
||||
utility.cpp
|
||||
;
|
||||
|
||||
Objects $(sources) ;
|
||||
|
||||
Ld runtime_loader :
|
||||
[ FGristFiles runtime_loader.o elf.o export.o heap.o utility.o ]
|
||||
[ FGristFiles $(sources:S=$(SUFOBJ)) ]
|
||||
libruntime_loader.a
|
||||
libruntime_loader_$(TARGET_ARCH).a
|
||||
$(TARGET_STATIC_LIBSUPC++)
|
||||
|
159
src/system/runtime_loader/add_ons.cpp
Normal file
159
src/system/runtime_loader/add_ons.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* 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);
|
||||
}
|
||||
}
|
59
src/system/runtime_loader/add_ons.h
Normal file
59
src/system/runtime_loader/add_ons.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* 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
|
File diff suppressed because it is too large
Load Diff
234
src/system/runtime_loader/elf_haiku_version.cpp
Normal file
234
src/system/runtime_loader/elf_haiku_version.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
16
src/system/runtime_loader/elf_haiku_version.h
Normal file
16
src/system/runtime_loader/elf_haiku_version.h
Normal file
@ -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
|
547
src/system/runtime_loader/elf_load_image.cpp
Normal file
547
src/system/runtime_loader/elf_load_image.cpp
Normal file
@ -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;
|
||||
}
|
17
src/system/runtime_loader/elf_load_image.h
Normal file
17
src/system/runtime_loader/elf_load_image.h
Normal file
@ -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
|
472
src/system/runtime_loader/elf_symbol_lookup.cpp
Normal file
472
src/system/runtime_loader/elf_symbol_lookup.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
69
src/system/runtime_loader/elf_symbol_lookup.h
Normal file
69
src/system/runtime_loader/elf_symbol_lookup.h
Normal file
@ -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
|
203
src/system/runtime_loader/elf_versioning.cpp
Normal file
203
src/system/runtime_loader/elf_versioning.cpp
Normal file
@ -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;
|
||||
}
|
15
src/system/runtime_loader/elf_versioning.h
Normal file
15
src/system/runtime_loader/elf_versioning.h
Normal file
@ -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
|
9
src/system/runtime_loader/errors.cpp
Normal file
9
src/system/runtime_loader/errors.cpp
Normal file
@ -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;
|
23
src/system/runtime_loader/errors.h
Normal file
23
src/system/runtime_loader/errors.h
Normal file
@ -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
|
541
src/system/runtime_loader/images.cpp
Normal file
541
src/system/runtime_loader/images.cpp
Normal file
@ -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);
|
||||
}
|
76
src/system/runtime_loader/images.h
Normal file
76
src/system/runtime_loader/images.h
Normal file
@ -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>
|
||||
|
||||
|
||||
//#define TRACE_RLD
|
||||
#ifdef TRACE_RLD
|
||||
# define TRACE(x) printf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
struct user_space_program_args *gProgramArgs;
|
||||
|
||||
|
||||
|
@ -5,46 +5,74 @@
|
||||
* Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef RUNTIME_LOADER_H
|
||||
#define RUNTIME_LOADER_H
|
||||
|
||||
#ifndef RUNTIME_LOADER_PRIVATE_H
|
||||
#define RUNTIME_LOADER_PRIVATE_H
|
||||
|
||||
#include <user_runtime.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 char *(*gGetEnv)(const char *name);
|
||||
extern char* (*gGetEnv)(const char* name);
|
||||
extern bool gProgramLoaded;
|
||||
extern image_t* gProgramImage;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int runtime_loader(void *arg);
|
||||
int open_executable(char *name, image_type type, const char *rpath,
|
||||
const char *programPath, const char *compatibilitySubDir);
|
||||
status_t test_executable(const char *path, char *interpreter);
|
||||
int runtime_loader(void* arg);
|
||||
int open_executable(char* name, image_type type, const char* rpath,
|
||||
const char* programPath, const char* compatibilitySubDir);
|
||||
status_t test_executable(const char* path, char* interpreter);
|
||||
|
||||
void terminate_program(void);
|
||||
image_id load_program(char const *path, void **entry);
|
||||
image_id load_library(char const *path, uint32 flags, bool addOn,
|
||||
image_id load_program(char const* path, void** entry);
|
||||
image_id load_library(char const* path, uint32 flags, bool addOn,
|
||||
void** _handle);
|
||||
status_t unload_library(void* handle, image_id imageID, bool addOn);
|
||||
status_t get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
|
||||
int32 *_nameLength, int32 *_type, void **_location);
|
||||
status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
|
||||
bool recursive, image_id *_inImage, void **_location);
|
||||
status_t get_nth_symbol(image_id imageID, int32 num, char* nameBuffer,
|
||||
int32* _nameLength, int32* _type, void** _location);
|
||||
status_t get_symbol(image_id imageID, char const* symbolName, int32 symbolType,
|
||||
bool recursive, image_id* _inImage, void** _location);
|
||||
status_t get_library_symbol(void* handle, void* caller, const char* symbolName,
|
||||
void **_location);
|
||||
status_t get_next_image_dependency(image_id id, uint32 *cookie,
|
||||
const char **_name);
|
||||
int resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
|
||||
addr_t *sym_addr);
|
||||
void** _location);
|
||||
status_t get_next_image_dependency(image_id id, uint32* cookie,
|
||||
const char** _name);
|
||||
int resolve_symbol(image_t* rootImage, image_t* image, struct Elf32_Sym* sym,
|
||||
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 rldexport_init(void);
|
||||
status_t elf_reinit_after_fork(void);
|
||||
@ -52,10 +80,10 @@ status_t elf_reinit_after_fork(void);
|
||||
status_t heap_init(void);
|
||||
|
||||
// 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
|
||||
}
|
||||
#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
|
||||
__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)
|
||||
{
|
||||
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
|
||||
|
28
src/system/runtime_loader/utility.h
Normal file
28
src/system/runtime_loader/utility.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user