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]

Re: PATCH: Preserve ELF program header


On Thu, May 25, 2006 at 09:32:39PM -0700, H. J. Lu wrote:
> On Fri, May 26, 2006 at 01:19:21PM +0930, Alan Modra wrote:
> > Sure.  Obviously you need to subtract off space for the headers then
> > align.  I'm thinking that you can do this by modifying the assignments
> > to "align" in the function, particularly places that set "align" from
> > "bed->maxpagesize" to instead use your m->p_align.  After all, the
> > problem you are trying to solve is one where alignment due to
> > bed->maxpagesize changes.
> 
> Here is the updated patch.

This still isn't correct.  You ignored bed->maxpagesize used when
aligning PT_TLS segments.  Applying the following.

bfd/
	* elf.c (assign_file_positions_for_load_sections): Retrieve
	maxpagesize from m->p_align if it is valid.  Set p_vaddr,
	p_paddr and p_align earlier.  Revert 2006-05-19 change to p_align.
	(copy_elf_program_header): Copy p_align.  Set p_align_valid.
include/elf/
	* internal.h (struct elf_segment_map): Add p_align and p_align_valid.

Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.339
diff -u -p -r1.339 elf.c
--- bfd/elf.c	25 May 2006 15:08:28 -0000	1.339
+++ bfd/elf.c	27 May 2006 00:23:13 -0000
@@ -4111,6 +4111,7 @@ assign_file_positions_for_load_sections 
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   file_ptr off, voff;
+  bfd_size_type maxpagesize;
   unsigned int count;
   unsigned int alloc;
   unsigned int i;
@@ -4196,6 +4197,10 @@ assign_file_positions_for_load_sections 
   if (phdrs == NULL)
     return FALSE;
 
+  maxpagesize = 1;
+  if ((abfd->flags & D_PAGED) != 0)
+    maxpagesize = bed->maxpagesize;
+
   off = bed->s->sizeof_ehdr;
   off += alloc * bed->s->sizeof_phdr;
 
@@ -4227,6 +4232,39 @@ assign_file_positions_for_load_sections 
       p->p_type = m->p_type;
       p->p_flags = m->p_flags;
 
+      if (m->count == 0)
+	p->p_vaddr = 0;
+      else
+	p->p_vaddr = m->sections[0]->vma;
+
+      if (m->p_paddr_valid)
+	p->p_paddr = m->p_paddr;
+      else if (m->count == 0)
+	p->p_paddr = 0;
+      else
+	p->p_paddr = m->sections[0]->lma;
+
+      if (p->p_type == PT_LOAD
+	  && (abfd->flags & D_PAGED) != 0)
+	{
+	  /* p_align in demand paged PT_LOAD segments effectively stores
+	     the maximum page size.  When copying an executable with
+	     objcopy, we set m->p_align from the input file.  Use this
+	     value for maxpagesize rather than bed->maxpagesize, which
+	     may be different.  Note that we use maxpagesize for PT_TLS
+	     segment alignment later in this function, so we are relying
+	     on at least one PT_LOAD segment appearing before a PT_TLS
+	     segment.  */
+	  if (m->p_align_valid)
+	    maxpagesize = m->p_align;
+
+	  p->p_align = maxpagesize;
+	}
+      else if (m->count == 0)
+	p->p_align = 1 << bed->s->log_file_align;
+      else
+	p->p_align = 0;
+
       if (p->p_type == PT_LOAD
 	  && m->count > 0)
 	{
@@ -4244,8 +4282,8 @@ assign_file_positions_for_load_sections 
 	    }
 	  align = (bfd_size_type) 1 << align_power;
 
-	  if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > align)
-	    align = bed->maxpagesize;
+	  if (align < maxpagesize)
+	    align = maxpagesize;
 
 	  adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
 	  off += adjust;
@@ -4286,26 +4324,6 @@ assign_file_positions_for_load_sections 
 	  return FALSE;
 	}
 
-      if (m->count == 0)
-	p->p_vaddr = 0;
-      else
-	p->p_vaddr = m->sections[0]->vma;
-
-      if (m->p_paddr_valid)
-	p->p_paddr = m->p_paddr;
-      else if (m->count == 0)
-	p->p_paddr = 0;
-      else
-	p->p_paddr = m->sections[0]->lma;
-
-      if (p->p_type == PT_LOAD
-	  && (abfd->flags & D_PAGED) != 0)
-	p->p_align = bed->maxpagesize;
-      else if (m->count == 0)
-	p->p_align = 1 << bed->s->log_file_align;
-      else
-	p->p_align = 0;
-
       p->p_offset = 0;
       p->p_filesz = 0;
       p->p_memsz = 0;
@@ -4386,7 +4404,7 @@ assign_file_positions_for_load_sections 
 
 	  sec = *secpp;
 	  flags = sec->flags;
-	  align = 1 << bfd_get_section_alignment (abfd, sec);
+	  align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
 
 	  if (p->p_type == PT_LOAD
 	      || p->p_type == PT_TLS)
@@ -4416,8 +4434,8 @@ assign_file_positions_for_load_sections 
 		  /* The section VMA must equal the file position
 		     modulo the page size.  */
 		  bfd_size_type page = align;
-		  if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > page)
-		    page = bed->maxpagesize;
+		  if (page < maxpagesize)
+		    page = maxpagesize;
 		  adjust = vma_page_aligned_bias (sec->vma,
 						  p->p_vaddr + p->p_memsz,
 						  page);
@@ -4494,8 +4512,7 @@ assign_file_positions_for_load_sections 
 
 	      if (align > p->p_align
 		  && (p->p_type != PT_LOAD
-		      || (abfd->flags & D_PAGED) == 0
-		      || ((p->p_vaddr - p->p_offset) & (align - 1)) == 0))
+		      || (abfd->flags & D_PAGED) == 0))
 		p->p_align = align;
 	    }
 
@@ -5800,6 +5817,8 @@ copy_elf_program_header (bfd *ibfd, bfd 
       map->p_flags_valid = 1;
       map->p_paddr = segment->p_paddr;
       map->p_paddr_valid = 1;
+      map->p_align = segment->p_align;
+      map->p_align_valid = 1;
 
       /* Determine if this segment contains the ELF file header
 	 and if it contains the program headers themselves.  */
Index: include/elf/internal.h
===================================================================
RCS file: /cvs/src/src/include/elf/internal.h,v
retrieving revision 1.13
diff -u -p -r1.13 internal.h
--- include/elf/internal.h	10 Feb 2006 15:04:19 -0000	1.13
+++ include/elf/internal.h	27 May 2006 00:23:13 -0000
@@ -235,12 +235,17 @@ struct elf_segment_map
   unsigned long p_flags;
   /* Program segment physical address.  */
   bfd_vma p_paddr;
+  /* Program segment alignment.  */
+  bfd_vma p_align;
   /* Whether the p_flags field is valid; if not, the flags are based
      on the section flags.  */
   unsigned int p_flags_valid : 1;
   /* Whether the p_paddr field is valid; if not, the physical address
      is based on the section lma values.  */
   unsigned int p_paddr_valid : 1;
+  /* Whether the p_align field is valid; if not, PT_LOAD segment
+     alignment is based on the default maximum page size.  */
+  unsigned int p_align_valid : 1;
   /* Whether this segment includes the file header.  */
   unsigned int includes_filehdr : 1;
   /* Whether this segment includes the program headers.  */

-- 
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]