* Also define the build system variables TARGET_STATIC_{LIBSTDC++,LIBSUPC++}.

* runtime loader:
  - Fixed gcc 4 warnings.
  - Enabled -Werror.
  - Renamed all remaining *.c source files to *.cpp.
  - Implemented GNU style ELF symbol versioning support.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30806 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-05-20 02:22:36 +00:00
parent 01b9223aa5
commit 003ebb0e83
14 changed files with 568 additions and 70 deletions

View File

@ -795,6 +795,7 @@ local buildVars =
PRIVATE_SYSTEM_HEADERS
LIBSTDC++ LIBSUPC++
STATIC_LIBSTDC++ STATIC_LIBSUPC++
NETWORK_LIBS NETAPI_LIB SELECT_UNAME_ETC_LIB
@ -1035,5 +1036,6 @@ EnableWerror src kits interface ;
EnableWerror src kits storage ;
EnableWerror src kits support ;
EnableWerror src system kernel ;
EnableWerror src system runtime_loader ;
EnableWerror src add-ons kernel file_systems bfs ;
EnableWerror src add-ons kernel file_systems userlandfs ;

View File

@ -1,4 +1,5 @@
/*
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
@ -20,6 +21,7 @@
struct user_space_program_args;
struct SymbolLookupInfo;
struct rld_export {
// runtime loader API export
@ -66,6 +68,13 @@ typedef struct elf_region_t {
uint32 flags;
} elf_region_t;
typedef struct elf_version_info {
uint32 hash; // version name hash
const char *name; // version name
const char *file_name; // dependency file name (needed versions only)
bool hidden; // version hidden (needed versions only)
} elf_version_info;
typedef struct image_t {
// image identification
char path[B_PATH_NAME_LENGTH];
@ -100,9 +109,26 @@ typedef struct image_t {
uint32 num_needed;
struct image_t **needed;
// versioning related structures
uint32 num_version_definitions;
struct Elf32_Verdef *version_definitions;
uint32 num_needed_versions;
struct Elf32_Verneed *needed_versions;
Elf32_Versym *symbol_versions;
elf_version_info *versions;
uint32 num_versions;
#ifdef __cplusplus
struct Elf32_Sym* (*find_undefined_symbol)(struct image_t* rootImage,
struct image_t* image, const char* name,
struct image_t* image,
const SymbolLookupInfo& lookupInfo,
struct image_t** foundInImage);
#else
struct Elf32_Sym* (*find_undefined_symbol)(struct image_t* rootImage,
struct image_t* image,
const struct SymbolLookupInfo* lookupInfo,
struct image_t** foundInImage);
#endif
// Singly-linked list of symbol patchers for symbols defined respectively
// referenced by this image.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2006, Haiku Inc. All Rights Reserved.
* Copyright 2002-2009, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT license.
*
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
@ -21,6 +21,7 @@ typedef uint32 Elf32_Off;
typedef int32 Elf32_Sword;
typedef uint32 Elf32_Word;
typedef Elf32_Half Elf32_Versym;
/*** ELF header ***/
@ -63,8 +64,8 @@ struct Elf32_Ehdr {
#define ELFCLASS32 1
#define ELFCLASS64 2
// endian (EI_DATA)
#define ELFDATA2LSB 1 // little endian
#define ELFDATA2MSB 2 // big endian
#define ELFDATA2LSB 1 /* little endian */
#define ELFDATA2MSB 2 /* big endian */
/*** section header ***/
@ -105,6 +106,10 @@ struct Elf32_Shdr {
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_GNU_verdef 0x6ffffffd /* version definition section */
#define SHT_GNU_verneed 0x6ffffffe /* version needs section */
#define SHT_GNU_versym 0x6fffffff /* version symbol table */
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000
@ -248,15 +253,100 @@ struct Elf32_Dyn {
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
#define DT_VERSYM 0x6ffffff0 /* symbol version table */
#define DT_VERDEF 0x6ffffffc /* version definition table */
#define DT_VERDEFNUM 0x6ffffffd /* number of version definitions */
#define DT_VERNEED 0x6ffffffe /* table with needed versions */
#define DT_VERNEEDNUM 0x6fffffff /* number of needed versions */
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
/* version definition section */
struct Elf32_Verdef {
Elf32_Half vd_version; /* version revision */
Elf32_Half vd_flags; /* version information flags */
Elf32_Half vd_ndx; /* version index as specified in the
symbol version table */
Elf32_Half vd_cnt; /* number of associated verdaux entries */
Elf32_Word vd_hash; /* version name hash value */
Elf32_Word vd_aux; /* byte offset to verdaux array */
Elf32_Word vd_next; /* byte offset to next verdef entry */
};
/* values for vd_version (version revision) */
#define VER_DEF_NONE 0 /* no version */
#define VER_DEF_CURRENT 1 /* current version */
#define VER_DEF_NUM 2 /* given version number */
/* values for vd_flags (version information flags) */
#define VER_FLG_BASE 0x1 /* version definition of file itself */
#define VER_FLG_WEAK 0x2 /* weak version identifier */
/* values for versym symbol index */
#define VER_NDX_LOCAL 0 /* symbol is local */
#define VER_NDX_GLOBAL 1 /* symbol is global/unversioned */
#define VER_NDX_INITIAL 2 /* initial version -- that's the one given
to symbols when a library becomes
versioned; handled by the linker (and
runtime loader) similar to
VER_NDX_GLOBAL */
#define VER_NDX_LORESERVE 0xff00 /* beginning of reserved entries */
#define VER_NDX_ELIMINATE 0xff01 /* symbol is to be eliminated */
#define VER_NDX_FLAG_HIDDEN 0x8000 /* flag: version is hidden */
#define VER_NDX_MASK 0x7fff /* mask to get the actual version index */
#define VER_NDX(x) ((x) & VER_NDX_MASK)
/* auxiliary version information */
struct Elf32_Verdaux {
Elf32_Word vda_name; /* string table offset to version or dependency
name */
Elf32_Word vda_next; /* byte offset to next verdaux entry */
};
/* version dependency section */
struct Elf32_Verneed {
Elf32_Half vn_version; /* version of structure */
Elf32_Half vn_cnt; /* number of associated vernaux entries */
Elf32_Word vn_file; /* byte offset to file name for this
dependency */
Elf32_Word vn_aux; /* byte offset to vernaux array */
Elf32_Word vn_next; /* byte offset to next verneed entry */
};
/* values for vn_version (version revision) */
#define VER_NEED_NONE 0 /* no version */
#define VER_NEED_CURRENT 1 /* current version */
#define VER_NEED_NUM 2 /* given version number */
/* auxiliary needed version information */
struct Elf32_Vernaux {
Elf32_Word vna_hash; /* dependency name hash value */
Elf32_Half vna_flags; /* dependency specific information flags */
Elf32_Half vna_other; /* version index as specified in the symbol
version table */
Elf32_Word vna_name; /* string table offset to dependency name */
Elf32_Word vna_next; /* byte offset to next vernaux entry */
};
/* values for vna_flags */
#define VER_FLG_WEAK 0x2 /* weak version identifier */
/*** inline functions ***/
#ifdef __cplusplus
inline bool
inline bool
Elf32_Ehdr::IsHostEndian() const
{
#if B_HOST_IS_LENDIAN
@ -267,7 +357,7 @@ Elf32_Ehdr::IsHostEndian() const
}
inline bool
inline bool
Elf32_Phdr::IsReadWrite() const
{
return !(~p_flags & (PF_READ | PF_WRITE));
@ -281,28 +371,28 @@ Elf32_Phdr::IsExecutable() const
}
inline uint8
inline uint8
Elf32_Sym::Bind() const
{
return ELF32_ST_BIND(st_info);
}
inline uint8
inline uint8
Elf32_Sym::Type() const
{
return ELF32_ST_TYPE(st_info);
}
inline uint8
inline uint8
Elf32_Rel::SymbolIndex() const
{
return ELF32_R_SYM(r_info);
}
inline uint8
inline uint8
Elf32_Rel::Type() const
{
return ELF32_R_TYPE(r_info);

View File

@ -13,6 +13,7 @@ SubDirC++Flags -fno-builtin -fno-exceptions ;
DEFINES +=
KMESSAGE_CONTAINER_ONLY
_LOADER_MODE
USING_LIBGCC=1
;
AddResources runtime_loader : runtime_loader.rdef ;
@ -65,9 +66,9 @@ SEARCH on [ FGristFiles KMessage.cpp ]
= [ FDirName $(HAIKU_TOP) src system kernel messaging ] ;
Objects
runtime_loader.c
runtime_loader.cpp
elf.cpp
export.c
export.cpp
heap.cpp
utility.cpp
;
@ -76,6 +77,7 @@ Ld runtime_loader :
[ FGristFiles runtime_loader.o elf.o export.o heap.o utility.o ]
libruntime_loader.a
libruntime_loader_$(TARGET_ARCH).a
$(TARGET_STATIC_LIBSUPC++)
$(TARGET_GCC_LIBGCC)
: $(HAIKU_TOP)/src/system/ldscripts/$(TARGET_ARCH)/runtime_loader.ld
;

View File

@ -6,7 +6,7 @@ UsePrivateSystemHeaders ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
StaticLibrary libruntime_loader_$(TARGET_ARCH).a :
arch_relocate.c
arch_relocate.cpp
:
<src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o
<src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o

View File

@ -6,7 +6,7 @@ UsePrivateSystemHeaders ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
StaticLibrary libruntime_loader_$(TARGET_ARCH).a :
arch_relocate.c
arch_relocate.cpp
:
<src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o
<src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o

View File

@ -6,7 +6,7 @@ UsePrivateSystemHeaders ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
StaticLibrary libruntime_loader_$(TARGET_ARCH).a :
arch_relocate.c
arch_relocate.cpp
:
<src!system!libroot!os!arch!$(TARGET_ARCH)>atomic.o
<src!system!libroot!os!arch!$(TARGET_ARCH)>thread.o

View File

@ -87,6 +87,10 @@ enum {
typedef void (*init_term_function)(image_id);
static Elf32_Sym* find_symbol(image_t* image,
const SymbolLookupInfo& lookupInfo);
static uint32 elf_hash(const uint8 *name);
// image events
enum {
@ -128,6 +132,41 @@ struct RuntimeLoaderSymbolPatcher {
};
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((const uint8*)name)),
flags(flags),
version(version)
{
}
};
// values for SymbolLookupInfo::flags
#define LOOKUP_FLAG_DEFAULT_VERSION 0x01
static image_queue_t sLoadedImages = {0, 0};
static image_queue_t sDisposableImages = {0, 0};
static uint32 sLoadedImageCount = 0;
@ -148,10 +187,6 @@ static int32 sSemCount;
extern runtime_loader_add_on_export gRuntimeLoaderAddOnExport;
static struct Elf32_Sym* find_symbol(image_t* image, const char* name,
int32 type);
void
dprintf(const char *format, ...)
{
@ -519,6 +554,7 @@ delete_image_struct(image_t *image)
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) {
@ -707,7 +743,8 @@ analyze_image_haiku_version_and_abi(image_t* image)
{
// Haiku API version
struct Elf32_Sym* symbol = find_symbol(image,
B_SHARED_OBJECT_HAIKU_VERSION_VARIABLE_NAME, B_SYMBOL_TYPE_DATA);
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
@ -718,8 +755,9 @@ analyze_image_haiku_version_and_abi(image_t* image)
image->api_version = 0;
// Haiku ABI
symbol = find_symbol(image, B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME,
B_SYMBOL_TYPE_DATA);
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
@ -1111,6 +1149,24 @@ parse_dynamic_segment(image_t *image)
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;
}
@ -1231,50 +1287,147 @@ runtime_loader_add_on_export gRuntimeLoaderAddOnExport = {
};
static struct Elf32_Sym *
find_symbol(image_t *image, const char *name, int32 type)
static bool
equals_image_name(image_t* image, const char* name)
{
uint32 hash, i;
const char* lastSlash = strrchr(name, '/');
return strcmp(image->name, lastSlash != NULL ? lastSlash + 1 : name) == 0;
}
// ToDo: "type" is currently ignored!
(void)type;
static Elf32_Sym*
find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo)
{
if (image->dynamic_ptr == 0)
return NULL;
hash = elf_hash((uint8 *)name) % HASHTABSIZE(image);
Elf32_Sym* versionedSymbol = NULL;
uint32 versionedSymbolCount = 0;
for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
struct Elf32_Sym *symbol = &image->syms[i];
uint32 bucket = lookupInfo.hash % HASHTABSIZE(image);
for (uint32 i = HASHBUCKETS(image)[bucket]; i != STN_UNDEF;
i = HASHCHAINS(image)[i]) {
struct 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), name)) {
&& !strcmp(SYMNAME(image, symbol), lookupInfo.name)) {
// check if the type matches
if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
|| (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT))
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;
return symbol;
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 NULL;
return versionedSymbolCount == 1 ? versionedSymbol : NULL;
}
static status_t
find_symbol(image_t* image, char const* symbolName, int32 symbolType,
find_symbol(image_t* image, const SymbolLookupInfo& lookupInfo,
void **_location)
{
// get the symbol in the image
struct Elf32_Sym* symbol = find_symbol(image, symbolName, symbolType);
struct 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);
patch_defined_symbol(image, symbolName, &location, &symbolType);
int32 symbolType = lookupInfo.type;
patch_defined_symbol(image, lookupInfo.name, &location, &symbolType);
if (_location != NULL)
*_location = location;
@ -1284,7 +1437,7 @@ find_symbol(image_t* image, char const* symbolName, int32 symbolType,
static status_t
find_symbol_breadth_first(image_t* image, const char* name, int32 type,
find_symbol_breadth_first(image_t* image, const SymbolLookupInfo& lookupInfo,
image_t** _foundInImage, void** _location)
{
image_t* queue[sLoadedImageCount];
@ -1298,7 +1451,7 @@ find_symbol_breadth_first(image_t* image, const char* name, int32 type,
// pop next image
image = queue[index++];
if (find_symbol(image, name, type, _location) == B_OK) {
if (find_symbol(image, lookupInfo, _location) == B_OK) {
found = true;
break;
}
@ -1322,16 +1475,16 @@ find_symbol_breadth_first(image_t* image, const char* name, int32 type,
static struct Elf32_Sym*
find_undefined_symbol_beos(image_t* rootImage, image_t* image, const char* name,
image_t** foundInImage)
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) {
struct Elf32_Sym *symbol = find_symbol(image->needed[i], name,
B_SYMBOL_TYPE_ANY);
struct Elf32_Sym *symbol = find_symbol(image->needed[i],
lookupInfo);
if (symbol) {
*foundInImage = image->needed[i];
return symbol;
@ -1345,7 +1498,7 @@ find_undefined_symbol_beos(image_t* rootImage, image_t* image, const char* name,
static struct Elf32_Sym*
find_undefined_symbol_global(image_t* rootImage, image_t* image,
const char* name, image_t** foundInImage)
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
@ -1356,8 +1509,7 @@ find_undefined_symbol_global(image_t* rootImage, image_t* image,
|| (otherImage->type != B_ADD_ON_IMAGE
&& (otherImage->flags
& (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0)) {
struct Elf32_Sym *symbol = find_symbol(otherImage, name,
B_SYMBOL_TYPE_ANY);
struct Elf32_Sym *symbol = find_symbol(otherImage, lookupInfo);
if (symbol) {
*foundInImage = otherImage;
return symbol;
@ -1372,7 +1524,7 @@ find_undefined_symbol_global(image_t* rootImage, image_t* image,
static struct Elf32_Sym*
find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
const char* name, image_t** foundInImage)
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
@ -1381,7 +1533,8 @@ find_undefined_symbol_add_on(image_t* rootImage, image_t* image,
// 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, name, foundInImage);
return find_undefined_symbol_beos(rootImage, image, lookupInfo,
foundInImage);
}
@ -1426,16 +1579,24 @@ resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
{
struct Elf32_Sym *sharedSym;
image_t *sharedImage;
const char *symName;
const char *symName = SYMNAME(image, sym);
// patch the symbol name
symName = SYMNAME(image, sym);
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;
@ -1444,7 +1605,7 @@ resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
// it's undefined, must be outside this image, try the other images
sharedSym = rootImage->find_undefined_symbol(rootImage, image,
symName, &sharedImage);
SymbolLookupInfo(symName, type, versionInfo), &sharedImage);
void* location = NULL;
enum {
@ -1557,6 +1718,193 @@ image_event(image_t* image, uint32 event)
}
static 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;
}
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;
}
static 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_image(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;
}
static void
register_image(image_t *image, int fd, const char *path)
{
@ -1786,6 +2134,9 @@ load_container(char const *name, image_type type, const char *rpath,
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);
@ -1924,6 +2275,7 @@ load_immediate_dependencies(image_t *image)
static status_t
load_dependencies(image_t* image)
{
// load dependencies (breadth-first)
for (image_t* otherImage = image; otherImage != NULL;
otherImage = otherImage->next) {
status_t status = load_immediate_dependencies(otherImage);
@ -1931,6 +2283,15 @@ load_dependencies(image_t* image)
return status;
}
// Check the needed versions for the given image and all newly loaded
// dependencies.
for (image_t* otherImage = image; otherImage != NULL;
otherImage = otherImage->next) {
status_t status = check_needed_image_versions(otherImage);
if (status != B_OK)
return status;
}
return B_OK;
}
@ -2055,8 +2416,9 @@ inject_runtime_loader_api(image_t* rootImage)
// API.
image_t* image;
void* _export;
if (find_symbol_breadth_first(rootImage, "__gRuntimeLoader",
B_SYMBOL_TYPE_DATA, &image, &_export) == B_OK) {
if (find_symbol_breadth_first(rootImage,
SymbolLookupInfo("__gRuntimeLoader", B_SYMBOL_TYPE_DATA), &image,
&_export) == B_OK) {
*(void**)_export = &gRuntimeLoader;
}
}
@ -2120,7 +2482,8 @@ preload_image(char const* path)
// if the image contains an add-on, register it
runtime_loader_add_on* addOnStruct;
if (find_symbol(image, "__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA,
if (find_symbol(image,
SymbolLookupInfo("__gRuntimeLoaderAddOn", B_SYMBOL_TYPE_DATA),
(void**)&addOnStruct) == B_OK) {
RuntimeLoaderAddOn* addOn = new(mynothrow) RuntimeLoaderAddOn(image,
addOnStruct);
@ -2222,8 +2585,9 @@ load_program(char const *path, void **_entry)
// Since the images are initialized now, we no longer should use our
// getenv(), but use the one from libroot.so
find_symbol_breadth_first(sProgramImage, "getenv", B_SYMBOL_TYPE_TEXT,
&image, (void**)&gGetEnv);
find_symbol_breadth_first(sProgramImage,
SymbolLookupInfo("getenv", B_SYMBOL_TYPE_TEXT), &image,
(void**)&gGetEnv);
if (sProgramImage->entry_point == 0) {
status = B_NOT_AN_EXECUTABLE;
@ -2505,10 +2869,16 @@ get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
if (image != NULL) {
if (recursive) {
// breadth-first search in the given image and its dependencies
status = find_symbol_breadth_first(image, symbolName, symbolType,
status = find_symbol_breadth_first(image,
SymbolLookupInfo(symbolName, symbolType, NULL,
LOOKUP_FLAG_DEFAULT_VERSION),
&image, _location);
} else
status = find_symbol(image, symbolName, symbolType, _location);
} else {
status = find_symbol(image,
SymbolLookupInfo(symbolName, symbolType, NULL,
LOOKUP_FLAG_DEFAULT_VERSION),
_location);
}
if (status == B_OK && _inImage != NULL)
*_inImage = image->id;
@ -2536,7 +2906,10 @@ get_library_symbol(void* handle, void* caller, const char* symbolName,
// look in the default scope
image_t* image;
Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage,
sProgramImage, symbolName, &image);
sProgramImage,
SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
LOOKUP_FLAG_DEFAULT_VERSION),
&image);
if (symbol != NULL) {
*_location = (void*)(symbol->st_value + image->regions[0].delta);
int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC
@ -2581,8 +2954,9 @@ get_library_symbol(void* handle, void* caller, const char* symbolName,
continue;
}
struct Elf32_Sym *symbol = find_symbol(image, symbolName,
B_SYMBOL_TYPE_TEXT);
struct Elf32_Sym *symbol = find_symbol(image,
SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_TEXT, NULL,
LOOKUP_FLAG_DEFAULT_VERSION));
if (symbol == NULL)
continue;
@ -2601,8 +2975,10 @@ get_library_symbol(void* handle, void* caller, const char* symbolName,
} else {
// breadth-first search in the given image and its dependencies
image_t* inImage;
status = find_symbol_breadth_first((image_t*)handle, symbolName,
B_SYMBOL_TYPE_ANY, &inImage, _location);
status = find_symbol_breadth_first((image_t*)handle,
SymbolLookupInfo(symbolName, B_SYMBOL_TYPE_ANY, NULL,
LOOKUP_FLAG_DEFAULT_VERSION),
&inImage, _location);
}
rld_unlock();

View File

@ -17,6 +17,8 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <algorithm>
//#define TRACE_RLD
#ifdef TRACE_RLD
@ -114,7 +116,7 @@ try_open_executable(const char *dir, int dirLength, const char *name,
// copy what's left (when the application name is removed)
if (lastSlash != NULL) {
strlcpy(buffer, programPath,
min((int)pathLength, lastSlash + 1 - programPath));
std::min((long)pathLength, lastSlash + 1 - programPath));
} else
strlcpy(buffer, ".", pathLength);

View File

@ -61,8 +61,8 @@ printf(const char *format, ...)
extern "C" uint32
__swap_int32(uint32 value)
{
return value >> 24 | (value >> 8) & 0xff00 | value << 24
| (value << 8) & 0xff0000;
return value >> 24 | ((value >> 8) & 0xff00) | value << 24
| ((value << 8) & 0xff0000);
}