Fix a problem with placing orphaned sections (like the ones with

C-referenceable names, i.e. "link sets") that happens with explicit
LMAs in the linker script:

	* As orphans are sorted after sections, the effective
	  size of the section is changed.  Record a size ajustment
	  for each orphan that is sorted after the section.

...and for sections which have an explicit load address expression:

	* The first time an orphan is sorted after a section,
	  copy the load_base expression to the orphan, adding
	  the _unadjusted_ size of the parent section.  We need
	  to use the unadjusted size because by the time the
	  expression can be folded, all of the orphan size
	  adjustments will have accumulated, resulting in misplacing
	  the orphan.

	* For each subsequent orphan sorted after a section,
	  set the load_base of the orphan to the load address
	  of the previous orphan plus the size of the previous
	  orphan (actually, the unadjusted size, but for orphans,
	  size and unadjusted size are always equal).
This commit is contained in:
thorpej 2002-11-20 06:51:07 +00:00
parent 1bee87041f
commit accdd8107f
5 changed files with 55 additions and 5 deletions

View File

@ -1005,6 +1005,7 @@ gld${EMULATION_NAME}_place_orphan (file, s)
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,9 +1074,13 @@ gld${EMULATION_NAME}_place_orphan (file, s)
&& (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_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,11 +1138,27 @@ gld${EMULATION_NAME}_place_orphan (file, s)
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,
(etree_type *) NULL);
load_base);
wild_doit (&os->children, s, os, file);
@ -1160,6 +1181,22 @@ gld${EMULATION_NAME}_place_orphan (file, s)
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. */
stat_ptr = old;

View File

@ -452,6 +452,7 @@ fold_name (tree, current_section, allocation_done, dot)
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,6 +461,13 @@ fold_name (tree, current_section, allocation_done, dot)
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 ();

View File

@ -130,7 +130,7 @@ static int error_index;
%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 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

View File

@ -718,6 +718,8 @@ lang_output_section_statement_lookup (name)
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,

View File

@ -131,6 +131,9 @@ typedef struct lang_output_section_statement_struct {
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;