aboutsummaryrefslogtreecommitdiff
path: root/bfd/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/format.c')
-rw-r--r--bfd/format.c186
1 files changed, 117 insertions, 69 deletions
diff --git a/bfd/format.c b/bfd/format.c
index a909b70..81f29c5 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -46,10 +46,7 @@ SUBSECTION
#include "sysdep.h"
#include "bfd.h"
#include "libbfd.h"
-#if BFD_SUPPORTS_PLUGINS
-#include "plugin-api.h"
#include "plugin.h"
-#endif
/* IMPORT from targets.c. */
extern const size_t _bfd_target_vector_entries;
@@ -367,9 +364,8 @@ struct lto_section
/* Set lto_type in ABFD. */
static void
-bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
+bfd_set_lto_type (bfd *abfd)
{
-#if BFD_SUPPORTS_PLUGINS
if (abfd->format == bfd_object
&& abfd->lto_type == lto_non_object
&& (abfd->flags
@@ -377,32 +373,52 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
| (bfd_get_flavour (abfd) == bfd_target_elf_flavour
? EXEC_P : 0))) == 0)
{
- asection *sec;
+ asection *sec = abfd->sections;
enum bfd_lto_object_type type = lto_non_ir_object;
- struct lto_section lsection = { 0, 0, 0, 0 };
- /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
- section. */
- for (sec = abfd->sections; sec != NULL; sec = sec->next)
- if (strcmp (sec->name, GNU_OBJECT_ONLY_SECTION_NAME) == 0)
- {
- type = lto_mixed_object;
- abfd->object_only_section = sec;
- break;
- }
- else if (lsection.major_version == 0
- && startswith (sec->name, ".gnu.lto_.lto.")
- && bfd_get_section_contents (abfd, sec, &lsection, 0,
- sizeof (struct lto_section)))
- {
- if (lsection.slim_object)
- type = lto_slim_ir_object;
- else
- type = lto_fat_ir_object;
+ if (sec == NULL)
+ {
+ /* If there are no sections, check for slim LLVM IR object whose
+ first 4 bytes are: 'B', 'C', 0xc0, 0xde. */
+ bfd_byte llvm_ir_magic[4];
+ if (bfd_seek (abfd, 0, SEEK_SET) == 0
+ && bfd_read (llvm_ir_magic, 4, abfd) == 4
+ && llvm_ir_magic[0] == 'B'
+ && llvm_ir_magic[1] == 'C'
+ && llvm_ir_magic[2] == 0xc0
+ && llvm_ir_magic[3] == 0xde)
+ type = lto_slim_ir_object;
+ }
+ else
+ {
+ struct lto_section lsection = { 0, 0, 0, 0 };
+ /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode
+ information section. */
+ for (; sec != NULL; sec = sec->next)
+ if (strcmp (sec->name, GNU_OBJECT_ONLY_SECTION_NAME) == 0)
+ {
+ type = lto_mixed_object;
+ abfd->object_only_section = sec;
+ break;
+ }
+ else if (strcmp (sec->name, ".llvm.lto") == 0)
+ {
+ type = lto_fat_ir_object;
+ break;
+ }
+ else if (lsection.major_version == 0
+ && startswith (sec->name, ".gnu.lto_.lto.")
+ && bfd_get_section_contents (abfd, sec, &lsection, 0,
+ sizeof (struct lto_section)))
+ {
+ if (lsection.slim_object)
+ type = lto_slim_ir_object;
+ else
+ type = lto_fat_ir_object;
}
+ }
abfd->lto_type = type;
}
-#endif
}
/*
@@ -415,10 +431,10 @@ SYNOPSIS
DESCRIPTION
Like <<bfd_check_format>>, except when it returns FALSE with
- <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that
- case, if @var{matching} is not NULL, it will be filled in with
- a NULL-terminated list of the names of the formats that matched,
- allocated with <<malloc>>.
+ <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>.
+ In that case, if @var{matching} is not NULL, it will be filled
+ in with a NULL-terminated list of the names of the formats
+ that matched, allocated with <<malloc>>.
Then the user may choose a format and try again.
When done with the list that @var{matching} points to, the caller
@@ -432,6 +448,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
const bfd_target * const *target;
const bfd_target **matching_vector = NULL;
const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ;
+ const bfd_target *fail_targ;
int match_count, best_count, best_match;
int ar_match_index;
unsigned int initial_section_id = _bfd_section_id;
@@ -452,10 +469,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
}
if (abfd->format != bfd_unknown)
- {
- bfd_set_lto_type (abfd);
- return abfd->format == format;
- }
+ return abfd->format == format;
if (matching != NULL || *bfd_associated_vector != NULL)
{
@@ -495,35 +509,69 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
if (!bfd_preserve_save (abfd, &preserve, NULL))
goto err_ret;
- /* If the target type was explicitly specified, just check that target. */
- if (!abfd->target_defaulted)
+ /* First try matching the plugin target if appropriate. Next try
+ the current target. The current target may have been set due to
+ a user option, or due to the linker trying optimistically to load
+ input files for the same target as the output. Either will
+ have target_defaulted false. Failing that, bfd_find_target will
+ have chosen a default target, and target_defaulted will be true. */
+ fail_targ = NULL;
+ if (bfd_plugin_enabled ()
+ && abfd->format == bfd_object
+ && abfd->target_defaulted
+ && !abfd->is_linker_input
+ && abfd->plugin_format != bfd_plugin_no)
{
- if (bfd_seek (abfd, 0, SEEK_SET) != 0) /* rewind! */
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0)
goto err_ret;
+ BFD_ASSERT (save_targ != bfd_plugin_vec ());
+ abfd->xvec = bfd_plugin_vec ();
+ bfd_set_error (bfd_error_no_error);
cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
-
if (cleanup)
goto ok_ret;
- /* For a long time the code has dropped through to check all
- targets if the specified target was wrong. I don't know why,
- and I'm reluctant to change it. However, in the case of an
- archive, it can cause problems. If the specified target does
- not permit archives (e.g., the binary target), then we should
- not allow some other target to recognize it as an archive, but
- should instead allow the specified target to recognize it as an
- object. When I first made this change, it broke the PE target,
- because the specified pei-i386 target did not recognize the
- actual pe-i386 archive. Since there may be other problems of
- this sort, I changed this test to check only for the binary
- target. */
- if (format == bfd_archive && save_targ == &binary_vec)
- goto err_unrecog;
+ bfd_reinit (abfd, initial_section_id, &preserve, cleanup);
+ bfd_release (abfd, preserve.marker);
+ preserve.marker = bfd_alloc (abfd, 1);
+ abfd->xvec = save_targ;
+ }
+
+ /* bfd_plugin_no excluding the plugin target is an optimisation.
+ The test can be removed if desired. */
+ if (!(abfd->plugin_format == bfd_plugin_no
+ && bfd_plugin_target_p (save_targ)))
+ {
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0)
+ goto err_ret;
+
+ bfd_set_error (bfd_error_no_error);
+ cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (cleanup)
+ {
+ if (abfd->format != bfd_archive
+ /* An archive with object files matching the archive
+ target is OK. Other archives should be further
+ tested. */
+ || (bfd_has_map (abfd)
+ && bfd_get_error () != bfd_error_wrong_object_format)
+ /* Empty archives can match the current target.
+ Attempting to read the armap will result in a file
+ truncated error. */
+ || (!bfd_has_map (abfd)
+ && bfd_get_error () == bfd_error_file_truncated))
+ goto ok_ret;
+ }
+ else
+ {
+ if (!abfd->target_defaulted && !abfd->is_linker_input)
+ goto err_unrecog;
+ fail_targ = save_targ;
+ }
}
- /* Since the target type was defaulted, check them all in the hope
- that one will be uniquely recognized. */
+ /* Check all targets in the hope that one will be recognized. */
right_targ = NULL;
ar_right_targ = NULL;
match_targ = NULL;
@@ -537,23 +585,22 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
void **high_water;
/* The binary target matches anything, so don't return it when
- searching. Don't match the plugin target if we have another
- alternative since we want to properly set the input format
- before allowing a plugin to claim the file. Also, don't
- check the default target twice. */
+ searching. Also, don't check the current target twice when
+ it has failed already.
+ Don't match the plugin target during linking if we have
+ another alternative since we want to properly set the input
+ format before allowing a plugin to claim the file.
+ Also as an optimisation don't match the plugin target when
+ abfd->plugin_format is set to bfd_plugin_no. (This occurs
+ when LTO sections have been stripped or when we have a
+ recursive call here from the plugin object_p via
+ bfd_plugin_get_symbols_in_object_only.) */
if (*target == &binary_vec
-#if BFD_SUPPORTS_PLUGINS
- || (match_count != 0 && bfd_plugin_target_p (*target))
-#endif
- || (!abfd->target_defaulted && *target == save_targ))
- continue;
-
-#if BFD_SUPPORTS_PLUGINS
- /* If the plugin target is explicitly specified when a BFD file
- is opened, don't check it twice. */
- if (bfd_plugin_specified_p () && bfd_plugin_target_p (*target))
+ || *target == fail_targ
+ || (((abfd->is_linker_input && match_count != 0)
+ || abfd->plugin_format == bfd_plugin_no)
+ && bfd_plugin_target_p (*target)))
continue;
-#endif
/* If we already tried a match, the bfd is modified and may
have sections attached, which will confuse the next
@@ -580,6 +627,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
if (bfd_seek (abfd, 0, SEEK_SET) != 0)
goto err_ret;
+ bfd_set_error (bfd_error_no_error);
cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
if (cleanup)
{