This is the mail archive of the binutils@sources.redhat.com 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]

elf.c assign_file_positions_for_segments


This patch reworks quite a lot of assign_file_positions_for_segments
code.  I won't commit this patch immediately as I intend to do some more
testing, and I'd like to give time for review.  This is a fairly
critical piece of code..

The impetus for this rework was noticing the curious behaviour of
objcopy --only-keep-debug on the linux kernel.  For instance, given a
ppc64 kernel with

Section Headers:
 [Nr] Name         Type       Address          Off    Size
 [ 0]              NULL       0000000000000000 000000 000000
 [ 1] .text        PROGBITS   c000000000000000 010000 37f000
 [ 2] .exit.text   PROGBITS   c00000000037f000 38f000 001328
 [ 3] __ex_table   PROGBITS   c000000000380328 390328 005d30
[snip]
 [27] .bss         NOBITS     c000000000548000 558000 103930
 [28] .comment     PROGBITS   0000000000000000 558000 00405b
 [29] .shstrtab    STRTAB     0000000000000000 55c05b 000169
 [30] .symtab      SYMTAB     0000000000000000 55c9c8 0d5540
 [31] .strtab      STRTAB     0000000000000000 631f08 0a50be

Program Headers:
 Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
 LOAD 0x010000 0xc000000000000000 0xc000000000000000 0x548000 0x64b930

objcopy --only-keep-debug would produce:

Section Headers:
 [Nr] Name         Type       Address          Off    Size
 [ 0]              NULL       0000000000000000 000000 000000
 [ 1] .text        NOBITS     c000000000000000 010000 37f000
 [ 2] .exit.text   NOBITS     c00000000037f000 010000 001328
 [ 3] __ex_table   NOBITS     c000000000380328 010000 005d30
[snip]
 [27] .bss         NOBITS     c000000000548000 014452 103930
 [28] .comment     PROGBITS   0000000000000000 014452 00405b
 [29] .shstrtab    STRTAB     0000000000000000 0184ad 000169
 [30] .symtab      SYMTAB     0000000000000000 018e18 0d5540
 [31] .strtab      STRTAB     0000000000000000 0ee358 0a50be

Program Headers:
 Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
 LOAD 0x010000 0xc000000000000000 0xc000000000000000 0x000000 0x64b930

Note the section offsets.  We have space reserved in the file for NOBITS
sections, with one large chunk at the start so that p_offset and p_vaddr
are equal, modulo maxpagesize, and other chunks between sections due to
various bugs in assign_file_positions_for_segments.  I think none of
this space is needed.  It should be possible to assign p_offset to any
location in the file, since nothing will be loaded.  Fixed version:

Section Headers:
 [Nr] Name         Type       Address          Off    Size
 [ 0]              NULL       0000000000000000 000000 000000
 [ 1] .text        NOBITS     c000000000000000 000078 37f000
 [ 2] .exit.text   NOBITS     c00000000037f000 000078 001328
 [ 3] __ex_table   NOBITS     c000000000380328 000078 005d30
[snip]
 [27] .bss         NOBITS     c000000000548000 000078 103930
 [28] .comment     PROGBITS   0000000000000000 000078 00405b
 [29] .shstrtab    STRTAB     0000000000000000 0040d3 000169
 [30] .symtab      SYMTAB     0000000000000000 004a40 0d5540
 [31] .strtab      STRTAB     0000000000000000 0d9f80 0a50be

Program Headers:
 Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
 LOAD 0x000000 0xc000000000000000 0xc000000000000000 0x000000 0x64b930


bfd/
	* elf.c (IS_LOADED): Define.
	(assign_file_positions_for_segments): Don't round up file offset of
	PT_LOAD segments containing no SEC_LOAD sections, instead round down.

Hunks at 3906, 4044, and 4055 implement the above.

	Delete code handling link script adjustment of lma.  Do the adjust
	in later code handling similar ajustments.  Remove dead code error
	check.  Warn if section lma would require a negative offset
	adjustment.

Hunk 4067.  The old code handling link script adjustment meant that the
test for section start equal to segment start would always pass.  Also,
the old code was buggy.  It incorrectly tested sec->lma and adjusted
"off" for non-loaded sections.  In moving this code, I'm not doing
exactly as before;  The new code doesn't adjust for core PT_NOTE section
lma changes.  I'm fairly certain this is OK since the linker doesn't
create core files.  (We could be here on objcopy --change-section-lma
but that seems an unlikely thing to want to do on a PT_NOTE section,
particularly since the sections in a core file are faked by bfd and have
zero vmas and lmas.)

	             Test for loadable sections consistently using IS_LOADED.
	Similarly, test for alloc-only sections other than .tbss consistently.

More from hunk 4067.  I'm not certain whether the comment I moved above
IS_LOADED is true regarding NOLOAD, but it's certainly safe to check
SEC_HAS_CONTENTS everywhere we check SEC_LOAD.  The extra .tbss checks
(ie. non-load, SEC_THREAD_LOCAL) ensure that .tbss alignment doesn't
affect a PT_LOAD segment.

	Don't bother checking SEC_ALLOC in PT_LOAD segments.  Remove FIXME.

Sections without SEC_ALLOC are removed earlier.  The code after the
FIXME is needed, at least now..

	Tidy PT_NOTE handling.  Use %B and %A in error messages.
	(assign_file_positions_except_relocs): Use %B in error message.

ld/testsuite
	* ld-scripts/overlay-size.d: Don't check .mbss lma.

Some fallout from this patch: bss section lmas are changed in overlays.
As the test says:
# The .bss[123] LMAs are deliberately blanked out.  We can't
# reliably map overlaid sections to segments.


--- cygnus.orig/bfd/elf.c	2004-09-20 15:58:11.000000000 +0930
+++ cygnus/bfd/elf.c	2004-09-21 19:56:20.269162159 +0930
@@ -3787,6 +3787,12 @@ vma_page_aligned_bias (bfd_vma vma, ufil
   return ((vma - off) % maxpagesize);
 }
 
+/* We check SEC_HAS_CONTENTS here because if NOLOAD is used in a linker
+   script we may have a section with SEC_LOAD clear but which is
+   supposed to have contents.  */
+#define IS_LOADED(FLAGS) \
+  (((FLAGS) & SEC_LOAD) != 0 || ((FLAGS) & SEC_HAS_CONTENTS) != 0)
+
 /* Assign file positions to the sections based on the mapping from
    sections to segments.  This function also sets up some fields in
    the file header, and writes out the program headers.  */
@@ -3866,8 +3872,8 @@ assign_file_positions_for_segments (bfd 
   if (alloc != 0 && count > alloc)
     {
       ((*_bfd_error_handler)
-       (_("%s: Not enough room for program headers (allocated %u, need %u)"),
-	bfd_get_filename (abfd), alloc, count));
+       (_("%B: Not enough room for program headers (allocated %u, need %u)"),
+	abfd, alloc, count));
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
@@ -3906,32 +3912,61 @@ assign_file_positions_for_segments (bfd 
 	qsort (m->sections, (size_t) m->count, sizeof (asection *),
 	       elf_sort_sections);
 
+      /* In this loop, OFF tracks next available file offset in PT_LOAD
+	 and PT_NOTE segments.  OFF is used to place sections that need
+	 file contents.  VOFF (virtual offset) serves a similar purpose
+	 for sections that have no file contents but need zero filled
+	 memory allocation.  An ELF segment (described by
+	 Elf_Internal_Phdr) may contain a number of sections with
+	 contents contributing to both p_filesz and p_memsz, followed
+	 by a number of sections with no contents that just contribute
+	 to p_memsz.  */
+      voff = off;
       p->p_type = m->p_type;
       p->p_flags = m->p_flags;
 
       if (p->p_type == PT_LOAD
-	  && m->count > 0
-	  && (m->sections[0]->flags & SEC_ALLOC) != 0)
+	  && m->count > 0)
 	{
+	  bfd_size_type align;
+	  bfd_vma adjust;
+
 	  if ((abfd->flags & D_PAGED) != 0)
-	    off += vma_page_aligned_bias (m->sections[0]->vma, off,
-					  bed->maxpagesize);
+	    align = bed->maxpagesize;
 	  else
 	    {
-	      bfd_size_type align;
-
-	      align = 0;
+	      unsigned int align_power = 0;
 	      for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
 		{
-		  bfd_size_type secalign;
+		  unsigned int secalign;
 
 		  secalign = bfd_get_section_alignment (abfd, *secpp);
-		  if (secalign > align)
-		    align = secalign;
+		  if (secalign > align_power)
+		    align_power = secalign;
 		}
+	      align = (bfd_size_type) 1 << align_power;
+	    }
 
-	      off += vma_page_aligned_bias (m->sections[0]->vma, off,
-					    1 << align);
+	  adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
+	  if (adjust != 0)
+	    {
+	      if (IS_LOADED (m->sections[0]->flags)
+		  || m->includes_filehdr
+		  || m->includes_phdrs)
+		{
+		  off += adjust;
+		  voff = off;
+		}
+	      else if ((m->sections[0]->flags & SEC_THREAD_LOCAL) == 0)
+		{
+		  voff += adjust;
+		  /* If the first section isn't loadable, the same holds
+		     for any other sections.  Since the segment won't
+		     need file space, we can make p_offset overlap some
+		     prior segment.  */
+		  if ((ufile_ptr) voff >= align)
+		    voff -= align;
+		}
 	    }
 	}
       /* Make sure the .dynamic section is the first section in the
@@ -3941,8 +3976,8 @@ assign_file_positions_for_segments (bfd 
 	       && strcmp (m->sections[0]->name, ".dynamic") != 0)
 	{
 	  _bfd_error_handler
-	    (_("%s: The first section in the PT_DYNAMIC segment is not the .dynamic section"),
-	     bfd_get_filename (abfd));
+	    (_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"),
+	     abfd);
 	  bfd_set_error (bfd_error_bad_value);
 	  return FALSE;
 	}
@@ -3985,8 +4020,8 @@ assign_file_positions_for_segments (bfd 
 	      if (p->p_vaddr < (bfd_vma) off)
 		{
 		  (*_bfd_error_handler)
-		    (_("%s: Not enough room for program headers, try linking with -N"),
-		     bfd_get_filename (abfd));
+		    (_("%B: Not enough room for program headers, try linking with -N"),
+		     abfd);
 		  bfd_set_error (bfd_error_bad_value);
 		  return FALSE;
 		}
@@ -4044,7 +4079,7 @@ assign_file_positions_for_segments (bfd 
 	  || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
 	{
 	  if (! m->includes_filehdr && ! m->includes_phdrs)
-	    p->p_offset = off;
+	    p->p_offset = voff;
 	  else
 	    {
 	      file_ptr adjust;
@@ -4055,8 +4090,6 @@ assign_file_positions_for_segments (bfd 
 	    }
 	}
 
-      voff = off;
-
       for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
 	{
 	  asection *sec;
@@ -4067,117 +4100,86 @@ assign_file_positions_for_segments (bfd 
 	  flags = sec->flags;
 	  align = 1 << bfd_get_section_alignment (abfd, sec);
 
-	  /* The section may have artificial alignment forced by a
-	     link script.  Notice this case by the gap between the
-	     cumulative phdr lma and the section's lma.  */
-	  if (p->p_paddr + p->p_memsz < sec->lma)
-	    {
-	      bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
-
-	      p->p_memsz += adjust;
-	      if (p->p_type == PT_LOAD
-		  || (p->p_type == PT_NOTE
-		      && bfd_get_format (abfd) == bfd_core))
-		{
-		  off += adjust;
-		  voff += adjust;
-		}
-	      if ((flags & SEC_LOAD) != 0
-		  || (flags & SEC_THREAD_LOCAL) != 0)
-		p->p_filesz += adjust;
-	    }
-
 	  if (p->p_type == PT_LOAD)
 	    {
 	      bfd_signed_vma adjust;
 
-	      if ((flags & SEC_LOAD) != 0)
+	      if (IS_LOADED (flags))
 		{
 		  adjust = sec->lma - (p->p_paddr + p->p_memsz);
 		  if (adjust < 0)
-		    adjust = 0;
+		    {
+		      (*_bfd_error_handler)
+			(_("%B: section %A lma 0x%lx overlaps previous sections"),
+			 abfd, sec, (unsigned long) sec->lma);
+		      adjust = 0;
+		    }
+		  off += adjust;
+		  voff = off;
+		  p->p_filesz += adjust;
+		  p->p_memsz += adjust;
 		}
-	      else if ((flags & SEC_ALLOC) != 0)
+	      else if ((flags & SEC_THREAD_LOCAL) == 0)
 		{
 		  /* The section VMA must equal the file position
-		     modulo the page size.  FIXME: I'm not sure if
-		     this adjustment is really necessary.  We used to
-		     not have the SEC_LOAD case just above, and then
-		     this was necessary, but now I'm not sure.  */
+		     modulo the page size.  */
 		  if ((abfd->flags & D_PAGED) != 0)
 		    adjust = vma_page_aligned_bias (sec->vma, voff,
 						    bed->maxpagesize);
 		  else
 		    adjust = vma_page_aligned_bias (sec->vma, voff,
 						    align);
-		}
-	      else
-		adjust = 0;
-
-	      if (adjust != 0)
-		{
-		  if (i == 0)
-		    {
-		      (* _bfd_error_handler) (_("\
-Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x"),
-					      bfd_section_name (abfd, sec),
-					      sec->lma,
-					      p->p_paddr);
-		      return FALSE;
-		    }
-		  p->p_memsz += adjust;
-		  off += adjust;
 		  voff += adjust;
-		  if ((flags & SEC_LOAD) != 0)
-		    p->p_filesz += adjust;
+		  p->p_memsz += adjust;
 		}
 
 	      sec->filepos = off;
 
-	      /* We check SEC_HAS_CONTENTS here because if NOLOAD is
-                 used in a linker script we may have a section with
-                 SEC_LOAD clear but which is supposed to have
-                 contents.  */
-	      if ((flags & SEC_LOAD) != 0
-		  || (flags & SEC_HAS_CONTENTS) != 0)
-		off += sec->size;
-
-	      if ((flags & SEC_ALLOC) != 0
-		  && ((flags & SEC_LOAD) != 0
-		      || (flags & SEC_THREAD_LOCAL) == 0))
+	      if (IS_LOADED (flags))
+		{
+		  off += sec->size;
+		  voff = off;
+		}
+	      /* .tbss is special.  It doesn't contribute to p_memsz of
+		 normal segments.  */
+	      else if ((flags & SEC_THREAD_LOCAL) == 0)
 		voff += sec->size;
 	    }
 
 	  if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
 	    {
-	      /* The actual "note" segment has i == 0.
-		 This is the one that actually contains everything.  */
+	      /* The section at i == 0 is the one that actually contains
+		 everything.  */
 	      if (i == 0)
 		{
 		  sec->filepos = off;
 		  p->p_filesz = sec->size;
 		  off += sec->size;
 		  voff = off;
+		  p->p_memsz = 0;
+		  p->p_align = 1;
 		}
 	      else
 		{
-		  /* Fake sections -- don't need to be written.  */
+		  /* The rest are fake sections that shouldn't be written.  */
 		  sec->filepos = 0;
 		  sec->size = 0;
-		  flags = sec->flags = 0;
+		  sec->flags = 0;
+		  continue;
 		}
-	      p->p_memsz = 0;
-	      p->p_align = 1;
 	    }
 	  else
 	    {
-	      if ((sec->flags & SEC_LOAD) != 0
-		  || (sec->flags & SEC_THREAD_LOCAL) == 0
-		  || p->p_type == PT_TLS)
-	      p->p_memsz += sec->size;
-
-	      if ((flags & SEC_LOAD) != 0)
-		p->p_filesz += sec->size;
+	      if (IS_LOADED (flags))
+		{
+		  p->p_filesz += sec->size;
+		  p->p_memsz += sec->size;
+		}
+	      /* .tbss is special.  It doesn't contribute to p_memsz of
+		 normal segments.  */
+	      else if ((flags & SEC_THREAD_LOCAL) == 0
+		       || p->p_type == PT_TLS)
+		p->p_memsz += sec->size;
 
 	      if (p->p_type == PT_TLS
 		  && sec->size == 0
@@ -4493,8 +4495,8 @@ assign_file_positions_except_relocs (bfd
 	  else if ((hdr->sh_flags & SHF_ALLOC) != 0)
 	    {
 	      ((*_bfd_error_handler)
-	       (_("%s: warning: allocated section `%s' not in segment"),
-		bfd_get_filename (abfd),
+	       (_("%B: warning: allocated section `%s' not in segment"),
+		abfd,
 		(hdr->bfd_section == NULL
 		 ? "*unknown*"
 		 : hdr->bfd_section->name)));

--- cygnus.orig/ld/testsuite/ld-scripts/overlay-size.d	2002-05-07 20:38:57.000000000 +0930
+++ cygnus/ld/testsuite/ld-scripts/overlay-size.d	2004-09-20 12:58:55.000000000 +0930
@@ -13,7 +13,7 @@
 #...
   3 \.mtext +0+020 +0+10000 +0+30000 .*
 #...
-  4 \.mbss +0+230 +0+20030 +0+20060 .*
+  4 \.mbss +0+230 +0+20030 .*
 #...
   5 \.text1 +0+080 +0+10020 +0+30020 .*
 #...

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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