aboutsummaryrefslogtreecommitdiff
path: root/binutils/objcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/objcopy.c')
-rw-r--r--binutils/objcopy.c181
1 files changed, 115 insertions, 66 deletions
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index e2e6bd7..2e98ba4 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -30,6 +30,8 @@
#include "coff/internal.h"
#include "libcoff.h"
#include "safe-ctype.h"
+#include "plugin-api.h"
+#include "plugin.h"
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
header in generic PE code. */
@@ -165,6 +167,11 @@ static struct section_list *change_sections;
/* TRUE if some sections are to be removed. */
static bool sections_removed;
+#if BFD_SUPPORTS_PLUGINS
+/* TRUE if all GCC LTO sections are to be removed. */
+static bool lto_sections_removed;
+#endif
+
/* TRUE if only some sections are to be copied. */
static bool sections_copied;
@@ -359,6 +366,7 @@ enum command_line_switch
OPTION_RENAME_SECTION,
OPTION_REVERSE_BYTES,
OPTION_PE_SECTION_ALIGNMENT,
+ OPTION_PLUGIN,
OPTION_SET_SECTION_FLAGS,
OPTION_SET_SECTION_ALIGNMENT,
OPTION_SET_START,
@@ -402,6 +410,7 @@ static struct option strip_options[] =
{"output-file", required_argument, 0, 'o'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
+ {"plugin", required_argument, 0, OPTION_PLUGIN},
{"preserve-dates", no_argument, 0, 'p'},
{"remove-section", required_argument, 0, 'R'},
{"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
@@ -533,7 +542,9 @@ extern char *program_name;
/* This flag distinguishes between strip and objcopy:
1 means this is 'strip'; 0 means this is 'objcopy'.
-1 means if we should use argv[0] to decide. */
+#ifndef is_strip
extern int is_strip;
+#endif
/* The maximum length of an S record. This variable is defined in srec.c
and can be modified by the --srec-len parameter. */
@@ -756,6 +767,10 @@ strip_usage (FILE *stream, int exit_status)
--info List object formats & architectures supported\n\
-o <file> Place stripped output into <file>\n\
"));
+#if BFD_SUPPORTS_PLUGINS
+ fprintf (stream, _("\
+ --plugin NAME Load the specified plugin\n"));
+#endif
list_supported_targets (program_name, stream);
if (REPORT_BUGS_TO[0] && exit_status == 0)
@@ -1914,20 +1929,11 @@ add_redefine_syms_file (const char *filename)
Returns TRUE upon success, FALSE otherwise. */
static bool
-copy_unknown_object (bfd *ibfd, bfd *obfd)
+copy_unknown_file (bfd *ibfd, bfd *obfd, off_t size, unsigned int mode)
{
char *cbuf;
bfd_size_type tocopy;
- off_t size;
- struct stat buf;
-
- if (bfd_stat_arch_elt (ibfd, &buf) != 0)
- {
- bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
- return false;
- }
- size = buf.st_size;
if (size < 0)
{
non_fatal (_("stat returns negative size for `%s'"),
@@ -1972,11 +1978,31 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
/* We should at least to be able to read it back when copying an
unknown object in an archive. */
- chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
+ chmod (bfd_get_filename (obfd), mode | S_IRUSR);
free (cbuf);
return true;
}
+/* Copy unknown object file archive member IBFD onto OBFD.
+ Returns TRUE upon success, FALSE otherwise. */
+
+static bool
+copy_unknown_object (bfd *ibfd, bfd *obfd)
+{
+ struct stat buf;
+
+ if (bfd_stat_arch_elt (ibfd, &buf) != 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
+ return false;
+ }
+
+ if (!copy_unknown_file (ibfd, obfd, buf.st_size, buf.st_mode))
+ return false;
+
+ return true;
+}
+
typedef struct objcopy_internal_note
{
Elf_Internal_Note note;
@@ -2832,7 +2858,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
if (pe_file_alignment != (bfd_vma) -1)
pe->pe_opthdr.FileAlignment = pe_file_alignment;
- else
+ else if (!is_strip)
pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
if (pe_heap_commit != (bfd_vma) -1)
@@ -2846,7 +2872,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
if (pe_section_alignment != (bfd_vma) -1)
pe->pe_opthdr.SectionAlignment = pe_section_alignment;
- else
+ else if (!is_strip)
pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
if (pe_stack_commit != (bfd_vma) -1)
@@ -3742,6 +3768,12 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
goto cleanup_and_exit;
}
+#if BFD_SUPPORTS_PLUGINS
+ /* Copy LTO IR file as unknown object. */
+ if (bfd_plugin_target_p (this_element->xvec))
+ ok_object = false;
+ else
+#endif
if (ok_object)
{
ok = copy_object (this_element, output_element, input_arch);
@@ -3843,6 +3875,7 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
char **obj_matching;
char **core_matching;
off_t size = get_file_size (input_filename);
+ const char *target = input_target;
if (size < 1)
{
@@ -3853,9 +3886,16 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
return;
}
+#if BFD_SUPPORTS_PLUGINS
+ /* Enable LTO plugin in strip unless all LTO sections should be
+ removed. */
+ if (is_strip && !target && !lto_sections_removed)
+ target = "plugin";
+#endif
+
/* To allow us to do "strip *" without dying on the first
non-object file, failures are nonfatal. */
- ibfd = bfd_openr (input_filename, input_target);
+ ibfd = bfd_openr (input_filename, target);
if (ibfd == NULL || bfd_stat (ibfd, in_stat) != 0)
{
bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
@@ -3972,17 +4012,31 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
return;
}
- if (! copy_object (ibfd, obfd, input_arch))
- status = 1;
-
- /* PR 17512: file: 0f15796a.
- If the file could not be copied it may not be in a writeable
- state. So use bfd_close_all_done to avoid the possibility of
- writing uninitialised data into the file. */
- if (! (status ? bfd_close_all_done (obfd) : bfd_close (obfd)))
+#if BFD_SUPPORTS_PLUGINS
+ if (bfd_plugin_target_p (ibfd->xvec))
{
- status = 1;
- bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+ /* Copy LTO IR file as unknown file. */
+ if (!copy_unknown_file (ibfd, obfd, in_stat->st_size,
+ in_stat->st_mode))
+ status = 1;
+ else if (!bfd_close_all_done (obfd))
+ status = 1;
+ }
+ else
+#endif
+ {
+ if (! copy_object (ibfd, obfd, input_arch))
+ status = 1;
+
+ /* PR 17512: file: 0f15796a.
+ If the file could not be copied it may not be in a writeable
+ state. So use bfd_close_all_done to avoid the possibility of
+ writing uninitialised data into the file. */
+ if (! (status ? bfd_close_all_done (obfd) : bfd_close (obfd)))
+ {
+ status = 1;
+ bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+ }
}
if (!bfd_close (ibfd))
@@ -4112,29 +4166,6 @@ power_of_two (bfd_vma val)
return result;
}
-static unsigned int
-image_scn_align (unsigned int alignment)
-{
- switch (alignment)
- {
- case 8192: return IMAGE_SCN_ALIGN_8192BYTES;
- case 4096: return IMAGE_SCN_ALIGN_4096BYTES;
- case 2048: return IMAGE_SCN_ALIGN_2048BYTES;
- case 1024: return IMAGE_SCN_ALIGN_1024BYTES;
- case 512: return IMAGE_SCN_ALIGN_512BYTES;
- case 256: return IMAGE_SCN_ALIGN_256BYTES;
- case 128: return IMAGE_SCN_ALIGN_128BYTES;
- case 64: return IMAGE_SCN_ALIGN_64BYTES;
- case 32: return IMAGE_SCN_ALIGN_32BYTES;
- case 16: return IMAGE_SCN_ALIGN_16BYTES;
- case 8: return IMAGE_SCN_ALIGN_8BYTES;
- case 4: return IMAGE_SCN_ALIGN_4BYTES;
- case 2: return IMAGE_SCN_ALIGN_2BYTES;
- case 1: return IMAGE_SCN_ALIGN_1BYTES;
- default: return 0;
- }
-}
-
/* Create a section in OBFD with the same
name and attributes as ISECTION in IBFD. */
@@ -4300,24 +4331,9 @@ setup_section (bfd *ibfd, sec_ptr isection, bfd *obfd)
if (p != NULL)
alignment = p->alignment;
else if (pe_section_alignment != (bfd_vma) -1
- && bfd_get_flavour (ibfd) == bfd_target_coff_flavour
- && bfd_get_flavour (obfd) == bfd_target_coff_flavour)
- {
- alignment = power_of_two (pe_section_alignment);
-
- if (coff_section_data (ibfd, isection))
- {
- struct pei_section_tdata * pei_data = pei_section_data (ibfd, isection);
-
- if (pei_data != NULL)
- {
- /* Set the alignment flag of the input section, which will
- be copied to the output section later on. */
- pei_data->pe_flags &= ~IMAGE_SCN_ALIGN_POWER_BIT_MASK;
- pei_data->pe_flags |= image_scn_align (pe_section_alignment);
- }
- }
- }
+ && bfd_get_flavour (obfd) == bfd_target_coff_flavour
+ && bfd_pei_p (obfd))
+ alignment = power_of_two (pe_section_alignment);
else
alignment = bfd_section_alignment (isection);
@@ -4634,6 +4650,7 @@ copy_section (bfd *ibfd, sec_ptr isection, bfd *obfd)
char *to = (char *) memhunk;
char *end = (char *) memhunk + size;
int i;
+ bfd_size_type memhunk_size = size;
/* If the section address is not exactly divisible by the interleave,
then we must bias the from address. If the copy_byte is less than
@@ -4653,6 +4670,11 @@ copy_section (bfd *ibfd, sec_ptr isection, bfd *obfd)
}
size = (size + interleave - 1 - copy_byte) / interleave * copy_width;
+
+ /* Don't extend the output section size. */
+ if (size > memhunk_size)
+ size = memhunk_size;
+
osection->lma /= interleave;
if (copy_byte < extra)
osection->lma++;
@@ -4873,6 +4895,10 @@ strip_main (int argc, char *argv[])
char *output_file = NULL;
bool merge_notes_set = false;
+#if BFD_SUPPORTS_PLUGINS
+ bfd_plugin_set_program_name (argv[0]);
+#endif
+
while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
@@ -4963,6 +4989,13 @@ strip_main (int argc, char *argv[])
case OPTION_KEEP_SECTION_SYMBOLS:
keep_section_symbols = true;
break;
+ case OPTION_PLUGIN: /* --plugin */
+#if BFD_SUPPORTS_PLUGINS
+ bfd_plugin_set_plugin (optarg);
+#else
+ fatal (_("sorry - this program has been built without plugin support\n"));
+#endif
+ break;
case 0:
/* We've been given a long option. */
break;
@@ -5007,6 +5040,14 @@ strip_main (int argc, char *argv[])
if (output_target == NULL)
output_target = input_target;
+#if BFD_SUPPORTS_PLUGINS
+ /* Check if all GCC LTO sections should be removed, assuming all LTO
+ sections will be removed with -R .gnu.lto_.*. * Remove .gnu.lto_.*
+ sections will also remove .gnu.debuglto_. sections. */
+ lto_sections_removed = !!find_section_list (".gnu.lto_.*", false,
+ SECTION_CONTEXT_REMOVE);
+#endif
+
i = optind;
if (i == argc
|| (output_file != NULL && (i + 1) < argc))
@@ -5979,6 +6020,11 @@ copy_main (int argc, char *argv[])
case OPTION_FILE_ALIGNMENT:
pe_file_alignment = parse_vma (optarg, "--file-alignment");
+ if (power_of_two (pe_file_alignment) == -1)
+ {
+ non_fatal (_("--file-alignment argument is not a power of two: %s - ignoring"), optarg);
+ pe_file_alignment = (bfd_vma) -1;
+ }
break;
case OPTION_HEAP:
@@ -6222,9 +6268,11 @@ main (int argc, char *argv[])
fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
+#ifndef is_strip
if (is_strip < 0)
{
- int i = strlen (program_name);
+ size_t i = strlen (program_name);
+
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* Drop the .exe suffix, if any. */
if (i > 4 && FILENAME_CMP (program_name + i - 4, ".exe") == 0)
@@ -6235,6 +6283,7 @@ main (int argc, char *argv[])
#endif
is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0);
}
+#endif /* is_strip */
create_symbol_htabs ();
xatexit (delete_symbol_htabs);