2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
6 * Copyright 2002, Manuel J. Petit. All rights reserved.
7 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8 * Distributed under the terms of the NewOS License.
11 #include "elf_symbol_lookup.h"
20 #include "runtime_loader_private.h"
23 /*! Checks whether \a name matches the name of \a image.
25 It is expected that \a name does not contain directory components. It is
26 compared with the base name of \a image's name.
28 \param image The image.
29 \param name The name to check against. Can be NULL, in which case \c false
31 \return \c true, iff \a name is non-NULL and matches the name of \a image.
34 equals_image_name(image_t
* image
, const char* name
)
39 const char* lastSlash
= strrchr(name
, '/');
40 return strcmp(image
->name
, lastSlash
!= NULL
? lastSlash
+ 1 : name
) == 0;
48 elf_hash(const char* _name
)
50 const uint8
* name
= (const uint8
*)_name
;
56 hash
= (hash
<< 4) + *name
++;
57 if ((temp
= hash
& 0xf0000000)) {
67 patch_defined_symbol(image_t
* image
, const char* name
, void** symbol
,
70 RuntimeLoaderSymbolPatcher
* patcher
= image
->defined_symbol_patchers
;
71 while (patcher
!= NULL
&& *symbol
!= 0) {
72 image_t
* inImage
= image
;
73 patcher
->patcher(patcher
->cookie
, NULL
, image
, name
, &inImage
,
75 patcher
= patcher
->next
;
81 patch_undefined_symbol(image_t
* rootImage
, image_t
* image
, const char* name
,
82 image_t
** foundInImage
, void** symbol
, int32
* type
)
84 if (*foundInImage
!= NULL
)
85 patch_defined_symbol(*foundInImage
, name
, symbol
, type
);
87 RuntimeLoaderSymbolPatcher
* patcher
= image
->undefined_symbol_patchers
;
88 while (patcher
!= NULL
) {
89 patcher
->patcher(patcher
->cookie
, rootImage
, image
, name
, foundInImage
,
91 patcher
= patcher
->next
;
97 find_symbol(image_t
* image
, const SymbolLookupInfo
& lookupInfo
)
99 if (image
->dynamic_ptr
== 0)
102 elf_sym
* versionedSymbol
= NULL
;
103 uint32 versionedSymbolCount
= 0;
105 uint32 bucket
= lookupInfo
.hash
% HASHTABSIZE(image
);
107 for (uint32 i
= HASHBUCKETS(image
)[bucket
]; i
!= STN_UNDEF
;
108 i
= HASHCHAINS(image
)[i
]) {
109 elf_sym
* symbol
= &image
->syms
[i
];
111 if (symbol
->st_shndx
!= SHN_UNDEF
112 && ((symbol
->Bind() == STB_GLOBAL
)
113 || (symbol
->Bind() == STB_WEAK
))
114 && !strcmp(SYMNAME(image
, symbol
), lookupInfo
.name
)) {
116 // check if the type matches
117 uint32 type
= symbol
->Type();
118 if ((lookupInfo
.type
== B_SYMBOL_TYPE_TEXT
&& type
!= STT_FUNC
)
119 || (lookupInfo
.type
== B_SYMBOL_TYPE_DATA
120 && type
!= STT_OBJECT
)) {
126 // Handle the simple cases -- the image doesn't have version
127 // information -- first.
128 if (image
->symbol_versions
== NULL
) {
129 if (lookupInfo
.version
== NULL
) {
130 // No specific symbol version was requested either, so the
131 // symbol is just fine.
135 // A specific version is requested. If it's the dependency
136 // referred to by the requested version, it's apparently an
137 // older version of the dependency and we're not happy.
138 if (equals_image_name(image
, lookupInfo
.version
->file_name
)) {
139 // TODO: That should actually be kind of fatal!
143 // This is some other image. We accept the symbol.
147 // The image has version information. Let's see what we've got.
148 uint32 versionID
= image
->symbol_versions
[i
];
149 uint32 versionIndex
= VER_NDX(versionID
);
150 elf_version_info
& version
= image
->versions
[versionIndex
];
152 // skip local versions
153 if (versionIndex
== VER_NDX_LOCAL
)
156 if (lookupInfo
.version
!= NULL
) {
157 // a specific version is requested
159 // compare the versions
160 if (version
.hash
== lookupInfo
.version
->hash
161 && strcmp(version
.name
, lookupInfo
.version
->name
) == 0) {
166 // The versions don't match. We're still fine with the
167 // base version, if it is public and we're not looking for
168 // the default version.
169 if ((versionID
& VER_NDX_FLAG_HIDDEN
) == 0
170 && versionIndex
== VER_NDX_GLOBAL
171 && (lookupInfo
.flags
& LOOKUP_FLAG_DEFAULT_VERSION
)
173 // TODO: Revise the default version case! That's how
174 // FreeBSD implements it, but glibc doesn't handle it
179 // No specific version requested, but the image has version
180 // information. This can happen in either of these cases:
182 // * The dependent object was linked against an older version
183 // of the now versioned dependency.
184 // * The symbol is looked up via find_image_symbol() or dlsym().
186 // In the first case we return the base version of the symbol
187 // (VER_NDX_GLOBAL or VER_NDX_INITIAL), or, if that doesn't
188 // exist, the unique, non-hidden versioned symbol.
190 // In the second case we want to return the public default
191 // version of the symbol. The handling is pretty similar to the
192 // first case, with the exception that we treat VER_NDX_INITIAL
193 // as regular version.
195 // VER_NDX_GLOBAL is always good, VER_NDX_INITIAL is fine, if
196 // we don't look for the default version.
197 if (versionIndex
== VER_NDX_GLOBAL
198 || ((lookupInfo
.flags
& LOOKUP_FLAG_DEFAULT_VERSION
) == 0
199 && versionIndex
== VER_NDX_INITIAL
)) {
203 // If not hidden, remember the version -- we'll return it, if
204 // it is the only one.
205 if ((versionID
& VER_NDX_FLAG_HIDDEN
) == 0) {
206 versionedSymbolCount
++;
207 versionedSymbol
= symbol
;
213 return versionedSymbolCount
== 1 ? versionedSymbol
: NULL
;
218 find_symbol(image_t
* image
, const SymbolLookupInfo
& lookupInfo
,
221 // get the symbol in the image
222 elf_sym
* symbol
= find_symbol(image
, lookupInfo
);
224 return B_ENTRY_NOT_FOUND
;
226 void* location
= (void*)(symbol
->st_value
+ image
->regions
[0].delta
);
227 int32 symbolType
= lookupInfo
.type
;
228 patch_defined_symbol(image
, lookupInfo
.name
, &location
, &symbolType
);
230 if (_location
!= NULL
)
231 *_location
= location
;
238 find_symbol_breadth_first(image_t
* image
, const SymbolLookupInfo
& lookupInfo
,
239 image_t
** _foundInImage
, void** _location
)
241 image_t
* queue
[count_loaded_images()];
244 queue
[count
++] = image
;
245 image
->flags
|= RFLAG_VISITED
;
247 elf_sym
* candidateSymbol
= NULL
;
248 image_t
* candidateImage
= NULL
;
250 while (index
< count
) {
252 image
= queue
[index
++];
254 elf_sym
* symbol
= find_symbol(image
, lookupInfo
);
255 if (symbol
!= NULL
) {
256 bool isWeak
= symbol
->Bind() == STB_WEAK
;
257 if (candidateImage
== NULL
|| !isWeak
) {
258 candidateSymbol
= symbol
;
259 candidateImage
= image
;
266 // push needed images
267 for (uint32 i
= 0; i
< image
->num_needed
; i
++) {
268 image_t
* needed
= image
->needed
[i
];
269 if ((needed
->flags
& RFLAG_VISITED
) == 0) {
270 queue
[count
++] = needed
;
271 needed
->flags
|= RFLAG_VISITED
;
276 // clear visited flags
277 for (uint32 i
= 0; i
< count
; i
++)
278 queue
[i
]->flags
&= ~RFLAG_VISITED
;
280 if (candidateSymbol
== NULL
)
281 return B_ENTRY_NOT_FOUND
;
283 // compute the symbol location
284 *_location
= (void*)(candidateSymbol
->st_value
285 + candidateImage
->regions
[0].delta
);
286 int32 symbolType
= lookupInfo
.type
;
287 patch_defined_symbol(candidateImage
, lookupInfo
.name
, _location
,
290 if (_foundInImage
!= NULL
)
291 *_foundInImage
= candidateImage
;
298 find_undefined_symbol_beos(image_t
* rootImage
, image_t
* image
,
299 const SymbolLookupInfo
& lookupInfo
, image_t
** foundInImage
)
301 // BeOS style symbol resolution: It is sufficient to check the image itself
302 // and its direct dependencies. The linker would have complained, if the
303 // symbol wasn't there. First we check whether the requesting symbol is
304 // defined already -- then we can simply return it, since, due to symbolic
305 // linking, that's the one we'd find anyway.
306 if (elf_sym
* symbol
= lookupInfo
.requestingSymbol
) {
307 if (symbol
->st_shndx
!= SHN_UNDEF
308 && ((symbol
->Bind() == STB_GLOBAL
)
309 || (symbol
->Bind() == STB_WEAK
))) {
310 *foundInImage
= image
;
316 elf_sym
* symbol
= find_symbol(image
, lookupInfo
);
317 if (symbol
!= NULL
) {
318 *foundInImage
= image
;
322 // lookup in dependencies
323 for (uint32 i
= 0; i
< image
->num_needed
; i
++) {
324 if (image
->needed
[i
]->dynamic_ptr
) {
325 symbol
= find_symbol(image
->needed
[i
], lookupInfo
);
326 if (symbol
!= NULL
) {
327 *foundInImage
= image
->needed
[i
];
338 find_undefined_symbol_global(image_t
* rootImage
, image_t
* image
,
339 const SymbolLookupInfo
& lookupInfo
, image_t
** _foundInImage
)
341 // Global load order symbol resolution: All loaded images are searched for
342 // the symbol in the order they have been loaded. We skip add-on images and
343 // RTLD_LOCAL images though.
344 image_t
* candidateImage
= NULL
;
345 elf_sym
* candidateSymbol
= NULL
;
347 // If the requesting image is linked symbolically, look up the symbol there
349 bool symbolic
= (image
->flags
& RFLAG_SYMBOLIC
) != 0;
351 candidateSymbol
= find_symbol(image
, lookupInfo
);
352 if (candidateSymbol
!= NULL
) {
353 if (candidateSymbol
->Bind() != STB_WEAK
) {
354 *_foundInImage
= image
;
355 return candidateSymbol
;
358 candidateImage
= image
;
362 image_t
* otherImage
= get_loaded_images().head
;
363 while (otherImage
!= NULL
) {
364 if (otherImage
== rootImage
366 : (otherImage
->type
!= B_ADD_ON_IMAGE
367 && (otherImage
->flags
368 & (RTLD_GLOBAL
| RFLAG_USE_FOR_RESOLVING
)) != 0)) {
369 if (elf_sym
* symbol
= find_symbol(otherImage
, lookupInfo
)) {
370 if (symbol
->Bind() != STB_WEAK
) {
371 *_foundInImage
= otherImage
;
375 if (candidateSymbol
== NULL
) {
376 candidateSymbol
= symbol
;
377 candidateImage
= otherImage
;
381 otherImage
= otherImage
->next
;
384 if (candidateSymbol
!= NULL
)
385 *_foundInImage
= candidateImage
;
387 return candidateSymbol
;
392 find_undefined_symbol_add_on(image_t
* rootImage
, image_t
* image
,
393 const SymbolLookupInfo
& lookupInfo
, image_t
** _foundInImage
)
395 // Similar to global load order symbol resolution: All loaded images are
396 // searched for the symbol in the order they have been loaded. We skip
397 // add-on images and RTLD_LOCAL images though. The root image (i.e. the
398 // add-on image) is skipped, too, but for the add-on itself we look up
399 // a symbol that hasn't been found anywhere else in the add-on image.
400 // The reason for skipping the add-on image is that we must not resolve
401 // library symbol references to symbol definitions in the add-on, as
402 // libraries can be shared between different add-ons and we must not
403 // introduce connections between add-ons.
405 // For the add-on image itself resolve non-weak symbols defined in the
406 // add-on to themselves. This makes the symbol resolution order inconsistent
407 // for those symbols, but avoids clashes of global symbols defined in the
408 // add-on with symbols defined e.g. in the application. There's really the
409 // same problem for weak symbols, but we don't have any way to discriminate
410 // weak symbols that must be resolved globally from those that should be
411 // resolved within the add-on.
412 if (rootImage
== image
) {
413 if (elf_sym
* symbol
= lookupInfo
.requestingSymbol
) {
414 if (symbol
->st_shndx
!= SHN_UNDEF
415 && (symbol
->Bind() == STB_GLOBAL
)) {
416 *_foundInImage
= image
;
422 image_t
* candidateImage
= NULL
;
423 elf_sym
* candidateSymbol
= NULL
;
425 // If the requesting image is linked symbolically, look up the symbol there
427 bool symbolic
= (image
->flags
& RFLAG_SYMBOLIC
) != 0;
429 candidateSymbol
= find_symbol(image
, lookupInfo
);
430 if (candidateSymbol
!= NULL
) {
431 if (candidateSymbol
->Bind() != STB_WEAK
) {
432 *_foundInImage
= image
;
433 return candidateSymbol
;
436 candidateImage
= image
;
440 image_t
* otherImage
= get_loaded_images().head
;
441 while (otherImage
!= NULL
) {
442 if (otherImage
!= rootImage
443 && otherImage
->type
!= B_ADD_ON_IMAGE
444 && (otherImage
->flags
445 & (RTLD_GLOBAL
| RFLAG_USE_FOR_RESOLVING
)) != 0) {
446 if (elf_sym
* symbol
= find_symbol(otherImage
, lookupInfo
)) {
447 if (symbol
->Bind() != STB_WEAK
) {
448 *_foundInImage
= otherImage
;
452 if (candidateSymbol
== NULL
) {
453 candidateSymbol
= symbol
;
454 candidateImage
= otherImage
;
458 otherImage
= otherImage
->next
;
461 // If the symbol has not been found and we're trying to resolve a reference
462 // in the add-on image, we also try to look it up there.
463 if (!symbolic
&& candidateSymbol
== NULL
&& image
== rootImage
) {
464 candidateSymbol
= find_symbol(image
, lookupInfo
);
465 candidateImage
= image
;
468 if (candidateSymbol
!= NULL
)
469 *_foundInImage
= candidateImage
;
471 return candidateSymbol
;
476 resolve_symbol(image_t
* rootImage
, image_t
* image
, elf_sym
* sym
,
477 SymbolLookupCache
* cache
, addr_t
* symAddress
, image_t
** symbolImage
)
479 uint32 index
= sym
- image
->syms
;
481 // check the cache first
482 if (cache
->IsSymbolValueCached(index
)) {
483 *symAddress
= cache
->SymbolValueAt(index
, symbolImage
);
488 image_t
* sharedImage
;
489 const char* symName
= SYMNAME(image
, sym
);
491 // get the symbol type
492 int32 type
= B_SYMBOL_TYPE_ANY
;
493 if (sym
->Type() == STT_FUNC
)
494 type
= B_SYMBOL_TYPE_TEXT
;
495 else if (sym
->Type() == STT_OBJECT
)
496 type
= B_SYMBOL_TYPE_DATA
;
498 if (sym
->Bind() == STB_LOCAL
) {
499 // Local symbols references are always resolved to the given symbol.
503 // get the version info
504 const elf_version_info
* versionInfo
= NULL
;
505 if (image
->symbol_versions
!= NULL
) {
506 uint32 versionIndex
= VER_NDX(image
->symbol_versions
[index
]);
507 if (versionIndex
>= VER_NDX_INITIAL
)
508 versionInfo
= image
->versions
+ versionIndex
;
512 sharedSym
= rootImage
->find_undefined_symbol(rootImage
, image
,
513 SymbolLookupInfo(symName
, type
, versionInfo
, 0, sym
), &sharedImage
);
523 uint32 lookupError
= ERROR_UNPATCHED
;
525 bool tlsSymbol
= sym
->Type() == STT_TLS
;
526 void* location
= NULL
;
527 if (sharedSym
== NULL
) {
528 // symbol not found at all
529 lookupError
= ERROR_NO_SYMBOL
;
531 } else if (sym
->Type() != STT_NOTYPE
532 && sym
->Type() != sharedSym
->Type()) {
533 // symbol not of the requested type
534 lookupError
= ERROR_WRONG_TYPE
;
536 } else if (sharedSym
->Bind() != STB_GLOBAL
537 && sharedSym
->Bind() != STB_WEAK
) {
538 // symbol not exported
539 lookupError
= ERROR_NOT_EXPORTED
;
542 // symbol is fine, get its location
543 location
= (void*)sharedSym
->st_value
;
546 = (void*)((addr_t
)location
+ sharedImage
->regions
[0].delta
);
548 lookupError
= SUCCESS
;
552 patch_undefined_symbol(rootImage
, image
, symName
, &sharedImage
,
556 if (location
== NULL
&& lookupError
!= SUCCESS
) {
557 switch (lookupError
) {
558 case ERROR_NO_SYMBOL
:
559 FATAL("%s: Could not resolve symbol '%s'\n",
560 image
->path
, symName
);
562 case ERROR_WRONG_TYPE
:
563 FATAL("%s: Found symbol '%s' in shared image but wrong "
564 "type\n", image
->path
, symName
);
566 case ERROR_NOT_EXPORTED
:
567 FATAL("%s: Found symbol '%s', but not exported\n",
568 image
->path
, symName
);
570 case ERROR_UNPATCHED
:
571 FATAL("%s: Found symbol '%s', but was hidden by symbol "
572 "patchers\n", image
->path
, symName
);
577 gErrorMessage
.AddString("missing symbol", symName
);
579 return B_MISSING_SYMBOL
;
582 cache
->SetSymbolValueAt(index
, (addr_t
)location
, sharedImage
);
585 *symbolImage
= sharedImage
;
586 *symAddress
= (addr_t
)location
;