| Index: bfd/linker.c
|
| diff --git a/bfd/linker.c b/bfd/linker.c
|
| index 7a01e114a21a268e58768859c85342e7740a0316..3caec96a8f038ac64e0df3e794484023c4370327 100644
|
| --- a/bfd/linker.c
|
| +++ b/bfd/linker.c
|
| @@ -1,6 +1,6 @@
|
| /* linker.c -- BFD linker routines
|
| Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
| - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
| + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
| Free Software Foundation, Inc.
|
| Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
|
|
|
| @@ -810,6 +810,7 @@ void
|
| _bfd_generic_link_just_syms (asection *sec,
|
| struct bfd_link_info *info ATTRIBUTE_UNUSED)
|
| {
|
| + sec->sec_info_type = SEC_INFO_TYPE_JUST_SYMS;
|
| sec->output_section = bfd_abs_section_ptr;
|
| sec->output_offset = sec->vma;
|
| }
|
| @@ -2664,7 +2665,14 @@ default_data_link_order (bfd *abfd,
|
|
|
| fill = link_order->u.data.contents;
|
| fill_size = link_order->u.data.size;
|
| - if (fill_size != 0 && fill_size < size)
|
| + if (fill_size == 0)
|
| + {
|
| + fill = abfd->arch_info->fill (size, bfd_big_endian (abfd),
|
| + (sec->flags & SEC_CODE) != 0);
|
| + if (fill == NULL)
|
| + return FALSE;
|
| + }
|
| + else if (fill_size < size)
|
| {
|
| bfd_byte *p;
|
| fill = (bfd_byte *) bfd_malloc (size);
|
| @@ -3123,6 +3131,76 @@ _bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED,
|
| return FALSE;
|
| }
|
|
|
| +/* Choose a neighbouring section to S in OBFD that will be output, or
|
| + the absolute section if ADDR is out of bounds of the neighbours. */
|
| +
|
| +asection *
|
| +_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
|
| +{
|
| + asection *next, *prev, *best;
|
| +
|
| + /* Find preceding kept section. */
|
| + for (prev = s->prev; prev != NULL; prev = prev->prev)
|
| + if ((prev->flags & SEC_EXCLUDE) == 0
|
| + && !bfd_section_removed_from_list (obfd, prev))
|
| + break;
|
| +
|
| + /* Find following kept section. Start at prev->next because
|
| + other sections may have been added after S was removed. */
|
| + if (s->prev != NULL)
|
| + next = s->prev->next;
|
| + else
|
| + next = s->owner->sections;
|
| + for (; next != NULL; next = next->next)
|
| + if ((next->flags & SEC_EXCLUDE) == 0
|
| + && !bfd_section_removed_from_list (obfd, next))
|
| + 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. */
|
| + best = next;
|
| + if (prev == NULL)
|
| + {
|
| + if (next == NULL)
|
| + best = bfd_abs_section_ptr;
|
| + }
|
| + else if (next == NULL)
|
| + best = prev;
|
| + else if (((prev->flags ^ next->flags)
|
| + & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
|
| + {
|
| + if (((next->flags ^ s->flags)
|
| + & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
|
| + /* We prefer to choose a loaded section. Section S
|
| + doesn't have SEC_LOAD set (it being excluded, that
|
| + part of the flag processing didn't happen) so we
|
| + can't compare that flag to those of NEXT and PREV. */
|
| + || ((prev->flags & SEC_LOAD) != 0
|
| + && (next->flags & SEC_LOAD) == 0))
|
| + best = prev;
|
| + }
|
| + else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
|
| + {
|
| + if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
|
| + best = prev;
|
| + }
|
| + else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
|
| + {
|
| + if (((next->flags ^ s->flags) & SEC_CODE) != 0)
|
| + best = prev;
|
| + }
|
| + else
|
| + {
|
| + /* Flags we care about are the same. Prefer the following
|
| + section if that will result in a positive valued sym. */
|
| + if (addr < next->vma)
|
| + best = prev;
|
| + }
|
| +
|
| + return best;
|
| +}
|
| +
|
| /* Convert symbols in excluded output sections to use a kept section. */
|
|
|
| static bfd_boolean
|
| @@ -3139,68 +3217,10 @@ 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;
|
| + asection *op;
|
|
|
| h->u.def.value += s->output_offset + s->output_section->vma;
|
| -
|
| - /* 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 | SEC_LOAD)) != 0)
|
| - {
|
| - if (((op->flags ^ s->flags)
|
| - & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
|
| - /* We prefer to choose a loaded section. Section S
|
| - doesn't have SEC_LOAD set (it being excluded, that
|
| - part of the flag processing didn't happen) so we
|
| - can't compare that flag to those of OP and OP1. */
|
| - || ((op1->flags & SEC_LOAD) != 0
|
| - && (op->flags & SEC_LOAD) == 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;
|
| - }
|
| -
|
| + op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
|
| h->u.def.value -= op->vma;
|
| h->u.def.section = op;
|
| }
|
|
|