[PATCH/RFA] Fix C-referenceable sections with explicit LMAs

Jason R Thorpe thorpej@wasabisystems.com
Wed Nov 20 10:53:00 GMT 2002


On Wed, Nov 20, 2002 at 07:49:16AM -0500, Hans-Peter Nilsson wrote:

 > On Tue, 19 Nov 2002, Jason R Thorpe wrote:
 > > On Tue, Nov 19, 2002 at 09:44:21AM -0800, Jason R Thorpe wrote:
 > > Ok, this patch (again, against 2.11.2) actually works.
 > 
 > > Anyway, I'd appreciate any comments people might have on this.
 > 
 > Perhaps a little something for the test-suite?

Yes indeed.  Here is the patch for current Binutils, as well as a
test case.  Test case fails without the patch, passes with, and no
new regressions (tested on arm-netbsdelf).

OK for mainline?  OK for 2.13 branch?

	* ldexp.c (fold_name): Handle SIZEOF_UNADJ.  When handling
	SIZEOF, apply any size adjustment that has been recorded
	for the section.
	* ldgram.y (SIZEOF_UNADJ): New token.
	* ldlang.c (lang_output_section_statement_lookup): Initialize
	size_adj and last_orphan members.
	* ldlang.h (lang_output_section_statement_type): Add size_adj
	and last_orphan members.
	* emultempl/elf32.em (place_orphan): If no .rodata output section
	is present, allow read-only data to be placed with .text.  If
	the output section has an explicit LMA, compute an explicit LMA
	for the orphan based on the LMA of the output section or the
	previous orphan.  Record a size adjustment of the output section
	for each orphan placed with it.

	* ld-scripts/refsec-lma.exp: New test.
	* ld-scripts/refsec-lma.s: New test.
	* ld-scripts/refsec-lma.t: New test.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>
-------------- next part --------------
Index: ldexp.c
===================================================================
RCS file: /cvs/src/src/ld/ldexp.c,v
retrieving revision 1.21
diff -c -r1.21 ldexp.c
*** ldexp.c	30 Oct 2002 03:57:38 -0000	1.21
--- ldexp.c	20 Nov 2002 18:51:06 -0000
***************
*** 635,640 ****
--- 635,641 ----
        break;
  
      case SIZEOF:
+     case SIZEOF_UNADJ:		/* not actually allowed in grammar  */
        if (allocation_done != lang_first_phase_enum)
  	{
  	  int opb = bfd_octets_per_byte (output_bfd);
***************
*** 643,648 ****
--- 644,656 ----
  	  os = lang_output_section_find (tree->name.name);
  	  check (os, tree->name.name, "SIZEOF");
  	  result = new_abs (os->bfd_section->_raw_size / opb);
+ 
+ 	  /* If the output section has a size adjustment, and we've
+ 	     not been asked for the unadjusted size, apply it.  */
+ 	  if (os->size_adj && tree->type.node_code != SIZEOF_UNADJ)
+ 	    result = exp_fold_tree_no_dot
+ 	      (exp_binop ('+', exp_intop (result.value), os->size_adj),
+ 	       abs_output_section, allocation_done);
  	}
        else
  	result = invalid ();
Index: ldgram.y
===================================================================
RCS file: /cvs/src/src/ld/ldgram.y,v
retrieving revision 1.22
diff -c -r1.22 ldgram.y
*** ldgram.y	11 Oct 2002 07:39:07 -0000	1.22
--- ldgram.y	20 Nov 2002 18:51:06 -0000
***************
*** 138,144 ****
  %token NOLOAD DSECT COPY INFO OVERLAY
  %token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
  %token <integer> NEXT
! %token SIZEOF ADDR LOADADDR MAX_K MIN_K
  %token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
  %token ORIGIN FILL
  %token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
--- 138,144 ----
  %token NOLOAD DSECT COPY INFO OVERLAY
  %token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
  %token <integer> NEXT
! %token SIZEOF SIZEOF_UNADJ ADDR LOADADDR MAX_K MIN_K
  %token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS
  %token ORIGIN FILL
  %token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
Index: ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.103
diff -c -r1.103 ldlang.c
*** ldlang.c	30 Oct 2002 03:57:38 -0000	1.103
--- ldlang.c	20 Nov 2002 18:51:10 -0000
***************
*** 751,756 ****
--- 751,758 ----
        lookup->section_alignment = -1;
        lookup->load_base = (union etree_union *) NULL;
        lookup->update_dot_tree = NULL;
+       lookup->size_adj = (union etree_union *) NULL;
+       lookup->last_orphan = (lang_output_section_statement_type *) NULL;
        lookup->phdrs = NULL;
  
        lang_statement_append (&lang_output_section_statement,
Index: ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.23
diff -c -r1.23 ldlang.h
*** ldlang.h	10 Oct 2002 15:59:10 -0000	1.23
--- ldlang.h	20 Nov 2002 18:51:10 -0000
***************
*** 141,146 ****
--- 141,155 ----
       to move '.' past all the overlaid sections.  */
    union etree_union *update_dot_tree;
  
+   /* These two members are used when sorting orphans after this
+      section.  size_adj contains an expression tree representing
+      the change in effective size of this section caused by adding
+      the orphans.  last_orphan points to the last orphan section
+      that was sorted after this section.  It is used to compute the
+      load address of the next orphan sorted after this section.  */
+   union etree_union *size_adj;
+   struct lang_output_section_statement_struct *last_orphan;
+ 
    struct lang_output_section_phdr_list *phdrs;
  } lang_output_section_statement_type;
  
Index: emultempl/elf32.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/elf32.em,v
retrieving revision 1.84
diff -c -r1.84 elf32.em
*** emultempl/elf32.em	30 Oct 2002 03:57:39 -0000	1.84
--- emultempl/elf32.em	20 Nov 2002 18:51:12 -0000
***************
*** 1090,1095 ****
--- 1090,1096 ----
    lang_statement_list_type *old;
    lang_statement_list_type add;
    etree_type *address;
+   etree_type *load_base;
    const char *secname;
    const char *ps = NULL;
    lang_output_section_statement_type *os;
***************
*** 1175,1183 ****
  	   && (hold_rel.os != NULL
  	       || (hold_rel.os = output_rel_find (s)) != NULL))
      place = &hold_rel;
!   else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
! 	   && HAVE_SECTION (hold_rodata, ".rodata"))
!     place = &hold_rodata;
    else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
  	   && hold_text.os != NULL)
      place = &hold_text;
--- 1176,1188 ----
  	   && (hold_rel.os != NULL
  	       || (hold_rel.os = output_rel_find (s)) != NULL))
      place = &hold_rel;
!   else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY)
!     {
!       /* If we have .rodata, fine.  If not, assume we can put read-only
! 	 data into .text.  */
!       place = HAVE_SECTION (hold_rodata, ".rodata") ? &hold_rodata
! 						    : &hold_text;
!     }
    else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
  	   && hold_text.os != NULL)
      place = &hold_text;
***************
*** 1232,1242 ****
    else
      address = NULL;
  
    os = lang_enter_output_section_statement (secname, address, 0,
  					    (bfd_vma) 0,
  					    (etree_type *) NULL,
  					    (etree_type *) NULL,
! 					    (etree_type *) NULL);
  
    lang_add_section (&os->children, s, os, file);
  
--- 1237,1269 ----
    else
      address = NULL;
  
+   /* If the output section (or the last orphan that sorted with it)
+      we're sorting with has an AT expression, then we need to copy
+      that AT expression, adjusting for the size of the previous
+      section.
+ 
+      Note: we need to use the unadjusted size because by the time
+      the tree can be folded, the original parent section will have
+      accumulated effective size adjustments for all the orphans,
+      which will cause the first (and subsequent) orphans to be
+      mis-placed.  */
+   if (place != NULL && place->os->load_base != NULL)
+     {
+       lang_output_section_statement_type *sort_os;
+ 
+       sort_os = place->os->last_orphan ? place->os->last_orphan
+ 				       : place->os;
+       load_base = exp_binop ('+', sort_os->load_base,
+ 			     exp_nameop (SIZEOF_UNADJ, sort_os->name));
+     }
+   else
+     load_base = NULL;
+ 
    os = lang_enter_output_section_statement (secname, address, 0,
  					    (bfd_vma) 0,
  					    (etree_type *) NULL,
  					    (etree_type *) NULL,
! 					    load_base);
  
    lang_add_section (&os->children, s, os, file);
  
***************
*** 1257,1262 ****
--- 1284,1305 ----
        sprintf (symname, "__stop_%s", secname);
        lang_add_assignment (exp_assop ('=', symname,
  				      exp_nameop (NAME, ".")));
+     }
+ 
+   if (place != NULL)
+     {
+       /* By sorting the orphan after place->os, we effectively changed
+ 	 the size of that section.  Adjust the size of the section to
+ 	 reflect the additional output.  */
+       if (place->os->size_adj == NULL)
+ 	place->os->size_adj = exp_nameop (SIZEOF, os->name);
+       else
+ 	place->os->size_adj = exp_binop ('+', place->os->size_adj,
+ 					 exp_nameop (SIZEOF, os->name));
+ 
+       /* Record this orphan in case there are any more that are
+ 	 sorted with this parent.  */
+       place->os->last_orphan = os;
      }
  
    /* Restore the global list pointer.  */
Index: testsuite/ld-scripts/refsec-lma.exp
===================================================================
RCS file: testsuite/ld-scripts/refsec-lma.exp
diff -N testsuite/ld-scripts/refsec-lma.exp
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/ld-scripts/refsec-lma.exp	20 Nov 2002 18:51:13 -0000
***************
*** 0 ****
--- 1,85 ----
+ # Test C-referenceable sections when explicit LMAs are used
+ # in the linker script.
+ #
+ # Written by: Jason Thorpe <thorpej@wasabisystems.com>
+ # Based on phdrs.exp by Ian Taylor.
+ #
+ #   Copyright 2002
+ #   Free Software Foundation, Inc.
+ #
+ # 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.
+ 
+ # This tests a feature found in the ELF back-end.
+ if { ![istarget *-*-sysv4*] \
+      && ![istarget *-*-unixware*] \
+      && ![istarget *-*-elf*] \
+      && ![istarget *-*-eabi*] \
+      && ![istarget hppa*64*-*-hpux*] \
+      && ![istarget *-*-linux*] \
+      && ![istarget *-*-netbsd*] \
+      && ![istarget *-*-irix5*] \
+      && ![istarget *-*-irix6*] \
+      && ![istarget *-*-solaris2*] } {
+     return
+ }
+      
+ if { [istarget *-*-linux*aout*] \
+      || [istarget *-*-linux*oldld*] } {
+     return
+ }   
+ 
+ if { ![istarget *-*-netbsdelf*] \
+      && [[istarget *-*-netbsd*aout*] \
+ 	 || [istarget *-*-netbsdpe*] \
+          || [istarget arm*-*-netbsd*] \
+ 	 || [istarget sparc-*-netbsd*] \
+ 	 || [istarget i*86-*-netbsd*] \
+ 	 || [istarget m68*-*-netbsd*] \
+ 	 || [istarget vax*-*-netbsd*] \
+ 	 || [istarget ns32k-*-netbsd*]] } {
+     return
+ }
+ 
+ set testname "C-referenceable sections with explicit LMA"
+ 
+ if ![ld_assemble $as $srcdir/$subdir/refsec-lma.s tmpdir/refsec-lma.o] {
+     unresolved $testname
+     return
+ }
+ 
+ # We don't particularly care about the Program headers.  The information we
+ # want is easily found in the Section headers.
+ set refsec_regexp \
+ ".*Sections:.*\.text.*00000008.*00800000.*10800000.*link_set_1.*00000004.*00800008.*10800008.*link_set_2.*00000004.*0080000c.*1080000c.*\.data.*00000004.*00801000.*10801000.*\.bss.*00000004.*00801004.*00801004.*SYMBOL TABLE:.*0080000c.*g.*__stop_link_set_1.*00800010.*g.*__stop_link_set_2.*00800008.*g.*__start_link_set_1.*0080000c.*g.*__start_link_set_2"
+ 
+ if ![ld_simple_link $ld tmpdir/refsec-lma "-T $srcdir/$subdir/refsec-lma.t tmpdir/refsec-lma.o"] {
+     fail $testname
+ } else {
+     if {[which $objdump] == 0} {
+ 	unresolved $testname
+ 	return
+     }
+ 
+     verbose -log "$objdump --all-headers tmpdir/refsec-lma"
+     catch "exec $objdump --all-headers tmpdir/refsec-lma" exec_output
+     set exec_output [prune_warnings $exec_output]
+     verbose -log $exec_output
+ 
+     if [regexp $refsec_regexp $exec_output] {
+ 	pass $testname
+     } else {
+ 	fail $testname
+     }
+ }
Index: testsuite/ld-scripts/refsec-lma.s
===================================================================
RCS file: testsuite/ld-scripts/refsec-lma.s
diff -N testsuite/ld-scripts/refsec-lma.s
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/ld-scripts/refsec-lma.s	20 Nov 2002 18:51:13 -0000
***************
*** 0 ****
--- 1,17 ----
+ 	.text
+ 	.long	1
+ 
+ 	.section .rodata
+ 	.long	2
+ 
+ 	.data
+ 	.long	3
+ 
+ 	.section .bss
+ 	.long	0
+ 
+ 	.section link_set_1,"a"
+ 	.long	4
+ 
+ 	.section link_set_2,"a"
+ 	.long	5
Index: testsuite/ld-scripts/refsec-lma.t
===================================================================
RCS file: testsuite/ld-scripts/refsec-lma.t
diff -N testsuite/ld-scripts/refsec-lma.t
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/ld-scripts/refsec-lma.t	20 Nov 2002 18:51:13 -0000
***************
*** 0 ****
--- 1,12 ----
+ SECTIONS
+ {
+   .text (0x00800000) :
+   AT (0x10800000)
+   { *(.text) *(.rodata) }
+   . = ALIGN(0x1000);
+   .data :
+   AT ((LOADADDR(.text) + SIZEOF(.text) + (0x1000 - 1)) & ~(0x1000 - 1))
+   { *(.data) }
+   .bss : { *(.bss) *(COMMON) }
+   /DISCARD/ : { *(.*) }
+ }


More information about the Binutils mailing list