Rev 5199 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5199 | Rev 6324 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* Plugin control for the GNU linker. |
1 | /* Plugin control for the GNU linker. |
2 | Copyright 2010, 2011, 2012, 2013 Free Software Foundation, Inc. |
2 | Copyright (C) 2010-2015 Free Software Foundation, Inc. |
Line 3... | Line 3... | ||
3 | 3 | ||
Line 4... | Line 4... | ||
4 | This file is part of the GNU Binutils. |
4 | This file is part of the GNU Binutils. |
5 | 5 | ||
Line 19... | Line 19... | ||
19 | MA 02110-1301, USA. */ |
19 | MA 02110-1301, USA. */ |
Line 20... | Line 20... | ||
20 | 20 | ||
21 | #include "sysdep.h" |
21 | #include "sysdep.h" |
22 | #include "libiberty.h" |
22 | #include "libiberty.h" |
- | 23 | #include "bfd.h" |
|
23 | #include "bfd.h" |
24 | #include "libbfd.h" |
24 | #include "bfdlink.h" |
25 | #include "bfdlink.h" |
25 | #include "bfdver.h" |
26 | #include "bfdver.h" |
26 | #include "ld.h" |
27 | #include "ld.h" |
27 | #include "ldmain.h" |
28 | #include "ldmain.h" |
28 | #include "ldmisc.h" |
29 | #include "ldmisc.h" |
29 | #include "ldexp.h" |
30 | #include "ldexp.h" |
30 | #include "ldlang.h" |
31 | #include "ldlang.h" |
- | 32 | #include "ldfile.h" |
|
31 | #include "ldfile.h" |
33 | #include "../bfd/plugin.h" |
32 | #include "plugin.h" |
34 | #include "plugin.h" |
33 | #include "plugin-api.h" |
35 | #include "plugin-api.h" |
34 | #include "elf-bfd.h" |
36 | #include "elf-bfd.h" |
35 | #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) |
37 | #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) |
Line 70... | Line 72... | ||
70 | ld_plugin_cleanup_handler cleanup_handler; |
72 | ld_plugin_cleanup_handler cleanup_handler; |
71 | /* TRUE if the cleanup handlers have been called. */ |
73 | /* TRUE if the cleanup handlers have been called. */ |
72 | bfd_boolean cleanup_done; |
74 | bfd_boolean cleanup_done; |
73 | } plugin_t; |
75 | } plugin_t; |
Line -... | Line 76... | ||
- | 76 | ||
- | 77 | typedef struct view_buffer |
|
- | 78 | { |
|
- | 79 | char *addr; |
|
- | 80 | size_t filesize; |
|
- | 81 | off_t offset; |
|
- | 82 | } view_buffer_t; |
|
- | 83 | ||
- | 84 | /* The internal version of struct ld_plugin_input_file with a BFD |
|
- | 85 | pointer. */ |
|
- | 86 | typedef struct plugin_input_file |
|
- | 87 | { |
|
- | 88 | bfd *abfd; |
|
- | 89 | view_buffer_t view_buffer; |
|
- | 90 | char *name; |
|
- | 91 | int fd; |
|
- | 92 | bfd_boolean use_mmap; |
|
- | 93 | off_t offset; |
|
- | 94 | off_t filesize; |
|
- | 95 | } plugin_input_file_t; |
|
74 | 96 | ||
75 | /* The master list of all plugins. */ |
97 | /* The master list of all plugins. */ |
Line 76... | Line 98... | ||
76 | static plugin_t *plugins_list = NULL; |
98 | static plugin_t *plugins_list = NULL; |
77 | 99 | ||
Line 112... | Line 134... | ||
112 | LDPT_REGISTER_CLAIM_FILE_HOOK, |
134 | LDPT_REGISTER_CLAIM_FILE_HOOK, |
113 | LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, |
135 | LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, |
114 | LDPT_REGISTER_CLEANUP_HOOK, |
136 | LDPT_REGISTER_CLEANUP_HOOK, |
115 | LDPT_ADD_SYMBOLS, |
137 | LDPT_ADD_SYMBOLS, |
116 | LDPT_GET_INPUT_FILE, |
138 | LDPT_GET_INPUT_FILE, |
- | 139 | LDPT_GET_VIEW, |
|
117 | LDPT_RELEASE_INPUT_FILE, |
140 | LDPT_RELEASE_INPUT_FILE, |
118 | LDPT_GET_SYMBOLS, |
141 | LDPT_GET_SYMBOLS, |
119 | LDPT_GET_SYMBOLS_V2, |
142 | LDPT_GET_SYMBOLS_V2, |
120 | LDPT_ADD_INPUT_FILE, |
143 | LDPT_ADD_INPUT_FILE, |
121 | LDPT_ADD_INPUT_LIBRARY, |
144 | LDPT_ADD_INPUT_LIBRARY, |
Line 125... | Line 148... | ||
125 | /* How many entries in the constant leading part of the tv array. */ |
148 | /* How many entries in the constant leading part of the tv array. */ |
126 | static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags); |
149 | static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags); |
Line 127... | Line 150... | ||
127 | 150 | ||
128 | /* Forward references. */ |
151 | /* Forward references. */ |
- | 152 | static bfd_boolean plugin_notice (struct bfd_link_info *, |
|
129 | static bfd_boolean plugin_notice (struct bfd_link_info *, |
153 | struct bfd_link_hash_entry *, |
130 | struct bfd_link_hash_entry *, bfd *, |
154 | struct bfd_link_hash_entry *, |
- | 155 | bfd *, asection *, bfd_vma, flagword); |
|
- | 156 | ||
Line 131... | Line 157... | ||
131 | asection *, bfd_vma, flagword, const char *); |
157 | static const bfd_target * plugin_object_p (bfd *); |
Line 132... | Line 158... | ||
132 | 158 | ||
Line 215... | Line 241... | ||
215 | plugin_arg_t *newarg; |
241 | plugin_arg_t *newarg; |
Line 216... | Line 242... | ||
216 | 242 | ||
217 | if (!last_plugin) |
243 | if (!last_plugin) |
Line -... | Line 244... | ||
- | 244 | return set_plugin_error (_(" |
|
- | 245 | ||
- | 246 | /* Ignore -pass-through= from GCC driver. */ |
|
- | 247 | if (*arg == '-') |
|
- | 248 | { |
|
- | 249 | const char *p = arg + 1; |
|
- | 250 | ||
- | 251 | if (*p == '-') |
|
- | 252 | ++p; |
|
- | 253 | if (strncmp (p, "pass-through=", 13) == 0) |
|
- | 254 | return 0; |
|
218 | return set_plugin_error (_(" |
255 | } |
219 | 256 | ||
220 | newarg = xmalloc (sizeof *newarg); |
257 | newarg = xmalloc (sizeof *newarg); |
Line 221... | Line 258... | ||
221 | newarg->arg = arg; |
258 | newarg->arg = arg; |
Line 226... | Line 263... | ||
226 | last_plugin_args_tail_chain_ptr = &newarg->next; |
263 | last_plugin_args_tail_chain_ptr = &newarg->next; |
227 | last_plugin->n_args++; |
264 | last_plugin->n_args++; |
228 | return 0; |
265 | return 0; |
229 | } |
266 | } |
Line 230... | Line 267... | ||
230 | 267 | ||
- | 268 | /* Generate a dummy BFD to represent an IR file, for any callers of |
|
- | 269 | plugin_call_claim_file to use as the handle in the ld_plugin_input_file |
|
- | 270 | struct that they build to pass in. The BFD is initially writable, so |
|
- | 271 | that symbols can be added to it; it must be made readable after the |
|
231 | /* Create a dummy BFD. */ |
272 | add_symbols hook has been called so that it can be read when linking. */ |
232 | bfd * |
273 | static bfd * |
233 | plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) |
274 | plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) |
234 | { |
275 | { |
- | 276 | bfd *abfd; |
|
Line 235... | Line 277... | ||
235 | bfd *abfd; |
277 | bfd_boolean bfd_plugin_target; |
- | 278 | ||
236 | 279 | bfd_use_reserved_id = 1; |
|
237 | bfd_use_reserved_id = 1; |
280 | bfd_plugin_target = bfd_plugin_target_p (srctemplate->xvec); |
238 | abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL), |
281 | abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL), |
239 | srctemplate); |
282 | bfd_plugin_target ? link_info.output_bfd : srctemplate); |
240 | if (abfd != NULL) |
283 | if (abfd != NULL) |
- | 284 | { |
|
- | 285 | abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN; |
|
- | 286 | if (!bfd_make_writable (abfd)) |
|
- | 287 | goto report_error; |
|
241 | { |
288 | if (!bfd_plugin_target) |
242 | abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN; |
289 | { |
243 | bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); |
- | |
244 | bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); |
290 | bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); |
- | 291 | bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); |
|
- | 292 | if (!bfd_copy_private_bfd_data (srctemplate, abfd)) |
|
245 | if (bfd_make_writable (abfd) |
293 | goto report_error; |
246 | && bfd_copy_private_bfd_data (srctemplate, abfd)) |
294 | } |
Line 247... | Line 295... | ||
247 | { |
295 | { |
248 | flagword flags; |
296 | flagword flags; |
249 | 297 | ||
250 | /* Create section to own the symbols. */ |
298 | /* Create section to own the symbols. */ |
251 | flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY |
299 | flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY |
252 | | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE); |
300 | | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE); |
253 | if (bfd_make_section_anyway_with_flags (abfd, ".text", flags)) |
301 | if (bfd_make_section_anyway_with_flags (abfd, ".text", flags)) |
- | 302 | return abfd; |
|
254 | return abfd; |
303 | } |
255 | } |
304 | } |
256 | } |
305 | report_error: |
Line 257... | Line 306... | ||
257 | einfo (_("could not create dummy IR bfd: %F%E\n")); |
306 | einfo (_("could not create dummy IR bfd: %F%E\n")); |
258 | return NULL; |
307 | return NULL; |
259 | } |
308 | } |
260 | 309 | ||
261 | /* Check if the BFD passed in is an IR dummy object file. */ |
310 | /* Check if the BFD passed in is an IR dummy object file. */ |
262 | static bfd_boolean |
311 | static inline bfd_boolean |
263 | is_ir_dummy_bfd (const bfd *abfd) |
312 | is_ir_dummy_bfd (const bfd *abfd) |
264 | { |
- | |
265 | /* ABFD can sometimes legitimately be NULL, e.g. when called from one |
- | |
266 | of the linker callbacks for a symbol in the *ABS* or *UND* sections. |
- | |
267 | Likewise, the usrdata field may be NULL if ABFD was added by the |
- | |
268 | backend without a corresponding input statement, as happens e.g. |
- | |
269 | when processing DT_NEEDED dependencies. */ |
313 | { |
Line 270... | Line 314... | ||
270 | return (abfd |
314 | /* ABFD can sometimes legitimately be NULL, e.g. when called from one |
271 | && abfd->usrdata |
315 | of the linker callbacks for a symbol in the *ABS* or *UND* sections. */ |
272 | && ((lang_input_statement_type *)(abfd->usrdata))->flags.claimed); |
316 | return abfd != NULL && (abfd->flags & BFD_PLUGIN) != 0; |
Line 404... | Line 448... | ||
404 | /* Add symbols from a plugin-claimed input file. */ |
448 | /* Add symbols from a plugin-claimed input file. */ |
405 | static enum ld_plugin_status |
449 | static enum ld_plugin_status |
406 | add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms) |
450 | add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms) |
407 | { |
451 | { |
408 | asymbol **symptrs; |
452 | asymbol **symptrs; |
- | 453 | plugin_input_file_t *input = handle; |
|
409 | bfd *abfd = handle; |
454 | bfd *abfd = input->abfd; |
410 | int n; |
455 | int n; |
Line 411... | Line 456... | ||
411 | 456 | ||
412 | ASSERT (called_plugin); |
457 | ASSERT (called_plugin); |
413 | symptrs = xmalloc (nsyms * sizeof *symptrs); |
458 | symptrs = xmalloc (nsyms * sizeof *symptrs); |
Line 427... | Line 472... | ||
427 | } |
472 | } |
Line 428... | Line 473... | ||
428 | 473 | ||
429 | /* Get the input file information with an open (possibly re-opened) |
474 | /* Get the input file information with an open (possibly re-opened) |
430 | file descriptor. */ |
475 | file descriptor. */ |
431 | static enum ld_plugin_status |
476 | static enum ld_plugin_status |
- | 477 | get_input_file (const void *handle, struct ld_plugin_input_file *file) |
|
432 | get_input_file (const void *handle ATTRIBUTE_UNUSED, |
478 | { |
- | 479 | const plugin_input_file_t *input = handle; |
|
- | 480 | ||
- | 481 | ASSERT (called_plugin); |
|
- | 482 | ||
- | 483 | file->name = input->name; |
|
- | 484 | file->offset = input->offset; |
|
- | 485 | file->filesize = input->filesize; |
|
- | 486 | file->handle = (void *) handle; |
|
- | 487 | ||
- | 488 | return LDPS_OK; |
|
- | 489 | } |
|
- | 490 | ||
- | 491 | /* Get view of the input file. */ |
|
- | 492 | static enum ld_plugin_status |
|
433 | struct ld_plugin_input_file *file ATTRIBUTE_UNUSED) |
493 | get_view (const void *handle, const void **viewp) |
434 | { |
494 | { |
435 | ASSERT (called_plugin); |
495 | ASSERT (called_plugin); |
436 | return LDPS_ERR; |
496 | return LDPS_ERR; |
Line 437... | Line 497... | ||
437 | } |
497 | } |
438 | 498 | ||
439 | /* Release the input file. */ |
499 | /* Release the input file. */ |
440 | static enum ld_plugin_status |
500 | static enum ld_plugin_status |
441 | release_input_file (const void *handle ATTRIBUTE_UNUSED) |
501 | release_input_file (const void *handle) |
442 | { |
502 | { |
443 | ASSERT (called_plugin); |
503 | ASSERT (called_plugin); |
Line 450... | Line 510... | ||
450 | is_visible_from_outside (struct ld_plugin_symbol *lsym, |
510 | is_visible_from_outside (struct ld_plugin_symbol *lsym, |
451 | struct bfd_link_hash_entry *blhe) |
511 | struct bfd_link_hash_entry *blhe) |
452 | { |
512 | { |
453 | struct bfd_sym_chain *sym; |
513 | struct bfd_sym_chain *sym; |
Line 454... | Line 514... | ||
454 | 514 | ||
455 | if (link_info.relocatable) |
515 | if (bfd_link_relocatable (&link_info)) |
456 | return TRUE; |
516 | return TRUE; |
457 | if (link_info.export_dynamic || !link_info.executable) |
517 | if (link_info.export_dynamic || bfd_link_dll (&link_info)) |
458 | { |
518 | { |
459 | /* Check if symbol is hidden by version script. */ |
519 | /* Check if symbol is hidden by version script. */ |
460 | if (bfd_hide_sym_by_version (link_info.version_info, |
520 | if (bfd_hide_sym_by_version (link_info.version_info, |
461 | blhe->root.string)) |
521 | blhe->root.string)) |
Line 492... | Line 552... | ||
492 | /* Get the symbol resolution info for a plugin-claimed input file. */ |
552 | /* Get the symbol resolution info for a plugin-claimed input file. */ |
493 | static enum ld_plugin_status |
553 | static enum ld_plugin_status |
494 | get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, |
554 | get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, |
495 | int def_ironly_exp) |
555 | int def_ironly_exp) |
496 | { |
556 | { |
- | 557 | const plugin_input_file_t *input = handle; |
|
497 | const bfd *abfd = handle; |
558 | const bfd *abfd = (const bfd *) input->abfd; |
498 | int n; |
559 | int n; |
Line 499... | Line 560... | ||
499 | 560 | ||
500 | ASSERT (called_plugin); |
561 | ASSERT (called_plugin); |
501 | for (n = 0; n < nsyms; n++) |
562 | for (n = 0; n < nsyms; n++) |
Line 610... | Line 671... | ||
610 | 671 | ||
611 | /* Add a new (real) input file generated by a plugin. */ |
672 | /* Add a new (real) input file generated by a plugin. */ |
612 | static enum ld_plugin_status |
673 | static enum ld_plugin_status |
613 | add_input_file (const char *pathname) |
674 | add_input_file (const char *pathname) |
- | 675 | { |
|
- | 676 | lang_input_statement_type *is; |
|
614 | { |
677 | |
615 | ASSERT (called_plugin); |
678 | ASSERT (called_plugin); |
616 | if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum, |
679 | is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum, |
- | 680 | NULL); |
|
617 | NULL)) |
681 | if (!is) |
- | 682 | return LDPS_ERR; |
|
618 | return LDPS_ERR; |
683 | is->flags.lto_output = 1; |
619 | return LDPS_OK; |
684 | return LDPS_OK; |
Line 620... | Line 685... | ||
620 | } |
685 | } |
621 | 686 | ||
622 | /* Add a new (real) library required by a plugin. */ |
687 | /* Add a new (real) library required by a plugin. */ |
623 | static enum ld_plugin_status |
688 | static enum ld_plugin_status |
- | 689 | add_input_library (const char *pathname) |
|
- | 690 | { |
|
624 | add_input_library (const char *pathname) |
691 | lang_input_statement_type *is; |
625 | { |
692 | |
626 | ASSERT (called_plugin); |
693 | ASSERT (called_plugin); |
- | 694 | is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum, |
|
627 | if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum, |
695 | NULL); |
- | 696 | if (!is) |
|
628 | NULL)) |
697 | return LDPS_ERR; |
629 | return LDPS_ERR; |
698 | is->flags.lto_output = 1; |
Line 630... | Line 699... | ||
630 | return LDPS_OK; |
699 | return LDPS_OK; |
631 | } |
700 | } |
Line 652... | Line 721... | ||
652 | case LDPL_INFO: |
721 | case LDPL_INFO: |
653 | vfinfo (stdout, format, args, FALSE); |
722 | vfinfo (stdout, format, args, FALSE); |
654 | putchar ('\n'); |
723 | putchar ('\n'); |
655 | break; |
724 | break; |
656 | case LDPL_WARNING: |
725 | case LDPL_WARNING: |
- | 726 | { |
|
- | 727 | char *newfmt = ACONCAT (("%P: warning: ", format, "\n", |
|
- | 728 | (const char *) NULL)); |
|
657 | vfinfo (stdout, format, args, TRUE); |
729 | vfinfo (stdout, newfmt, args, TRUE); |
658 | putchar ('\n'); |
730 | } |
659 | break; |
731 | break; |
660 | case LDPL_FATAL: |
732 | case LDPL_FATAL: |
661 | case LDPL_ERROR: |
733 | case LDPL_ERROR: |
662 | default: |
734 | default: |
663 | { |
735 | { |
664 | char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ", |
736 | char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F" : "%P%X", |
- | 737 | ": error: ", format, "\n", |
|
665 | format, "\n", (const char *) NULL)); |
738 | (const char *) NULL)); |
666 | fflush (stdout); |
739 | fflush (stdout); |
667 | vfinfo (stderr, newfmt, args, TRUE); |
740 | vfinfo (stderr, newfmt, args, TRUE); |
668 | fflush (stderr); |
741 | fflush (stderr); |
669 | } |
742 | } |
670 | break; |
743 | break; |
Line 698... | Line 771... | ||
698 | break; |
771 | break; |
699 | case LDPT_GNU_LD_VERSION: |
772 | case LDPT_GNU_LD_VERSION: |
700 | TVU(val) = major * 100 + minor; |
773 | TVU(val) = major * 100 + minor; |
701 | break; |
774 | break; |
702 | case LDPT_LINKER_OUTPUT: |
775 | case LDPT_LINKER_OUTPUT: |
703 | TVU(val) = (link_info.relocatable |
776 | TVU(val) = (bfd_link_relocatable (&link_info) ? LDPO_REL |
704 | ? LDPO_REL |
- | |
705 | : (link_info.executable |
777 | : bfd_link_pde (&link_info) ? LDPO_EXEC |
706 | ? (link_info.pie ? LDPO_PIE : LDPO_EXEC) |
778 | : bfd_link_pie (&link_info) ? LDPO_PIE |
707 | : LDPO_DYN)); |
779 | : LDPO_DYN); |
708 | break; |
780 | break; |
709 | case LDPT_OUTPUT_NAME: |
781 | case LDPT_OUTPUT_NAME: |
710 | TVU(string) = output_filename; |
782 | TVU(string) = output_filename; |
711 | break; |
783 | break; |
712 | case LDPT_REGISTER_CLAIM_FILE_HOOK: |
784 | case LDPT_REGISTER_CLAIM_FILE_HOOK: |
Line 722... | Line 794... | ||
722 | TVU(add_symbols) = add_symbols; |
794 | TVU(add_symbols) = add_symbols; |
723 | break; |
795 | break; |
724 | case LDPT_GET_INPUT_FILE: |
796 | case LDPT_GET_INPUT_FILE: |
725 | TVU(get_input_file) = get_input_file; |
797 | TVU(get_input_file) = get_input_file; |
726 | break; |
798 | break; |
- | 799 | case LDPT_GET_VIEW: |
|
- | 800 | TVU(get_view) = get_view; |
|
- | 801 | break; |
|
727 | case LDPT_RELEASE_INPUT_FILE: |
802 | case LDPT_RELEASE_INPUT_FILE: |
728 | TVU(release_input_file) = release_input_file; |
803 | TVU(release_input_file) = release_input_file; |
729 | break; |
804 | break; |
730 | case LDPT_GET_SYMBOLS: |
805 | case LDPT_GET_SYMBOLS: |
731 | TVU(get_symbols) = get_symbols_v1; |
806 | TVU(get_symbols) = get_symbols_v1; |
Line 765... | Line 840... | ||
765 | } |
840 | } |
766 | tv->tv_tag = LDPT_NULL; |
841 | tv->tv_tag = LDPT_NULL; |
767 | tv->tv_u.tv_val = 0; |
842 | tv->tv_u.tv_val = 0; |
768 | } |
843 | } |
Line 769... | Line -... | ||
769 | - | ||
770 | /* Return true if any plugins are active this run. Only valid |
- | |
771 | after options have been processed. */ |
- | |
772 | bfd_boolean |
- | |
773 | plugin_active_plugins_p (void) |
- | |
774 | { |
- | |
775 | return plugins_list != NULL; |
- | |
776 | } |
- | |
777 | 844 | ||
778 | /* Load up and initialise all plugins after argument parsing. */ |
845 | /* Load up and initialise all plugins after argument parsing. */ |
779 | void |
846 | void |
780 | plugin_load_plugins (void) |
847 | plugin_load_plugins (void) |
781 | { |
848 | { |
Line 828... | Line 895... | ||
828 | orig_notice_all = link_info.notice_all; |
895 | orig_notice_all = link_info.notice_all; |
829 | orig_callbacks = link_info.callbacks; |
896 | orig_callbacks = link_info.callbacks; |
830 | plugin_callbacks = *orig_callbacks; |
897 | plugin_callbacks = *orig_callbacks; |
831 | plugin_callbacks.notice = &plugin_notice; |
898 | plugin_callbacks.notice = &plugin_notice; |
832 | link_info.notice_all = TRUE; |
899 | link_info.notice_all = TRUE; |
- | 900 | link_info.lto_plugin_active = TRUE; |
|
833 | link_info.callbacks = &plugin_callbacks; |
901 | link_info.callbacks = &plugin_callbacks; |
- | 902 | ||
- | 903 | register_ld_plugin_object_p (plugin_object_p); |
|
- | 904 | ||
- | 905 | #if HAVE_MMAP && HAVE_GETPAGESIZE |
|
- | 906 | plugin_pagesize = getpagesize (); |
|
- | 907 | #endif |
|
834 | } |
908 | } |
Line 835... | Line 909... | ||
835 | 909 | ||
836 | /* Call 'claim file' hook for all plugins. */ |
910 | /* Call 'claim file' hook for all plugins. */ |
837 | static int |
911 | static int |
Line 855... | Line 929... | ||
855 | curplug = curplug->next; |
929 | curplug = curplug->next; |
856 | } |
930 | } |
857 | return plugin_error_p () ? -1 : 0; |
931 | return plugin_error_p () ? -1 : 0; |
858 | } |
932 | } |
Line -... | Line 933... | ||
- | 933 | ||
859 | 934 | /* Duplicates a character string with memory attached to ABFD. */ |
|
860 | void |
935 | |
861 | plugin_maybe_claim (struct ld_plugin_input_file *file, |
936 | static char * |
862 | lang_input_statement_type *entry) |
937 | plugin_strdup (bfd *abfd, const char *str) |
- | 938 | { |
|
- | 939 | size_t strlength; |
|
- | 940 | char *copy; |
|
- | 941 | strlength = strlen (str) + 1; |
|
- | 942 | copy = bfd_alloc (abfd, strlength); |
|
- | 943 | if (copy == NULL) |
|
- | 944 | einfo (_("%P%F: plugin_strdup failed to allocate memory: %s\n"), |
|
- | 945 | bfd_get_error ()); |
|
- | 946 | memcpy (copy, str, strlength); |
|
- | 947 | return copy; |
|
- | 948 | } |
|
- | 949 | ||
- | 950 | static const bfd_target * |
|
- | 951 | plugin_object_p (bfd *ibfd) |
|
863 | { |
952 | { |
- | 953 | int claimed; |
|
- | 954 | plugin_input_file_t *input; |
|
- | 955 | off_t offset, filesize; |
|
- | 956 | struct ld_plugin_input_file file; |
|
- | 957 | bfd *abfd; |
|
- | 958 | bfd_boolean inarchive; |
|
- | 959 | const char *name; |
|
- | 960 | int fd; |
|
- | 961 | ||
- | 962 | /* Don't try the dummy object file. */ |
|
- | 963 | if ((ibfd->flags & BFD_PLUGIN) != 0) |
|
- | 964 | return NULL; |
|
- | 965 | ||
- | 966 | if (ibfd->plugin_format != bfd_plugin_uknown) |
|
- | 967 | { |
|
- | 968 | if (ibfd->plugin_format == bfd_plugin_yes) |
|
- | 969 | return ibfd->plugin_dummy_bfd->xvec; |
|
- | 970 | else |
|
- | 971 | return NULL; |
|
- | 972 | } |
|
- | 973 | ||
- | 974 | inarchive = bfd_my_archive (ibfd) != NULL; |
|
- | 975 | name = inarchive ? bfd_my_archive (ibfd)->filename : ibfd->filename; |
|
- | 976 | fd = open (name, O_RDONLY | O_BINARY); |
|
- | 977 | ||
- | 978 | if (fd < 0) |
|
Line 864... | Line 979... | ||
864 | int claimed = 0; |
979 | return NULL; |
865 | 980 | ||
866 | /* We create a dummy BFD, initially empty, to house whatever symbols |
981 | /* We create a dummy BFD, initially empty, to house whatever symbols |
- | 982 | the plugin may want to add. */ |
|
- | 983 | abfd = plugin_get_ir_dummy_bfd (ibfd->filename, ibfd); |
|
- | 984 | ||
- | 985 | input = bfd_alloc (abfd, sizeof (*input)); |
|
- | 986 | if (input == NULL) |
|
- | 987 | einfo (_("%P%F: plugin failed to allocate memory for input: %s\n"), |
|
- | 988 | bfd_get_error ()); |
|
- | 989 | ||
- | 990 | if (inarchive) |
|
- | 991 | { |
|
- | 992 | /* Offset and filesize must refer to the individual archive |
|
- | 993 | member, not the whole file, and must exclude the header. |
|
- | 994 | Fortunately for us, that is how the data is stored in the |
|
- | 995 | origin field of the bfd and in the arelt_data. */ |
|
- | 996 | offset = ibfd->origin; |
|
- | 997 | filesize = arelt_size (ibfd); |
|
- | 998 | } |
|
- | 999 | else |
|
- | 1000 | { |
|
- | 1001 | offset = 0; |
|
- | 1002 | filesize = lseek (fd, 0, SEEK_END); |
|
- | 1003 | ||
- | 1004 | /* We must copy filename attached to ibfd if it is not an archive |
|
- | 1005 | member since it may be freed by bfd_close below. */ |
|
- | 1006 | name = plugin_strdup (abfd, name); |
|
- | 1007 | } |
|
- | 1008 | ||
- | 1009 | file.name = name; |
|
- | 1010 | file.offset = offset; |
|
- | 1011 | file.filesize = filesize; |
|
- | 1012 | file.fd = fd; |
|
- | 1013 | file.handle = input; |
|
- | 1014 | ||
- | 1015 | input->abfd = abfd; |
|
- | 1016 | input->view_buffer.addr = NULL; |
|
867 | the plugin may want to add. */ |
1017 | input->view_buffer.filesize = 0; |
- | 1018 | input->view_buffer.offset = 0; |
|
- | 1019 | input->fd = fd; |
|
- | 1020 | input->use_mmap = FALSE; |
|
- | 1021 | input->offset = offset; |
|
- | 1022 | input->filesize = filesize; |
|
- | 1023 | input->name = plugin_strdup (abfd, ibfd->filename); |
|
- | 1024 | ||
868 | file->handle = plugin_get_ir_dummy_bfd (entry->the_bfd->filename, |
1025 | claimed = 0; |
869 | entry->the_bfd); |
1026 | |
870 | if (plugin_call_claim_file (file, &claimed)) |
1027 | if (plugin_call_claim_file (&file, &claimed)) |
- | 1028 | einfo (_("%P%F: %s: plugin reported error claiming file\n"), |
|
- | 1029 | plugin_error_plugin ()); |
|
- | 1030 | ||
871 | einfo (_("%P%F: %s: plugin reported error claiming file\n"), |
1031 | if (input->fd != -1 && ! bfd_plugin_target_p (ibfd->xvec)) |
- | 1032 | { |
|
- | 1033 | /* FIXME: fd belongs to us, not the plugin. GCC plugin, which |
|
- | 1034 | doesn't need fd after plugin_call_claim_file, doesn't use |
|
- | 1035 | BFD plugin target vector. Since GCC plugin doesn't call |
|
- | 1036 | release_input_file, we close it here. LLVM plugin, which |
|
- | 1037 | needs fd after plugin_call_claim_file and calls |
|
- | 1038 | release_input_file after it is done, uses BFD plugin target |
|
872 | plugin_error_plugin ()); |
1039 | vector. This scheme doesn't work when a plugin needs fd and |
- | 1040 | doesn't use BFD plugin target vector neither. */ |
|
- | 1041 | close (fd); |
|
- | 1042 | input->fd = -1; |
|
873 | /* fd belongs to us, not the plugin; but we don't need it. */ |
1043 | } |
874 | close (file->fd); |
1044 | |
- | 1045 | if (claimed) |
|
- | 1046 | { |
|
- | 1047 | ibfd->plugin_format = bfd_plugin_yes; |
|
- | 1048 | ibfd->plugin_dummy_bfd = abfd; |
|
- | 1049 | bfd_make_readable (abfd); |
|
- | 1050 | return abfd->xvec; |
|
- | 1051 | } |
|
- | 1052 | else |
|
- | 1053 | { |
|
- | 1054 | #if HAVE_MMAP |
|
- | 1055 | if (input->use_mmap) |
|
- | 1056 | { |
|
- | 1057 | /* If plugin didn't claim the file, unmap the buffer. */ |
|
- | 1058 | char *addr = input->view_buffer.addr; |
|
- | 1059 | off_t size = input->view_buffer.filesize; |
|
- | 1060 | # if HAVE_GETPAGESIZE |
|
- | 1061 | off_t bias = input->view_buffer.offset % plugin_pagesize; |
|
- | 1062 | size += bias; |
|
- | 1063 | addr -= bias; |
|
- | 1064 | # endif |
|
- | 1065 | munmap (addr, size); |
|
- | 1066 | } |
|
- | 1067 | #endif |
|
- | 1068 | ||
- | 1069 | /* If plugin didn't claim the file, we don't need the dummy bfd. |
|
- | 1070 | Can't avoid speculatively creating it, alas. */ |
|
- | 1071 | ibfd->plugin_format = bfd_plugin_no; |
|
- | 1072 | bfd_close_all_done (abfd); |
|
- | 1073 | return NULL; |
|
- | 1074 | } |
|
- | 1075 | } |
|
- | 1076 | ||
- | 1077 | void |
|
- | 1078 | plugin_maybe_claim (lang_input_statement_type *entry) |
|
- | 1079 | { |
|
- | 1080 | if (plugin_object_p (entry->the_bfd)) |
|
- | 1081 | { |
|
875 | if (claimed) |
1082 | bfd *abfd = entry->the_bfd->plugin_dummy_bfd; |
Line 876... | Line 1083... | ||
876 | { |
1083 | |
877 | /* Discard the real file's BFD and substitute the dummy one. */ |
1084 | /* Discard the real file's BFD and substitute the dummy one. */ |
878 | 1085 | ||
879 | /* BFD archive handling caches elements so we can't call |
1086 | /* BFD archive handling caches elements so we can't call |
880 | bfd_close for archives. */ |
1087 | bfd_close for archives. */ |
881 | if (entry->the_bfd->my_archive == NULL) |
1088 | if (entry->the_bfd->my_archive == NULL) |
882 | bfd_close (entry->the_bfd); |
- | |
883 | entry->the_bfd = file->handle; |
- | |
884 | entry->flags.claimed = TRUE; |
- | |
885 | bfd_make_readable (entry->the_bfd); |
- | |
886 | } |
- | |
887 | else |
- | |
888 | { |
- | |
889 | /* If plugin didn't claim the file, we don't need the dummy bfd. |
- | |
890 | Can't avoid speculatively creating it, alas. */ |
1089 | bfd_close (entry->the_bfd); |
891 | bfd_close_all_done (file->handle); |
1090 | entry->the_bfd = abfd; |
Line 892... | Line 1091... | ||
892 | entry->flags.claimed = FALSE; |
1091 | entry->flags.claimed = 1; |
893 | } |
1092 | } |
Line 948... | Line 1147... | ||
948 | notice_all symbols, because we won't necessarily know until later |
1147 | notice_all symbols, because we won't necessarily know until later |
949 | which ones will be contributed by IR files. */ |
1148 | which ones will be contributed by IR files. */ |
950 | static bfd_boolean |
1149 | static bfd_boolean |
951 | plugin_notice (struct bfd_link_info *info, |
1150 | plugin_notice (struct bfd_link_info *info, |
952 | struct bfd_link_hash_entry *h, |
1151 | struct bfd_link_hash_entry *h, |
- | 1152 | struct bfd_link_hash_entry *inh, |
|
953 | bfd *abfd, |
1153 | bfd *abfd, |
954 | asection *section, |
1154 | asection *section, |
955 | bfd_vma value, |
1155 | bfd_vma value, |
956 | flagword flags, |
1156 | flagword flags) |
957 | const char *string) |
- | |
958 | { |
1157 | { |
- | 1158 | struct bfd_link_hash_entry *orig_h = h; |
|
- | 1159 | ||
959 | if (h != NULL) |
1160 | if (h != NULL) |
960 | { |
1161 | { |
961 | bfd *sym_bfd; |
1162 | bfd *sym_bfd; |
Line -... | Line 1163... | ||
- | 1163 | ||
- | 1164 | if (h->type == bfd_link_hash_warning) |
|
- | 1165 | h = h->u.i.link; |
|
962 | 1166 | ||
963 | /* Nothing to do here if this def/ref is from an IR dummy BFD. */ |
1167 | /* Nothing to do here if this def/ref is from an IR dummy BFD. */ |
964 | if (is_ir_dummy_bfd (abfd)) |
1168 | if (is_ir_dummy_bfd (abfd)) |
Line 965... | Line 1169... | ||
965 | ; |
1169 | ; |
966 | 1170 | ||
967 | /* Making an indirect symbol counts as a reference unless this |
1171 | /* Making an indirect symbol counts as a reference unless this |
968 | is a brand new symbol. */ |
1172 | is a brand new symbol. */ |
969 | else if (bfd_is_ind_section (section) |
1173 | else if (bfd_is_ind_section (section) |
- | 1174 | || (flags & BSF_INDIRECT) != 0) |
|
- | 1175 | { |
|
970 | || (flags & BSF_INDIRECT) != 0) |
1176 | /* ??? Some of this is questionable. See comments in |
971 | { |
1177 | _bfd_generic_link_add_one_symbol for case IND. */ |
972 | if (h->type != bfd_link_hash_new) |
- | |
973 | { |
- | |
974 | struct bfd_link_hash_entry *inh; |
1178 | if (h->type != bfd_link_hash_new) |
975 | - | ||
976 | h->non_ir_ref = TRUE; |
- | |
977 | inh = bfd_wrapped_link_hash_lookup (abfd, info, string, FALSE, |
- | |
978 | FALSE, FALSE); |
1179 | { |
979 | if (inh != NULL) |
1180 | h->non_ir_ref = TRUE; |
- | 1181 | inh->non_ir_ref = TRUE; |
|
- | 1182 | } |
|
980 | inh->non_ir_ref = TRUE; |
1183 | else if (inh->type == bfd_link_hash_new) |
Line 981... | Line 1184... | ||
981 | } |
1184 | inh->non_ir_ref = TRUE; |
982 | } |
1185 | } |
983 | 1186 | ||
Line 1017... | Line 1220... | ||
1017 | h->u.undef.abfd = sym_bfd; |
1220 | h->u.undef.abfd = sym_bfd; |
1018 | } |
1221 | } |
1019 | } |
1222 | } |
Line 1020... | Line 1223... | ||
1020 | 1223 | ||
1021 | /* Continue with cref/nocrossref/trace-sym processing. */ |
1224 | /* Continue with cref/nocrossref/trace-sym processing. */ |
1022 | if (h == NULL |
1225 | if (orig_h == NULL |
1023 | || orig_notice_all |
1226 | || orig_notice_all |
1024 | || (info->notice_hash != NULL |
1227 | || (info->notice_hash != NULL |
1025 | && bfd_hash_lookup (info->notice_hash, h->root.string, |
1228 | && bfd_hash_lookup (info->notice_hash, orig_h->root.string, |
1026 | FALSE, FALSE) != NULL)) |
1229 | FALSE, FALSE) != NULL)) |
1027 | return (*orig_callbacks->notice) (info, h, |
1230 | return (*orig_callbacks->notice) (info, orig_h, inh, |
1028 | abfd, section, value, flags, string); |
1231 | abfd, section, value, flags); |
1029 | return TRUE; |
1232 | return TRUE; |
1030 | } |
- | |
1031 | - | ||
1032 | /* Return true if bfd is a dynamic library that should be reloaded. */ |
- | |
1033 | - | ||
1034 | bfd_boolean |
- | |
1035 | plugin_should_reload (bfd *abfd) |
- | |
1036 | { |
- | |
1037 | return ((abfd->flags & DYNAMIC) != 0 |
- | |
1038 | && bfd_get_flavour (abfd) == bfd_target_elf_flavour |
- | |
1039 | && bfd_get_format (abfd) == bfd_object |
- | |
1040 | && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0); |
- |