aboutsummaryrefslogtreecommitdiff
path: root/ld/ldmain.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/ldmain.c')
-rw-r--r--ld/ldmain.c96
1 files changed, 88 insertions, 8 deletions
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 08679ec..04b5633 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -40,6 +40,11 @@
#include "ldfile.h"
#include "ldemul.h"
#include "ldctor.h"
+#ifdef ENABLE_PLUGINS
+#include "plugin.h"
+#include "plugin-api.h"
+#include "libbfd.h"
+#endif /* ENABLE_PLUGINS */
/* Somewhere above, sys/stat.h got included. */
#if !defined(S_ISDIR) && defined(S_IFDIR)
@@ -116,7 +121,7 @@ static const char *get_sysroot
static char *get_emulation
(int, char **);
static bfd_boolean add_archive_element
- (struct bfd_link_info *, bfd *, const char *);
+ (struct bfd_link_info *, bfd *, const char *, bfd **);
static bfd_boolean multiple_definition
(struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma,
bfd *, asection *, bfd_vma);
@@ -474,6 +479,12 @@ main (int argc, char **argv)
lang_finish ();
+#ifdef ENABLE_PLUGINS
+ /* Now everything is finished, we can tell the plugins to clean up. */
+ if (plugin_call_cleanup ())
+ info_msg (_("%P: %s: error in plugin cleanup (ignored)\n"), plugin_error_plugin ());
+#endif /* ENABLE_PLUGINS */
+
/* Even if we're producing relocatable output, some non-fatal errors should
be reported in the exit status. (What non-fatal errors, if any, do we
want to ignore for relocatable output?) */
@@ -781,9 +792,11 @@ add_keepsyms_file (const char *filename)
static bfd_boolean
add_archive_element (struct bfd_link_info *info,
bfd *abfd,
- const char *name)
+ const char *name,
+ bfd **subsbfd ATTRIBUTE_UNUSED)
{
lang_input_statement_type *input;
+ lang_input_statement_type orig_input;
input = (lang_input_statement_type *)
xcalloc (1, sizeof (lang_input_statement_type));
@@ -791,6 +804,52 @@ add_archive_element (struct bfd_link_info *info,
input->local_sym_name = abfd->filename;
input->the_bfd = abfd;
+ /* Save the original data for trace files/tries below, as plugins
+ (if enabled) may possibly alter it to point to a replacement
+ BFD, but we still want to output the original BFD filename. */
+ orig_input = *input;
+#ifdef ENABLE_PLUGINS
+ if (bfd_my_archive (abfd) != NULL)
+ {
+ /* We must offer this archive member to the plugins to claim. */
+ int fd = open (bfd_my_archive (abfd)->filename, O_RDONLY | O_BINARY);
+ if (fd >= 0)
+ {
+ struct ld_plugin_input_file file;
+ int claimed = 0;
+ /* Offset and filesize must refer to the individual archive
+ member, not the whole file, and must exclude the header.
+ Fortunately for us, that is how the data is stored in the
+ origin field of the bfd and in the arelt_data. */
+ file.name = bfd_my_archive (abfd)->filename;
+ file.offset = abfd->origin;
+ file.filesize = arelt_size (abfd);
+ file.fd = fd;
+ /* We create a dummy BFD, initially empty, to house
+ whatever symbols the plugin may want to add. */
+ file.handle = plugin_get_ir_dummy_bfd (abfd->filename, abfd);
+ if (plugin_call_claim_file (&file, &claimed))
+ einfo (_("%P%F: %s: plugin reported error claiming file\n"),
+ plugin_error_plugin ());
+ if (claimed)
+ {
+ /* Substitute the dummy BFD. */
+ input->the_bfd = file.handle;
+ input->claimed = TRUE;
+ bfd_make_readable (input->the_bfd);
+ *subsbfd = input->the_bfd;
+ }
+ else
+ {
+ /* Abandon the dummy BFD. */
+ bfd_close_all_done (file.handle);
+ close (fd);
+ input->claimed = FALSE;
+ }
+ }
+ }
+#endif /* ENABLE_PLUGINS */
+
ldlang_add_file (input);
if (config.map_file != NULL)
@@ -871,8 +930,7 @@ add_archive_element (struct bfd_link_info *info,
}
if (trace_files || trace_file_tries)
- info_msg ("%I\n", input);
-
+ info_msg ("%I\n", &orig_input);
return TRUE;
}
@@ -889,6 +947,17 @@ multiple_definition (struct bfd_link_info *info ATTRIBUTE_UNUSED,
asection *nsec,
bfd_vma nval)
{
+#ifdef ENABLE_PLUGINS
+ /* We may get called back even when --allow-multiple-definition is in
+ effect, as the plugin infrastructure needs to use this hook in
+ order to swap out IR-only symbols for real ones. In that case,
+ it will let us know not to continue by returning TRUE even if this
+ is not an IR-only vs. non-IR symbol conflict. */
+ if (plugin_multiple_definition (info, name, obfd, osec, oval, nbfd,
+ nsec, nval))
+ return TRUE;
+#endif /* ENABLE_PLUGINS */
+
/* If either section has the output_section field set to
bfd_abs_section_ptr, it means that the section is being
discarded, and this is not really a multiple definition at all.
@@ -1371,7 +1440,10 @@ unattached_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED,
/* This is called if link_info.notice_all is set, or when a symbol in
link_info.notice_hash is found. Symbols are put in notice_hash
- using the -y option. */
+ using the -y option, while notice_all is set if the --cref option
+ has been supplied, or if there are any NOCROSSREFS sections in the
+ linker script; and if plugins are active, since they need to monitor
+ all references from non-IR files. */
static bfd_boolean
notice (struct bfd_link_info *info,
@@ -1387,9 +1459,17 @@ notice (struct bfd_link_info *info,
return TRUE;
}
- if (! info->notice_all
- || (info->notice_hash != NULL
- && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
+#ifdef ENABLE_PLUGINS
+ /* We should hide symbols in the dummy IR BFDs from the nocrossrefs list
+ and let the real object files that are generated and added later trip
+ the error instead. Similarly would be better to trace the real symbol
+ from the real file than the temporary dummy. */
+ if (!plugin_notice (info, name, abfd, section, value))
+ return TRUE;
+#endif /* ENABLE_PLUGINS */
+
+ if (info->notice_hash != NULL
+ && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)
{
if (bfd_is_und_section (section))
einfo ("%B: reference to %s\n", abfd, name);