This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
binutils-2.10 elf32.em place_orphan merge
- To: binutils at sourceware dot cygnus dot com
- Subject: binutils-2.10 elf32.em place_orphan merge
- From: Alan Modra <alan at linuxcare dot com dot au>
- Date: Mon, 6 Nov 2000 20:36:33 +1100 (EST)
I've applied this patch to the branch which merges most of the
place_orphan changes from the trunk. Keeps orphan sections in order
rather than reversing them, and fixes a few corner cases where it was
possible to lose sections.
ld/ChangeLog
Merge most place_orphan changes from mainline.
2000-09-07 Alan Modra <alan@linuxcare.com.au>
* emultempl/elf32.em (gld${EMULATION_NAME}_place_orphan): Fix
broken list handling. Create __start_SECNAME and __stop_SECNAME
when no place-holder. Add some comments. Test both SEC_CODE and
SEC_READONLY for hold_text to prevent .rodata orphan poisoning.
Handle case where no output section statement created.
2000-09-06 Alan Modra <alan@linuxcare.com.au>
* emultempl/elf32.em (gld${EMULATION_NAME}_place_orphan): Don't
try shuffling sections when the orphan happens to be the place
holder. Keep count of unique section names generated so we speed
the search for a new name.
2000-04-25 Alan Modra <alan@linuxcare.com.au>
* emultempl/elf32.em (gld${EMULATION_NAME}_place_section): Delete.
(output_rel_find): New function.
(hold_section, hold_use): Delete.
(hold_text, hold_rodata, hold_data, hold_bss, hold_rel,
hold_interp): Make local to place_orphan.
(gld${EMULATION_NAME}_place_orphan): Use lang_output_section_find
rather than place_section to find possible previous use of orphan.
Similarly find the place-holder output sections. Use returned
value from lang_enter_output_section_statement rather than calling
lang_output_section_statement_lookup.
* ldlang.c (lang_enter_output_section_statement): Return output
section statement.
* ldlang.h (lang_enter_output_section_statement): Change
declaration too.
* ldlang.h (lang_output_section_statement): Export it.
* ldlang.c (lang_output_section_statement): Ditto.
2000-04-18 H.J. Lu <hjl@gnu.org>
* emultempl/elf32.em (gld${EMULATION_NAME}_place_orphan): Call
lang_leave_output_section_statement () after calling
lang_enter_output_section_statement ().
2000-04-18 Alan Modra <alan@linuxcare.com.au>
* emultempl/elf32.em (struct orphan_save): Add section field.
(gld${EMULATION_NAME}_place_orphan): Use above to keep sections in
better order, and place first orphan section as we did before the
2000-04-12 patch. Ignore ~SEC_ALLOC sections when choosing place.
Don't call make_bfd_section here, let wild_doit do the job for us.
Don't build a statement list when we'll only throw it away.
2000-04-14 Alan Modra <alan@linuxcare.com.au>
* emultempl/elf32.em (gld${EMULATION_NAME}_place_orphan): Process
~SEC_ALLOC sections too. Init start address of debug sections.
2000-04-12 Alan Modra <alan@linuxcare.com.au>
* emultempl/elf32.em (struct orphan_save): New.
(hold_text, hold_rodata, hold_data, hold_bss, hold_rel,
hold_interp): Make them struct orphan_save.
(gld${EMULATION_NAME}_place_section): Modify for new hold_*.
(gld${EMULATION_NAME}_place_orphan): Add new orphan sections to
the end of the relevant section list. Also add associated section
statements to the end of any previous orphan statements.
Alan Modra
--
Linuxcare. Support for the Revolution.
Index: ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.24
diff -u -p -r1.24 ldlang.c
--- ldlang.c 2000/02/21 12:01:27 1.24
+++ ldlang.c 2000/11/06 09:11:41
@@ -58,7 +58,6 @@ static lang_output_section_statement_typ
static boolean map_option_f;
static bfd_vma print_dot;
static lang_input_statement_type *first_file;
-static lang_statement_list_type lang_output_section_statement;
static CONST char *current_target;
static CONST char *output_target;
static lang_statement_list_type statement_list;
@@ -166,6 +165,7 @@ static char * get_first_input_target PAR
/* EXPORTS */
lang_output_section_statement_type *abs_output_section;
+lang_statement_list_type lang_output_section_statement;
lang_statement_list_type *stat_ptr = &statement_list;
lang_statement_list_type file_chain = { NULL, NULL };
const char *entry_symbol = NULL;
@@ -3813,7 +3813,7 @@ topower (x)
return 0;
}
-void
+lang_output_section_statement_type *
lang_enter_output_section_statement (output_section_statement_name,
address_exp, sectype, block_value,
align, subalign, ebase)
@@ -3861,6 +3861,7 @@ lang_enter_output_section_statement (out
"section alignment", 0));
os->load_base = ebase;
+ return os;
}
Index: ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.4
diff -u -p -r1.4 ldlang.h
--- ldlang.h 2000/02/16 18:53:32 1.4
+++ ldlang.h 2000/11/06 09:11:43
@@ -371,6 +371,7 @@ struct lang_nocrossrefs
extern struct lang_nocrossrefs *nocrossref_list;
extern lang_output_section_statement_type *abs_output_section;
+extern lang_statement_list_type lang_output_section_statement;
extern boolean lang_has_input_file;
extern etree_type *base;
extern lang_statement_list_type *stat_ptr;
@@ -388,7 +389,7 @@ extern void lang_map PARAMS ((void));
extern void lang_set_flags PARAMS ((lang_memory_region_type *, const char *,
int));
extern void lang_add_output PARAMS ((const char *, int from_script));
-extern void lang_enter_output_section_statement
+extern lang_output_section_statement_type *lang_enter_output_section_statement
PARAMS ((const char *output_section_statement_name,
etree_type * address_exp,
enum section_type sectype,
Index: emultempl/elf32.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/elf32.em,v
retrieving revision 1.12.2.1
diff -u -p -r1.12.2.1 elf32.em
--- elf32.em 2000/10/12 13:56:39 1.12.2.1
+++ elf32.em 2000/11/06 09:11:48
@@ -7,7 +7,7 @@ cat >e${EMULATION_NAME}.c <<EOF
/* This file is is generated by a shell script. DO NOT EDIT! */
/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME}
- Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999
+ Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 99, 2000
Free Software Foundation, Inc.
Written by Steve Chamberlain <sac@cygnus.com>
ELF support by Ian Lance Taylor <ian@cygnus.com>
@@ -63,10 +63,9 @@ static void gld${EMULATION_NAME}_before_
static void gld${EMULATION_NAME}_find_statement_assignment
PARAMS ((lang_statement_union_type *));
static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
+static lang_output_section_statement_type *output_rel_find PARAMS ((void));
static boolean gld${EMULATION_NAME}_place_orphan
PARAMS ((lang_input_statement_type *, asection *));
-static void gld${EMULATION_NAME}_place_section
- PARAMS ((lang_statement_union_type *));
static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
static void
@@ -862,58 +861,83 @@ gld${EMULATION_NAME}_find_exp_assignment
}
}
+/* A variant of lang_output_section_find. Used by place_orphan. */
+
+static lang_output_section_statement_type *
+output_rel_find ()
+{
+ 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 (strncmp (".rel", lookup->name, 4) == 0
+ && lookup->bfd_section != NULL
+ && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
+ {
+ return lookup;
+ }
+ }
+ return (lang_output_section_statement_type *) NULL;
+}
+
/* Place an orphan section. We use this to put random SHF_ALLOC
sections in the right segment. */
-static asection *hold_section;
-static lang_output_section_statement_type *hold_use;
-static lang_output_section_statement_type *hold_text;
-static lang_output_section_statement_type *hold_rodata;
-static lang_output_section_statement_type *hold_data;
-static lang_output_section_statement_type *hold_bss;
-static lang_output_section_statement_type *hold_rel;
-static lang_output_section_statement_type *hold_interp;
+struct orphan_save {
+ lang_output_section_statement_type *os;
+ asection **section;
+ lang_statement_union_type **stmt;
+};
-/*ARGSUSED*/
static boolean
gld${EMULATION_NAME}_place_orphan (file, s)
lang_input_statement_type *file;
asection *s;
{
- lang_output_section_statement_type *place;
- asection *snew, **pps;
- lang_statement_list_type *old = NULL;
+ 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;
+ struct orphan_save *place;
+ lang_statement_list_type *old;
lang_statement_list_type add;
etree_type *address;
- const char *secname, *ps = NULL;
+ const char *secname;
const char *outsecname;
+ const char *ps = NULL;
lang_output_section_statement_type *os;
- if ((s->flags & SEC_ALLOC) == 0)
- return false;
+ secname = bfd_get_section_name (s->owner, s);
- /* Look through the script to see where to place this section. */
- hold_section = s;
- hold_use = NULL;
- lang_for_each_statement (gld${EMULATION_NAME}_place_section);
+ /* Look through the script to see where to place this section. */
+ os = lang_output_section_find (secname);
- if (hold_use != NULL)
+ if (os != NULL
+ && os->bfd_section != NULL
+ && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)
{
/* We have already placed a section with this name. */
- wild_doit (&hold_use->children, s, hold_use, file);
+ wild_doit (&os->children, s, os, file);
return true;
}
- secname = bfd_get_section_name (s->owner, s);
+ if (hold_text.os == NULL)
+ hold_text.os = lang_output_section_find (".text");
/* 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.shared
&& ! link_info.relocateable
&& strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
- && hold_text != NULL)
+ && hold_text.os != NULL)
{
- wild_doit (&hold_text->children, s, hold_text, file);
+ wild_doit (&hold_text.os->children, s, hold_text.os, file);
return true;
}
@@ -922,31 +946,37 @@ gld${EMULATION_NAME}_place_orphan (file,
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. */
- place = NULL;
+#define HAVE_SECTION(hold, name) \
+(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
+
if (s->flags & SEC_EXCLUDE)
return false;
+
+ place = NULL;
+ if ((s->flags & SEC_ALLOC) == 0)
+ ;
else if ((s->flags & SEC_LOAD) != 0
- && strncmp (secname, ".note", 4) == 0
- && hold_interp != NULL)
- place = hold_interp;
+ && strncmp (secname, ".note", 4) == 0
+ && HAVE_SECTION (hold_interp, ".interp"))
+ place = &hold_interp;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
- && hold_bss != NULL)
- place = hold_bss;
+ && HAVE_SECTION (hold_bss, ".bss"))
+ place = &hold_bss;
else if ((s->flags & SEC_READONLY) == 0
- && hold_data != NULL)
- place = hold_data;
+ && HAVE_SECTION (hold_data, ".data"))
+ place = &hold_data;
else if (strncmp (secname, ".rel", 4) == 0
- && hold_rel != NULL)
- place = hold_rel;
- else if ((s->flags & SEC_CODE) == 0
- && (s->flags & SEC_READONLY) != 0
- && hold_rodata != NULL)
- place = hold_rodata;
- else if ((s->flags & SEC_READONLY) != 0
- && hold_text != NULL)
- place = hold_text;
- if (place == NULL)
- return false;
+ && (hold_rel.os != NULL
+ || (hold_rel.os = output_rel_find ()) != NULL))
+ place = &hold_rel;
+ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
+ && HAVE_SECTION (hold_rodata, ".rodata"))
+ place = &hold_rodata;
+ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
+ && hold_text.os != NULL)
+ place = &hold_text;
+
+#undef HAVE_SECTION
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
@@ -971,114 +1001,143 @@ gld${EMULATION_NAME}_place_orphan (file,
outsecname = newname;
}
-
- /* Create the section in the output file, and put it in the right
- place. This shuffling is to make the output file look neater. */
- snew = bfd_make_section (output_bfd, outsecname);
- if (snew == NULL)
- einfo ("%P%F: output format %s cannot represent section called %s\n",
- output_bfd->xvec->name, outsecname);
- if (place->bfd_section != NULL)
- {
- for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
- ;
- *pps = snew->next;
- snew->next = place->bfd_section->next;
- place->bfd_section->next = snew;
- }
- /* Start building a list of statements for this section. */
+ /* Start building a list of statements for this section.
+ First save the current statement pointer. */
old = stat_ptr;
- stat_ptr = &add;
- lang_list_init (stat_ptr);
- /* 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' && config.build_constructors)
+ /* 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)
{
- char *symname;
+ stat_ptr = &add;
+ lang_list_init (stat_ptr);
+ }
- symname = (char *) xmalloc (ps - outsecname + sizeof "__start_");
- sprintf (symname, "__start_%s", outsecname);
- lang_add_assignment (exp_assop ('=', symname,
- exp_unop (ALIGN_K,
- exp_intop ((bfd_vma) 1
- << s->alignment_power))));
+ 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.relocateable)
- address = NULL;
- else
+ if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop ((bfd_vma) 0);
+ else
+ address = NULL;
- lang_enter_output_section_statement (outsecname, address, 0,
- (bfd_vma) 0,
- (etree_type *) NULL,
- (etree_type *) NULL,
- (etree_type *) NULL);
+ os = lang_enter_output_section_statement (outsecname, address, 0,
+ (bfd_vma) 0,
+ (etree_type *) NULL,
+ (etree_type *) NULL,
+ (etree_type *) NULL);
- os = lang_output_section_statement_lookup (outsecname);
wild_doit (&os->children, s, os, file);
lang_leave_output_section_statement
- ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL,
- "*default*");
- stat_ptr = &add;
+ ((bfd_vma) 0, "*default*",
+ (struct lang_output_section_phdr_list *) NULL, "*default*");
- if (*ps == '\0' && config.build_constructors)
+ 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, ".")));
}
- /* Now stick the new statement list right after PLACE. */
- *add.tail = place->header.next;
- place->header.next = add.head;
-
+ /* Restore the global list pointer. */
stat_ptr = old;
- return true;
-}
+ if (place != NULL)
+ {
+ asection *snew, **pps;
-static void
-gld${EMULATION_NAME}_place_section (s)
- lang_statement_union_type *s;
-{
- lang_output_section_statement_type *os;
+ snew = os->bfd_section;
+ if (place->section != NULL
+ || (place->os->bfd_section != NULL
+ && place->os->bfd_section != snew))
+ {
+ /* Shuffle the section to make the output file look neater.
+ This is really only cosmetic. */
+ if (place->section == NULL)
+ {
+#if 0
+ /* Finding the end of the list is a little tricky. We
+ make a wild stab at it by comparing section flags. */
+ flagword first_flags = place->os->bfd_section->flags;
+ for (pps = &place->os->bfd_section->next;
+ *pps != NULL && (*pps)->flags == first_flags;
+ pps = &(*pps)->next)
+ ;
+ place->section = pps;
+#else
+ /* Put orphans after the first section on the list. */
+ place->section = &place->os->bfd_section->next;
+#endif
+ }
- if (s->header.type != lang_output_section_statement_enum)
- return;
+ /* Unlink the section. */
+ for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
+ ;
+ *pps = snew->next;
+
+ /* Now tack it on to the "place->os" section list. */
+ snew->next = *place->section;
+ *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;
+ }
- os = &s->output_section_statement;
+ /* 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;
- if (strcmp (os->name, hold_section->name) == 0
- && os->bfd_section != NULL
- && ((hold_section->flags & (SEC_LOAD | SEC_ALLOC))
- == (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC))))
- hold_use = os;
-
- if (strcmp (os->name, ".text") == 0)
- hold_text = os;
- else if (strcmp (os->name, ".rodata") == 0)
- hold_rodata = os;
- else if (strcmp (os->name, ".data") == 0)
- hold_data = os;
- else if (strcmp (os->name, ".bss") == 0)
- hold_bss = os;
- else if (hold_rel == NULL
- && os->bfd_section != NULL
- && (os->bfd_section->flags & SEC_ALLOC) != 0
- && strncmp (os->name, ".rel", 4) == 0)
- hold_rel = os;
- else if (strcmp (os->name, ".interp") == 0)
- hold_interp = os;
+ /* Save the end of this list. */
+ place->stmt = add.tail;
+ }
+ }
+
+ return true;
}
static char *