aboutsummaryrefslogtreecommitdiff
path: root/bfd/elflink.c
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 /bfd/elflink.c
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 'bfd/elflink.c')
-rw-r--r--bfd/elflink.c82
1 files changed, 43 insertions, 39 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 8e7ae2a..6f03c5c 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3501,23 +3501,21 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info,
return TRUE;
}
-/* Add a DT_NEEDED entry for this dynamic object if DO_IT is true,
- otherwise just check whether one already exists. Returns -1 on error,
+/* Add a DT_NEEDED entry for this dynamic object. Returns -1 on error,
1 if a DT_NEEDED tag already exists, and 0 on success. */
-static int
-elf_add_dt_needed_tag (bfd *abfd,
- struct bfd_link_info *info,
- const char *soname,
- bfd_boolean do_it)
+int
+bfd_elf_add_dt_needed_tag (bfd *abfd, struct bfd_link_info *info)
{
struct elf_link_hash_table *hash_table;
size_t strindex;
+ const char *soname;
if (!_bfd_elf_link_create_dynstrtab (abfd, info))
return -1;
hash_table = elf_hash_table (info);
+ soname = elf_dt_name (abfd);
strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
if (strindex == (size_t) -1)
return -1;
@@ -3547,17 +3545,11 @@ elf_add_dt_needed_tag (bfd *abfd,
}
}
- if (do_it)
- {
- if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
- return -1;
+ if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
+ return -1;
- if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
- return -1;
- }
- else
- /* We were just checking for existence of the tag. */
- _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+ if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+ return -1;
return 0;
}
@@ -4069,7 +4061,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
char *audit = NULL;
struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
const Elf_Internal_Phdr *phdr;
- int ret;
+ struct elf_link_loaded_list *loaded_lib;
/* ld --just-symbols and dynamic objects don't mix very well.
ld shouldn't allow it. */
@@ -4258,15 +4250,22 @@ error_free_dyn:
will need to know it. */
elf_dt_name (abfd) = soname;
- ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
- if (ret < 0)
- goto error_return;
-
/* If we have already included this dynamic object in the
link, just ignore it. There is no reason to include a
particular dynamic object more than once. */
- if (ret > 0)
- return TRUE;
+ for (loaded_lib = htab->dyn_loaded;
+ loaded_lib != NULL;
+ loaded_lib = loaded_lib->next)
+ {
+ if (strcmp (elf_dt_name (loaded_lib->abfd), soname) == 0)
+ return TRUE;
+ }
+
+ /* Create dynamic sections for backends that require that be done
+ before setup_gnu_properties. */
+ if (add_needed
+ && !_bfd_elf_link_create_dynamic_sections (abfd, info))
+ return FALSE;
/* Save the DT_AUDIT entry for the linker emulation code. */
elf_dt_audit (abfd) = audit;
@@ -4389,9 +4388,13 @@ error_free_dyn:
old_table = htab->root.table.table;
old_size = htab->root.table.size;
old_count = htab->root.table.count;
- old_strtab = _bfd_elf_strtab_save (htab->dynstr);
- if (old_strtab == NULL)
- goto error_free_vers;
+ old_strtab = NULL;
+ if (htab->dynstr != NULL)
+ {
+ old_strtab = _bfd_elf_strtab_save (htab->dynstr);
+ if (old_strtab == NULL)
+ goto error_free_vers;
+ }
for (i = 0; i < htab->root.table.size; i++)
{
@@ -5102,7 +5105,6 @@ error_free_dyn:
&& !on_needed_list (elf_dt_name (abfd),
htab->needed, NULL))))
{
- int ret;
const char *soname = elf_dt_name (abfd);
info->callbacks->minfo ("%!", soname, old_bfd,
@@ -5127,12 +5129,11 @@ error_free_dyn:
elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
(elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
+ /* Create dynamic sections for backends that require
+ that be done before setup_gnu_properties. */
+ if (!_bfd_elf_link_create_dynamic_sections (abfd, info))
+ return FALSE;
add_needed = TRUE;
- ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
- if (ret < 0)
- goto error_free_vers;
-
- BFD_ASSERT (ret == 0);
}
}
}
@@ -5222,7 +5223,8 @@ error_free_dyn:
memcpy (htab->root.table.table, old_tab, tabsize);
htab->root.undefs = old_undefs;
htab->root.undefs_tail = old_undefs_tail;
- _bfd_elf_strtab_restore (htab->dynstr, old_strtab);
+ if (htab->dynstr != NULL)
+ _bfd_elf_strtab_restore (htab->dynstr, old_strtab);
free (old_strtab);
old_strtab = NULL;
for (i = 0; i < htab->root.table.size; i++)
@@ -5550,7 +5552,7 @@ error_free_dyn:
}
}
- if (is_elf_hash_table (htab) && add_needed)
+ if (dynamic && add_needed)
{
/* Add this bfd to the loaded list. */
struct elf_link_loaded_list *n;
@@ -5559,9 +5561,12 @@ error_free_dyn:
if (n == NULL)
goto error_return;
n->abfd = abfd;
- n->next = htab->loaded;
- htab->loaded = n;
+ n->next = htab->dyn_loaded;
+ htab->dyn_loaded = n;
}
+ if (dynamic && !add_needed
+ && (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) != 0)
+ elf_dyn_lib_class (abfd) |= DYN_NO_NEEDED;
return TRUE;
@@ -9689,7 +9694,7 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
}
BFD_ASSERT (abfd != NULL);
- for (loaded = elf_hash_table (info)->loaded;
+ for (loaded = elf_hash_table (info)->dyn_loaded;
loaded != NULL;
loaded = loaded->next)
{
@@ -9709,7 +9714,6 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
/* We check each DSO for a possible hidden versioned definition. */
if (input == abfd
- || (input->flags & DYNAMIC) == 0
|| elf_dynversym (input) == 0)
continue;