ppc-aix: .bss relocation problem when overlapping with the .data section
authorJoel Brobecker <brobecker@gnat.com>
Tue, 1 Jan 2013 08:37:20 +0000 (08:37 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Tue, 1 Jan 2013 08:37:20 +0000 (08:37 +0000)
It has been observed that the GNU linker can sometimes improperly
set the address of the .bss section in such a way that it overlaps
with the end of the .data section.  This causes problems in GDB
when trying to print the value of variables located in that section,
because the loader appears to be gracefully but silently adjusting
the address of the .bss section to avoid the overlap, thus causing
a mismatch between the address where GDB thinks it is, vs the address
where it actually lives.

This patch works around the problem while it a fix in the linker
is being explored.

gdb/ChangeLog:

        * rs6000-nat.c (bss_data_overlap): New function.
        (vmap_symtab): Use it to adjust the .bss section's offset.

gdb/rs6000-nat.c

index d7b9571..a40b9a7 100644 (file)
@@ -651,6 +651,71 @@ vmap_secs (struct vmap *vp, LdInfo *ldi, int arch64)
   vp->tstart += vp->toffs;
 }
 
+/* If the .bss section's VMA is set to an address located before
+   the end of the .data section, causing the two sections to overlap,
+   return the overlap in bytes.  Otherwise, return zero.
+
+   Motivation:
+
+   The GNU linker sometimes sets the start address of the .bss session
+   before the end of the .data section, making the 2 sections overlap.
+   The loader appears to handle this situation gracefully, by simply
+   loading the bss section right after the end of the .data section.
+
+   This means that the .data and the .bss sections are sometimes
+   no longer relocated by the same amount.  The problem is that
+   the ldinfo data does not contain any information regarding
+   the relocation of the .bss section, assuming that it would be
+   identical to the information provided for the .data section
+   (this is what would normally happen if the program was linked
+   correctly).
+
+   GDB therefore needs to detect those cases, and make the corresponding
+   adjustment to the .bss section offset computed from the ldinfo data
+   when necessary.  This function returns the adjustment amount  (or
+   zero when no adjustment is needed).  */
+
+static CORE_ADDR
+bss_data_overlap (struct objfile *objfile)
+{
+  struct obj_section *osect;
+  struct bfd_section *data = NULL;
+  struct bfd_section *bss = NULL;
+
+  /* First, find the .data and .bss sections.  */
+  ALL_OBJFILE_OSECTIONS (objfile, osect)
+    {
+      if (strcmp (bfd_section_name (objfile->obfd,
+                                   osect->the_bfd_section),
+                 ".data") == 0)
+       data = osect->the_bfd_section;
+      else if (strcmp (bfd_section_name (objfile->obfd,
+                                        osect->the_bfd_section),
+                      ".bss") == 0)
+       bss = osect->the_bfd_section;
+    }
+
+  /* If either section is not defined, there can be no overlap.  */
+  if (data == NULL || bss == NULL)
+    return 0;
+
+  /* Assume the problem only occurs with linkers that place the .bss
+     section after the .data section (the problem has only been
+     observed when using the GNU linker, and the default linker
+     script always places the .data and .bss sections in that order).  */
+  if (bfd_section_vma (objfile->obfd, bss)
+      < bfd_section_vma (objfile->obfd, data))
+    return 0;
+
+  if (bfd_section_vma (objfile->obfd, bss)
+      < bfd_section_vma (objfile->obfd, data) + bfd_get_section_size (data))
+    return ((bfd_section_vma (objfile->obfd, data)
+            + bfd_get_section_size (data))
+           - bfd_section_vma (objfile->obfd, bss));
+
+  return 0;
+}
+
 /* Handle symbol translation on vmapping.  */
 
 static void
@@ -687,6 +752,10 @@ vmap_symtab (struct vmap *vp)
   new_offsets->offsets[SECT_OFF_DATA (objfile)] = vp->dstart - vp->dvma;
   new_offsets->offsets[SECT_OFF_BSS (objfile)] = vp->dstart - vp->dvma;
 
+  /* Perform the same adjustment as the loader if the .data and
+     .bss sections overlap.  */
+  new_offsets->offsets[SECT_OFF_BSS (objfile)] += bss_data_overlap (objfile);
+
   objfile_relocate (objfile, new_offsets);
 }
 \f