aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2020-02-25 12:50:10 +1030
committerAlan Modra <amodra@gmail.com>2020-02-26 10:37:25 +1030
commite310298cf3fc02112ac0018260748828affa4061 (patch)
treefd7444bdd4f804c1cf0304e82011ea576a731077 /ld
parentb570b954bc5c1d6a6edb363c7bdba814bc1fd174 (diff)
downloadgdb-e310298cf3fc02112ac0018260748828affa4061.zip
gdb-e310298cf3fc02112ac0018260748828affa4061.tar.gz
gdb-e310298cf3fc02112ac0018260748828affa4061.tar.bz2
PR25593, --as-needed breaks DT_NEEDED order with linker plugin
This patch delays setting up DT_NEEDED dynamic tags until all object files and libraries have been opened and their symbols processed, rather than adding the tags while processing symbols. Tags are ordered according to the position of the associated library on the command line and linker scripts. It is still possible with --as-needed libs that are mentioned more than once for tags to be ordered according to which mention was needed. For example with "--as-needed a.so b.so c.so b.so" when b.so is not needed by a.so or any other prior object file but is needed by c.so, the order of tags will be "A C B". bfd/ PR 25593 * elf-bfd.h (struct elf_link_hash_table): Rename "loaded" to "dyn_loaded". (bfd_elf_add_dt_needed_tag): Declare. * elf-strtab.c (_bfd_elf_strtab_restore): Handle NULL buf. * elflink.c (bfd_elf_add_dt_needed_tag): Make global and rename from elf_add_dt_needed_tag. Remove soname and doit param. (elf_link_add_object_symbols): Don't use elf_add_dt_needed_tag to see whether as-needed lib is already loaded, use dyn_loaded list instead. When saving and restoring around as-needed lib handle possibility that dynstr has not been initialised. Don't add DT_NEEDED tags here. Limit dyn_loaded list to dynamic libs. Mark libs loaded via DT_NEEDED entries of other libs with DYN_NO_NEEDED if they should not be mentioned in DT_NEEDED of the output. (elf_link_check_versioned_symbol): Remove now unneccesary DYNAMIC check when traversing dyn_loaded list. ld/ PR 25593 * ldelf.c (ldelf_try_needed): Add DT_NEEDED lib to input_bfds. (ldelf_after_open): Save state of input_bfds list before loading DT_NEEDED libs. Traverse input_bfds list adding DT_NEEDED tags. Restore input_bfds list. * testsuite/ld-cris/gotplt1.d: Adjust for changed .dynstr order.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/ldelf.c19
-rw-r--r--ld/testsuite/ld-cris/gotplt1.d2
3 files changed, 29 insertions, 1 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 9bc9bd6..3cb0cf8 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,12 @@
+2020-02-26 Alan Modra <amodra@gmail.com>
+
+ PR 25593
+ * ldelf.c (ldelf_try_needed): Add DT_NEEDED lib to input_bfds.
+ (ldelf_after_open): Save state of input_bfds list before loading
+ DT_NEEDED libs. Traverse input_bfds list adding DT_NEEDED tags.
+ Restore input_bfds list.
+ * testsuite/ld-cris/gotplt1.d: Adjust for changed .dynstr order.
+
2020-02-24 Nick Clifton <nickc@redhat.com>
* po/fr.po: Update French translation.
diff --git a/ld/ldelf.c b/ld/ldelf.c
index 3ac3bb4..b055929 100644
--- a/ld/ldelf.c
+++ b/ld/ldelf.c
@@ -375,6 +375,9 @@ ldelf_try_needed (struct dt_needed *needed, int force, int is_linux)
bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class);
+ *link_info.input_bfds_tail = abfd;
+ link_info.input_bfds_tail = &abfd->link.next;
+
/* Add this file into the symbol table. */
if (! bfd_link_add_symbols (abfd, &link_info))
einfo (_("%F%P: %pB: error adding symbols: %E\n"), abfd);
@@ -992,6 +995,7 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
struct elf_link_hash_table *htab;
asection *s;
bfd *abfd;
+ bfd **save_input_bfd_tail;
after_open_default ();
@@ -1134,6 +1138,7 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
special action by the person doing the link. Note that the
needed list can actually grow while we are stepping through this
loop. */
+ save_input_bfd_tail = link_info.input_bfds_tail;
needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info);
for (l = needed; l != NULL; l = l->next)
{
@@ -1290,6 +1295,20 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
l->name, l->by);
}
+ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next)
+ if (bfd_get_format (abfd) == bfd_object
+ && ((abfd->flags) & DYNAMIC) != 0
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && (elf_dyn_lib_class (abfd) & (DYN_AS_NEEDED | DYN_NO_NEEDED)) == 0
+ && elf_dt_name (abfd) != NULL)
+ {
+ if (bfd_elf_add_dt_needed_tag (abfd, &link_info) < 0)
+ einfo (_("%F%P: failed to add DT_NEEDED dynamic tag\n"));
+ }
+
+ link_info.input_bfds_tail = save_input_bfd_tail;
+ *save_input_bfd_tail = NULL;
+
if (link_info.eh_frame_hdr_type == COMPACT_EH_HDR)
if (!bfd_elf_parse_eh_frame_entries (NULL, &link_info))
einfo (_("%F%P: failed to parse EH frame entries\n"));
diff --git a/ld/testsuite/ld-cris/gotplt1.d b/ld/testsuite/ld-cris/gotplt1.d
index 28724d7..defba8a 100644
--- a/ld/testsuite/ld-cris/gotplt1.d
+++ b/ld/testsuite/ld-cris/gotplt1.d
@@ -34,7 +34,7 @@ Contents of section \.text:
80178 6f0d1000 0000611a 6f2e5401 08000000 .*
80188 6f3e70df ffff0000 .*
Contents of section \.dynamic:
- 82190 01000000 01000000 04000000 e4000800 .*
+ 82190 01000000 07000000 04000000 e4000800 .*
821a0 05000000 18010800 06000000 f8000800 .*
821b0 0a000000 1a000000 0b000000 10000000 .*
821c0 15000000 00000000 03000000 18220800 .*