* linker.c (_bfd_nearby_section): New function, split out from..
authorAlan Modra <amodra@gmail.com>
Fri, 23 Mar 2012 09:27:43 +0000 (09:27 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 23 Mar 2012 09:27:43 +0000 (09:27 +0000)
(fix_syms): ..here.
* bfd-in.h (_bfd_nearby_section): Declare.
* bfd-in2.h: Regenerate.
* elflink.c (elf_link_input_bfd): Don't use text_index_section or
data_index_section with ld -q or ld -r output relocs against
stripped output sections.  Instead use _bfd_nearby_section.

bfd/ChangeLog
bfd/bfd-in.h
bfd/bfd-in2.h
bfd/elflink.c
bfd/linker.c

index 854beee0a54c43216964ecd3a8be43df4f1087f1..c59bb4c6a9484e69e2110365c0c7d5c3c3363e8f 100644 (file)
@@ -1,3 +1,13 @@
+2012-03-23  Alan Modra  <amodra@gmail.com>
+
+       * linker.c (_bfd_nearby_section): New function, split out from..
+       (fix_syms): ..here.
+       * bfd-in.h (_bfd_nearby_section): Declare.
+       * bfd-in2.h: Regenerate.
+       * elflink.c (elf_link_input_bfd): Don't use text_index_section or
+       data_index_section with ld -q or ld -r output relocs against
+       stripped output sections.  Instead use _bfd_nearby_section.
+
 2012-03-23  Alan Modra  <amodra@gmail.com>
 
        PR binutils/13894
index 40ed78662885615bcfc1a5254875f7922f638912..c331f3bbf896ae5c2e30c699faedb602a123bfa0 100644 (file)
@@ -705,6 +705,9 @@ extern int bfd_get_sign_extend_vma
 extern struct bfd_section *_bfd_elf_tls_setup
   (bfd *, struct bfd_link_info *);
 
+extern struct bfd_section *
+_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma);
+
 extern void _bfd_fix_excluded_sec_syms
   (bfd *, struct bfd_link_info *);
 
index bea3a05d4d70bbb2399b2bec9e9653aaadcd66e8..61513f20ede165f18720207c68d6667430ae1ba7 100644 (file)
@@ -712,6 +712,9 @@ extern int bfd_get_sign_extend_vma
 extern struct bfd_section *_bfd_elf_tls_setup
   (bfd *, struct bfd_link_info *);
 
+extern struct bfd_section *
+_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma);
+
 extern void _bfd_fix_excluded_sec_syms
   (bfd *, struct bfd_link_info *);
 
index 7f9ec609b53276217550d2bddf98f8f00c77e707..3236911744848dd290dc0d43f01cb79588c285c1 100644 (file)
@@ -9747,23 +9747,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                              r_symndx = osec->target_index;
                              if (r_symndx == STN_UNDEF)
                                {
-                                 struct elf_link_hash_table *htab;
-                                 asection *oi;
-
-                                 htab = elf_hash_table (finfo->info);
-                                 oi = htab->text_index_section;
-                                 if ((osec->flags & SEC_READONLY) == 0
-                                     && htab->data_index_section != NULL)
-                                   oi = htab->data_index_section;
-
-                                 if (oi != NULL)
-                                   {
-                                     irela->r_addend += osec->vma - oi->vma;
-                                     r_symndx = oi->target_index;
-                                   }
+                                 irela->r_addend += osec->vma;
+                                 osec = _bfd_nearby_section (output_bfd, osec,
+                                                             osec->vma);
+                                 irela->r_addend -= osec->vma;
+                                 r_symndx = osec->target_index;
                                }
-
-                             BFD_ASSERT (r_symndx != STN_UNDEF);
                            }
                        }
 
index 04044743f263bc7207eecd89dba17de9cd27f4ed..2f8ecbb3da11d5dc8b458e73ba19678b2d10395b 100644 (file)
@@ -3130,6 +3130,81 @@ _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;
+    }
+
+  /* Refuse to choose a section for which we are out of bounds.  */
+  /* ??? This may make most of the above moot.  */
+  if (addr < best->vma || addr > best->vma + best->size)
+    best = bfd_abs_section_ptr;
+
+  return best;
+}
+
 /* Convert symbols in excluded output sections to use a kept section.  */
 
 static bfd_boolean
@@ -3146,74 +3221,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;
-           }
-
-         /* Refuse to choose a section for which we are out of bounds.  */
-         /* ??? This may make most of the above moot.  */
-         if (h->u.def.value < op->vma
-             || h->u.def.value > op->vma + op->size)
-           op = bfd_abs_section_ptr;
-
+         op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
          h->u.def.value -= op->vma;
          h->u.def.section = op;
        }