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:
parent
1bee87041f
commit
accdd8107f
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue