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: binutils/2258: p_paddr in ELF progam header isn't handled properly


On Mon, Feb 06, 2006 at 03:57:27PM +0000, Nick Clifton wrote:
> Hi H. J.
> 
> >I think we can rename copy_private_bfd_data in elf.c to something
> >like rewrite_elf_program_header and add a new function,
> >copy_elf_program_header. Then copy_private_bfd_data can be
> >
> >  if any section covered by ELF program header is changed then
> >    call rewrite_elf_program_header
> >  else
> >    call copy_elf_program_header
> >
> >I really don't mind if rewrite_elf_program_header doesn't work
> >correctly in all cases. But copy_elf_program_header should work
> >correctly in all cases.
> 
> This approach sounds fine to me.  Just please be careful when testing it 
> (I am assuming that you are volunteering! :-) to make sure that you test 
> as big a range of targets as possible and especially to look for 
> possible uses of objcopy and strip that might encounter problems with 
> the new code.

Here is the patch. I tested it on Linux/i686, Linux/x86-64 and
Linux/ia64. There are no regressions. The statically linked busy box
is stripped correctly now.

----
bfd/

2006-02-08  H.J. Lu  <hongjiu.lu@intel.com>

	PR binutils/2258
	* elf.c (copy_private_bfd_data): Renamed to ...
	(rewrite_elf_program_header): This.
	(copy_elf_program_header): New function.
	(copy_private_bfd_data): Likewise.

binutils/

2006-02-08  H.J. Lu  <hongjiu.lu@intel.com>

	* readelf.c (process_program_headers): Use
	ELF_IS_SECTION_IN_SEGMENT_MEMORY.

include/elf/

2006-02-08  H.J. Lu  <hongjiu.lu@intel.com>

	* common.h (ELF_IS_SECTION_IN_SEGMENT_FILE): New.
	(ELF_IS_SECTION_IN_SEGMENT_MEMORY): Likewise.

--- binutils/bfd/elf.c.phdr	2006-01-20 08:53:55.000000000 -0800
+++ binutils/bfd/elf.c	2006-02-08 09:30:09.000000000 -0800
@@ -5045,10 +5045,10 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *ab
   return idx;
 }
 
-/* Copy private BFD data.  This copies any program header information.  */
+/* Rewrite program header information.  */
 
 static bfd_boolean
-copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 {
   Elf_Internal_Ehdr *iehdr;
   struct elf_segment_map *map;
@@ -5064,13 +5064,6 @@ copy_private_bfd_data (bfd *ibfd, bfd *o
   unsigned int phdr_adjust_num = 0;
   const struct elf_backend_data *bed;
 
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
-
-  if (elf_tdata (ibfd)->phdr == NULL)
-    return TRUE;
-
   bed = get_elf_backend_data (ibfd);
   iehdr = elf_elfheader (ibfd);
 
@@ -5630,6 +5623,186 @@ copy_private_bfd_data (bfd *ibfd, bfd *o
   return TRUE;
 }
 
+/* Copy ELF program header information.  */
+
+static bfd_boolean
+copy_elf_program_header (bfd *ibfd, bfd *obfd)
+{
+  Elf_Internal_Ehdr *iehdr;
+  struct elf_segment_map *map;
+  struct elf_segment_map *map_first;
+  struct elf_segment_map **pointer_to_map;
+  Elf_Internal_Phdr *segment;
+  unsigned int i;
+  unsigned int num_segments;
+  bfd_boolean phdr_included = FALSE;
+
+  iehdr = elf_elfheader (ibfd);
+
+  map_first = NULL;
+  pointer_to_map = &map_first;
+
+  num_segments = elf_elfheader (ibfd)->e_phnum;
+  for (i = 0, segment = elf_tdata (ibfd)->phdr;
+       i < num_segments;
+       i++, segment++)
+    {
+      asection *section;
+      unsigned int section_count;
+      bfd_size_type amt;
+      Elf_Internal_Shdr *this_hdr;
+
+      /* FIXME: Do we need to copy PT_NULL segment?  */
+      if (segment->p_type == PT_NULL)
+	continue;
+
+      /* Compute how many sections are in this segment.  */
+      for (section = ibfd->sections, section_count = 0;
+	   section != NULL;
+	   section = section->next)
+	{
+	  this_hdr = &(elf_section_data(section)->this_hdr);
+	  if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+	    section_count++;
+	}
+
+      /* Allocate a segment map big enough to contain
+	 all of the sections we have selected.  */
+      amt = sizeof (struct elf_segment_map);
+      if (section_count != 0)
+	amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
+      map = bfd_alloc (obfd, amt);
+      if (map == NULL)
+	return FALSE;
+
+      /* Initialize the fields of the output segment map with the
+	 input segment.  */
+      map->next = NULL;
+      map->p_type = segment->p_type;
+      map->p_flags = segment->p_flags;
+      map->p_flags_valid = 1;
+      map->p_paddr = segment->p_paddr;
+      map->p_paddr_valid = 1;
+
+      /* Determine if this segment contains the ELF file header
+	 and if it contains the program headers themselves.  */
+      map->includes_filehdr = (segment->p_offset == 0
+			       && segment->p_filesz >= iehdr->e_ehsize);
+
+      map->includes_phdrs = 0;
+      if (! phdr_included || segment->p_type != PT_LOAD)
+	{
+	  map->includes_phdrs =
+	    (segment->p_offset <= (bfd_vma) iehdr->e_phoff
+	     && (segment->p_offset + segment->p_filesz
+		 >= ((bfd_vma) iehdr->e_phoff
+		     + iehdr->e_phnum * iehdr->e_phentsize)));
+
+	  if (segment->p_type == PT_LOAD && map->includes_phdrs)
+	    phdr_included = TRUE;
+	}
+
+      if (section_count != 0)
+	{
+	  unsigned int isec = 0;
+
+	  for (section = ibfd->sections;
+	       section != NULL;
+	       section = section->next)
+	    {
+	      this_hdr = &(elf_section_data(section)->this_hdr);
+	      if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+		map->sections[isec++] = section->output_section;
+	    }
+	}
+
+      map->count = section_count;
+      *pointer_to_map = map;
+      pointer_to_map = &map->next;
+    }
+
+  elf_tdata (obfd)->segment_map = map_first;
+  return TRUE;
+}
+
+/* Copy private BFD data.  This copies or rewrites ELF program header
+   information.  */
+
+static bfd_boolean
+copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+  Elf_Internal_Phdr *segment;
+
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  if (elf_tdata (ibfd)->phdr == NULL)
+    return TRUE;
+
+  if (ibfd->xvec == obfd->xvec)
+    {
+      /* Check if any sections in the input BFD covered by ELF program
+	 header are changed.  */
+      asection *section, *osec;
+      unsigned int i, num_segments;
+      Elf_Internal_Shdr *this_hdr;
+
+      /* Initialize the segment mark field.  */
+      for (section = obfd->sections; section != NULL;
+	   section = section->next)
+	section->segment_mark = FALSE;
+
+      num_segments = elf_elfheader (ibfd)->e_phnum;
+      for (i = 0, segment = elf_tdata (ibfd)->phdr;
+	   i < num_segments;
+	   i++, segment++)
+	{
+	  for (section = ibfd->sections;
+	       section != NULL; section = section->next)
+	    {
+	      /* We mark the output section so that we know it comes
+		 from the input BFD.  */
+	      osec = section->output_section;
+	      if (osec)
+		osec->segment_mark = TRUE;
+
+	      /* Check if this section is covered by the segment.  */
+	      this_hdr = &(elf_section_data(section)->this_hdr);
+	      if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+		{
+		  /* FIXME: Check if its output section is changed or
+		     removed.  What else do we need to check?  */
+		  if (osec == NULL
+		      || section->flags != osec->flags
+		      || section->lma != osec->lma
+		      || section->vma != osec->vma
+		      || section->size != osec->size
+		      || section->rawsize != osec->rawsize
+		      || section->alignment_power != osec->alignment_power)
+		    goto rewrite;
+		}
+	    }
+	}
+
+      /* Check to see if any output section doesn't come from the
+	 input BFD.  */
+      for (section = obfd->sections; section != NULL;
+	   section = section->next)
+	{
+	  if (section->segment_mark == FALSE)
+	    goto rewrite;
+	  else
+	    section->segment_mark = FALSE;
+	}
+
+      return copy_elf_program_header (ibfd, obfd);
+    }
+
+rewrite:
+  return rewrite_elf_program_header (ibfd, obfd);
+}
+
 /* Initialize private output section information from input section.  */
 
 bfd_boolean
--- binutils/binutils/readelf.c.phdr	2006-02-08 08:49:33.000000000 -0800
+++ binutils/binutils/readelf.c	2006-02-08 09:13:42.000000000 -0800
@@ -3447,24 +3447,7 @@ process_program_headers (FILE *file)
 
 	  for (j = 1; j < elf_header.e_shnum; j++, section++)
 	    {
-	      if (section->sh_size > 0
-		  /* PT_TLS segment contains only SHF_TLS sections.  */
-		  && (segment->p_type != PT_TLS
-		      || (section->sh_flags & SHF_TLS) != 0)
-		  /* Compare allocated sections by VMA, unallocated
-		     sections by file offset.  */
-		  && (section->sh_flags & SHF_ALLOC
-		      ? (section->sh_addr >= segment->p_vaddr
-			 && section->sh_addr + section->sh_size
-			 <= segment->p_vaddr + segment->p_memsz)
-		      : ((bfd_vma) section->sh_offset >= segment->p_offset
-			 && (section->sh_offset + section->sh_size
-			     <= segment->p_offset + segment->p_filesz)))
-		  /* .tbss is special.  It doesn't contribute memory space
-		     to normal segments.  */
-		  && (!((section->sh_flags & SHF_TLS) != 0
-			&& section->sh_type == SHT_NOBITS)
-		      || segment->p_type == PT_TLS))
+	      if (ELF_IS_SECTION_IN_SEGMENT_MEMORY(section, segment))
 		printf ("%s ", SECTION_NAME (section));
 	    }
 
--- binutils/include/elf/common.h.phdr	2006-01-20 08:53:57.000000000 -0800
+++ binutils/include/elf/common.h	2006-02-08 09:13:01.000000000 -0800
@@ -762,5 +762,29 @@
 #define AT_SUN_MMU      2015    /* String for name of MMU module.   */
 #define AT_SUN_LDDATA   2016    /* Dynamic linker's data segment address.  */
 
+/* Decide if the given sec_hdr is in the given segment in file.  */
+#define ELF_IS_SECTION_IN_SEGMENT_FILE(sec_hdr, segment)	\
+  (sec_hdr->sh_size > 0						\
+   /* PT_TLS segment contains only SHF_TLS sections.  */	\
+   && (segment->p_type != PT_TLS				\
+       || (sec_hdr->sh_flags & SHF_TLS) != 0)			\
+   /* Compare allocated sec_hdrs by VMA, unallocated sec_hdrs	\
+      by file offset.  */					\
+   && (sec_hdr->sh_flags & SHF_ALLOC				\
+       ? (sec_hdr->sh_addr >= segment->p_vaddr			\
+	  && sec_hdr->sh_addr + sec_hdr->sh_size		\
+	  <= segment->p_vaddr + segment->p_memsz)		\
+       : ((bfd_vma) sec_hdr->sh_offset >= segment->p_offset	\
+	  && (sec_hdr->sh_offset + sec_hdr->sh_size		\
+	      <= segment->p_offset + segment->p_filesz))))
+
+/* Decide if the given sec_hdr is in the given segment in memory.  */
+#define ELF_IS_SECTION_IN_SEGMENT_MEMORY(sec_hdr, segment)	\
+  (ELF_IS_SECTION_IN_SEGMENT_FILE (sec_hdr, segment)		\
+   /* .tbss is special.  It doesn't contribute memory space to	\
+      normal segments.  */					\
+   && (!((sec_hdr->sh_flags & SHF_TLS) != 0			\
+	 && sec_hdr->sh_type == SHT_NOBITS)			\
+       || segment->p_type == PT_TLS))
 
 #endif /* _ELF_COMMON_H */


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