BFD supplies symbols to be indirected with the BFD_INDIRECT bit
set. Whenever the linker gets one of these, it calls add_indirect
- with the symbol. We create an entry into the ldsym hash table as if it
- were a normal symbol, but with the SYM_INDIRECT bit set in the
- flags.
-
- When it comes time to tie up the symbols at a later date, the flag
- will be seen and a call made to do the right thing (tm)
-
+ with the symbol. We look up the symbol which this one dereferneces,
+ and stop if they are the same. If they are not the same, copy all
+ the information from the current to the dereffed symbol. Set the
+ indirect bit in the flag. From now on the ldsym_get stuff will
+ perform the indirection for us, at no charge.
*/
#include "bfd.h"
#include "ld.h"
#include "ldsym.h"
+#include "ldmisc.h"
-extern ld_config_type config;
-void
-DEFUN(add_indirect,(ptr),
-asymbol **ptr)
+
+
+static asymbol **
+DEFUN(move_it,(a_list, b_list),
+asymbol **a_list AND
+asymbol **b_list)
{
- if (config.relocateable_output == false) {
- ldsym_type *sp = ldsym_get((*ptr)->name);
- sp->flags |= SYM_INDIRECT;
- sp->sdefs_chain = ptr;
+ asymbol **head = a_list;
+ asymbol **cursor = head;
+
+ if (a_list == 0) return b_list;
+ if (b_list == 0) return a_list;
+
+ while (1) {
+ asymbol *ptr = cursor[0];
+ asymbol **next = (asymbol **)(ptr->udata);
+ if (next == 0) {
+ ptr->udata = (PTR) b_list;
+ return head;
+ }
+ cursor = next;
}
}
-
-
void
-DEFUN(do_indirect,(ptr),
-ldsym_type *ptr)
+DEFUN(add_indirect,(ptr),
+asymbol **ptr)
{
-if (config.relocateable_output == false) {
- /* Dig out the symbol were indirecting to. It's held in the value
- field.
- */
+ ldsym_type *lgs = ldsym_get((*ptr)->name);
+ ldsym_type *new = ldsym_get(((asymbol *)((*ptr)->value))->name);
+ /* If the mapping has already been done, stop now */
+ if (lgs == new) return;
+ lgs->flags |= SYM_INDIRECT;
- CONST char *name = ((asymbol *)(*(ptr->sdefs_chain))->value)->name;
+ new->scoms_chain = move_it(new->scoms_chain, lgs->scoms_chain);
+ lgs->scoms_chain = 0;
+ new->srefs_chain = move_it(new->srefs_chain, lgs->srefs_chain);
+ lgs->srefs_chain = 0;
+ new->sdefs_chain = move_it(new->sdefs_chain, lgs->sdefs_chain);
+ lgs->sdefs_chain = 0;
- ldsym_type *new = ldsym_get(name);
+ lgs->sdefs_chain = (asymbol **)new;
+}
- /* We have to make a copy of the sdefs_chain item name, since
- symbols will be clobbered on writing, and we want to write the
- same string twice */
- ptr->sdefs_chain[0][0] = new->sdefs_chain[0][0];
- ptr->sdefs_chain[0][0].name = name;
-}
-}
Written by Steve Chamberlain steve@cygnus.com
All symbol handling for the linker
- */
+
+
+ We keep a hash table of global symbols. Each entry in a hash table
+ is called an ldsym_type. Each has three chains; a pointer to a
+ chain of definitions for the symbol (hopefully one long), a pointer
+ to a chain of references to the symbol, and a pointer to a chain of
+ common symbols. Each pointer points into the canonical symbol table
+ provided by bfd, each one of which points to an asymbol. Duringing
+ linkage, the linker uses the udata field to point to the next entry
+ in a canonical table....
+
+
+ ld_sym
+ | |
+ +----------+ +----------+
+ | defs | a canonical symbol table
+ +----------+ +----------+
+ | refs | -----> | one entry| -----> asymbol
+ +----------+ +----------+ | |
+ | coms | | | +---------+
+ +----------+ +----------+ | udata |-----> another canonical symbol
+ +---------+
+
+
+
+ It is very simple to make all the symbol pointers point to the same
+ definition - just run down the chain and make the asymbols pointers
+ within the canonical table point to the asymbol attacthed to the
+ definition of the symbol.
+
+*/
+
#include "sysdep.h"
#include "bfd.h"
static ldsym_type *global_symbol_hash_table[TABSIZE];
/* Compute the hash code for symbol name KEY. */
-
+static
+#ifdef __GNUC__
+inline
+#endif
int
-hash_string (key)
- char *key;
+DEFUN(hash_string,(key),
+ CONST char *key)
{
- register char *cp;
+ register CONST char *cp;
register int k;
cp = key;
return k;
}
+static
+#ifdef __GNUC__
+inline
+#endif ldsym_type *bp;
+ldsym_type *
+DEFUN(search,(key,hashval) ,
+ CONST char *key AND
+ int hashval)
+{
+ ldsym_type *bp;
+ for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
+ if (! strcmp (key, bp->name)) {
+ if (bp->flags & SYM_INDIRECT) {
+ /* Use the symbol we're aliased to instead */
+ return (ldsym_type *)(bp->sdefs_chain);
+ }
+ return bp;
+ }
+ return 0;
+}
+
+
/* Get the symbol table entry for the global symbol named KEY.
Create one if there is none. */
ldsym_type *
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
-
- for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
- if (! strcmp (key, bp->name))
- return bp;
+ bp = search(key, hashval);
+ if(bp) {
+ return bp;
+ }
/* Nothing was found; create a new symbol table entry. */
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
-
- for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
- if (! strcmp (key, bp->name))
- return bp;
-
- return 0;
+return search(key, hashval);
}
for (sp = symbol_head; sp; sp = sp->next)
{
+ if (sp->flags & SYM_INDIRECT) {
+ fprintf(stdout,"indirect %s to %s\n",
+ sp->name, (((ldsym_type *)(sp->sdefs_chain))->name));
+ }
+ else {
if (sp->sdefs_chain)
{
asymbol *defsym = *(sp->sdefs_chain);
else {
printf("undefined ");
printf("%s ",sp->name);
+
}
+ }
print_nl();
}
{
FOR_EACH_LDSYM(sp)
{
- if (sp->sdefs_chain != (asymbol **)NULL) {
+ if ((sp->flags & SYM_INDIRECT) == 0 && sp->sdefs_chain != (asymbol **)NULL) {
asymbol *bufp = (*(sp->sdefs_chain));
if ((bufp->flags & BSF_KEEP) ==0) {