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: bfd/elf.c: more wrap/overlap/overflow weirdness


On Fri, Aug 20, 2010 at 10:50:43PM -0400, DJ Delorie wrote:
> 
> > I think things have gone haywire before you get to this code.
> 
> Well, yeah - in real cases, this type of wrap is *bad*.

This patch fixes two issues with our handling of the ELF file header
and program headers.  One is that when sections wrap around the target
address space, they may occupy the same lma as the headers.  The
second is that when building with a 64-bit bfd_vma for a 32-bit
target, it was possible to assign addresses to "dot" in a linker
script that aliased the header lma address.

	* elf.c (_bfd_elf_map_sections_to_segments): Don't load program
	headers if any loaded section wraps the address space.  Simplify
	~(m-1) to -m.  Use lma rather than vma when determining whether
	note sections are adjacent.

Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.515
diff -u -p -r1.515 elf.c
--- bfd/elf.c	18 Aug 2010 12:24:05 -0000	1.515
+++ bfd/elf.c	23 Aug 2010 14:53:51 -0000
@@ -3624,6 +3624,7 @@ _bfd_elf_map_sections_to_segments (bfd *
       asection *first_tls = NULL;
       asection *dynsec, *eh_frame_hdr;
       bfd_size_type amt;
+      bfd_vma addr_mask, wrap_to = 0;
 
       /* Select the allocated sections, and sort them.  */
 
@@ -3632,6 +3633,12 @@ _bfd_elf_map_sections_to_segments (bfd *
       if (sections == NULL)
 	goto error_return;
 
+      /* Calculate top address, avoiding undefined behaviour of shift
+	 left operator when shift count is equal to size of type
+	 being shifted.  */
+      addr_mask = ((bfd_vma) 1 << (bfd_arch_bits_per_address (abfd) - 1)) - 1;
+      addr_mask = (addr_mask << 1) + 1;
+
       i = 0;
       for (s = abfd->sections; s != NULL; s = s->next)
 	{
@@ -3639,6 +3646,9 @@ _bfd_elf_map_sections_to_segments (bfd *
 	    {
 	      sections[i] = s;
 	      ++i;
+	      /* A wrapping section potentially clashes with header.  */
+	      if (((s->lma + s->size) & addr_mask) < (s->lma & addr_mask))
+		wrap_to = (s->lma + s->size) & addr_mask;
 	    }
 	}
       BFD_ASSERT (i <= bfd_count_sections (abfd));
@@ -3708,8 +3718,10 @@ _bfd_elf_map_sections_to_segments (bfd *
 	  if (phdr_size == (bfd_size_type) -1)
 	    phdr_size = get_program_header_size (abfd, info);
 	  if ((abfd->flags & D_PAGED) == 0
-	      || sections[0]->lma < phdr_size
-	      || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
+	      || (sections[0]->lma & addr_mask) < phdr_size
+	      || ((sections[0]->lma & addr_mask) % maxpagesize
+		  < phdr_size % maxpagesize)
+	      || (sections[0]->lma & addr_mask & -maxpagesize) < wrap_to)
 	    phdr_in_segment = FALSE;
 	}
 
@@ -3774,9 +3786,8 @@ _bfd_elf_map_sections_to_segments (bfd *
 	    }
 	  else if (! writable
 		   && (hdr->flags & SEC_READONLY) == 0
-		   && (((last_hdr->lma + last_size - 1)
-			& ~(maxpagesize - 1))
-		       != (hdr->lma & ~(maxpagesize - 1))))
+		   && (((last_hdr->lma + last_size - 1) & -maxpagesize)
+		       != (hdr->lma & -maxpagesize)))
 	    {
 	      /* We don't want to put a writable section in a read only
 		 segment, unless they are on the same page in memory
@@ -3883,8 +3894,8 @@ _bfd_elf_map_sections_to_segments (bfd *
 		    if (s2->next->alignment_power == 2
 			&& (s2->next->flags & SEC_LOAD) != 0
 			&& CONST_STRNEQ (s2->next->name, ".note")
-			&& align_power (s2->vma + s2->size, 2)
-			   == s2->next->vma)
+			&& align_power (s2->lma + s2->size, 2)
+			   == s2->next->lma)
 		      count++;
 		    else
 		      break;

-- 
Alan Modra
Australia Development Lab, IBM


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