* ld.texinfo (INSERT): Describe.
	* ldgram.y (ldgram_in_script, ldgram_had_equals): Delete.
	(INSERT_K, AFTER, BEFORE): Add as tokens.
	(ifile_p1): Handle INSERT statements.
	(saved_script_handle, force_make_executable): Move to..
	* ldmain.c: ..here.
	(previous_script_handle): New global var.
	* ldmain.h (saved_script_handle, force_make_executable): Declare.
	(previous_script_handle): Likewise.
	* ldlex.l (INSERT_K, AFTER, BEFORE): Add tokens.
	* lexsup.c (parge_args <-T>): Set previous_script_handle.
	* ldlang.c (lang_for_each_statement_worker): Handle insert statement.
	(map_input_to_output_sections, print_statement): Likewise.
	(lang_size_sections_1, lang_do_assignments_1): Likewise.
	(insert_os_after): New function, extracted from..
	(lang_insert_orphan): ..here.
	(process_insert_statements): New function.
	(lang_process): Call it.
	(lang_add_insert): New function.
	* ldlang.h (lang_insert_statement_enum): New.
	(lang_insert_statement_type): New.
	(lang_statement_union_type): Add insert_statement.
	(lang_add_insert): Declare.
ld/testsuite/
	* ld-spu/ovl.lnk: Delete overlay.
	* ld-spu/ovl1.lnk: New file.
	* ld-spu/ovl2.lnk: New file.
	* ld-spu/ovl.d: Update.
	* ld-spu/ovl2.d: Update.
This commit is contained in:
Alan Modra 2008-01-25 12:03:37 +00:00
parent 5ca3b13d65
commit 53d25da64b
15 changed files with 363 additions and 81 deletions

View File

@ -1,3 +1,29 @@
2008-01-25 Alan Modra <amodra@bigpond.net.au>
* ld.texinfo (INSERT): Describe.
* ldgram.y (ldgram_in_script, ldgram_had_equals): Delete.
(INSERT_K, AFTER, BEFORE): Add as tokens.
(ifile_p1): Handle INSERT statements.
(saved_script_handle, force_make_executable): Move to..
* ldmain.c: ..here.
(previous_script_handle): New global var.
* ldmain.h (saved_script_handle, force_make_executable): Declare.
(previous_script_handle): Likewise.
* ldlex.l (INSERT_K, AFTER, BEFORE): Add tokens.
* lexsup.c (parge_args <-T>): Set previous_script_handle.
* ldlang.c (lang_for_each_statement_worker): Handle insert statement.
(map_input_to_output_sections, print_statement): Likewise.
(lang_size_sections_1, lang_do_assignments_1): Likewise.
(insert_os_after): New function, extracted from..
(lang_insert_orphan): ..here.
(process_insert_statements): New function.
(lang_process): Call it.
(lang_add_insert): New function.
* ldlang.h (lang_insert_statement_enum): New.
(lang_insert_statement_type): New.
(lang_statement_union_type): Add insert_statement.
(lang_add_insert): Declare.
2008-01-18 Bob Wilson <bob.wilson@acm.org>
* scripttempl/elfxtensa.sc: Merge ENTRY and .note.gnu.build-id

View File

@ -297,10 +297,11 @@ augments the main linker script used for the link (either the default
linker script or the one specified by using @samp{-T}). This feature
permits the linker to link against a file which appears to be an object
or an archive, but actually merely defines some symbol values, or uses
@code{INPUT} or @code{GROUP} to load other objects. Note that
specifying a script in this way merely augments the main linker script;
use the @samp{-T} option to replace the default linker script entirely.
@xref{Scripts}.
@code{INPUT} or @code{GROUP} to load other objects. Specifying a
script in this way merely augments the main linker script, with the
extra commands placed after the main script; use the @samp{-T} option
to replace the default linker script entirely, but note the effect of
the @code{INSERT} command. @xref{Scripts}.
For options whose names are a single letter,
option arguments must either follow the option letter without intervening
@ -2903,6 +2904,35 @@ This command has the same effect as the @samp{--no-define-common}
command-line option: to make @code{ld} omit the assignment of addresses
to common symbols even for a non-relocatable output file.
@item INSERT [ AFTER | BEFORE ] @var{output_section}
@kindex INSERT
@cindex insert user script into default script
This command is typically used in a script specified by @samp{-T} to
augment the default @code{SECTIONS} with, for example, overlays. It
inserts all prior linker script statements after (or before)
@var{output_section}, and also causes @samp{-T} to not override the
default linker script. The exact insertion point is as for orphan
sections. @xref{Location Counter}. The insertion happens after the
linker has mapped input sections to output sections. Prior to the
insertion, since @samp{-T} scripts are parsed before the default
linker script, statements in the @samp{-T} script occur before the
default linker script statements in the internal linker representation
of the script. In particular, input section assignments will be made
to @samp{-T} output sections before those in the default script. Here
is an example of how a @samp{-T} script using @code{INSERT} might look:
@smallexample
SECTIONS
@{
OVERLAY :
@{
.ov1 @{ ov1*(.text) @}
.ov2 @{ ov2*(.text) @}
@}
@}
INSERT AFTER .text;
@end smallexample
@item NOCROSSREFS(@var{section} @var{section} @dots{})
@kindex NOCROSSREFS(@var{sections})
@cindex cross references

View File

@ -49,11 +49,6 @@
static enum section_type sectype;
static lang_memory_region_type *region;
FILE *saved_script_handle = NULL;
bfd_boolean force_make_executable = FALSE;
bfd_boolean ldgram_in_script = FALSE;
bfd_boolean ldgram_had_equals = FALSE;
bfd_boolean ldgram_had_keep = FALSE;
char *ldgram_vers_current_lang = NULL;
@ -127,7 +122,8 @@ static int error_index;
%token END
%left <token> '('
%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
%token SECTIONS PHDRS DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
%token SECTIONS PHDRS INSERT_K AFTER BEFORE
%token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
%token SORT_BY_NAME SORT_BY_ALIGNMENT
%token '{' '}'
%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH
@ -352,6 +348,10 @@ ifile_p1:
lang_add_nocrossref ($3);
}
| EXTERN '(' extern_name_list ')'
| INSERT_K AFTER NAME
{ lang_add_insert ($3, 0); }
| INSERT_K BEFORE NAME
{ lang_add_insert ($3, 1); }
;
input_list:

View File

@ -845,6 +845,7 @@ lang_for_each_statement_worker (void (*func) (lang_statement_union_type *),
case lang_padding_statement_enum:
case lang_address_statement_enum:
case lang_fill_statement_enum:
case lang_insert_statement_enum:
break;
default:
FAIL ();
@ -1451,6 +1452,73 @@ output_prev_sec_find (lang_output_section_statement_type *os)
return NULL;
}
/* Look for a suitable place for a new output section statement. 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. An exception to this rule is made for
the first assignment to dot, otherwise we might put an orphan
before . = . + SIZEOF_HEADERS or similar assignments that set the
initial address. */
static lang_statement_union_type **
insert_os_after (lang_output_section_statement_type *after)
{
lang_statement_union_type **where;
lang_statement_union_type **assign = NULL;
bfd_boolean ignore_first;
ignore_first
= after == &lang_output_section_statement.head->output_section_statement;
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
&& !ignore_first)
assign = where;
}
ignore_first = FALSE;
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;
break;
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_insert_statement_enum:
continue;
}
break;
}
return where;
}
lang_output_section_statement_type *
lang_insert_orphan (asection *s,
const char *secname,
@ -1606,64 +1674,7 @@ lang_insert_orphan (asection *s,
if (place->stmt == NULL)
{
lang_statement_union_type **where;
lang_statement_union_type **assign = NULL;
bfd_boolean ignore_first;
/* 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. An exception to this rule is made for
the first assignment to dot, otherwise we might put an
orphan before . = . + SIZEOF_HEADERS or similar
assignments that set the initial address. */
ignore_first = after == (&lang_output_section_statement.head
->output_section_statement);
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
&& !ignore_first)
assign = where;
}
ignore_first = FALSE;
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;
break;
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:
continue;
}
break;
}
lang_statement_union_type **where = insert_os_after (after);
*add.tail = *where;
*where = add.head;
@ -3312,6 +3323,154 @@ map_input_to_output_sections
aos->addr_tree = s->address_statement.address;
}
break;
case lang_insert_statement_enum:
break;
}
}
}
/* An insert statement snips out all the linker statements from the
start of the list and places them after the output section
statement specified by the insert. This operation is complicated
by the fact that we keep a doubly linked list of output section
statements as well as the singly linked list of all statements. */
static void
process_insert_statements (void)
{
lang_statement_union_type **s;
lang_output_section_statement_type *first_os = NULL;
lang_output_section_statement_type *last_os = NULL;
/* "start of list" is actually the statement immediately after
the special abs_section output statement, so that it isn't
reordered. */
s = &lang_output_section_statement.head;
while (*(s = &(*s)->header.next) != NULL)
{
if ((*s)->header.type == lang_output_section_statement_enum)
{
/* Keep pointers to the first and last output section
statement in the sequence we may be about to move. */
last_os = &(*s)->output_section_statement;
if (first_os == NULL)
first_os = last_os;
}
else if ((*s)->header.type == lang_insert_statement_enum)
{
lang_insert_statement_type *i = &(*s)->insert_statement;
lang_output_section_statement_type *where;
lang_output_section_statement_type *os;
lang_statement_union_type **ptr;
lang_statement_union_type *first;
where = lang_output_section_find (i->where);
if (where != NULL && i->is_before)
{
do
where = where->prev;
while (where != NULL && where->constraint == -1);
}
if (where == NULL)
{
einfo (_("%X%P: %s not found for insert\n"), i->where);
continue;
}
/* You can't insert into the list you are moving. */
for (os = first_os; os != NULL; os = os->next)
if (os == where || os == last_os)
break;
if (os == where)
{
einfo (_("%X%P: %s not found for insert\n"), i->where);
continue;
}
/* Deal with reordering the output section statement list. */
if (last_os != NULL)
{
asection *first_sec, *last_sec;
/* Snip out the output sections we are moving. */
first_os->prev->next = last_os->next;
if (last_os->next == NULL)
lang_output_section_statement.tail
= (union lang_statement_union **) &first_os->prev->next;
else
last_os->next->prev = first_os->prev;
/* Add them in at the new position. */
last_os->next = where->next;
if (where->next == NULL)
lang_output_section_statement.tail
= (union lang_statement_union **) &last_os->next;
else
where->next->prev = last_os;
first_os->prev = where;
where->next = first_os;
/* Move the bfd sections in the same way. */
first_sec = NULL;
last_sec = NULL;
for (os = first_os; os != NULL; os = os->next)
{
if (os->bfd_section != NULL
&& os->bfd_section->owner != NULL)
{
last_sec = os->bfd_section;
if (first_sec == NULL)
first_sec = last_sec;
}
if (os == last_os)
break;
}
if (last_sec != NULL)
{
asection *sec = where->bfd_section;
if (sec == NULL)
sec = output_prev_sec_find (where);
/* The place we want to insert must come after the
sections we are moving. So if we find no
section or if the section is the same as our
last section, then no move is needed. */
if (sec != NULL && sec != last_sec)
{
/* Trim them off. */
if (first_sec->prev != NULL)
first_sec->prev->next = last_sec->next;
else
output_bfd->sections = last_sec->next;
if (last_sec->next != NULL)
last_sec->next->prev = first_sec->prev;
else
output_bfd->section_last = first_sec->prev;
/* Add back. */
last_sec->next = sec->next;
if (sec->next != NULL)
sec->next->prev = last_sec;
else
output_bfd->section_last = last_sec;
first_sec->prev = sec;
sec->next = first_sec;
}
}
first_os = NULL;
last_os = NULL;
}
ptr = insert_os_after (where);
/* Snip everything after the abs_section output statement we
know is at the start of the list, up to and including
the insert statement we are currently processing. */
first = lang_output_section_statement.head->header.next;
lang_output_section_statement.head->header.next = (*s)->header.next;
/* Add them back where they belong. */
*s = *ptr;
if (*s == NULL)
statement_list.tail = s;
*ptr = first;
s = &lang_output_section_statement.head;
}
}
}
@ -3954,6 +4113,11 @@ print_statement (lang_statement_union_type *s,
case lang_group_statement_enum:
print_group (&s->group_statement, os);
break;
case lang_insert_statement_enum:
minfo ("INSERT %s %s\n",
s->insert_statement.is_before ? "BEFORE" : "AFTER",
s->insert_statement.where);
break;
}
}
@ -4734,13 +4898,16 @@ lang_size_sections_1
fill, dot, relax, check_regions);
break;
default:
FAIL ();
case lang_insert_statement_enum:
break;
/* We can only get here when relaxing is turned on. */
case lang_address_statement_enum:
break;
default:
FAIL ();
break;
}
prev = &s->header.next;
}
@ -4999,12 +5166,15 @@ lang_do_assignments_1 (lang_statement_union_type *s,
current_os, fill, dot);
break;
default:
FAIL ();
case lang_insert_statement_enum:
break;
case lang_address_statement_enum:
break;
default:
FAIL ();
break;
}
}
return dot;
@ -5853,6 +6023,8 @@ lang_process (void)
to the correct output sections. */
map_input_to_output_sections (statement_list.head, NULL, NULL);
process_insert_statements ();
/* Find any sections not attached explicitly and handle them. */
lang_place_orphans ();
@ -6269,6 +6441,17 @@ lang_add_output_format (const char *format,
}
}
void
lang_add_insert (const char *where, int is_before)
{
lang_insert_statement_type *new;
new = new_stat (lang_insert_statement, stat_ptr);
new->where = where;
new->is_before = is_before;
saved_script_handle = previous_script_handle;
}
/* Enter a group. This creates a new lang_group_statement, and sets
stat_ptr to build new statements within the group. */

View File

@ -79,6 +79,7 @@ typedef struct lang_statement_header_struct
lang_output_statement_enum,
lang_padding_statement_enum,
lang_group_statement_enum,
lang_insert_statement_enum,
lang_constructors_statement_enum
} type;
} lang_statement_header_type;
@ -352,6 +353,13 @@ typedef struct
lang_statement_list_type children;
} lang_group_statement_type;
typedef struct
{
lang_statement_header_type header;
const char *where;
bfd_boolean is_before;
} lang_insert_statement_type;
typedef union lang_statement_union
{
lang_statement_header_type header;
@ -370,6 +378,7 @@ typedef union lang_statement_union
lang_fill_statement_type fill_statement;
lang_padding_statement_type padding_statement;
lang_group_statement_type group_statement;
lang_insert_statement_type insert_statement;
} lang_statement_union_type;
/* This structure holds information about a program header, from the
@ -565,6 +574,8 @@ extern void lang_size_sections
(bfd_boolean *, bfd_boolean);
extern void one_lang_size_sections_pass
(bfd_boolean *, bfd_boolean);
extern void lang_add_insert
(const char *, int);
extern void lang_enter_group
(void);
extern void lang_leave_group

View File

@ -274,6 +274,9 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
<BOTH,SCRIPT>"FORCE_COMMON_ALLOCATION" { RTOKEN(FORCE_COMMON_ALLOCATION);}
<BOTH,SCRIPT>"INHIBIT_COMMON_ALLOCATION" { RTOKEN(INHIBIT_COMMON_ALLOCATION);}
<BOTH,SCRIPT>"SECTIONS" { RTOKEN(SECTIONS);}
<BOTH,SCRIPT>"INSERT" { RTOKEN(INSERT_K);}
<BOTH,SCRIPT>"AFTER" { RTOKEN(AFTER);}
<BOTH,SCRIPT>"BEFORE" { RTOKEN(BEFORE);}
<BOTH,SCRIPT>"FILL" { RTOKEN(FILL);}
<BOTH,SCRIPT>"STARTUP" { RTOKEN(STARTUP);}
<BOTH,SCRIPT>"OUTPUT_FORMAT" { RTOKEN(OUTPUT_FORMAT);}

View File

@ -60,6 +60,10 @@ extern void *sbrk ();
/* EXPORTS */
FILE *saved_script_handle = NULL;
FILE *previous_script_handle = NULL;
bfd_boolean force_make_executable = FALSE;
char *default_target;
const char *output_filename = "a.out";

View File

@ -26,6 +26,9 @@ extern char *program_name;
extern const char *ld_sysroot;
extern char *ld_canon_sysroot;
extern int ld_canon_sysroot_len;
extern FILE *saved_script_handle;
extern FILE *previous_script_handle;
extern bfd_boolean force_make_executable;
extern bfd *output_bfd;
extern char *default_target;
extern bfd_boolean trace_files;

View File

@ -1166,9 +1166,11 @@ parse_args (unsigned argc, char **argv)
trace_files = TRUE;
break;
case 'T':
previous_script_handle = saved_script_handle;
ldfile_open_command_file (optarg);
parser_input = input_script;
yyparse ();
previous_script_handle = NULL;
break;
case OPTION_DEFAULT_SCRIPT:
command_line.default_script = optarg;

View File

@ -1,3 +1,11 @@
2008-01-25 Alan Modra <amodra@bigpond.net.au>
* ld-spu/ovl.lnk: Delete overlay.
* ld-spu/ovl1.lnk: New file.
* ld-spu/ovl2.lnk: New file.
* ld-spu/ovl.d: Update.
* ld-spu/ovl2.d: Update.
2008-01-23 Andreas Schwab <schwab@suse.de>
* ld-gc/gc.c: Make sure used_func is not inlined.

View File

@ -1,5 +1,5 @@
#source: ovl.s
#ld: -N -T ovl.lnk --emit-relocs
#ld: -N -T ovl1.lnk -T ovl.lnk --emit-relocs
#objdump: -D -r
.*elf32-spu

View File

@ -2,13 +2,6 @@ SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text) *(.stub) }
OVERLAY 0x400 :
{
.ov_a1 { *(.ov_a1) }
.ov_a2 { *(.ov_a2) }
}
.data : { *(.data) *(.ovtab) }
.bss : { *(.bss) }
}

View File

@ -0,0 +1,9 @@
SECTIONS
{
OVERLAY 0x400 :
{
.ov_a1 { *(.ov_a1) }
.ov_a2 { *(.ov_a2) }
}
}
INSERT AFTER .text;

View File

@ -1,5 +1,5 @@
#source: ovl2.s
#ld: -N -T ovl.lnk --emit-relocs
#ld: -N -T ovl2.lnk -T ovl.lnk --emit-relocs
#objdump: -D -r
.*elf32-spu

View File

@ -0,0 +1,10 @@
SECTIONS
{
OVERLAY 0x400 :
{
.ov_a1 { *(.ov_a1) }
.ov_a2 { *(.ov_a2) }
.empty { empty.o?(.text) }
}
}
INSERT BEFORE .data;