ld/
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:
parent
ad4c72d283
commit
afd7a018c9
45
ld/ChangeLog
45
ld/ChangeLog
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
571
ld/ldlang.c
571
ld/ldlang.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
19
ld/ldlang.h
19
ld/ldlang.h
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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+
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user