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; |
} |