X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Flinker.c;h=fb293cca71f3d1882fbc34df5233c6bd5c6512fc;hb=4145f1d576aa2f43ec679836c45accaaf5c01d6f;hp=ea14d7645d4513d2c67bdba79db330b42eb4e61e;hpb=0112cd268b205d8176b8b4d00988a334822956cf;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/linker.c b/bfd/linker.c index ea14d7645d..fb293cca71 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1,13 +1,14 @@ /* linker.c -- BFD linker routines Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,10 +18,11 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libbfd.h" #include "bfdlink.h" #include "genlink.h" @@ -1314,7 +1316,7 @@ generic_link_add_symbol_list (bfd *abfd, struct generic_link_hash_entry *h; struct bfd_link_hash_entry *bh; - name = bfd_asymbol_name (p); + string = name = bfd_asymbol_name (p); if (((p->flags & BSF_INDIRECT) != 0 || bfd_is_ind_section (p->section)) && pp + 1 < ppend) @@ -1327,12 +1329,9 @@ generic_link_add_symbol_list (bfd *abfd, { /* The name of P is actually the warning string, and the next symbol is the one to warn about. */ - string = name; pp++; name = bfd_asymbol_name (*pp); } - else - string = NULL; bh = NULL; if (! (_bfd_generic_link_add_one_symbol @@ -2876,14 +2875,15 @@ FUNCTION bfd_section_already_linked SYNOPSIS - void bfd_section_already_linked (bfd *abfd, asection *sec); + void bfd_section_already_linked (bfd *abfd, asection *sec, + struct bfd_link_info *info); DESCRIPTION Check if @var{sec} has been already linked during a reloceatable or final link. -.#define bfd_section_already_linked(abfd, sec) \ -. BFD_SEND (abfd, _section_already_linked, (abfd, sec)) +.#define bfd_section_already_linked(abfd, sec, info) \ +. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) . */ @@ -2923,7 +2923,7 @@ bfd_section_already_linked_table_lookup (const char *name) TRUE, FALSE)); } -void +bfd_boolean bfd_section_already_linked_table_insert (struct bfd_section_already_linked_hash_entry *already_linked_list, asection *sec) @@ -2933,9 +2933,12 @@ bfd_section_already_linked_table_insert /* Allocate the memory from the same obstack as the hash table is kept in. */ l = bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l); + if (l == NULL) + return FALSE; l->sec = sec; l->next = already_linked_list->entry; already_linked_list->entry = l; + return TRUE; } static struct bfd_hash_entry * @@ -2946,6 +2949,9 @@ already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED, struct bfd_section_already_linked_hash_entry *ret = bfd_hash_allocate (table, sizeof *ret); + if (ret == NULL) + return NULL; + ret->entry = NULL; return &ret->root; @@ -2969,7 +2975,8 @@ bfd_section_already_linked_table_free (void) /* This is used on non-ELF inputs. */ void -_bfd_generic_section_already_linked (bfd *abfd, asection *sec) +_bfd_generic_section_already_linked (bfd *abfd, asection *sec, + struct bfd_link_info *info) { flagword flags; const char *name; @@ -3070,10 +3077,11 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec) } /* This is the first section with this name. Record it. */ - bfd_section_already_linked_table_insert (already_linked_list, sec); + if (! bfd_section_already_linked_table_insert (already_linked_list, sec)) + info->callbacks->einfo (_("%F%P: already_linked_table: %E")); } -/* Convert symbols in excluded output sections to absolute. */ +/* Convert symbols in excluded output sections to use a kept section. */ static bfd_boolean fix_syms (struct bfd_link_hash_entry *h, void *data) @@ -3092,8 +3100,64 @@ fix_syms (struct bfd_link_hash_entry *h, void *data) && (s->output_section->flags & SEC_EXCLUDE) != 0 && bfd_section_removed_from_list (obfd, s->output_section)) { + asection *op, *op1; + h->u.def.value += s->output_offset + s->output_section->vma; - h->u.def.section = bfd_abs_section_ptr; + + /* Find preceding kept section. */ + for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev) + if ((op1->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, op1)) + break; + + /* Find following kept section. Start at prev->next because + other sections may have been added after S was removed. */ + if (s->output_section->prev != NULL) + op = s->output_section->prev->next; + else + op = s->output_section->owner->sections; + for (; op != NULL; op = op->next) + if ((op->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, op)) + break; + + /* Choose better of two sections, based on flags. The idea + is to choose a section that will be in the same segment + as S would have been if it was kept. */ + if (op1 == NULL) + { + if (op == NULL) + op = bfd_abs_section_ptr; + } + else if (op == NULL) + op = op1; + else if (((op1->flags ^ op->flags) + & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0) + { + if (((op->flags ^ s->flags) + & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0) + op = op1; + } + else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0) + { + if (((op->flags ^ s->flags) & SEC_READONLY) != 0) + op = op1; + } + else if (((op1->flags ^ op->flags) & SEC_CODE) != 0) + { + if (((op->flags ^ s->flags) & SEC_CODE) != 0) + op = op1; + } + else + { + /* Flags we care about are the same. Prefer the following + section if that will result in a positive valued sym. */ + if (h->u.def.value < op->vma) + op = op1; + } + + h->u.def.value -= op->vma; + h->u.def.section = op; } }