diff options
Diffstat (limited to 'ld/ldindr.c')
-rw-r--r-- | ld/ldindr.c | 73 |
1 files changed, 41 insertions, 32 deletions
diff --git a/ld/ldindr.c b/ld/ldindr.c index 8e19842..7770e8d 100644 --- a/ld/ldindr.c +++ b/ld/ldindr.c @@ -3,13 +3,11 @@ 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. */ @@ -18,41 +16,52 @@ #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; -} -} |