On 01/02/2011 02:33, Joel Sherrill wrote: > Hi, > > There are ~100 failures on each *-rtems* target > in the latest test runs when various lto related > flags are on. The symbols in questions are in the > RTEMS libraries which are picked up via the > -B... argument. Other symbols from the same > library are resolved.
These have all cropped up since -fuse-linker-plugin became the default. > Should LTO work with a target not using gold? Yes, it should, but some work is needed at the binutils end. I am testing the attached two patches at the moment; the idea is to have fully-debugged support for LTO+plugin in the 2.20.1 release, to support 4.6.0 when it comes out. cheers, DaveK -- Apologies if dup - ENOPATCH first time I hit send.
>From 6cad541c1902edf5ceb483a20666a90be954e3d4 Mon Sep 17 00:00:00 2001 From: Dave Korn <dave.korn.cyg...@gmail.com> Date: Mon, 31 Jan 2011 03:26:05 +0000 Subject: [PATCH] ld/ChangeLog: 2011-01-29 Dave Korn <... * ldlang.h (lang_input_statement_type): Add new 'claim_archive' flag. * ldmain.c (add_archive_element): Set it if the member is claimed. * ldlang.c (new_afile): Initialise claim_archive and claimed members. (find_replacements_insert_point): New helper function. (lang_process): After adding and opening replacement files passed from plugin, splice them into correct place in statement list and file chains to preserve critical link order. (lang_list_insert_after): New helper function. (lang_list_remove_tail): Likewise. --- ld/ldlang.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- ld/ldlang.h | 3 + ld/ldmain.c | 1 + 3 files changed, 129 insertions(+), 9 deletions(-) diff --git a/ld/ldlang.c b/ld/ldlang.c index 7ffe760..53d2901 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -85,6 +85,11 @@ static void print_statement_list (lang_statement_union_type *, static void print_statements (void); static void print_input_section (asection *, bfd_boolean); static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *); +static void lang_list_insert_after (lang_statement_list_type *destlist, + lang_statement_list_type *srclist, + lang_statement_union_type **field); +static void lang_list_remove_tail (lang_statement_list_type *destlist, + lang_statement_list_type *origlist); static void lang_record_phdrs (void); static void lang_do_version_exports_section (void); static void lang_finalize_version_expr_head @@ -1126,6 +1131,8 @@ new_afile (const char *name, p->whole_archive = whole_archive; p->loaded = FALSE; p->missing_file = FALSE; + p->claimed = FALSE; + p->claim_archive = FALSE; lang_statement_append (&input_file_chain, (lang_statement_union_type *) p, @@ -6394,6 +6401,38 @@ lang_relax_sections (bfd_boolean need_layout) } } +/* Find the insert point for the plugin's replacement files. We + place them after the first claimed real object file, or if the + first claimed object is an archive member, after the last real + object file immediately preceding the archive. In the event + no objects have been claimed at all, we return the first dummy + object file on the list as the insert point; that works, but + the callee must be careful when relinking the file_chain as it + is not actually on that chain, only the statement_list and the + input_file list; in that case, the replacement files must be + inserted at the head of the file_chain. */ + +static lang_input_statement_type * +find_replacements_insert_point (void) +{ + lang_input_statement_type *claim1, *lastobject; + lastobject = &input_file_chain.head->input_statement; + for (claim1 = &file_chain.head->input_statement; + claim1 != NULL; + claim1 = &claim1->next->input_statement) + { + if (claim1->claimed) + return claim1->claim_archive ? lastobject : claim1; + /* Update lastobject if this is a real object file. */ + if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL)) + lastobject = claim1; + } + /* No files were claimed by the plugin. Choose the last object + file found on the list (maybe the first, dummy entry) as the + insert point. */ + return lastobject; +} + void lang_process (void) { @@ -6420,21 +6459,54 @@ lang_process (void) open_input_bfds (statement_list.head, FALSE); #ifdef ENABLE_PLUGINS + if (plugin_active_plugins_p ()) { - union lang_statement_union **listend; + lang_statement_list_type added; + lang_statement_list_type files, inputfiles; /* Now all files are read, let the plugin(s) decide if there are any more to be added to the link before we call the - emulation's after_open hook. */ - listend = statement_list.tail; - ASSERT (!*listend); + emulation's after_open hook. We create a private list of + input statements for this purpose, which we will eventually + insert into the global statment list after the first claimed + file. */ + added = *stat_ptr; + /* We need to manipulate all three chains in synchrony. */ + files = file_chain; + inputfiles = input_file_chain; if (plugin_call_all_symbols_read ()) einfo (_("%P%F: %s: plugin reported error after all symbols read\n"), plugin_error_plugin ()); - /* If any new files were added, they will be on the end of the - statement list, and we can open them now by getting open_input_bfds - to carry on from where it ended last time. */ - if (*listend) - open_input_bfds (*listend, FALSE); + /* Open any newly added files, updating the file chains. */ + open_input_bfds (added.head, FALSE); + /* Restore the global list pointer now they have all been added. */ + lang_list_remove_tail (stat_ptr, &added); + /* And detach the fresh ends of the file lists. */ + lang_list_remove_tail (&file_chain, &files); + lang_list_remove_tail (&input_file_chain, &inputfiles); + /* Were any new files added? */ + if (added.head != NULL) + { + /* If so, we will insert them into the statement list immediately + after the first input file that was claimed by the plugin. */ + lang_input_statement_type *claim1 = find_replacements_insert_point (); + /* If a plugin adds input files without having claimed any, we + don't really have a good idea where to place them. Just putting + them at the start or end of the list is liable to leave them + outside the crtbegin...crtend range. */ + ASSERT (claim1 != NULL); + /* Splice the new statement list into the old one after claim1. */ + lang_list_insert_after (stat_ptr, &added, &claim1->header.next); + /* Likewise for the file chains. */ + lang_list_insert_after (&input_file_chain, &inputfiles, + &claim1->next_real_file); + /* We must be careful when relinking file_chain; we may need to + insert the new files at the head of the list if the insert + point chosen is the dummy first input file. */ + if (claim1->filename) + lang_list_insert_after (&file_chain, &files, &claim1->next); + else + lang_list_insert_after (&file_chain, &files, &file_chain.head); + } } #endif /* ENABLE_PLUGINS */ @@ -6857,6 +6929,50 @@ lang_statement_append (lang_statement_list_type *list, list->tail = field; } +/* Insert SRCLIST into DESTLIST after given element by chaining + on FIELD as the next-pointer. (Counterintuitively does not need + a pointer to the actual after-node itself, just its chain field.) */ + +static void +lang_list_insert_after (lang_statement_list_type *destlist, + lang_statement_list_type *srclist, + lang_statement_union_type **field) +{ + /* Are we adding at the very end of the list? */ + if (*field == NULL) + { + /* (*field == NULL) should imply (destlist->tail == field), + if not then the element isn't really in the DESTLIST. */ + ASSERT (destlist->tail == field); + /* Yes, append to and update tail pointer. */ + *(destlist->tail) = srclist->head; + destlist->tail = srclist->tail; + } + else + { + /* We're inserting in the middle somewhere. */ + *(srclist->tail) = *field; + *field = srclist->head; + } +} + +/* Detach new nodes added to DESTLIST since the time ORIGLIST + was taken as a copy of it and leave them in ORIGLIST. */ + +static void +lang_list_remove_tail (lang_statement_list_type *destlist, + lang_statement_list_type *origlist) +{ + union lang_statement_union **savetail; + /* Check that ORIGLIST really is an earlier state of DESTLIST. */ + ASSERT (origlist->head == destlist->head); + savetail = origlist->tail; + origlist->head = *(savetail); + origlist->tail = destlist->tail; + destlist->tail = savetail; + *savetail = NULL; +} + /* Set the output format type. -oformat overrides scripts. */ void diff --git a/ld/ldlang.h b/ld/ldlang.h index 8aff0b3..105253a 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -290,6 +290,9 @@ typedef struct lang_input_statement_struct /* Set if the file was claimed by a plugin. */ unsigned int claimed : 1; + /* Set if the file was claimed from an archive. */ + unsigned int claim_archive : 1; + } lang_input_statement_type; typedef struct diff --git a/ld/ldmain.c b/ld/ldmain.c index 19c42d9..1c6d4be 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -834,6 +834,7 @@ add_archive_element (struct bfd_link_info *info, /* Substitute the dummy BFD. */ input->the_bfd = file.handle; input->claimed = TRUE; + input->claim_archive = TRUE; bfd_make_readable (input->the_bfd); *subsbfd = input->the_bfd; }
>From fd18b9d502186db79ec84bfd5f43b0eb285281c6 Mon Sep 17 00:00:00 2001 From: Dave Korn <dave.korn.cyg...@gmail.com> Date: Tue, 1 Feb 2011 10:18:04 +0000 Subject: [PATCH] ld/ChangeLog: 2011-01-29 Dave Korn <... * ldlang.c (rescan_input_libs): New function. (lang_process): Call it if replacement files have added any new undefined symbols. * plugin.c (plugin_opt_plugin_arg): Discard any instances of the (now-obsolete) "-pass-through=" option if found. --- ld/ldlang.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ld/plugin.c | 3 +++ 2 files changed, 62 insertions(+), 0 deletions(-) diff --git a/ld/ldlang.c b/ld/ldlang.c index 53d2901..4e528d1 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -3273,6 +3273,60 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force) einfo ("%F"); } +/* Rescan all the input library files starting from S. */ + +static void +rescan_input_libs (lang_statement_union_type *s) +{ + for (; s != NULL; s = s->header.next) + { + switch (s->header.type) + { + default: + break; + case lang_group_statement_enum: + { + struct bfd_link_hash_entry *undefs; + /* We must continually search the entries in the group + until no new symbols are added to the list of undefined + symbols. */ + do + { + undefs = link_info.hash->undefs_tail; + rescan_input_libs (s->group_statement.children.head); + } + while (undefs != link_info.hash->undefs_tail); + } + break; + case lang_input_statement_enum: + if (s->input_statement.real && s->input_statement.the_bfd + && bfd_check_format (s->input_statement.the_bfd, bfd_archive)) + { + lang_statement_list_type add; + + /* If this archive has already been searched, then + force it to be researched unless the whole archive + has been loaded already. */ + if (!s->input_statement.whole_archive + && s->input_statement.loaded) + s->input_statement.loaded = FALSE; + + lang_list_init (&add); + + if (!load_symbols (&s->input_statement, &add)) + config.make_executable = FALSE; + + if (add.head != NULL) + { + *add.tail = s->header.next; + s->header.next = add.head; + } + } + break; + } + } +} + /* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions. */ void @@ -6463,6 +6517,7 @@ lang_process (void) { lang_statement_list_type added; lang_statement_list_type files, inputfiles; + struct bfd_link_hash_entry *undefs = link_info.hash->undefs_tail; /* Now all files are read, let the plugin(s) decide if there are any more to be added to the link before we call the emulation's after_open hook. We create a private list of @@ -6506,6 +6561,10 @@ lang_process (void) lang_list_insert_after (&file_chain, &files, &claim1->next); else lang_list_insert_after (&file_chain, &files, &file_chain.head); + /* Now, if there are any new undefined symbols, rescan any + libraries after the insertion point. */ + if (undefs != link_info.hash->undefs_tail) + rescan_input_libs (claim1->next_real_file); } } #endif /* ENABLE_PLUGINS */ diff --git a/ld/plugin.c b/ld/plugin.c index b285787..cd8aeb9 100644 --- a/ld/plugin.c +++ b/ld/plugin.c @@ -214,6 +214,9 @@ plugin_opt_plugin_arg (const char *arg) if (!last_plugin) return set_plugin_error (_("<no plugin>")); + if (CONST_STRNEQ (arg, "-pass-through=")) + return 0; + newarg = xmalloc (sizeof *newarg); newarg->arg = arg; newarg->next = NULL;