This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: XCOFF : Ensure .text/.data file offset == vma % pagesize


Hi,

this patch solves an almost invisible issue.

For XCOFF (and for almost all formats), the linker works hard to be
sure that the file offset of .text (and .data) is the same as the
page offset, so that the file can be mmap'ed easily.

But because of the ABI (AIX binaries are always PIE/PIC), the AIX
loader is able to silently work-around shifts by relocating the
TOC. So shifts are usually unnoticed.

But tools such as addr2line won't work well with such shifts, and even
gdb may have some issues.  So we'd better to avoid shifts (and I suppose
load time is better without shifts).

Unfortunately, the way we compute the size of the header is not correct:
possibility of overflows in lineno or relocs numbers is ignored, but may
happen for large executable (particularly because relocs are kept in
execs by default).

So I modified _bfd_xcoff_sizeof_headers to estimate the number of lineno
and relocs entry.  Overestimation is safe, although I think it is accurate.
However, this is not very efficient.

Furthermore, stripping an executable may reduce the header size (particularly
when using dwarf debug info, as several sections are stripped).  So
coff_compute_section_file_positions now takes the offset in consideration.

Ok for trunk ?

Tristan.

bfd/
       * coff-rs6000.c (_bfd_xcoff_sizeof_headers): Also count
       .ovrflo sections.
       * coffcode.h (coff_compute_section_file_positions): Force
       match between file offset and vma offset.

diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 8259899..5af17e1 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -2570,6 +2570,60 @@ _bfd_xcoff_sizeof_headers (bfd *abfd,
   else
     size += SMALL_AOUTSZ;
   size += abfd->section_count * SCNHSZ;
+
+  if (info->strip != strip_all)
+    {
+      /* There can be additional sections just for dealing with overflow in
+	 reloc and lineno counts. But the numbers of relocs and lineno aren't
+	 known zhen bfd_sizeof_headers is called, so we compute them by
+	 summing the numbers from input sections.  */
+      struct nbr_reloc_lineno
+      {
+	unsigned int nbr_relocs;
+	unsigned int nbr_lineno;
+      };
+      struct nbr_reloc_lineno *n_rl;
+      bfd *sub;
+      int max_index;
+      asection *s;
+
+      /* Although the number of sections is known, the maximum value of
+	 section->index isn't (because some sections may have been removed).
+	 Don't try to renumber sections, just compute the upper bound.  */
+      max_index = 0;
+      for (s = abfd->sections; s != NULL; s = s->next)
+	if (s->index > max_index)
+	  max_index = s->index;
+
+      /* Allocate the per section counters. It could be possible to use a
+	 preallocated array as the number of sections is limited on XCOFF,
+	 but this creates a maintainance issue.  */
+      n_rl = bfd_zmalloc ((max_index + 1) * sizeof (*n_rl));
+      if (n_rl == NULL)
+	return -1;
+
+      /* Sum.  */
+      for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+	for (s = sub->sections; s != NULL; s = s->next)
+	  {
+	    struct nbr_reloc_lineno *e = &n_rl[s->output_section->index];
+	    e->nbr_relocs += s->reloc_count;
+	    e->nbr_lineno += s->lineno_count;
+	  }
+
+      /* Add the size of a section for each section with an overflow.  */
+      for (s = abfd->sections; s != NULL; s = s->next)
+	{
+	  struct nbr_reloc_lineno *e = &n_rl[s->index];
+
+	  if (e->nbr_relocs >= 0xffff
+	      || (e->nbr_lineno >= 0xffff && info->strip != strip_debugger))
+	    size += SCNHSZ;
+	}
+
+      free (n_rl);
+    }
+
   return size;
 }
 

diff --git a/bfd/coffcode.h b/bfd/coffcode.h
index 2a1a172..650013e 100644
--- a/bfd/coffcode.h
+++ b/bfd/coffcode.h
@@ -3363,36 +3363,38 @@ coff_compute_section_file_positions (bfd * abfd)
 	     padding the previous section up if necessary.  */
 	  old_sofar = sofar;
 
+	  sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+
 #ifdef RS6000COFF_C
-	  /* AIX loader checks the text section alignment of (vma - filepos)
-	     So even though the filepos may be aligned wrt the o_algntext, for
-	     AIX executables, this check fails. This shows up when a native
-	     AIX executable is stripped with gnu strip because the default vma
-	     of native is 0x10000150 but default for gnu is 0x10000140.  Gnu
-	     stripped gnu excutable passes this check because the filepos is
-	     0x0140.  This problem also show up with 64 bit shared objects. The
-	     data section must also be aligned.  */
+	  /* Make sure the file offset and the vma of .text/.data are at the
+	     same page offset, so that the file can be mmap'ed without being
+	     relocated.  Failing that, AIX is able to load and execute the
+	     program, but it will be silently relocated (possible as
+	     executables are PIE).  But the relocation is slightly costly and
+	     complexify the use of addr2line or gdb.  So better to avoid it,
+	     like does the native linker.  Usually gnu ld makes sure that
+	     the vma of .text is the file offset so this issue shouldn't
+	     appear unless you are stripping such an executable.
+
+	     AIX loader checks the text section alignment of (vma - filepos),
+	     and the native linker doesn't try to align the text sections.
+	     For example:
+
+	     0 .text         000054cc  10000128  10000128  00000128  2**5
+                             CONTENTS, ALLOC, LOAD, CODE
+	  */
+
 	  if (!strcmp (current->name, _TEXT)
 	      || !strcmp (current->name, _DATA))
 	    {
-	      bfd_vma pad;
-	      bfd_vma align;
-
-	      sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
-
-	      align = 1 << current->alignment_power;
-	      pad = abs (current->vma - sofar) % align;
-
-	      if (pad)
-		{
-		  pad = align - pad;
-		  sofar += pad;
-		}
-	    }
-	  else
-#else
-	    {
-	      sofar = BFD_ALIGN (sofar, 1 << current->alignment_power);
+	      bfd_vma align = 4096;
+	      bfd_vma sofar_off = sofar % align;
+	      bfd_vma vma_off = current->vma % align;
+
+	      if (vma_off > sofar_off)
+		sofar += vma_off - sofar_off;
+	      else if (vma_off < sofar_off)
+		sofar += align + vma_off - sofar_off;
 	    }
 #endif
 	  if (previous != NULL)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]