void plugin_maybe_claim (struct ld_plugin_input_file *file, lang_input_statement_type *entry) { int claimed = 0; /* We create a dummy BFD, initially empty, to house whatever symbols the plugin may want to add. */ file->handle = plugin_get_ir_dummy_bfd (entry->the_bfd->filename, entry->the_bfd); if (plugin_call_claim_file (file, &claimed)) einfo (_("%P%F: %s: plugin reported error claiming file\n"), plugin_error_plugin ()); /* fd belongs to us, not the plugin; but we don't need it. */ close (file->fd); if (claimed) { /* Discard the real file's BFD and substitute the dummy one. */ /* BFD archive handling caches elements so we can't call bfd_close for archives. */ if (entry->the_bfd->my_archive == NULL) bfd_close (entry->the_bfd); entry->the_bfd = file->handle; entry->flags.claimed = TRUE; bfd_make_readable (entry->the_bfd); } else { /* If plugin didn't claim the file, we don't need the dummy bfd. Can't avoid speculatively creating it, alas. */ bfd_close_all_done (file->handle); entry->flags.claimed = FALSE; } }
/* Call 'cleanup' hook for all plugins at exit. */ void plugin_call_cleanup (void) { plugin_t *curplug = plugins_list; while (curplug) { if (curplug->cleanup_handler && !curplug->cleanup_done) { enum ld_plugin_status rv; curplug->cleanup_done = TRUE; called_plugin = curplug; rv = (*curplug->cleanup_handler) (); called_plugin = NULL; if (rv != LDPS_OK) set_plugin_error (curplug->name); dlclose (curplug->dlhandle); } curplug = curplug->next; } if (plugin_error_p ()) info_msg (_("%P: %s: error in plugin cleanup (ignored)\n"), plugin_error_plugin ()); }
int main (int argc, char **argv) { char *emulation; long start_time = get_run_time (); #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) setlocale (LC_MESSAGES, ""); #endif #if defined (HAVE_SETLOCALE) setlocale (LC_CTYPE, ""); #endif bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); program_name = argv[0]; xmalloc_set_program_name (program_name); START_PROGRESS (program_name, 0); expandargv (&argc, &argv); bfd_init (); bfd_set_error_program_name (program_name); /* We want to notice and fail on those nasty BFD assertions which are likely to signal incorrect output being generated but otherwise may leave no trace. */ default_bfd_assert_handler = bfd_set_assert_handler (ld_bfd_assert_handler); xatexit (ld_cleanup); /* Set up the sysroot directory. */ ld_sysroot = get_sysroot (argc, argv); if (*ld_sysroot) { if (*TARGET_SYSTEM_ROOT == 0) { einfo ("%P%F: this linker was not configured to use sysroots\n"); ld_sysroot = ""; } else ld_canon_sysroot = lrealpath (ld_sysroot); } if (ld_canon_sysroot) ld_canon_sysroot_len = strlen (ld_canon_sysroot); else ld_canon_sysroot_len = -1; /* Set the default BFD target based on the configured target. Doing this permits the linker to be configured for a particular target, and linked against a shared BFD library which was configured for a different target. The macro TARGET is defined by Makefile. */ if (! bfd_set_default_target (TARGET)) { einfo (_("%X%P: can't set BFD default target to `%s': %E\n"), TARGET); xexit (1); } #if YYDEBUG { extern int yydebug; yydebug = 1; } #endif config.build_constructors = TRUE; config.rpath_separator = ':'; config.split_by_reloc = (unsigned) -1; config.split_by_file = (bfd_size_type) -1; config.make_executable = TRUE; config.magic_demand_paged = TRUE; config.text_read_only = TRUE; command_line.warn_mismatch = TRUE; command_line.warn_search_mismatch = TRUE; command_line.check_section_addresses = -1; command_line.disable_target_specific_optimizations = -1; /* We initialize DEMANGLING based on the environment variable COLLECT_NO_DEMANGLE. The gcc collect2 program will demangle the output of the linker, unless COLLECT_NO_DEMANGLE is set in the environment. Acting the same way here lets us provide the same interface by default. */ demangling = getenv ("COLLECT_NO_DEMANGLE") == NULL; link_info.allow_undefined_version = TRUE; link_info.keep_memory = TRUE; link_info.combreloc = TRUE; link_info.strip_discarded = TRUE; link_info.emit_hash = TRUE; link_info.callbacks = &link_callbacks; link_info.input_bfds_tail = &link_info.input_bfds; /* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init and _fini symbols. We are compatible. */ link_info.init_function = "_init"; link_info.fini_function = "_fini"; link_info.relax_pass = 1; link_info.pei386_auto_import = -1; link_info.spare_dynamic_tags = 5; link_info.path_separator = ':'; ldfile_add_arch (""); emulation = get_emulation (argc, argv); ldemul_choose_mode (emulation); default_target = ldemul_choose_target (argc, argv); config.maxpagesize = bfd_emul_get_maxpagesize (default_target); config.commonpagesize = bfd_emul_get_commonpagesize (default_target); lang_init (); ldemul_before_parse (); lang_has_input_file = FALSE; parse_args (argc, argv); if (config.hash_table_size != 0) bfd_hash_set_default_size (config.hash_table_size); #ifdef ENABLE_PLUGINS /* Now all the plugin arguments have been gathered, we can load them. */ if (plugin_load_plugins ()) einfo (_("%P%F: %s: error loading plugin\n"), plugin_error_plugin ()); #endif /* ENABLE_PLUGINS */ ldemul_set_symbols (); /* If we have not already opened and parsed a linker script, try the default script from command line first. */ if (saved_script_handle == NULL && command_line.default_script != NULL) { ldfile_open_command_file (command_line.default_script); parser_input = input_script; yyparse (); } /* If we have not already opened and parsed a linker script read the emulation's appropriate default script. */ if (saved_script_handle == NULL) { int isfile; char *s = ldemul_get_script (&isfile); if (isfile) ldfile_open_default_command_file (s); else { lex_string = s; lex_redirect (s, _("built in linker script"), 1); } parser_input = input_script; yyparse (); lex_string = NULL; } if (verbose) { if (saved_script_handle) info_msg (_("using external linker script:")); else info_msg (_("using internal linker script:")); info_msg ("\n==================================================\n"); if (saved_script_handle) { static const int ld_bufsz = 8193; size_t n; char *buf = (char *) xmalloc (ld_bufsz); rewind (saved_script_handle); while ((n = fread (buf, 1, ld_bufsz - 1, saved_script_handle)) > 0) { buf[n] = 0; info_msg (buf); } rewind (saved_script_handle); free (buf); } else { int isfile; info_msg (ldemul_get_script (&isfile)); } info_msg ("\n==================================================\n"); } if (command_line.print_output_format) info_msg ("%s\n", lang_get_output_target ()); lang_final (); if (!lang_has_input_file) { if (version_printed || command_line.print_output_format) xexit (0); einfo (_("%P%F: no input files\n")); } if (trace_files) info_msg (_("%P: mode %s\n"), emulation); ldemul_after_parse (); if (config.map_filename) { if (strcmp (config.map_filename, "-") == 0) { config.map_file = stdout; } else { config.map_file = fopen (config.map_filename, FOPEN_WT); if (config.map_file == (FILE *) NULL) { bfd_set_error (bfd_error_system_call); einfo (_("%P%F: cannot open map file %s: %E\n"), config.map_filename); } } } lang_process (); /* Print error messages for any missing symbols, for any warning symbols, and possibly multiple definitions. */ if (link_info.relocatable) link_info.output_bfd->flags &= ~EXEC_P; else link_info.output_bfd->flags |= EXEC_P; ldwrite (); if (config.map_file != NULL) lang_map (); if (command_line.cref) output_cref (config.map_file != NULL ? config.map_file : stdout); if (nocrossref_list != NULL) check_nocrossrefs (); lang_finish (); /* 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?) */ if (!config.make_executable && !force_make_executable) { if (trace_files) einfo (_("%P: link errors found, deleting executable `%s'\n"), output_filename); /* The file will be removed by ld_cleanup. */ xexit (1); } else { if (! bfd_close (link_info.output_bfd)) einfo (_("%F%B: final close failed: %E\n"), link_info.output_bfd); /* If the --force-exe-suffix is enabled, and we're making an executable file and it doesn't end in .exe, copy it to one which does. */ if (! link_info.relocatable && command_line.force_exe_suffix) { int len = strlen (output_filename); if (len < 4 || (strcasecmp (output_filename + len - 4, ".exe") != 0 && strcasecmp (output_filename + len - 4, ".dll") != 0)) { FILE *src; FILE *dst; const int bsize = 4096; char *buf = (char *) xmalloc (bsize); int l; char *dst_name = (char *) xmalloc (len + 5); strcpy (dst_name, output_filename); strcat (dst_name, ".exe"); src = fopen (output_filename, FOPEN_RB); dst = fopen (dst_name, FOPEN_WB); if (!src) einfo (_("%X%P: unable to open for source of copy `%s'\n"), output_filename); if (!dst) einfo (_("%X%P: unable to open for destination of copy `%s'\n"), dst_name); while ((l = fread (buf, 1, bsize, src)) > 0) { int done = fwrite (buf, 1, l, dst); if (done != l) einfo (_("%P: Error writing file `%s'\n"), dst_name); } fclose (src); if (fclose (dst) == EOF) einfo (_("%P: Error closing file `%s'\n"), dst_name); free (dst_name); free (buf); } } } END_PROGRESS (program_name); if (config.stats) { #ifdef HAVE_SBRK char *lim = (char *) sbrk (0); #endif long run_time = get_run_time () - start_time; fflush (stdout); fprintf (stderr, _("%s: total time in link: %ld.%06ld\n"), program_name, run_time / 1000000, run_time % 1000000); #ifdef HAVE_SBRK fprintf (stderr, _("%s: data size %ld\n"), program_name, (long) (lim - (char *) &environ)); #endif fflush (stderr); } /* Prevent ld_cleanup from doing anything, after a successful link. */ output_filename = NULL; xexit (0); return 0; }
static const bfd_target * plugin_object_p (bfd *ibfd) { int claimed; plugin_input_file_t *input; struct ld_plugin_input_file file; bfd *abfd; /* Don't try the dummy object file. */ if ((ibfd->flags & BFD_PLUGIN) != 0) return NULL; if (ibfd->plugin_format != bfd_plugin_unknown) { if (ibfd->plugin_format == bfd_plugin_yes) return ibfd->plugin_dummy_bfd->xvec; else return NULL; } /* We create a dummy BFD, initially empty, to house whatever symbols the plugin may want to add. */ abfd = plugin_get_ir_dummy_bfd (ibfd->filename, ibfd); input = bfd_alloc (abfd, sizeof (*input)); if (input == NULL) einfo (_("%P%F: plugin failed to allocate memory for input: %s\n"), bfd_get_error ()); if (!bfd_plugin_open_input (ibfd, &file)) return NULL; if (file.name == ibfd->filename) { /* We must copy filename attached to ibfd if it is not an archive member since it may be freed by bfd_close below. */ file.name = plugin_strdup (abfd, file.name); } file.handle = input; /* The plugin API expects that the file descriptor won't be closed and reused as done by the bfd file cache. So dup one. */ file.fd = dup (file.fd); if (file.fd < 0) return NULL; input->abfd = abfd; input->view_buffer.addr = NULL; input->view_buffer.filesize = 0; input->view_buffer.offset = 0; input->fd = file.fd; input->use_mmap = FALSE; input->offset = file.offset; input->filesize = file.filesize; input->name = plugin_strdup (abfd, ibfd->filename); claimed = 0; if (plugin_call_claim_file (&file, &claimed)) einfo (_("%P%F: %s: plugin reported error claiming file\n"), plugin_error_plugin ()); if (input->fd != -1 && !bfd_plugin_target_p (ibfd->xvec)) { /* FIXME: fd belongs to us, not the plugin. GCC plugin, which doesn't need fd after plugin_call_claim_file, doesn't use BFD plugin target vector. Since GCC plugin doesn't call release_input_file, we close it here. LLVM plugin, which needs fd after plugin_call_claim_file and calls release_input_file after it is done, uses BFD plugin target vector. This scheme doesn't work when a plugin needs fd and doesn't use BFD plugin target vector neither. */ close (input->fd); input->fd = -1; } if (claimed) { ibfd->plugin_format = bfd_plugin_yes; ibfd->plugin_dummy_bfd = abfd; bfd_make_readable (abfd); return abfd->xvec; } else { #if HAVE_MMAP if (input->use_mmap) { /* If plugin didn't claim the file, unmap the buffer. */ char *addr = input->view_buffer.addr; off_t size = input->view_buffer.filesize; # if HAVE_GETPAGESIZE off_t bias = input->view_buffer.offset % plugin_pagesize; size += bias; addr -= bias; # endif munmap (addr, size); } #endif /* If plugin didn't claim the file, we don't need the dummy bfd. Can't avoid speculatively creating it, alas. */ ibfd->plugin_format = bfd_plugin_no; bfd_close_all_done (abfd); return NULL; } }
static const bfd_target * plugin_object_p (bfd *ibfd) { int claimed; plugin_input_file_t *input; off_t offset, filesize; struct ld_plugin_input_file file; bfd *abfd; bfd_boolean inarchive; const char *name; int fd; /* Don't try the dummy object file. */ if ((ibfd->flags & BFD_PLUGIN) != 0) return NULL; if (ibfd->plugin_format != bfd_plugin_uknown) { if (ibfd->plugin_format == bfd_plugin_yes) return ibfd->plugin_dummy_bfd->xvec; else return NULL; } inarchive = bfd_my_archive (ibfd) != NULL; name = inarchive ? bfd_my_archive (ibfd)->filename : ibfd->filename; fd = open (name, O_RDONLY | O_BINARY); if (fd < 0) return NULL; /* We create a dummy BFD, initially empty, to house whatever symbols the plugin may want to add. */ abfd = plugin_get_ir_dummy_bfd (ibfd->filename, ibfd); input = bfd_alloc (abfd, sizeof (*input)); if (input == NULL) einfo (_("%P%F: plugin failed to allocate memory for input: %s\n"), bfd_get_error ()); if (inarchive) { /* 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. */ offset = ibfd->origin; filesize = arelt_size (ibfd); } else { offset = 0; filesize = lseek (fd, 0, SEEK_END); /* We must copy filename attached to ibfd if it is not an archive member since it may be freed by bfd_close below. */ name = plugin_strdup (abfd, name); } file.name = name; file.offset = offset; file.filesize = filesize; file.fd = fd; file.handle = input; input->abfd = abfd; input->view_buffer.addr = NULL; input->view_buffer.filesize = 0; input->view_buffer.offset = 0; input->fd = fd; input->use_mmap = FALSE; input->offset = offset; input->filesize = filesize; input->name = plugin_strdup (abfd, ibfd->filename); claimed = 0; if (plugin_call_claim_file (&file, &claimed)) einfo (_("%P%F: %s: plugin reported error claiming file\n"), plugin_error_plugin ()); if (input->fd != -1 && ! bfd_plugin_target_p (ibfd->xvec)) { /* FIXME: fd belongs to us, not the plugin. GCC plugin, which doesn't need fd after plugin_call_claim_file, doesn't use BFD plugin target vector. Since GCC plugin doesn't call release_input_file, we close it here. LLVM plugin, which needs fd after plugin_call_claim_file and calls release_input_file after it is done, uses BFD plugin target vector. This scheme doesn't work when a plugin needs fd and doesn't use BFD plugin target vector neither. */ close (fd); input->fd = -1; } if (claimed) { ibfd->plugin_format = bfd_plugin_yes; ibfd->plugin_dummy_bfd = abfd; bfd_make_readable (abfd); return abfd->xvec; } else { #if HAVE_MMAP if (input->use_mmap) { /* If plugin didn't claim the file, unmap the buffer. */ char *addr = input->view_buffer.addr; off_t size = input->view_buffer.filesize; # if HAVE_GETPAGESIZE off_t bias = input->view_buffer.offset % plugin_pagesize; size += bias; addr -= bias; # endif munmap (addr, size); } #endif /* If plugin didn't claim the file, we don't need the dummy bfd. Can't avoid speculatively creating it, alas. */ ibfd->plugin_format = bfd_plugin_no; bfd_close_all_done (abfd); return NULL; } }