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] program header instability


This patch fixes a problem with instability in calculating program headers. The original testcase came from a vxworks build, but the problem can manifest on any elf target. The problem occurs when a section boundary happens to lie on a page boundary, and the previous and next sections differ in the WRITABLE attribute.

This bit of code in elf.c:
	  else if (! writable
		   && (hdr->flags & SEC_READONLY) == 0
		   && (((last_hdr->lma + last_size - 1)
			& ~(maxpagesize - 1))
		       != (hdr->lma & ~(maxpagesize - 1))))
	    {
	      /* We don't want to put a writable section in a read only
		 segment, unless they are on the same page in memory
		 anyhow.  We already know that the last section does not
		 bring us past the current section on the page, so the
		 only case in which the new section is not on the same
		 page as the previous section is when the previous section
		 ends precisely on a page boundary.  */
	      new_segment = TRUE;

places those two sections in different segments, necessitating an additional program header. Now, when the new program header is included, the section boundary is no longer page aligned, and we decide we only need 1 program header for the two sections. So the section boundary shifts down and we're back where we started.

The linker bails out with
	./ld-new: looping in map_segments

That loop fails because, even though bfd caches the program_header size during the linking layout phase, we keep changing our minds as to whether the first segment contains the pheaders or not, depending on whether we think we need N or N+1 of them.
if ((abfd->flags & D_PAGED) == 0
|| sections[0]->lma < phdr_size
|| sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
phdr_in_segment = FALSE;


This patch changes elf.c to initialize the program_header_size to zero (rather than the 'unknown' value of -1), and then always recalculate it. furthermore we never reduce the size of the program headers, to avoid the above instability.

Tested in i686-pc-linux-gnu, ok?

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2006-12-19  Nathan Sidwell  <nathan@codesourcery.com>

	* elf.c (bfd_elf_mkobject): Default program_header_size to zero.
	(_bfd_elf_map_sections_to_segments): Adjust default
	program_header_size value.  Don't shrink the program header size.
	(assign_file_positions_for_load_sections): Adjust for default
	program_header_size value.  Assert we've got enough room.
	(_bfd_elf_sizeof_headers): Always recalculate the header size.
	Never shrink it.

	* ld/testsuite/ld-elf/header.d: New.
	* ld/testsuite/ld-elf/header.t: New.
	* ld/testsuite/ld-elf/header.s: New.

Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.369
diff -c -3 -p -r1.369 elf.c
*** bfd/elf.c	19 Dec 2006 08:49:38 -0000	1.369
--- bfd/elf.c	19 Dec 2006 15:32:08 -0000
*************** bfd_elf_mkobject (bfd *abfd)
*** 231,237 ****
  	return FALSE;
      }
  
!   elf_tdata (abfd)->program_header_size = (bfd_size_type) -1;
  
    return TRUE;
  }
--- 231,237 ----
  	return FALSE;
      }
  
!   elf_tdata (abfd)->program_header_size = 0;
  
    return TRUE;
  }
*************** _bfd_elf_map_sections_to_segments (bfd *
*** 3894,3900 ****
  	{
  	  bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
  
! 	  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
--- 3894,3900 ----
  	{
  	  bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
  
! 	  if (!phdr_size)
  	    phdr_size = get_program_header_size (abfd, info);
  	  if ((abfd->flags & D_PAGED) == 0
  	      || sections[0]->lma < phdr_size
*************** _bfd_elf_map_sections_to_segments (bfd *
*** 4145,4151 ****
  
    for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
      ++count;
!   elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr;
  
    return TRUE;
  
--- 4145,4152 ----
  
    for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
      ++count;
!   if (elf_tdata (abfd)->program_header_size < count * bed->s->sizeof_phdr)
!     elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr;
  
    return TRUE;
  
*************** assign_file_positions_for_load_sections 
*** 4271,4281 ****
    elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
    elf_elfheader (abfd)->e_phnum = alloc;
  
!   if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
      elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
    else
      BFD_ASSERT (elf_tdata (abfd)->program_header_size
! 		== alloc * bed->s->sizeof_phdr);
  
    if (alloc == 0)
      {
--- 4272,4282 ----
    elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
    elf_elfheader (abfd)->e_phnum = alloc;
  
!   if (!elf_tdata (abfd)->program_header_size)
      elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
    else
      BFD_ASSERT (elf_tdata (abfd)->program_header_size
! 		>= alloc * bed->s->sizeof_phdr);
  
    if (alloc == 0)
      {
*************** _bfd_elf_sizeof_headers (bfd *abfd, stru
*** 7193,7213 ****
  
    if (!info->relocatable)
      {
!       bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
  
!       if (phdr_size == (bfd_size_type) -1)
! 	{
! 	  struct elf_segment_map *m;
  
! 	  phdr_size = 0;
! 	  for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
! 	    phdr_size += bed->s->sizeof_phdr;
  
! 	  if (phdr_size == 0)
! 	    phdr_size = get_program_header_size (abfd, info);
! 	}
! 
!       elf_tdata (abfd)->program_header_size = phdr_size;
        ret += phdr_size;
      }
  
--- 7194,7216 ----
  
    if (!info->relocatable)
      {
!       bfd_size_type phdr_size = 0;
!       struct elf_segment_map *m;
  
!       for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
! 	phdr_size += bed->s->sizeof_phdr;
  
!       if (phdr_size == 0)
! 	phdr_size = get_program_header_size (abfd, info);
  
!       /* Avoid shrinking program header size.  Shrinking can lead to
!          instability when a section's placement becomes aligned on a
!          page boundary with N segments, requiring N+1 segments.  And
!          with N+1 segments it no longer is aligned.  */
!       if (elf_tdata (abfd)->program_header_size > phdr_size)
! 	phdr_size = elf_tdata (abfd)->program_header_size;
!       else
! 	elf_tdata (abfd)->program_header_size = phdr_size;
        ret += phdr_size;
      }
  
Index: ld/testsuite/ld-elf/header.d
===================================================================
RCS file: ld/testsuite/ld-elf/header.d
diff -N ld/testsuite/ld-elf/header.d
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-elf/header.d	19 Dec 2006 15:32:08 -0000
***************
*** 0 ****
--- 1,12 ----
+ # ld: -T header.t -z max-page-size=0x10000
+ # objdump: -hpw
+ 
+ #...
+ Program Header:
+     LOAD off    0x0*0000000 vaddr 0x0*0010000 paddr 0x0*0010000 align 2..16
+          filesz 0x0*0010024 memsz 0x0*0010024 flags rwx
+ 
+ Sections:
+ Idx Name          Size      VMA       LMA       File off  Algn  Flags
+   0 .text         0*000ffac  0*0010074  0*0010074  0*0000074  2...  CONTENTS, ALLOC, LOAD, READONLY, CODE
+   1 .data         0*0000004  0*0020020  0*0020020  0*0010020  2...  CONTENTS, ALLOC, LOAD, DATA
Index: ld/testsuite/ld-elf/header.s
===================================================================
RCS file: ld/testsuite/ld-elf/header.s
diff -N ld/testsuite/ld-elf/header.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-elf/header.s	19 Dec 2006 15:32:08 -0000
***************
*** 0 ****
--- 1,8 ----
+ 	.text
+ 	.globl main
+ main:
+ 	.rept 0x4000 - 0x15
+ 	.long 0xfedcba98
+ 	.endr
+ 	.data
+ 	.long 0x76543210
Index: ld/testsuite/ld-elf/header.t
===================================================================
RCS file: ld/testsuite/ld-elf/header.t
diff -N ld/testsuite/ld-elf/header.t
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- ld/testsuite/ld-elf/header.t	19 Dec 2006 15:32:08 -0000
***************
*** 0 ****
--- 1,8 ----
+ ENTRY(main)
+ 
+ SECTIONS
+ {
+   . = 0x10000 + SIZEOF_HEADERS;
+   .text : { *(.text) }
+   .data : { *(.data) }
+ }

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