This is the mail archive of the binutils@sources.redhat.com 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]

Explicit PHDRS and empty sections


When specifying an explicit PHDRS statement to in a linker script, the
bfd library has  problems when dealing with empty output sections and
empty elf section headers.

Problems with empty output sections
---------------------------
These occur because
bfd/elf.c:assign_file_positions_for_segments() assumes in many places
that
only SEC_ALLOC sections will be mapped into PT_LOAD elf header sections
--
in particular, it assumes that information on the first section in a
PT_LOAD segment can be used to determine allocation state, alignment and

file offsets for the segment.

1) the alignment test for properly aligning sections into misaligned
memories can fail
when the first section is empty and a subsequent section is SEC_ALLOC.

2) Similarly, the address calculation for the section header can produce
a misaligned address when the memory is misaligned and the first section
is empty.

3)  Even after the above two problems above are dealt with, performing
an objcopy on any executable generated with empty output sections (with
SEC_CONTENTS set, but not SEC_ALLOC) will produce file offsets that
differ from the original file because the sections not marked
"SEC_ALLOC" are not mapped into a PT_LOAD elf section header.

To fix the above problems, I propose removing any section not marked
SEC_ALLOC from
the section -> segment mapping before assigning file positions in the
assign_file_positions_for_segments() function.

For an example of this problem, see the attached testcase.  For a more
explicit
error message, try to run objcopy on the executable resulting from the
testcase.


Problems with empty elf section headers:
------------------------------
There is a warning in the bfd library about empty loadable elf section
headers.  I believe that the elf specification allows empty loadable
headers and it is certainly easy to generate them with explicit PHDRS,
thus I am unsure why this warning exists. I would like to remove this
"Empty loadable segment detected" warning.

Included for consideration is a proposed patch to bfd/elf.c
(empty_ptload.patch)
for both of the above problems and a testcase (phdrs2.exp, phdrs2.t and
phdrs2.s) that can be added to the ld/testsuite/ld-scripts/ directory to
validate it.


Index: elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.137
diff -c -r1.137 elf.c
*** elf.c	12 Apr 2002 03:30:56 -0000	1.137
--- elf.c	30 Apr 2002 23:58:49 -0000
***************
*** 3294,3299 ****
--- 3294,3332 ----
      {
        if (! map_sections_to_segments (abfd))
  	return false;
+     } 
+   else
+     {
+       /*
+        * The placement algorithm assumes that
+        * non allocated sections are not in PT_LOAD segments
+        * We ensure this here by removing such sections from the segment map
+        */
+       for (m = elf_tdata (abfd)->segment_map;
+ 	   m != NULL;
+ 	   m = m->next)
+ 	{
+ 	  unsigned int new_count;
+ 	  unsigned int i;
+ 	  
+ 	  if (m->p_type != PT_LOAD)
+ 	    continue;
+ 	  
+ 	  new_count = 0;
+ 	  for (i = 0; i < m->count; i++)
+ 	    {
+ 	      if ((m->sections[i]->flags & SEC_ALLOC) != 0)
+ 		{
+ 		  if (i != new_count) 
+ 		    {
+ 		      m->sections[new_count] = m->sections[i];
+ 		    }
+ 		  new_count++;
+ 		}
+ 	    }
+ 	  if (new_count != m->count)
+ 	    m->count = new_count;
+ 	}
      }
  
    if (bed->elf_backend_modify_segment_map)
***************
*** 4407,4420 ****
  
        if (section_count == 0)
  	{
! 	  /* Special segments, such as the PT_PHDR segment, may contain
! 	     no sections, but ordinary, loadable segments should contain
! 	     something.  */
! 	  if (segment->p_type == PT_LOAD)
! 	      _bfd_error_handler
! 		(_("%s: warning: Empty loadable segment detected\n"),
! 		 bfd_archive_filename (ibfd));
! 
  	  map->count = 0;
  	  *pointer_to_map = map;
  	  pointer_to_map = &map->next;
--- 4440,4448 ----
  
        if (section_count == 0)
  	{
! 	  /* Previously, a warning was generated for empty loadable
! 	     segments.  These can be generated by the linker using
! 	     explicit PHDRS and the Elf spec allows them. */
  	  map->count = 0;
  	  *pointer_to_map = map;
  	  pointer_to_map = &map->next;
Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/bfd/ChangeLog,v
retrieving revision 1.1442
diff -c -r1.1442 ChangeLog
*** ChangeLog	30 Apr 2002 04:32:49 -0000	1.1442
--- ChangeLog	30 Apr 2002 23:58:50 -0000
***************
*** 1,3 ****
--- 1,10 ----
+ 2002-04-30  David Heine <dlheine@tensilica.com>
+ 
+ 	* elf.c (assign_file_positions_for_segments): Remove unallocated
+ 	sections from the section to segment mapping for PT_LOAD elf
+ 	section headers.  Also remove warning about empty loadable elf 
+ 	section headers
+ 
  2002-04-30  Tom Rix  <trix@redhat.com>
  
  	* xcofflink.c (xcoff_link_add_symbols): Always copy undef C_EXT
# Test PHDRS with empty sections in a linker script.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# PHDRS2 is only meaningful for ELF.
if { ![istarget *-*-sysv4*] \
     && ![istarget *-*-unixware*] \
     && ![istarget *-*-elf*] \
     && ![istarget *-*-eabi*] \
     && ![istarget *-*-linux*] \
     && ![istarget *-*-irix5*] \
     && ![istarget *-*-irix6*] \
     && ![istarget *-*-solaris2*] } {
    return
}

if { [istarget *-*-linux*aout*] \
     || [istarget *-*-linux*oldld*] } {
    return
}

# This is a very simplistic test.

set testname "PHDRS2"

if ![ld_assemble $as $srcdir/$subdir/phdrs2.s tmpdir/phdrs2.o] {
    unresolved $testname
    return
}

set phdrs_regexp \
    ".*Program Header:.*LOAD *off *0x00\[0-9a-f\]* *vaddr *0x00*800000 *paddr *0x00*800000.*filesz *0x0\[0-9a-f\]* *memsz *0x0\[0-9a-f\]*.*LOAD *off *0x00\[0-9a-f\]* *vaddr *0x00*800004 *paddr *0x00*800004.*filesz *0x00*\[0-9a-f\]* *memsz *0x0\[0-9a-f\]* *flags rw.*"

if ![ld_simple_link $ld tmpdir/phdrs2 "-T $srcdir/$subdir/phdrs2.t tmpdir/phdrs2.o"] {
    fail $testname
} else {
    if {[which $objdump] == 0} {
	unresolved $testname
	return
    }

    verbose -log "$objdump --private tmpdir/phdrs2"
    catch "exec $objdump --private tmpdir/phdrs2" exec_output
    set exec_output [prune_warnings $exec_output]
    verbose -log $exec_output

    if [regexp $phdrs_regexp $exec_output] {
	pass $testname
    } else {
	fail $testname
    }
}

Attachment: phdrs2.t
Description: Troff document

	.text
	.align 4
	.long	1

	.data
	.align 4
	.long	2
	

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