public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* PATCH: Preserve ELF program header
@ 2006-05-26  3:05 H. J. Lu
  2006-05-26 14:00 ` Alan Modra
  0 siblings, 1 reply; 6+ messages in thread
From: H. J. Lu @ 2006-05-26  3:05 UTC (permalink / raw)
  To: binutils

When an ELF executable/shared object is created with different
maximum page size, strip may change ELF program header if it uses
different maximum page size. This patch preserves ELF program header
when copying executable/shared object.


H.J.
----
bfd/

2006-05-25  H.J. Lu  <hongjiu.lu@intel.com>

	* elf.c (assign_file_positions_for_load_sections): Set
	p->p_vaddr with m->p_vaddr if it is valid. Set p->p_align with
	m->p_align if it is valid. Adjust p->p_vaddr only if m->p_vaddr
	isn't valid.
	(copy_elf_program_header): Copy p_vaddr and p_align. Set
	p_vaddr_valid and p_align_valid to 1.

include/elf/

2006-05-25  H.J. Lu  <hongjiu.lu@intel.com>

	* internal.h (elf_segment_map): Add p_vaddr, p_align,
	p_vaddr_valid and p_align_valid.

--- binutils/bfd/elf.c.pagesize	2006-05-22 12:36:40.000000000 -0700
+++ binutils/bfd/elf.c	2006-05-22 16:24:05.000000000 -0700
@@ -4292,7 +4292,9 @@ assign_file_positions_for_load_sections 
 	  return FALSE;
 	}
 
-      if (m->count == 0)
+      if (m->p_vaddr_valid)
+	p->p_vaddr = m->p_vaddr;
+      else if (m->count == 0)
 	p->p_vaddr = 0;
       else
 	p->p_vaddr = m->sections[0]->vma;
@@ -4304,7 +4306,9 @@ assign_file_positions_for_load_sections 
       else
 	p->p_paddr = m->sections[0]->lma;
 
-      if (p->p_type == PT_LOAD
+      if (m->p_align_valid)
+	p->p_align = m->p_align;
+      else if (p->p_type == PT_LOAD
 	  && (abfd->flags & D_PAGED) != 0)
 	p->p_align = bed->maxpagesize;
       else if (m->count == 0)
@@ -4327,16 +4331,18 @@ assign_file_positions_for_load_sections 
 	    {
 	      BFD_ASSERT (p->p_type == PT_LOAD);
 
-	      if (p->p_vaddr < (bfd_vma) off)
+	      if (!m->p_vaddr_valid)
 		{
-		  (*_bfd_error_handler)
-		    (_("%B: Not enough room for program headers, try linking with -N"),
-		     abfd);
-		  bfd_set_error (bfd_error_bad_value);
-		  return FALSE;
+		  if (p->p_vaddr < (bfd_vma) off)
+		    {
+		      (*_bfd_error_handler)
+			(_("%B: Not enough room for program headers, try linking with -N"),
+			 abfd);
+		      bfd_set_error (bfd_error_bad_value);
+		      return FALSE;
+		    }
+		  p->p_vaddr -= off;
 		}
-
-	      p->p_vaddr -= off;
 	      if (! m->p_paddr_valid)
 		p->p_paddr -= off;
 	    }
@@ -5805,6 +5811,10 @@ 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_vaddr = segment->p_vaddr;
+      map->p_vaddr_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.  */
--- binutils/include/elf/internal.h	2006-05-22 12:47:06.000000000 -0700
+++ binutils/include/elf/internal.h	2006-05-22 12:47:06.000000000 -0700
@@ -235,12 +235,22 @@ struct elf_segment_map
   unsigned long p_flags;
   /* Program segment physical address.  */
   bfd_vma p_paddr;
+  /* Program segment virtual address.  */
+  bfd_vma p_vaddr;
+  /* 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_vaddr field is valid; if not, the virtual address
+     is based on the section vma values.  */
+  unsigned int p_vaddr_valid : 1;
+  /* Whether the p_align field is valid; if not, the 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.  */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Preserve ELF program header
  2006-05-26  3:05 PATCH: Preserve ELF program header H. J. Lu
@ 2006-05-26 14:00 ` Alan Modra
  2006-05-26 17:28   ` H. J. Lu
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Modra @ 2006-05-26 14:00 UTC (permalink / raw)
  To: H. J. Lu; +Cc: binutils

On Thu, May 25, 2006 at 02:44:16PM -0700, H. J. Lu wrote:
> --- binutils/bfd/elf.c.pagesize	2006-05-22 12:36:40.000000000 -0700
> +++ binutils/bfd/elf.c	2006-05-22 16:24:05.000000000 -0700
> @@ -4292,7 +4292,9 @@ assign_file_positions_for_load_sections 
>  	  return FALSE;
>  	}
>  
> -      if (m->count == 0)
> +      if (m->p_vaddr_valid)
> +	p->p_vaddr = m->p_vaddr;
> +      else if (m->count == 0)
>  	p->p_vaddr = 0;
>        else
>  	p->p_vaddr = m->sections[0]->vma;

I don't see the need for m->p_vaddr and m->p_vaddr_valid.  How can you
get into a situation where m->sections[0]->vma or 0 is not the right
initialisation for p->p_vaddr?

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Preserve ELF program header
  2006-05-26 14:00 ` Alan Modra
@ 2006-05-26 17:28   ` H. J. Lu
  2006-05-27 16:23     ` Alan Modra
  0 siblings, 1 reply; 6+ messages in thread
From: H. J. Lu @ 2006-05-26 17:28 UTC (permalink / raw)
  To: binutils

On Fri, May 26, 2006 at 10:21:00AM +0930, Alan Modra wrote:
> On Thu, May 25, 2006 at 02:44:16PM -0700, H. J. Lu wrote:
> > --- binutils/bfd/elf.c.pagesize	2006-05-22 12:36:40.000000000 -0700
> > +++ binutils/bfd/elf.c	2006-05-22 16:24:05.000000000 -0700
> > @@ -4292,7 +4292,9 @@ assign_file_positions_for_load_sections 
> >  	  return FALSE;
> >  	}
> >  
> > -      if (m->count == 0)
> > +      if (m->p_vaddr_valid)
> > +	p->p_vaddr = m->p_vaddr;
> > +      else if (m->count == 0)
> >  	p->p_vaddr = 0;
> >        else
> >  	p->p_vaddr = m->sections[0]->vma;
> 
> I don't see the need for m->p_vaddr and m->p_vaddr_valid.  How can you
> get into a situation where m->sections[0]->vma or 0 is not the right
> initialisation for p->p_vaddr?
> 

Here is an x86 example, which is generated with 2MB maximum page size.
Due to

TEXT_START_ADDR=0x08048000

We got p->p_vaddr != m->sections[0]->vma to satisfy 2MB alignment.


H.J.
---
There are 6 section headers, starting at offset 0x480a4:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        08048074 048074 000004 00  AX  0   0  4
  [ 2] .data             PROGBITS        08248078 048078 000004 00  WA  0   0  4
  [ 3] .shstrtab         STRTAB          00000000 04807c 000027 00      0   0  1
  [ 4] .symtab           SYMTAB          00000000 048194 0000a0 10      5   6  4
  [ 5] .strtab           STRTAB          00000000 048234 000020 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point 0x8048074
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08000000 0x08000000 0x48078 0x48078 R E 0x200000
  LOAD           0x048078 0x08248078 0x08248078 0x00004 0x00004 RW  0x200000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .data 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Preserve ELF program header
  2006-05-26 17:28   ` H. J. Lu
@ 2006-05-27 16:23     ` Alan Modra
  2006-05-27 16:23       ` H. J. Lu
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Modra @ 2006-05-27 16:23 UTC (permalink / raw)
  To: H. J. Lu; +Cc: binutils

On Thu, May 25, 2006 at 07:30:23PM -0700, H. J. Lu wrote:
> On Fri, May 26, 2006 at 10:21:00AM +0930, Alan Modra wrote:
> > I don't see the need for m->p_vaddr and m->p_vaddr_valid.  How can you
> > get into a situation where m->sections[0]->vma or 0 is not the right
> > initialisation for p->p_vaddr?
> > 
> 
> Here is an x86 example, which is generated with 2MB maximum page size.
> Due to
> 
> TEXT_START_ADDR=0x08048000
> 
> We got p->p_vaddr != m->sections[0]->vma to satisfy 2MB alignment.

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.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Preserve ELF program header
  2006-05-27 16:23     ` Alan Modra
@ 2006-05-27 16:23       ` H. J. Lu
  2006-05-27 16:33         ` Alan Modra
  0 siblings, 1 reply; 6+ messages in thread
From: H. J. Lu @ 2006-05-27 16:23 UTC (permalink / raw)
  To: binutils

On Fri, May 26, 2006 at 01:19:21PM +0930, Alan Modra wrote:
> On Thu, May 25, 2006 at 07:30:23PM -0700, H. J. Lu wrote:
> > On Fri, May 26, 2006 at 10:21:00AM +0930, Alan Modra wrote:
> > > I don't see the need for m->p_vaddr and m->p_vaddr_valid.  How can you
> > > get into a situation where m->sections[0]->vma or 0 is not the right
> > > initialisation for p->p_vaddr?
> > > 
> > 
> > Here is an x86 example, which is generated with 2MB maximum page size.
> > Due to
> > 
> > TEXT_START_ADDR=0x08048000
> > 
> > We got p->p_vaddr != m->sections[0]->vma to satisfy 2MB alignment.
> 
> 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.



H.J.
----
bfd/

2006-05-25  H.J. Lu  <hongjiu.lu@intel.com>

	* elf.c (assign_file_positions_for_load_sections): Align
	segment and set p->p_align with m->p_align if it is valid.
	(copy_elf_program_header): Copy p_align. Set p_align_valid to 1.

include/elf/

2006-05-25  H.J. Lu  <hongjiu.lu@intel.com>

	* internal.h (elf_segment_map): Add p_align and p_align_valid.

--- binutils/bfd/elf.c.phdr	2006-05-25 21:11:34.000000000 -0700
+++ binutils/bfd/elf.c	2006-05-25 21:26:44.000000000 -0700
@@ -4244,8 +4244,13 @@ 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 ((abfd->flags & D_PAGED) != 0)
+	    {
+	      if (m->p_align_valid)
+		align = m->p_align;
+	      else if (bed->maxpagesize > align)
+		align = bed->maxpagesize;
+	    }
 
 	  adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
 	  off += adjust;
@@ -4298,7 +4303,9 @@ assign_file_positions_for_load_sections 
       else
 	p->p_paddr = m->sections[0]->lma;
 
-      if (p->p_type == PT_LOAD
+      if (m->p_align_valid)
+	p->p_align = m->p_align;
+      else if (p->p_type == PT_LOAD
 	  && (abfd->flags & D_PAGED) != 0)
 	p->p_align = bed->maxpagesize;
       else if (m->count == 0)
@@ -5800,6 +5807,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.  */
--- binutils/include/elf/internal.h.phdr	2006-02-10 08:59:44.000000000 -0800
+++ binutils/include/elf/internal.h	2006-05-25 21:22:19.000000000 -0700
@@ -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, the 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.  */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Preserve ELF program header
  2006-05-27 16:23       ` H. J. Lu
@ 2006-05-27 16:33         ` Alan Modra
  0 siblings, 0 replies; 6+ messages in thread
From: Alan Modra @ 2006-05-27 16:33 UTC (permalink / raw)
  To: H. J. Lu; +Cc: binutils

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2006-05-27  0:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-05-26  3:05 PATCH: Preserve ELF program header H. J. Lu
2006-05-26 14:00 ` Alan Modra
2006-05-26 17:28   ` H. J. Lu
2006-05-27 16:23     ` Alan Modra
2006-05-27 16:23       ` H. J. Lu
2006-05-27 16:33         ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).