PR 63
	* ldlang.h (lang_output_section_statement_type): Make "next" a
	struct lang_output_section_statement_struct *.
	(struct orphan_save): Move from elf32.em.  Add "name" and "flags".
	(lang_output_section_find_by_flags, lang_insert_orphan): Declare.
	* ldlang.c (lang_output_section_find_1): Adjust for changed
	output_section_statement "next".
	(strip_excluded_output_sections): Likewise.
	(lang_record_phdrs): Likewise.
	(lang_output_section_find_by_flags): New function.
	(output_prev_sec_find): Move from pe.em.  Adjust iterator.
	(lang_insert_orphan): New function.  Tail end of elf32.em's
	place_orphan merged with that from pe.em.  Allow bfd_section to
	be placed first.  New heuristic for placing new output section
	statement in existing script, and accompanying split of __start
	symbol alignment into a separate assignment to dot.
	(lang_add_section): Consistently use output->bfd_section rather than
	an alias, section->output_section.
	(map_input_to_output_sections): Rename overly long arg.  Move
	initialization of data_statement output section to here..
	(lang_check_section_addresses): ..from here.
	(print_assignment): Correct printing of etree_assert.
	(print_all_symbols): Don't bomb if userdata is NULL.
	(IGNORE_SECTION): Rearrange.
	* emultempl/elf32.em (output_rel_find): Adjust interator.
	(output_prev_sec_find): Delete.
	(struct orphan_save): Delete.
	(gld${EMULATION_NAME}_place_orphan): Cater for zero bfd_section
	flags without creating a duplicate output section statement.
	Revise code holding history of various orphan section placements.
	Allow orphan sections to place before script specified output
	sections.  Call lang_output_section_find_by_flags when placement
	by name fails.  Use lang_insert_orphan.
	* emultempl/mmo.em (output_prev_sec_find): Delete.
	(struct orphan_save): Delete.
	(mmo_place_orphan): Revise code holding history of orphan placement.
	Allow orphans to place before existing output sections.  Use
	lang_insert_orphan.
	* emultempl/pe.em (output_prev_sec_find): Delete.
	(struct orphan_save): Delete.
	(gld_${EMULATION_NAME}_place_orphan): Revise to suit use of
	lang_insert_orphan.
ld/testsuite/
	* ld-scripts/overlay-size.d: Update for changed orphan section
	placement.
	* ld-mmix/bpo-18.d: Likewise.
This commit is contained in:
Alan Modra 2004-10-14 12:54:47 +00:00
parent ad4c72d283
commit afd7a018c9
9 changed files with 780 additions and 776 deletions

View File

@ -1,3 +1,48 @@
2004-10-14 Alan Modra <amodra@bigpond.net.au>
PR 63
* ldlang.h (lang_output_section_statement_type): Make "next" a
struct lang_output_section_statement_struct *.
(struct orphan_save): Move from elf32.em. Add "name" and "flags".
(lang_output_section_find_by_flags, lang_insert_orphan): Declare.
* ldlang.c (lang_output_section_find_1): Adjust for changed
output_section_statement "next".
(strip_excluded_output_sections): Likewise.
(lang_record_phdrs): Likewise.
(lang_output_section_find_by_flags): New function.
(output_prev_sec_find): Move from pe.em. Adjust iterator.
(lang_insert_orphan): New function. Tail end of elf32.em's
place_orphan merged with that from pe.em. Allow bfd_section to
be placed first. New heuristic for placing new output section
statement in existing script, and accompanying split of __start
symbol alignment into a separate assignment to dot.
(lang_add_section): Consistently use output->bfd_section rather than
an alias, section->output_section.
(map_input_to_output_sections): Rename overly long arg. Move
initialization of data_statement output section to here..
(lang_check_section_addresses): ..from here.
(print_assignment): Correct printing of etree_assert.
(print_all_symbols): Don't bomb if userdata is NULL.
(IGNORE_SECTION): Rearrange.
* emultempl/elf32.em (output_rel_find): Adjust interator.
(output_prev_sec_find): Delete.
(struct orphan_save): Delete.
(gld${EMULATION_NAME}_place_orphan): Cater for zero bfd_section
flags without creating a duplicate output section statement.
Revise code holding history of various orphan section placements.
Allow orphan sections to place before script specified output
sections. Call lang_output_section_find_by_flags when placement
by name fails. Use lang_insert_orphan.
* emultempl/mmo.em (output_prev_sec_find): Delete.
(struct orphan_save): Delete.
(mmo_place_orphan): Revise code holding history of orphan placement.
Allow orphans to place before existing output sections. Use
lang_insert_orphan.
* emultempl/pe.em (output_prev_sec_find): Delete.
(struct orphan_save): Delete.
(gld_${EMULATION_NAME}_place_orphan): Revise to suit use of
lang_insert_orphan.
2004-10-13 Mark Mitchell <mark@codesourcery.com>
* scripttempl/armbpabi.sc: Do not put .gnu.version.* into a

View File

@ -1172,12 +1172,11 @@ fi
if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
cat >>e${EMULATION_NAME}.c <<EOF
/* A variant of lang_output_section_find. Used by place_orphan. */
/* A variant of lang_output_section_find used by place_orphan. */
static lang_output_section_statement_type *
output_rel_find (asection *sec, int isdyn)
{
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
lang_output_section_statement_type *last = NULL;
lang_output_section_statement_type *last_alloc = NULL;
@ -1185,9 +1184,10 @@ output_rel_find (asection *sec, int isdyn)
lang_output_section_statement_type *last_rel_alloc = NULL;
int rela = sec->name[4] == 'a';
for (u = lang_output_section_statement.head; u; u = lookup->next)
for (lookup = &lang_output_section_statement.head->output_section_statement;
lookup != NULL;
lookup = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup->constraint != -1
&& strncmp (".rel", lookup->name, 4) == 0)
{
@ -1229,63 +1229,52 @@ output_rel_find (asection *sec, int isdyn)
return last;
}
/* Find the last output section before given output statement.
Used by place_orphan. */
static asection *
output_prev_sec_find (lang_output_section_statement_type *os)
{
asection *s = (asection *) NULL;
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head;
u != (lang_statement_union_type *) NULL;
u = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup == os)
return s;
if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
s = lookup->bfd_section;
}
return NULL;
}
/* Place an orphan section. We use this to put random SHF_ALLOC
sections in the right segment. */
struct orphan_save {
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
lang_statement_union_type **os_tail;
};
static bfd_boolean
gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
{
static struct orphan_save hold_text;
static struct orphan_save hold_rodata;
static struct orphan_save hold_data;
static struct orphan_save hold_bss;
static struct orphan_save hold_rel;
static struct orphan_save hold_interp;
static struct orphan_save hold_sdata;
static int count = 1;
static struct orphan_save hold[] =
{
{ ".text",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
0, 0, 0, 0 },
{ ".rodata",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
0, 0, 0, 0 },
{ ".data",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA,
0, 0, 0, 0 },
{ ".bss",
SEC_ALLOC,
0, 0, 0, 0 },
{ 0,
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
0, 0, 0, 0 },
{ ".interp",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
0, 0, 0, 0 },
{ ".sdata",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA,
0, 0, 0, 0 }
};
enum orphan_save_index
{
orphan_text = 0,
orphan_rodata,
orphan_data,
orphan_bss,
orphan_rel,
orphan_interp,
orphan_sdata
};
static int orphan_init_done = 0;
struct orphan_save *place;
lang_statement_list_type *old;
lang_statement_list_type add;
etree_type *address;
const char *secname;
const char *ps = NULL;
lang_output_section_statement_type *after;
lang_output_section_statement_type *os;
lang_statement_union_type **os_tail;
etree_type *load_base;
int isdyn = 0;
asection *sec;
secname = bfd_get_section_name (s->owner, s);
@ -1308,27 +1297,42 @@ gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
if (os != NULL
&& (os->bfd_section == NULL
|| os->bfd_section->flags == 0
|| ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0))
{
/* We already have an output section statement with this
name, and its bfd section, if any, has compatible flags. */
name, and its bfd section, if any, has compatible flags.
If the section already exists but does not have any flags
set, then it has been created by the linker, probably as a
result of a --section-start command line switch. */
lang_add_section (&os->children, s, os, file);
return TRUE;
}
}
if (hold_text.os == NULL)
hold_text.os = lang_output_section_find (".text");
if (!orphan_init_done)
{
struct orphan_save *ho;
for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
if (ho->name != NULL)
{
ho->os = lang_output_section_find (ho->name);
if (ho->os != NULL && ho->os->flags == 0)
ho->os->flags = ho->flags;
}
orphan_init_done = 1;
}
/* If this is a final link, then always put .gnu.warning.SYMBOL
sections into the .text section to get them out of the way. */
if (link_info.executable
&& ! link_info.relocatable
&& strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
&& hold_text.os != NULL)
&& hold[orphan_text].os != NULL)
{
lang_add_section (&hold_text.os->children, s, hold_text.os, file);
lang_add_section (&hold[orphan_text].os->children, s,
hold[orphan_text].os, file);
return TRUE;
}
@ -1337,220 +1341,57 @@ gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
right after the .interp section, so that the PT_NOTE segment is
stored right after the program headers where the OS can read it
in the first page. */
#define HAVE_SECTION(hold, name) \
(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
place = NULL;
if ((s->flags & SEC_ALLOC) == 0)
;
else if ((s->flags & SEC_LOAD) != 0
&& strncmp (secname, ".note", 5) == 0
&& HAVE_SECTION (hold_interp, ".interp"))
place = &hold_interp;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
&& HAVE_SECTION (hold_bss, ".bss"))
place = &hold_bss;
else if ((s->flags & SEC_SMALL_DATA) != 0
&& HAVE_SECTION (hold_sdata, ".sdata"))
place = &hold_sdata;
else if ((s->flags & SEC_READONLY) == 0
&& HAVE_SECTION (hold_data, ".data"))
place = &hold_data;
&& strncmp (secname, ".note", 5) == 0)
place = &hold[orphan_interp];
else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
place = &hold[orphan_bss];
else if ((s->flags & SEC_SMALL_DATA) != 0)
place = &hold[orphan_sdata];
else if ((s->flags & SEC_READONLY) == 0)
place = &hold[orphan_data];
else if (strncmp (secname, ".rel", 4) == 0
&& (s->flags & SEC_LOAD) != 0
&& (hold_rel.os != NULL
|| (hold_rel.os = output_rel_find (s, isdyn)) != 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;
&& (s->flags & SEC_LOAD) != 0)
place = &hold[orphan_rel];
else if ((s->flags & SEC_CODE) == 0)
place = &hold[orphan_rodata];
else
place = &hold[orphan_text];
#undef HAVE_SECTION
after = NULL;
if (place != NULL)
{
if (place->os == NULL)
{
if (place->name != NULL)
place->os = lang_output_section_find (place->name);
else
place->os = output_rel_find (s, isdyn);
}
after = place->os;
if (after == NULL)
after = lang_output_section_find_by_flags (s, &place->os);
if (after == NULL)
/* *ABS* is always the first output section statement. */
after = &lang_output_section_statement.head->output_section_statement;
}
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
loadable or allocatable characteristics. But if the section
already exists but does not have any flags set, then it has been
created by the linker, probably as a result of a --section-start
command line switch. */
if ((sec = bfd_get_section_by_name (output_bfd, secname)) != NULL
&& bfd_get_section_flags (output_bfd, sec) != 0)
loadable or allocatable characteristics. */
if (bfd_get_section_by_name (output_bfd, secname) != NULL)
{
static int count = 1;
secname = bfd_get_unique_section_name (output_bfd, secname, &count);
if (secname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
/* Start building a list of statements for this section.
First save the current statement pointer. */
old = stat_ptr;
/* If we have found an appropriate place for the output section
statements for this orphan, add them to our own private list,
inserting them later into the global statement list. */
if (place != NULL)
{
stat_ptr = &add;
lang_list_init (stat_ptr);
}
if (config.build_constructors)
{
/* If the name of the section is representable in C, then create
symbols to mark the start and the end of the section. */
for (ps = secname; *ps != '\0'; ps++)
if (! ISALNUM (*ps) && *ps != '_')
break;
if (*ps == '\0')
{
char *symname;
etree_type *e_align;
symname = (char *) xmalloc (ps - secname + sizeof "__start_");
sprintf (symname, "__start_%s", secname);
e_align = exp_unop (ALIGN_K,
exp_intop ((bfd_vma) 1 << s->alignment_power));
lang_add_assignment (exp_assop ('=', symname, e_align));
}
}
address = NULL;
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop ((bfd_vma) 0);
load_base = NULL;
if (place != NULL && place->os->load_base != NULL)
{
etree_type *lma_from_vma;
lma_from_vma = exp_binop ('-', place->os->load_base,
exp_nameop (ADDR, place->os->name));
load_base = exp_binop ('+', lma_from_vma,
exp_nameop (ADDR, secname));
}
os_tail = lang_output_section_statement.tail;
os = lang_enter_output_section_statement (secname, address, 0,
(etree_type *) NULL,
(etree_type *) NULL,
load_base, 0);
lang_add_section (&os->children, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, NULL);
if (config.build_constructors && *ps == '\0')
{
char *symname;
/* lang_leave_ouput_section_statement resets stat_ptr. Put
stat_ptr back where we want it. */
if (place != NULL)
stat_ptr = &add;
symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
sprintf (symname, "__stop_%s", secname);
lang_add_assignment (exp_assop ('=', symname,
exp_nameop (NAME, ".")));
}
/* Restore the global list pointer. */
stat_ptr = old;
if (place != NULL && os->bfd_section != NULL)
{
asection *snew, **pps;
snew = os->bfd_section;
/* Shuffle the bfd section list to make the output file look
neater. This is really only cosmetic. */
if (place->section == NULL)
{
asection *bfd_section = place->os->bfd_section;
/* If the output statement hasn't been used to place
any input sections (and thus doesn't have an output
bfd_section), look for the closest prior output statement
having an output section. */
if (bfd_section == NULL)
bfd_section = output_prev_sec_find (place->os);
if (bfd_section != NULL && bfd_section != snew)
place->section = &bfd_section->next;
}
if (place->section != NULL)
{
/* Unlink the section. */
for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
;
bfd_section_list_remove (output_bfd, pps);
/* Now tack it on to the "place->os" section list. */
bfd_section_list_insert (output_bfd, place->section, snew);
}
/* Save the end of this list. Further ophans of this type will
follow the one we've just added. */
place->section = &snew->next;
/* The following is non-cosmetic. We try to put the output
statements in some sort of reasonable order here, because
they determine the final load addresses of the orphan
sections. In addition, placing output statements in the
wrong order may require extra segments. For instance,
given a typical situation of all read-only sections placed
in one segment and following that a segment containing all
the read-write sections, we wouldn't want to place an orphan
read/write section before or amongst the read-only ones. */
if (add.head != NULL)
{
lang_statement_union_type *newly_added_os;
if (place->stmt == NULL)
{
/* Put the new statement list right at the head. */
*add.tail = place->os->header.next;
place->os->header.next = add.head;
place->os_tail = &place->os->next;
}
else
{
/* Put it after the last orphan statement we added. */
*add.tail = *place->stmt;
*place->stmt = add.head;
}
/* Fix the global list pointer if we happened to tack our
new list at the tail. */
if (*old->tail == add.head)
old->tail = add.tail;
/* Save the end of this list. */
place->stmt = add.tail;
/* Do the same for the list of output section statements. */
newly_added_os = *os_tail;
*os_tail = NULL;
newly_added_os->output_section_statement.next = *place->os_tail;
*place->os_tail = newly_added_os;
place->os_tail = &newly_added_os->output_section_statement.next;
/* Fixing the global list pointer here is a little different.
We added to the list in lang_enter_output_section_statement,
trimmed off the new output_section_statment above when
assigning *os_tail = NULL, but possibly added it back in
the same place when assigning *place->os_tail. */
if (*os_tail == NULL)
lang_output_section_statement.tail = os_tail;
}
}
lang_insert_orphan (file, s, secname, after, place, NULL, NULL);
return TRUE;
}
@ -1603,49 +1444,49 @@ cat >>e${EMULATION_NAME}.c <<EOF
if (link_info.relocatable && config.build_constructors)
return
EOF
sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else
echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
fi
if test -n "$GENERATE_PIE_SCRIPT" ; then
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c
fi
echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c
fi
if test -n "$GENERATE_SHLIB_SCRIPT" ; then
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
fi
echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
fi
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
fi
echo ' ; else return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
echo '; }' >> e${EMULATION_NAME}.c
echo ' ; else return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
echo '; }' >> e${EMULATION_NAME}.c
else
# Scripts read from the filesystem.

View File

@ -32,47 +32,6 @@ EOF
cat >>e${EMULATION_NAME}.c <<EOF
/* Find the last output section before given output statement.
Used by place_orphan. */
static asection *
output_prev_sec_find (lang_output_section_statement_type *os)
{
asection *s = NULL;
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head;
u != (lang_statement_union_type *) NULL;
u = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup->constraint == -1)
continue;
if (lookup == os)
break;
if (lookup->bfd_section != NULL
&& lookup->bfd_section != bfd_abs_section_ptr
&& lookup->bfd_section != bfd_com_section_ptr
&& lookup->bfd_section != bfd_und_section_ptr)
s = lookup->bfd_section;
}
if (u == NULL)
return NULL;
return s;
}
struct orphan_save {
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
};
#define HAVE_SECTION(hold, name) \
(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
/* Place an orphan section. We use this to put random SEC_CODE or
SEC_READONLY sections right after MMO_TEXT_SECTION_NAME. Much borrowed
from elf32.em. */
@ -80,21 +39,25 @@ struct orphan_save {
static bfd_boolean
mmo_place_orphan (lang_input_statement_type *file, asection *s)
{
static struct orphan_save hold_text;
static struct orphan_save hold_text =
{
MMO_TEXT_SECTION_NAME,
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
0, 0, 0, 0
};
struct orphan_save *place;
const char *secname;
lang_output_section_statement_type *after;
lang_output_section_statement_type *os;
lang_statement_list_type *old;
lang_statement_list_type add;
asection *snew, **pps, *bfd_section;
/* We have nothing to say for anything other than a final link. */
if (link_info.relocatable
|| (bfd_get_section_flags (s->owner, s)
& (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD)
|| (s->flags & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD)
return FALSE;
/* Only care for sections we're going to load. */
os = lang_output_section_find (bfd_get_section_name (s->owner, s));
secname = s->name;
os = lang_output_section_find (secname);
/* We have an output section by this name. Place the section inside it
(regardless of whether the linker script lists it as input). */
@ -106,108 +69,28 @@ mmo_place_orphan (lang_input_statement_type *file, asection *s)
/* If this section does not have .text-type section flags or there's no
MMO_TEXT_SECTION_NAME, we don't have anything to say. */
if ((bfd_get_section_flags (s->owner, s) & (SEC_CODE | SEC_READONLY)) == 0)
if ((s->flags & (SEC_CODE | SEC_READONLY)) == 0)
return FALSE;
if (hold_text.os == NULL)
hold_text.os = lang_output_section_find (MMO_TEXT_SECTION_NAME);
hold_text.os = lang_output_section_find (hold_text.name);
place = &hold_text;
if (hold_text.os != NULL)
after = hold_text.os;
else
after = &lang_output_section_statement.head->output_section_statement;
/* If there's an output section by this name, we'll use it, regardless
of section flags, in contrast to what's done in elf32.em. */
/* Start building a list of statements for this section.
First save the current statement pointer. */
old = stat_ptr;
/* Add the output section statements for this orphan to our own private
list, inserting them later into the global statement list. */
stat_ptr = &add;
lang_list_init (stat_ptr);
os = lang_enter_output_section_statement (bfd_get_section_name (s->owner,
s),
NULL, 0,
(etree_type *) NULL,
(etree_type *) NULL,
(etree_type *) NULL, 0);
lang_add_section (&os->children, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, NULL);
/* Restore the global list pointer. */
stat_ptr = old;
snew = os->bfd_section;
if (snew == NULL)
/* /DISCARD/ section. */
return TRUE;
os = lang_insert_orphan (file, s, secname, after, place, NULL, NULL);
/* We need an output section for .text as a root, so if there was none
(might happen with a peculiar linker script such as in "map
addresses", map-address.exp), we grab the output section created
above. */
if (hold_text.os == NULL)
{
if (os == NULL)
return FALSE;
hold_text.os = os;
}
bfd_section = place->os->bfd_section;
if (place->section == NULL && bfd_section == NULL)
bfd_section = output_prev_sec_find (place->os);
if (place->section != NULL
|| (bfd_section != NULL
&& bfd_section != snew))
{
/* Shuffle the section to make the output file look neater. This is
really only cosmetic. */
if (place->section == NULL)
/* Put orphans after the first section on the list. */
place->section = &bfd_section->next;
/* Unlink the section. */
for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
;
bfd_section_list_remove (output_bfd, pps);
/* Now tack it on to the "place->os" section list. */
bfd_section_list_insert (output_bfd, place->section, snew);
}
place->section = &snew->next; /* Save the end of this list. */
if (add.head != NULL)
{
/* We try to put the output statements in some sort of reasonable
order here, because they determine the final load addresses of
the orphan sections. */
if (place->stmt == NULL)
{
/* Put the new statement list right at the head. */
*add.tail = place->os->header.next;
place->os->header.next = add.head;
}
else
{
/* Put it after the last orphan statement we added. */
*add.tail = *place->stmt;
*place->stmt = add.head;
}
/* Fix the global list pointer if we happened to tack our new list
at the tail. */
if (*old->tail == add.head)
old->tail = add.tail;
/* Save the end of this list. */
place->stmt = add.tail;
}
hold_text.os = os;
return TRUE;
}

View File

@ -1485,33 +1485,6 @@ gld_${EMULATION_NAME}_finish (void)
}
/* Find the last output section before given output statement.
Used by place_orphan. */
static asection *
output_prev_sec_find (lang_output_section_statement_type *os)
{
asection *s = (asection *) NULL;
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head;
u != (lang_statement_union_type *) NULL;
u = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup->constraint == -1)
continue;
if (lookup == os)
return s;
if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
s = lookup->bfd_section;
}
return NULL;
}
/* Place an orphan section.
We use this to put sections in a reasonable place in the file, and
@ -1525,280 +1498,132 @@ output_prev_sec_find (lang_output_section_statement_type *os)
default linker script using wildcards, and are sorted by
sort_sections. */
struct orphan_save
{
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
lang_statement_union_type **os_tail;
};
static bfd_boolean
gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
{
const char *secname;
char *hold_section_name;
const char *orig_secname;
char *dollar = NULL;
const char *ps = NULL;
lang_output_section_statement_type *os;
lang_statement_list_type add_child;
secname = bfd_get_section_name (s->owner, s);
/* Look through the script to see where to place this section. */
hold_section_name = xstrdup (secname);
if (!link_info.relocatable)
orig_secname = secname;
if (!link_info.relocatable
&& (dollar = strchr (secname, '$')) != NULL)
{
dollar = strchr (hold_section_name, '$');
if (dollar != NULL)
*dollar = '\0';
size_t len = dollar - orig_secname;
char *newname = xmalloc (len + 1);
memcpy (newname, orig_secname, len);
newname[len] = '\0';
secname = newname;
}
os = lang_output_section_find (hold_section_name);
os = lang_output_section_find (secname);
lang_list_init (&add_child);
if (os != NULL
&& (os->bfd_section == NULL
|| os->bfd_section->flags == 0
|| ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0))
{
/* We already have an output section statement with this
name, and its bfd section, if any, has compatible flags. */
name, and its bfd section, if any, has compatible flags.
If the section already exists but does not have any flags set,
then it has been created by the linker, probably as a result of
a --section-start command line switch. */
lang_add_section (&add_child, s, os, file);
}
else
{
static struct orphan_save hold[] =
{
{ ".text",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
0, 0, 0, 0 },
{ ".rdata",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
0, 0, 0, 0 },
{ ".data",
SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA,
0, 0, 0, 0 },
{ ".bss",
SEC_ALLOC,
0, 0, 0, 0 }
};
enum orphan_save_index
{
orphan_text = 0,
orphan_rodata,
orphan_data,
orphan_bss
};
static int orphan_init_done = 0;
struct orphan_save *place;
static struct orphan_save hold_text;
static struct orphan_save hold_rdata;
static struct orphan_save hold_data;
static struct orphan_save hold_bss;
static int count = 1;
char *outsecname;
lang_statement_list_type *old;
lang_statement_list_type add;
lang_statement_union_type **os_tail;
lang_output_section_statement_type *after;
etree_type *address;
etree_type *load_base;
asection *sec;
if (!orphan_init_done)
{
struct orphan_save *ho;
for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
if (ho->name != NULL)
{
ho->os = lang_output_section_find (ho->name);
if (ho->os != NULL && ho->os->flags == 0)
ho->os->flags = ho->flags;
}
orphan_init_done = 1;
}
/* Try to put the new output section in a reasonable place based
on the section name and section flags. */
#define HAVE_SECTION(hold, name) \
(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
place = NULL;
if ((s->flags & SEC_ALLOC) == 0)
;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
&& HAVE_SECTION (hold_bss, ".bss"))
place = &hold_bss;
else if ((s->flags & SEC_READONLY) == 0
&& HAVE_SECTION (hold_data, ".data"))
place = &hold_data;
else if ((s->flags & SEC_CODE) == 0
&& (s->flags & SEC_READONLY) != 0
&& HAVE_SECTION (hold_rdata, ".rdata"))
place = &hold_rdata;
else if ((s->flags & SEC_CODE) != 0
&& (s->flags & SEC_READONLY) != 0
&& HAVE_SECTION (hold_text, ".text"))
place = &hold_text;
else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
place = &hold[orphan_bss];
else if ((s->flags & SEC_READONLY) == 0)
place = &hold[orphan_data];
else if ((s->flags & SEC_CODE) == 0)
place = &hold[orphan_rodata];
else
place = &hold[orphan_text];
#undef HAVE_SECTION
after = NULL;
if (place != NULL)
{
if (place->os == NULL)
place->os = lang_output_section_find (place->name);
after = place->os;
if (after == NULL)
after = lang_output_section_find_by_flags (s, &place->os);
if (after == NULL)
/* *ABS* is always the first output section statement. */
after = (&lang_output_section_statement.head
->output_section_statement);
}
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
loadable or allocatable characteristics. But if the section
already exists but does not have any flags set, then it has been
created by the linker, probably as a result of a --section-start
command line switch. */
sec = bfd_get_section_by_name (output_bfd, hold_section_name);
if (sec != NULL
&& bfd_get_section_flags (output_bfd, sec) != 0)
loadable or allocatable characteristics. */
if (bfd_get_section_by_name (output_bfd, secname) != NULL)
{
outsecname = bfd_get_unique_section_name (output_bfd,
hold_section_name, &count);
if (outsecname == NULL)
static int count = 1;
secname = bfd_get_unique_section_name (output_bfd, secname, &count);
if (secname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
else
outsecname = xstrdup (hold_section_name);
/* Start building a list of statements for this section. */
old = stat_ptr;
/* If we have found an appropriate place for the output section
statements for this orphan, add them to our own private list,
inserting them later into the global statement list. */
if (place != NULL)
{
stat_ptr = &add;
lang_list_init (stat_ptr);
}
if (config.build_constructors)
{
/* If the name of the section is representable in C, then create
symbols to mark the start and the end of the section. */
for (ps = outsecname; *ps != '\0'; ps++)
if (! ISALNUM ((unsigned char) *ps) && *ps != '_')
break;
if (*ps == '\0')
{
char *symname;
etree_type *e_align;
symname = (char *) xmalloc (ps - outsecname + sizeof "___start_");
sprintf (symname, "___start_%s", outsecname);
e_align = exp_unop (ALIGN_K,
exp_intop ((bfd_vma) 1 << s->alignment_power));
lang_add_assignment (exp_assop ('=', symname, e_align));
}
}
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop ((bfd_vma) 0);
else
{
/* All sections in an executable must be aligned to a page
boundary. */
address = exp_unop (ALIGN_K,
exp_nameop (NAME, "__section_alignment__"));
}
load_base = NULL;
if (place != NULL && place->os->load_base != NULL)
{
etree_type *lma_from_vma;
lma_from_vma = exp_binop ('-', place->os->load_base,
exp_nameop (ADDR, place->os->name));
load_base = exp_binop ('+', lma_from_vma,
exp_nameop (ADDR, secname));
}
os_tail = lang_output_section_statement.tail;
os = lang_enter_output_section_statement (outsecname, address, 0,
(etree_type *) NULL,
(etree_type *) NULL,
load_base, 0);
lang_add_section (&add_child, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, NULL);
if (config.build_constructors && *ps == '\0')
{
char *symname;
/* lang_leave_ouput_section_statement resets stat_ptr.
Put stat_ptr back where we want it. */
if (place != NULL)
stat_ptr = &add;
symname = (char *) xmalloc (ps - outsecname + sizeof "___stop_");
sprintf (symname, "___stop_%s", outsecname);
lang_add_assignment (exp_assop ('=', symname,
exp_nameop (NAME, ".")));
}
stat_ptr = old;
if (place != NULL && os->bfd_section != NULL)
{
asection *snew, **pps;
snew = os->bfd_section;
/* Shuffle the bfd section list to make the output file look
neater. This is really only cosmetic. */
if (place->section == NULL)
{
asection *bfd_section = place->os->bfd_section;
/* If the output statement hasn't been used to place
any input sections (and thus doesn't have an output
bfd_section), look for the closest prior output statement
having an output section. */
if (bfd_section == NULL)
bfd_section = output_prev_sec_find (place->os);
if (bfd_section != NULL && bfd_section != snew)
place->section = &bfd_section->next;
}
if (place->section != NULL)
{
/* Unlink the section. */
for (pps = &output_bfd->sections;
*pps != snew;
pps = &(*pps)->next)
;
bfd_section_list_remove (output_bfd, pps);
/* Now tack it on to the "place->os" section list. */
bfd_section_list_insert (output_bfd, place->section, snew);
}
/* Save the end of this list. Further ophans of this type will
follow the one we've just added. */
place->section = &snew->next;
/* The following is non-cosmetic. We try to put the output
statements in some sort of reasonable order here, because
they determine the final load addresses of the orphan
sections. In addition, placing output statements in the
wrong order may require extra segments. For instance,
given a typical situation of all read-only sections placed
in one segment and following that a segment containing all
the read-write sections, we wouldn't want to place an orphan
read/write section before or amongst the read-only ones. */
if (add.head != NULL)
{
lang_statement_union_type *newly_added_os;
if (place->stmt == NULL)
{
/* Put the new statement list right at the head. */
*add.tail = place->os->header.next;
place->os->header.next = add.head;
place->os_tail = &place->os->next;
}
else
{
/* Put it after the last orphan statement we added. */
*add.tail = *place->stmt;
*place->stmt = add.head;
}
/* Fix the global list pointer if we happened to tack our
new list at the tail. */
if (*old->tail == add.head)
old->tail = add.tail;
/* Save the end of this list. */
place->stmt = add.tail;
/* Do the same for the list of output section statements. */
newly_added_os = *os_tail;
*os_tail = NULL;
newly_added_os->output_section_statement.next = *place->os_tail;
*place->os_tail = newly_added_os;
place->os_tail = &newly_added_os->output_section_statement.next;
/* Fixing the global list pointer here is a little different.
We added to the list in lang_enter_output_section_statement,
trimmed off the new output_section_statment above when
assigning *os_tail = NULL, but possibly added it back in
the same place when assigning *place->os_tail. */
if (*os_tail == NULL)
lang_output_section_statement.tail = os_tail;
}
}
/* All sections in an executable must be aligned to a page boundary. */
address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__"));
os = lang_insert_orphan (file, s, secname, after, place, address,
&add_child);
}
{
@ -1830,7 +1655,7 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s
else
{
found_dollar = TRUE;
if (strcmp (secname, lname) < 0)
if (strcmp (orig_secname, lname) < 0)
break;
}
}
@ -1843,8 +1668,6 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s
}
}
free (hold_section_name);
return TRUE;
}

View File

@ -612,13 +612,12 @@ lang_memory_default (asection *section)
static lang_output_section_statement_type *
lang_output_section_find_1 (const char *const name, int constraint)
{
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head; u != NULL; u = lookup->next)
for (lookup = &lang_output_section_statement.head->output_section_statement;
lookup != NULL;
lookup = lookup->next)
{
lookup = &u->output_section_statement;
if (strcmp (name, lookup->name) == 0
&& lookup->constraint != -1
&& (constraint == 0 || constraint == lookup->constraint))
@ -666,7 +665,7 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint)
lang_statement_append (&lang_output_section_statement,
(lang_statement_union_type *) lookup,
&lookup->next);
(lang_statement_union_type **) &lookup->next);
}
return lookup;
}
@ -677,6 +676,389 @@ lang_output_section_statement_lookup (const char *const name)
return lang_output_section_statement_lookup_1 (name, 0);
}
/* A variant of lang_output_section_find used by place_orphan.
Returns the output statement that should precede a new output
statement for SEC. If an exact match is found on certain flags,
sets *EXACT too. */
lang_output_section_statement_type *
lang_output_section_find_by_flags (const asection *sec,
lang_output_section_statement_type **exact)
{
lang_output_section_statement_type *first, *look, *found;
flagword flags;
/* We know the first statement on this list is *ABS*. May as well
skip it. */
first = &lang_output_section_statement.head->output_section_statement;
first = first->next;
/* First try for an exact match. */
found = NULL;
for (look = first; look; look = look->next)
{
flags = look->flags;
if (look->bfd_section != NULL)
flags = look->bfd_section->flags;
flags ^= sec->flags;
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
if (found != NULL)
{
*exact = found;
return found;
}
if (sec->flags & SEC_CODE)
{
/* Try for a rw code section. */
for (look = first; look; look = look->next)
{
flags = look->flags;
if (look->bfd_section != NULL)
flags = look->bfd_section->flags;
flags ^= sec->flags;
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
| SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
return found;
}
if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL))
{
/* .rodata can go after .text, .sdata2 after .rodata. */
for (look = first; look; look = look->next)
{
flags = look->flags;
if (look->bfd_section != NULL)
flags = look->bfd_section->flags;
flags ^= sec->flags;
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
| SEC_READONLY))
&& !(look->flags & (SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
return found;
}
if (sec->flags & SEC_SMALL_DATA)
{
/* .sdata goes after .data, .sbss after .sdata. */
for (look = first; look; look = look->next)
{
flags = look->flags;
if (look->bfd_section != NULL)
flags = look->bfd_section->flags;
flags ^= sec->flags;
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
| SEC_THREAD_LOCAL))
|| ((look->flags & SEC_SMALL_DATA)
&& !(sec->flags & SEC_HAS_CONTENTS)))
found = look;
}
return found;
}
if (sec->flags & SEC_HAS_CONTENTS)
{
/* .data goes after .rodata. */
for (look = first; look; look = look->next)
{
flags = look->flags;
if (look->bfd_section != NULL)
flags = look->bfd_section->flags;
flags ^= sec->flags;
if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
| SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
return found;
}
/* .bss goes last. */
for (look = first; look; look = look->next)
{
flags = look->flags;
if (look->bfd_section != NULL)
flags = look->bfd_section->flags;
flags ^= sec->flags;
if (!(flags & SEC_ALLOC))
found = look;
}
return found;
}
/* Find the last output section before given output statement.
Used by place_orphan. */
static asection *
output_prev_sec_find (lang_output_section_statement_type *os)
{
asection *s = (asection *) NULL;
lang_output_section_statement_type *lookup;
for (lookup = &lang_output_section_statement.head->output_section_statement;
lookup != NULL;
lookup = lookup->next)
{
if (lookup->constraint == -1)
continue;
if (lookup == os)
return s;
if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
s = lookup->bfd_section;
}
return NULL;
}
lang_output_section_statement_type *
lang_insert_orphan (lang_input_statement_type *file,
asection *s,
const char *secname,
lang_output_section_statement_type *after,
struct orphan_save *place,
etree_type *address,
lang_statement_list_type *add_child)
{
lang_statement_list_type *old;
lang_statement_list_type add;
const char *ps;
etree_type *load_base;
lang_output_section_statement_type *os;
lang_output_section_statement_type **os_tail;
/* Start building a list of statements for this section.
First save the current statement pointer. */
old = stat_ptr;
/* If we have found an appropriate place for the output section
statements for this orphan, add them to our own private list,
inserting them later into the global statement list. */
if (after != NULL)
{
stat_ptr = &add;
lang_list_init (stat_ptr);
}
ps = NULL;
if (config.build_constructors)
{
/* If the name of the section is representable in C, then create
symbols to mark the start and the end of the section. */
for (ps = secname; *ps != '\0'; ps++)
if (! ISALNUM ((unsigned char) *ps) && *ps != '_')
break;
if (*ps == '\0')
{
char *symname;
etree_type *e_align;
symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
symname[0] = bfd_get_symbol_leading_char (output_bfd);
sprintf (symname + (symname[0] != 0), "__start_%s", secname);
e_align = exp_unop (ALIGN_K,
exp_intop ((bfd_vma) 1 << s->alignment_power));
lang_add_assignment (exp_assop ('=', ".", e_align));
lang_add_assignment (exp_assop ('=', symname,
exp_nameop (NAME, ".")));
}
}
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop (0);
load_base = NULL;
if (after != NULL && after->load_base != NULL)
{
etree_type *lma_from_vma;
lma_from_vma = exp_binop ('-', after->load_base,
exp_nameop (ADDR, after->name));
load_base = exp_binop ('+', lma_from_vma,
exp_nameop (ADDR, secname));
}
os_tail = ((lang_output_section_statement_type **)
lang_output_section_statement.tail);
os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
load_base, 0);
if (add_child == NULL)
add_child = &os->children;
lang_add_section (add_child, s, os, file);
lang_leave_output_section_statement (0, "*default*", NULL, NULL);
if (config.build_constructors && *ps == '\0')
{
char *symname;
/* lang_leave_ouput_section_statement resets stat_ptr.
Put stat_ptr back where we want it. */
if (after != NULL)
stat_ptr = &add;
symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
symname[0] = bfd_get_symbol_leading_char (output_bfd);
sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
lang_add_assignment (exp_assop ('=', symname,
exp_nameop (NAME, ".")));
}
/* Restore the global list pointer. */
if (after != NULL)
stat_ptr = old;
if (after != NULL && os->bfd_section != NULL)
{
asection *snew, **pps;
snew = os->bfd_section;
/* Shuffle the bfd section list to make the output file look
neater. This is really only cosmetic. */
if (place->section == NULL
&& after != (&lang_output_section_statement.head
->output_section_statement))
{
asection *bfd_section = after->bfd_section;
/* If the output statement hasn't been used to place any input
sections (and thus doesn't have an output bfd_section),
look for the closest prior output statement having an
output section. */
if (bfd_section == NULL)
bfd_section = output_prev_sec_find (after);
if (bfd_section != NULL && bfd_section != snew)
place->section = &bfd_section->next;
}
if (place->section == NULL)
place->section = &output_bfd->sections;
/* Unlink the section. */
for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
continue;
bfd_section_list_remove (output_bfd, pps);
/* Now tack it back on in the right place. */
bfd_section_list_insert (output_bfd, place->section, snew);
/* Save the end of this list. Further ophans of this type will
follow the one we've just added. */
place->section = &snew->next;
/* The following is non-cosmetic. We try to put the output
statements in some sort of reasonable order here, because they
determine the final load addresses of the orphan sections.
In addition, placing output statements in the wrong order may
require extra segments. For instance, given a typical
situation of all read-only sections placed in one segment and
following that a segment containing all the read-write
sections, we wouldn't want to place an orphan read/write
section before or amongst the read-only ones. */
if (add.head != NULL)
{
lang_output_section_statement_type *newly_added_os;
if (place->stmt == NULL)
{
lang_statement_union_type **where;
lang_statement_union_type **assign = NULL;
/* Look for a suitable place for the new statement list.
The idea is to skip over anything that might be inside
a SECTIONS {} statement in a script, before we find
another output_section_statement. Assignments to "dot"
before an output section statement are assumed to
belong to it. */
for (where = &after->header.next;
*where != NULL;
where = &(*where)->header.next)
{
switch ((*where)->header.type)
{
case lang_assignment_statement_enum:
if (assign == NULL)
{
lang_assignment_statement_type *ass;
ass = &(*where)->assignment_statement;
if (ass->exp->type.node_class != etree_assert
&& ass->exp->assign.dst[0] == '.'
&& ass->exp->assign.dst[1] == 0)
assign = where;
}
continue;
case lang_wild_statement_enum:
case lang_input_section_enum:
case lang_object_symbols_statement_enum:
case lang_fill_statement_enum:
case lang_data_statement_enum:
case lang_reloc_statement_enum:
case lang_padding_statement_enum:
case lang_constructors_statement_enum:
assign = NULL;
continue;
case lang_output_section_statement_enum:
if (assign != NULL)
where = assign;
case lang_input_statement_enum:
case lang_address_statement_enum:
case lang_target_statement_enum:
case lang_output_statement_enum:
case lang_group_statement_enum:
case lang_afile_asection_pair_statement_enum:
break;
}
break;
}
*add.tail = *where;
*where = add.head;
place->os_tail = &after->next;
}
else
{
/* Put it after the last orphan statement we added. */
*add.tail = *place->stmt;
*place->stmt = add.head;
}
/* Fix the global list pointer if we happened to tack our
new list at the tail. */
if (*old->tail == add.head)
old->tail = add.tail;
/* Save the end of this list. */
place->stmt = add.tail;
/* Do the same for the list of output section statements. */
newly_added_os = *os_tail;
*os_tail = NULL;
newly_added_os->next = *place->os_tail;
*place->os_tail = newly_added_os;
place->os_tail = &newly_added_os->next;
/* Fixing the global list pointer here is a little different.
We added to the list in lang_enter_output_section_statement,
trimmed off the new output_section_statment above when
assigning *os_tail = NULL, but possibly added it back in
the same place when assigning *place->os_tail. */
if (*os_tail == NULL)
lang_output_section_statement.tail
= (lang_statement_union_type **) os_tail;
}
}
return os;
}
static void
lang_map_flags (flagword flag)
{
@ -792,7 +1174,7 @@ sort_def_symbol (hash_entry, info)
}
else if (!ud->map_symbol_def_tail)
ud->map_symbol_def_tail = &ud->map_symbol_def_head;
def = obstack_alloc (&map_obstack, sizeof *def);
def->entry = hash_entry;
*(ud->map_symbol_def_tail) = def;
@ -867,7 +1249,7 @@ exp_init_os (etree_type *exp)
case etree_assert:
exp_init_os (exp->assert_s.child);
break;
case etree_unary:
exp_init_os (exp->unary.child);
break;
@ -991,32 +1373,32 @@ lang_add_section (lang_statement_list_type *ptr,
flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES);
/* If this is not the first input section, and the SEC_READONLY
flag is not currently set, then don't set it just because the
input section has it set. */
flag is not currently set, then don't set it just because the
input section has it set. */
if (! first && (section->output_section->flags & SEC_READONLY) == 0)
if (! first && (output->bfd_section->flags & SEC_READONLY) == 0)
flags &= ~ SEC_READONLY;
/* Keep SEC_MERGE and SEC_STRINGS only if they are the same. */
if (! first
&& ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS))
&& ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS))
!= (flags & (SEC_MERGE | SEC_STRINGS))
|| ((flags & SEC_MERGE)
&& section->output_section->entsize != section->entsize)))
&& output->bfd_section->entsize != section->entsize)))
{
section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
flags &= ~ (SEC_MERGE | SEC_STRINGS);
}
section->output_section->flags |= flags;
output->bfd_section->flags |= flags;
if (flags & SEC_MERGE)
section->output_section->entsize = section->entsize;
output->bfd_section->entsize = section->entsize;
/* If SEC_READONLY is not set in the input section, then clear
it from the output section. */
it from the output section. */
if ((section->flags & SEC_READONLY) == 0)
section->output_section->flags &= ~SEC_READONLY;
output->bfd_section->flags &= ~SEC_READONLY;
switch (output->sectype)
{
@ -1036,7 +1418,7 @@ lang_add_section (lang_statement_list_type *ptr,
/* Copy over SEC_SMALL_DATA. */
if (section->flags & SEC_SMALL_DATA)
section->output_section->flags |= SEC_SMALL_DATA;
output->bfd_section->flags |= SEC_SMALL_DATA;
if (section->alignment_power > output->bfd_section->alignment_power)
output->bfd_section->alignment_power = section->alignment_power;
@ -1047,7 +1429,7 @@ lang_add_section (lang_statement_list_type *ptr,
if (section->flags & SEC_BLOCK)
{
section->output_section->flags |= SEC_BLOCK;
output->bfd_section->flags |= SEC_BLOCK;
/* FIXME: This value should really be obtained from the bfd... */
output->block_value = 128;
}
@ -1122,7 +1504,7 @@ wild_sort (lang_wild_statement_type *wild,
ls = &l->input_section;
/* Sorting by filename takes precedence over sorting by section
name. */
name. */
if (wild->filenames_sorted)
{
@ -1131,9 +1513,9 @@ wild_sort (lang_wild_statement_type *wild,
int i;
/* The PE support for the .idata section as generated by
dlltool assumes that files will be sorted by the name of
the archive and then the name of the file within the
archive. */
dlltool assumes that files will be sorted by the name of
the archive and then the name of the file within the
archive. */
if (file->the_bfd != NULL
&& bfd_my_archive (file->the_bfd) != NULL)
@ -1181,7 +1563,7 @@ wild_sort (lang_wild_statement_type *wild,
}
/* Here either the files are not sorted by name, or we are
looking at the sections for this file. */
looking at the sections for this file. */
if (sec != NULL && sec->spec.sorted != none)
{
@ -1832,8 +2214,8 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
s->input_statement.target = current_target;
/* If we are being called from within a group, and this
is an archive which has already been searched, then
force it to be researched unless the whole archive
is an archive which has already been searched, then
force it to be researched unless the whole archive
has been loaded already. */
if (force
&& !s->input_statement.whole_archive
@ -2125,19 +2507,19 @@ update_wild_statements (lang_statement_union_type *s)
static void
map_input_to_output_sections
(lang_statement_union_type *s, const char *target,
lang_output_section_statement_type *output_section_statement)
lang_output_section_statement_type *os)
{
for (; s != NULL; s = s->header.next)
{
switch (s->header.type)
{
case lang_wild_statement_enum:
wild (&s->wild_statement, target, output_section_statement);
wild (&s->wild_statement, target, os);
break;
case lang_constructors_statement_enum:
map_input_to_output_sections (constructor_list.head,
target,
output_section_statement);
os);
break;
case lang_output_section_statement_enum:
if (s->output_section_statement.constraint)
@ -2169,27 +2551,32 @@ map_input_to_output_sections
case lang_group_statement_enum:
map_input_to_output_sections (s->group_statement.children.head,
target,
output_section_statement);
os);
break;
case lang_data_statement_enum:
/* Make sure that any sections mentioned in the expression
are initialized. */
exp_init_os (s->data_statement.exp);
/* FALLTHROUGH */
if (os != NULL && os->bfd_section == NULL)
init_os (os);
/* The output section gets contents, and then we inspect for
any flags set in the input script which override any ALLOC. */
os->bfd_section->flags |= SEC_HAS_CONTENTS;
if (!(os->flags & SEC_NEVER_LOAD))
os->bfd_section->flags |= SEC_ALLOC | SEC_LOAD;
break;
case lang_fill_statement_enum:
case lang_input_section_enum:
case lang_object_symbols_statement_enum:
case lang_reloc_statement_enum:
case lang_padding_statement_enum:
case lang_input_statement_enum:
if (output_section_statement != NULL
&& output_section_statement->bfd_section == NULL)
init_os (output_section_statement);
if (os != NULL && os->bfd_section == NULL)
init_os (os);
break;
case lang_assignment_statement_enum:
if (output_section_statement != NULL
&& output_section_statement->bfd_section == NULL)
init_os (output_section_statement);
if (os != NULL && os->bfd_section == NULL)
init_os (os);
/* Make sure that any sections mentioned in the assignment
are initialized. */
@ -2201,13 +2588,13 @@ map_input_to_output_sections
case lang_address_statement_enum:
/* Mark the specified section with the supplied address. */
{
lang_output_section_statement_type *os =
lang_output_section_statement_lookup
(s->address_statement.section_name);
lang_output_section_statement_type *aos
= (lang_output_section_statement_lookup
(s->address_statement.section_name));
if (os->bfd_section == NULL)
init_os (os);
os->addr_tree = s->address_statement.address;
if (aos->bfd_section == NULL)
init_os (aos);
aos->addr_tree = s->address_statement.address;
}
break;
}
@ -2221,16 +2608,14 @@ map_input_to_output_sections
static void
strip_excluded_output_sections (void)
{
lang_statement_union_type *u;
lang_output_section_statement_type *os;
for (u = lang_output_section_statement.head;
u != NULL;
u = u->output_section_statement.next)
for (os = &lang_output_section_statement.head->output_section_statement;
os != NULL;
os = os->next)
{
lang_output_section_statement_type *os;
asection *s;
os = &u->output_section_statement;
if (os->constraint == -1)
continue;
s = os->bfd_section;
@ -2302,23 +2687,35 @@ print_assignment (lang_assignment_statement_type *assignment,
lang_output_section_statement_type *output_section)
{
int i;
int is_dot;
etree_type *tree;
etree_value_type result;
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
print_space ();
result = exp_fold_tree (assignment->exp->assign.src, output_section,
lang_final_phase_enum, print_dot, &print_dot);
if (assignment->exp->type.node_class == etree_assert)
{
is_dot = 0;
tree = assignment->exp->assert_s.child;
}
else
{
const char *dst = assignment->exp->assign.dst;
is_dot = dst[0] == '.' && dst[1] == 0;
tree = assignment->exp->assign.src;
}
result = exp_fold_tree (tree, output_section, lang_final_phase_enum,
print_dot, &print_dot);
if (result.valid_p)
{
const char *dst;
bfd_vma value;
value = result.value + result.section->bfd_section->vma;
dst = assignment->exp->assign.dst;
minfo ("0x%V", value);
if (dst[0] == '.' && dst[1] == 0)
if (is_dot)
print_dot = value;
}
else
@ -2330,9 +2727,7 @@ print_assignment (lang_assignment_statement_type *assignment,
}
minfo (" ");
exp_print_tree (assignment->exp);
print_nl ();
}
@ -2379,6 +2774,9 @@ print_all_symbols (sec)
struct fat_user_section_struct *ud = get_userdata (sec);
struct map_symbol_def *def;
if (!ud)
return;
*ud->map_symbol_def_tail = 0;
for (def = ud->map_symbol_def_head; def; def = def->next)
print_one_symbol (def->entry, sec);
@ -2863,14 +3261,15 @@ size_input_section
}
#define IGNORE_SECTION(s) \
(((s->flags & SEC_THREAD_LOCAL) != 0 \
? (s->flags & (SEC_LOAD | SEC_NEVER_LOAD)) != SEC_LOAD \
: (s->flags & (SEC_ALLOC | SEC_NEVER_LOAD)) != SEC_ALLOC) \
((s->flags & SEC_NEVER_LOAD) != 0 \
|| (s->flags & SEC_ALLOC) == 0 \
|| ((s->flags & SEC_THREAD_LOCAL) != 0 \
&& (s->flags & SEC_LOAD) == 0) \
|| s->size == 0)
/* Check to see if any allocated sections overlap with other allocated
sections. This can happen when the linker script specifically specifies
the output section addresses of the two sections. */
sections. This can happen if a linker script specifies the output
section addresses of the two sections. */
static void
lang_check_section_addresses (void)
@ -3090,7 +3489,7 @@ lang_size_sections_1
lang_allocating_phase_enum,
dot, &dot);
os->processed = 0;
if (!r.valid_p)
einfo (_("%F%S: non constant or forward reference"
" address expression for section %s\n"),
@ -3220,14 +3619,6 @@ lang_size_sections_1
size = TO_SIZE ((unsigned) 1);
dot += TO_ADDR (size);
output_section_statement->bfd_section->size += size;
/* The output section gets contents, and then we inspect for
any flags set in the input script which override any ALLOC. */
output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS;
if (!(output_section_statement->flags & SEC_NEVER_LOAD))
{
output_section_statement->bfd_section->flags |=
SEC_ALLOC | SEC_LOAD;
}
}
break;
@ -3714,7 +4105,7 @@ lang_finish (void)
const char *send;
/* We couldn't find the entry symbol. Try parsing it as a
number. */
number. */
val = bfd_scan_vma (entry_symbol.name, &send, 0);
if (*send == '\0')
{
@ -3815,10 +4206,10 @@ lang_check (void)
bfd_error_handler_type pfn = NULL;
/* If we aren't supposed to warn about mismatched input
files, temporarily set the BFD error handler to a
function which will do nothing. We still want to call
bfd_merge_private_bfd_data, since it may set up
information which is needed in the output file. */
files, temporarily set the BFD error handler to a
function which will do nothing. We still want to call
bfd_merge_private_bfd_data, since it may set up
information which is needed in the output file. */
if (! command_line.warn_mismatch)
pfn = bfd_set_error_handler (ignore_bfd_errors);
if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
@ -3965,7 +4356,7 @@ lang_place_orphans (void)
if (s->output_section == NULL)
{
/* This section of the file is not attached, root
around for a sensible place for it to go. */
around for a sensible place for it to go. */
if (file->just_syms_flag)
abort ();
@ -3984,8 +4375,8 @@ lang_place_orphans (void)
{
#if 0
/* This message happens when using the
svr3.ifile linker script, so I have
disabled it. */
svr3.ifile linker script, so I have
disabled it. */
info_msg (_("%P: no [COMMON] command,"
" defaulting to .bss\n"));
#endif
@ -4855,7 +5246,7 @@ lang_record_phdrs (void)
asection **secs;
lang_output_section_phdr_list *last;
struct lang_phdr *l;
lang_statement_union_type *u;
lang_output_section_statement_type *os;
alc = 10;
secs = xmalloc (alc * sizeof (asection *));
@ -4867,14 +5258,12 @@ lang_record_phdrs (void)
bfd_vma at;
c = 0;
for (u = lang_output_section_statement.head;
u != NULL;
u = u->output_section_statement.next)
for (os = &lang_output_section_statement.head->output_section_statement;
os != NULL;
os = os->next)
{
lang_output_section_statement_type *os;
lang_output_section_phdr_list *pl;
os = &u->output_section_statement;
if (os->constraint == -1)
continue;
@ -4930,22 +5319,22 @@ lang_record_phdrs (void)
free (secs);
/* Make sure all the phdr assignments succeeded. */
for (u = lang_output_section_statement.head;
u != NULL;
u = u->output_section_statement.next)
for (os = &lang_output_section_statement.head->output_section_statement;
os != NULL;
os = os->next)
{
lang_output_section_phdr_list *pl;
if (u->output_section_statement.constraint == -1
|| u->output_section_statement.bfd_section == NULL)
if (os->constraint == -1
|| os->bfd_section == NULL)
continue;
for (pl = u->output_section_statement.phdrs;
for (pl = os->phdrs;
pl != NULL;
pl = pl->next)
if (! pl->used && strcmp (pl->name, "NONE") != 0)
einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"),
u->output_section_statement.name, pl->name);
os->name, pl->name);
}
}

View File

@ -131,7 +131,7 @@ typedef struct lang_output_section_statement_struct
union etree_union *addr_tree;
lang_statement_list_type children;
const char *memspec;
union lang_statement_union *next;
struct lang_output_section_statement_struct *next;
const char *name;
int processed;
@ -410,6 +410,17 @@ struct lang_definedness_hash_entry
int iteration;
};
/* Used by place_orphan to keep track of orphan sections and statements. */
struct orphan_save {
const char *name;
flagword flags;
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
lang_output_section_statement_type **os_tail;
};
extern struct unique_sections *unique_section_list;
extern lang_output_section_statement_type *abs_output_section;
@ -501,6 +512,12 @@ extern void ldlang_add_file
(lang_input_statement_type *);
extern lang_output_section_statement_type *lang_output_section_find
(const char * const);
extern lang_output_section_statement_type *lang_output_section_find_by_flags
(const asection *, lang_output_section_statement_type **exact);
extern lang_output_section_statement_type *lang_insert_orphan
(lang_input_statement_type *, asection *, const char *,
lang_output_section_statement_type *, struct orphan_save *,
etree_type *, lang_statement_list_type *);
extern lang_input_statement_type *lang_add_input_file
(const char *, lang_input_file_enum_type, const char *);
extern void lang_add_keepsyms_file

View File

@ -1,3 +1,9 @@
2004-10-14 Alan Modra <amodra@bigpond.net.au>
* ld-scripts/overlay-size.d: Update for changed orphan section
placement.
* ld-mmix/bpo-18.d: Likewise.
2004-10-07 Bob Wilson <bob.wilson@acm.org>
* ld-xtensa/lcall1.s: Use .literal directive.

View File

@ -12,9 +12,9 @@
SYMBOL TABLE:
0+100 l d \.text 0+
4000000000001060 l d \.text\.away 0+
400000000000106c l d \.data 0+
400000000000106c l d \.bss 0+
0+7e0 l d \.MMIX\.reg_contents 0+
4000000000001088 l d \.data 0+
4000000000001088 l d \.bss 0+
0+ l d \*ABS\* 0+
0+ l d \*ABS\* 0+
0+ l d \*ABS\* 0+

View File

@ -5,25 +5,25 @@
# The .bss[123] LMAs are deliberately blanked out. We can't
# reliably map overlaid sections to segments.
#...
0 \.bss1 +0+010 +0+20000 .*
.. \.bss1 +0+010 +0+20000 .*
#...
1 \.bss2 +0+030 +0+20000 .*
.. \.bss2 +0+030 +0+20000 .*
#...
2 \.bss3 +0+020 +0+20000 .*
.. \.bss3 +0+020 +0+20000 .*
#...
3 \.mtext +0+020 +0+10000 +0+30000 .*
.. \.mtext +0+020 +0+10000 +0+30000 .*
#...
4 \.mbss +0+230 +0+20030 .*
.. \.mbss +0+230 +0+20030 .*
#...
5 \.text1 +0+080 +0+10020 +0+30020 .*
.. \.text1 +0+080 +0+10020 +0+30020 .*
#...
6 \.text2 +0+040 +0+10020 +0+300a0 .*
.. \.text2 +0+040 +0+10020 +0+300a0 .*
#...
7 \.text3 +0+020 +0+10020 +0+300e0 .*
.. \.text3 +0+020 +0+10020 +0+300e0 .*
#...
8 \.data1 +0+030 +0+20260 +0+30100 .*
.. \.data1 +0+030 +0+20260 +0+30100 .*
#...
9 \.data2 +0+040 +0+20260 +0+30130 .*
.. \.data2 +0+040 +0+20260 +0+30130 .*
#...
10 \.data3 +0+050 +0+20260 +0+30170 .*
.. \.data3 +0+050 +0+20260 +0+30170 .*
#pass