[PATCH/RFC] Re: Problem with referenceable sections ("link sets")

Jason R Thorpe thorpej@wasabisystems.com
Tue Nov 19 22:42:00 GMT 2002


On Tue, Nov 19, 2002 at 09:44:21AM -0800, Jason R Thorpe wrote:

 > Well, this patch (against 2.11.2) almost does it ... if there is one
 > orphan section, the right thing happens.  But if there are two, the
 > two orphans get overlapped.

Ok, this patch (again, against 2.11.2) actually works.  I needed to add
a new token, SIZEOF_UNADJ, to fetch the unadjusted size of a section.
This isn't actually allowed in the grammar, just used internally.

The way it works is:

	* When a section gets its first orphan, the orphan is
	  placed at LOADADDR(section)+SIZEOF_UNADJ(section).
	  The SIZEOF_UNADJ is needed for the first one, because
	  the parent's section SIZEOF value is adjusted to reflect
	  the contents of all of the orphans sorted after it, and
	  using that SIZEOF would misplace the first orphan, because
	  the parent section would have accumulated all of the
	  ajustments by the time the expression can be folded.

	* For all subsequent orphans sorted after that section,
	  the orphan is placed at LOADADDR(prev_orphan)+
	  SIZEOF_UNADJ(prev_orphan).  However, note that SIZEOF_UNADJ
	  and SIZEOF are equivalent in this case, since orphans never
	  have their SIZEOF's adjusted.

Also included in this patch is a change that allows sorting
read-only data after .text if .rodata is not present as an
output section.  This matches the behavior of compilers which
do not emit .rodata sections (as GCC 2.95.3 for arm-elf did not
until fixed it while working on this).

Anyway, I'd appreciate any comments people might have on this.  Tomorrow
I'll cook up a patch for current Binutils...

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>
-------------- next part --------------
Index: ldexp.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/ld/ldexp.c,v
retrieving revision 1.1.1.3
diff -c -r1.1.1.3 ldexp.c
*** ldexp.c	2001/08/14 02:59:08	1.1.1.3
--- ldexp.c	2002/11/20 06:19:33
***************
*** 452,457 ****
--- 452,458 ----
        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);
***************
*** 460,465 ****
--- 461,473 ----
  	  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: /cvsroot/gnusrc/gnu/dist/toolchain/ld/ldgram.y,v
retrieving revision 1.4
diff -c -r1.4 ldgram.y
*** ldgram.y	2001/08/14 04:43:12	1.4
--- ldgram.y	2002/11/20 06:19:38
***************
*** 130,136 ****
  %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
--- 130,136 ----
  %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: /cvsroot/gnusrc/gnu/dist/toolchain/ld/ldlang.c,v
retrieving revision 1.1.1.4
diff -c -r1.1.1.4 ldlang.c
*** ldlang.c	2001/08/14 02:59:13	1.1.1.4
--- ldlang.c	2002/11/20 06:19:42
***************
*** 718,723 ****
--- 718,725 ----
        lookup->subsection_alignment = -1;
        lookup->section_alignment = -1;
        lookup->load_base = (union etree_union *) 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: /cvsroot/gnusrc/gnu/dist/toolchain/ld/ldlang.h,v
retrieving revision 1.1.1.4
diff -c -r1.1.1.4 ldlang.h
*** ldlang.h	2001/08/14 02:59:14	1.1.1.4
--- ldlang.h	2002/11/20 06:19:42
***************
*** 131,136 ****
--- 131,139 ----
    int section_alignment;	/* alignment of start of section */
  
    union etree_union *load_base;
+   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: /cvsroot/gnusrc/gnu/dist/toolchain/ld/emultempl/elf32.em,v
retrieving revision 1.3
diff -c -r1.3 elf32.em
*** emultempl/elf32.em	2002/11/01 16:07:37	1.3
--- emultempl/elf32.em	2002/11/20 06:19:44
***************
*** 1005,1010 ****
--- 1005,1011 ----
    lang_statement_list_type *old;
    lang_statement_list_type add;
    etree_type *address;
+   etree_type *load_base;
    const char *secname;
    const char *outsecname;
    const char *ps = NULL;
***************
*** 1073,1081 ****
  	   && (hold_rel.os != NULL
  	       || (hold_rel.os = output_rel_find ()) != 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;
--- 1074,1086 ----
  	   && (hold_rel.os != NULL
  	       || (hold_rel.os = output_rel_find ()) != 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;
***************
*** 1133,1143 ****
    else
      address = NULL;
  
    os = lang_enter_output_section_statement (outsecname, address, 0,
  					    (bfd_vma) 0,
  					    (etree_type *) NULL,
  					    (etree_type *) NULL,
! 					    (etree_type *) NULL);
  
    wild_doit (&os->children, s, os, file);
  
--- 1138,1164 ----
    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 it for the size of the previous
+      section.  */
+   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 (outsecname, address, 0,
  					    (bfd_vma) 0,
  					    (etree_type *) NULL,
  					    (etree_type *) NULL,
! 					    load_base);
  
    wild_doit (&os->children, s, os, file);
  
***************
*** 1158,1163 ****
--- 1179,1200 ----
        sprintf (symname, "__stop_%s", outsecname);
        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.  */


More information about the Binutils mailing list