0c88ef8beafedb9576cf868180cb8fa70a6101b3
[deliverable/binutils-gdb.git] / ld / plugin.c
1 /* Plugin control for the GNU linker.
2 Copyright 2010 Free Software Foundation, Inc.
3
4 This file is part of the GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 #include "sysdep.h"
22 #include "libiberty.h"
23 #include "bfd.h"
24 #include "bfdlink.h"
25 #include "bfdver.h"
26 #include "ld.h"
27 #include "ldmain.h"
28 #include "ldmisc.h"
29 #include "ldexp.h"
30 #include "ldlang.h"
31 #include "ldfile.h"
32 #include "plugin.h"
33 #include "plugin-api.h"
34 #include "elf-bfd.h"
35
36 /* The suffix to append to the name of the real (claimed) object file
37 when generating a dummy BFD to hold the IR symbols sent from the
38 plugin. */
39 #define IRONLY_SUFFIX ".ironly\004"
40
41 /* This is sizeof an array of chars, not sizeof a const char *. We
42 also have to avoid inadvertently counting the trailing NUL. */
43 #define IRONLY_SUFFIX_LEN (sizeof (IRONLY_SUFFIX) - 1)
44
45 /* Stores a single argument passed to a plugin. */
46 typedef struct plugin_arg
47 {
48 struct plugin_arg *next;
49 const char *arg;
50 } plugin_arg_t;
51
52 /* Holds all details of a single plugin. */
53 typedef struct plugin
54 {
55 /* Next on the list of plugins, or NULL at end of chain. */
56 struct plugin *next;
57 /* The argument string given to --plugin. */
58 const char *name;
59 /* The shared library handle returned by dlopen. */
60 void *dlhandle;
61 /* The list of argument string given to --plugin-opt. */
62 plugin_arg_t *args;
63 /* Number of args in the list, for convenience. */
64 size_t n_args;
65 /* The plugin's event handlers. */
66 ld_plugin_claim_file_handler claim_file_handler;
67 ld_plugin_all_symbols_read_handler all_symbols_read_handler;
68 ld_plugin_cleanup_handler cleanup_handler;
69 /* TRUE if the cleanup handlers have been called. */
70 bfd_boolean cleanup_done;
71 } plugin_t;
72
73 /* The master list of all plugins. */
74 static plugin_t *plugins_list = NULL;
75
76 /* We keep a tail pointer for easy linking on the end. */
77 static plugin_t **plugins_tail_chain_ptr = &plugins_list;
78
79 /* The last plugin added to the list, for receiving args. */
80 static plugin_t *last_plugin = NULL;
81
82 /* The tail of the arg chain of the last plugin added to the list. */
83 static plugin_arg_t **last_plugin_args_tail_chain_ptr = NULL;
84
85 /* The plugin which is currently having a callback executed. */
86 static plugin_t *called_plugin = NULL;
87
88 /* Last plugin to cause an error, if any. */
89 static const char *error_plugin = NULL;
90
91 /* A hash table that records symbols referenced by non-IR files. Used
92 at get_symbols time to determine whether any prevailing defs from
93 IR files are referenced only from other IR files, so tthat we can
94 we can distinguish the LDPR_PREVAILING_DEF and LDPR_PREVAILING_DEF_IRONLY
95 cases when establishing symbol resolutions. */
96 static struct bfd_hash_table *non_ironly_hash = NULL;
97
98 /* Set at all symbols read time, to avoid recursively offering the plugin
99 its own newly-added input files and libs to claim. */
100 static bfd_boolean no_more_claiming = FALSE;
101
102 /* If the --allow-multiple-definition command-line option is active, we
103 have to disable it so that BFD always calls our hook, and simulate the
104 effect (when not resolving IR vs. real symbols) ourselves by ensuring
105 TRUE is returned from the hook. */
106 static bfd_boolean plugin_cached_allow_multiple_defs = FALSE;
107
108 /* List of tags to set in the constant leading part of the tv array. */
109 static const enum ld_plugin_tag tv_header_tags[] =
110 {
111 LDPT_MESSAGE,
112 LDPT_API_VERSION,
113 LDPT_GNU_LD_VERSION,
114 LDPT_LINKER_OUTPUT,
115 LDPT_OUTPUT_NAME,
116 LDPT_REGISTER_CLAIM_FILE_HOOK,
117 LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
118 LDPT_REGISTER_CLEANUP_HOOK,
119 LDPT_ADD_SYMBOLS,
120 LDPT_GET_INPUT_FILE,
121 LDPT_RELEASE_INPUT_FILE,
122 LDPT_GET_SYMBOLS,
123 LDPT_ADD_INPUT_FILE,
124 LDPT_ADD_INPUT_LIBRARY,
125 LDPT_SET_EXTRA_LIBRARY_PATH
126 };
127
128 /* How many entries in the constant leading part of the tv array. */
129 static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags);
130
131 /* Helper function for exiting with error status. */
132 static int
133 set_plugin_error (const char *plugin)
134 {
135 error_plugin = plugin;
136 return -1;
137 }
138
139 /* Test if an error occurred. */
140 static bfd_boolean
141 plugin_error_p (void)
142 {
143 return error_plugin != NULL;
144 }
145
146 /* Return name of plugin which caused an error if any. */
147 const char *plugin_error_plugin (void)
148 {
149 return error_plugin ? error_plugin : _("<no plugin>");
150 }
151
152 /* Handle -plugin arg: find and load plugin, or return error. */
153 int plugin_opt_plugin (const char *plugin)
154 {
155 plugin_t *newplug;
156
157 newplug = xmalloc (sizeof *newplug);
158 memset (newplug, 0, sizeof *newplug);
159 newplug->name = plugin;
160 newplug->dlhandle = dlopen (plugin, RTLD_NOW);
161 if (!newplug->dlhandle)
162 return set_plugin_error (plugin);
163
164 /* Chain on end, so when we run list it is in command-line order. */
165 *plugins_tail_chain_ptr = newplug;
166 plugins_tail_chain_ptr = &newplug->next;
167
168 /* Record it as current plugin for receiving args. */
169 last_plugin = newplug;
170 last_plugin_args_tail_chain_ptr = &newplug->args;
171 return 0;
172 }
173
174 /* Accumulate option arguments for last-loaded plugin, or return
175 error if none. */
176 int plugin_opt_plugin_arg (const char *arg)
177 {
178 plugin_arg_t *newarg;
179
180 if (!last_plugin)
181 return set_plugin_error (_("<no plugin>"));
182
183 newarg = xmalloc (sizeof *newarg);
184 newarg->arg = arg;
185 newarg->next = NULL;
186
187 /* Chain on end to preserve command-line order. */
188 *last_plugin_args_tail_chain_ptr = newarg;
189 last_plugin_args_tail_chain_ptr = &newarg->next;
190 last_plugin->n_args++;
191 return 0;
192 }
193
194 /* Create a dummy BFD. */
195 bfd *
196 plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
197 {
198 asection *sec;
199 bfd *abfd = bfd_create (
200 concat (name, IRONLY_SUFFIX, (const char *)NULL),
201 srctemplate);
202 bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
203 bfd_make_writable (abfd);
204 /* Create a minimal set of sections to own the symbols. */
205 sec = bfd_make_section_old_way (abfd, ".text");
206 bfd_set_section_flags (abfd, sec,
207 SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
208 | SEC_ALLOC | SEC_LOAD | SEC_KEEP);
209 sec->output_section = sec;
210 sec->output_offset = 0;
211 return abfd;
212 }
213
214 /* Check if the BFD is an IR dummy. */
215 bfd_boolean
216 is_ir_dummy_bfd (const bfd *abfd)
217 {
218 size_t namlen = strlen (abfd->filename);
219 if (namlen < IRONLY_SUFFIX_LEN)
220 return FALSE;
221 return !strcmp (abfd->filename + namlen - IRONLY_SUFFIX_LEN, IRONLY_SUFFIX);
222 }
223
224 /* Helpers to convert between BFD and GOLD symbol formats. */
225 static enum ld_plugin_status
226 asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
227 const struct ld_plugin_symbol *ldsym)
228 {
229 flagword flags = BSF_NO_FLAGS;
230 struct bfd_section *section;
231
232 asym->the_bfd = abfd;
233 asym->name = ldsym->version
234 ? concat (ldsym->name, "@", ldsym->version, NULL)
235 : ldsym->name;
236 asym->value = 0;
237 switch (ldsym->def)
238 {
239 case LDPK_WEAKDEF:
240 flags = BSF_WEAK;
241 /* FALLTHRU */
242 case LDPK_DEF:
243 flags |= BSF_GLOBAL;
244 section = bfd_get_section_by_name (abfd, ".text");
245 break;
246
247 case LDPK_WEAKUNDEF:
248 flags = BSF_WEAK;
249 /* FALLTHRU */
250 case LDPK_UNDEF:
251 section = bfd_und_section_ptr;
252 break;
253
254 case LDPK_COMMON:
255 flags = BSF_GLOBAL;
256 section = bfd_com_section_ptr;
257 asym->value = ldsym->size;
258 break;
259
260 default:
261 return LDPS_ERR;
262 }
263 asym->flags = flags;
264 asym->section = section;
265
266 /* Visibility only applies on ELF targets. */
267 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
268 {
269 elf_symbol_type *elfsym = elf_symbol_from (abfd, asym);
270 if (!elfsym)
271 einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!"), asym->name);
272 elfsym->internal_elf_sym.st_other &= ~3;
273 elfsym->internal_elf_sym.st_other |= ldsym->visibility;
274 }
275
276 return LDPS_OK;
277 }
278
279 /* Register a claim-file handler. */
280 static enum ld_plugin_status
281 register_claim_file (ld_plugin_claim_file_handler handler)
282 {
283 ASSERT (called_plugin);
284 called_plugin->claim_file_handler = handler;
285 return LDPS_OK;
286 }
287
288 /* Register an all-symbols-read handler. */
289 static enum ld_plugin_status
290 register_all_symbols_read (ld_plugin_all_symbols_read_handler handler)
291 {
292 ASSERT (called_plugin);
293 called_plugin->all_symbols_read_handler = handler;
294 return LDPS_OK;
295 }
296
297 /* Register a cleanup handler. */
298 static enum ld_plugin_status
299 register_cleanup (ld_plugin_cleanup_handler handler)
300 {
301 ASSERT (called_plugin);
302 called_plugin->cleanup_handler = handler;
303 return LDPS_OK;
304 }
305
306 /* Add symbols from a plugin-claimed input file. */
307 static enum ld_plugin_status
308 add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms)
309 {
310 asymbol **symptrs;
311 bfd *abfd = handle;
312 int n;
313 ASSERT (called_plugin);
314 symptrs = xmalloc (nsyms * sizeof *symptrs);
315 for (n = 0; n < nsyms; n++)
316 {
317 enum ld_plugin_status rv;
318 asymbol *bfdsym = bfd_make_empty_symbol (abfd);
319 symptrs[n] = bfdsym;
320 rv = asymbol_from_plugin_symbol (abfd, bfdsym, syms + n);
321 if (rv != LDPS_OK)
322 return rv;
323 }
324 bfd_set_symtab (abfd, symptrs, nsyms);
325 return LDPS_OK;
326 }
327
328 /* Get the input file information with an open (possibly re-opened)
329 file descriptor. */
330 static enum ld_plugin_status
331 get_input_file (const void *handle, struct ld_plugin_input_file *file)
332 {
333 ASSERT (called_plugin);
334 handle = handle;
335 file = file;
336 return LDPS_ERR;
337 }
338
339 /* Release the input file. */
340 static enum ld_plugin_status
341 release_input_file (const void *handle)
342 {
343 ASSERT (called_plugin);
344 handle = handle;
345 return LDPS_ERR;
346 }
347
348 /* Get the symbol resolution info for a plugin-claimed input file. */
349 static enum ld_plugin_status
350 get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
351 {
352 const bfd *abfd = handle;
353 int n;
354 ASSERT (called_plugin);
355 for (n = 0; n < nsyms; n++)
356 {
357 struct bfd_link_hash_entry *blhe;
358 bfd_boolean ironly;
359
360 blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
361 FALSE, FALSE, TRUE);
362 if (!blhe)
363 {
364 syms[n].resolution = LDPR_UNKNOWN;
365 continue;
366 }
367
368 /* Determine resolution from blhe type and symbol's original type. */
369 if (blhe->type == bfd_link_hash_undefined
370 || blhe->type == bfd_link_hash_undefweak)
371 {
372 syms[n].resolution = LDPR_UNDEF;
373 continue;
374 }
375 if (blhe->type != bfd_link_hash_defined
376 && blhe->type != bfd_link_hash_defweak
377 && blhe->type != bfd_link_hash_common)
378 {
379 /* We should not have a new, indirect or warning symbol here. */
380 einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)",
381 called_plugin->name, blhe->type);
382 }
383
384 /* We need to know if the sym is referenced from non-IR files. */
385 ironly = !bfd_hash_lookup (non_ironly_hash, syms[n].name, FALSE, FALSE);
386
387 /* If it was originally undefined or common, then it has been
388 resolved; determine how. */
389 if (syms[n].def == LDPK_UNDEF || syms[n].def == LDPK_WEAKUNDEF
390 || syms[n].def == LDPK_COMMON)
391 {
392 asection *owner_sec = (syms[n].def == LDPK_COMMON)
393 ? blhe->u.c.p->section
394 : blhe->u.def.section;
395 if (owner_sec->owner == link_info.output_bfd)
396 syms[n].resolution = LDPR_RESOLVED_EXEC;
397 else if (owner_sec->owner == abfd)
398 syms[n].resolution = (ironly)
399 ? LDPR_PREVAILING_DEF_IRONLY
400 : LDPR_PREVAILING_DEF;
401 else if (is_ir_dummy_bfd (owner_sec->owner))
402 syms[n].resolution = LDPR_RESOLVED_IR;
403 else if (owner_sec->owner->flags & DYNAMIC)
404 syms[n].resolution = LDPR_RESOLVED_DYN;
405 else
406 syms[n].resolution = LDPR_RESOLVED_EXEC;
407 continue;
408 }
409
410 /* Was originally def, or weakdef. Does it prevail? If the
411 owner is the original dummy bfd that supplied it, then this
412 is the definition that has prevailed. */
413 if (blhe->u.def.section->owner == link_info.output_bfd)
414 syms[n].resolution = LDPR_PREEMPTED_REG;
415 else if (blhe->u.def.section->owner == abfd)
416 {
417 syms[n].resolution = (ironly)
418 ? LDPR_PREVAILING_DEF_IRONLY
419 : LDPR_PREVAILING_DEF;
420 continue;
421 }
422
423 /* Was originally def, weakdef, or common, but has been pre-empted. */
424 syms[n].resolution = is_ir_dummy_bfd (blhe->u.def.section->owner)
425 ? LDPR_PREEMPTED_IR
426 : LDPR_PREEMPTED_REG;
427 }
428 return LDPS_OK;
429 }
430
431 /* Add a new (real) input file generated by a plugin. */
432 static enum ld_plugin_status
433 add_input_file (const char *pathname)
434 {
435 ASSERT (called_plugin);
436 if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum,
437 NULL))
438 return LDPS_ERR;
439 return LDPS_OK;
440 }
441
442 /* Add a new (real) library required by a plugin. */
443 static enum ld_plugin_status
444 add_input_library (const char *pathname)
445 {
446 ASSERT (called_plugin);
447 if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum,
448 NULL))
449 return LDPS_ERR;
450 return LDPS_OK;
451 }
452
453 /* Set the extra library path to be used by libraries added via
454 add_input_library. */
455 static enum ld_plugin_status
456 set_extra_library_path (const char *path)
457 {
458 ASSERT (called_plugin);
459 ldfile_add_library_path (xstrdup (path), FALSE);
460 return LDPS_OK;
461 }
462
463 /* Issue a diagnostic message from a plugin. */
464 static enum ld_plugin_status
465 message (int level, const char *format, ...)
466 {
467 va_list args;
468 va_start (args, format);
469
470 switch (level)
471 {
472 case LDPL_INFO:
473 vfinfo (stdout, format, args, FALSE);
474 break;
475 case LDPL_WARNING:
476 vfinfo (stdout, format, args, TRUE);
477 break;
478 case LDPL_FATAL:
479 case LDPL_ERROR:
480 default:
481 {
482 char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%F" : "%X",
483 format, NULL));
484 vfinfo (stderr, newfmt, args, TRUE);
485 }
486 break;
487 }
488
489 va_end (args);
490 return LDPS_OK;
491 }
492
493 /* Helper to size leading part of tv array and set it up. */
494 static size_t
495 set_tv_header (struct ld_plugin_tv *tv)
496 {
497 size_t i;
498
499 /* Version info. */
500 static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL);
501 static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100;
502
503 if (!tv)
504 return tv_header_size;
505
506 for (i = 0; i < tv_header_size; i++)
507 {
508 tv[i].tv_tag = tv_header_tags[i];
509 #define TVU(x) tv[i].tv_u.tv_ ## x
510 switch (tv[i].tv_tag)
511 {
512 case LDPT_MESSAGE:
513 TVU(message) = message;
514 break;
515 case LDPT_API_VERSION:
516 TVU(val) = LD_PLUGIN_API_VERSION;
517 break;
518 case LDPT_GNU_LD_VERSION:
519 TVU(val) = major * 100 + minor;
520 break;
521 case LDPT_LINKER_OUTPUT:
522 TVU(val) = link_info.relocatable ? LDPO_REL
523 : (link_info.shared ? LDPO_DYN : LDPO_EXEC);
524 break;
525 case LDPT_OUTPUT_NAME:
526 TVU(string) = output_filename;
527 break;
528 case LDPT_REGISTER_CLAIM_FILE_HOOK:
529 TVU(register_claim_file) = register_claim_file;
530 break;
531 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
532 TVU(register_all_symbols_read) = register_all_symbols_read;
533 break;
534 case LDPT_REGISTER_CLEANUP_HOOK:
535 TVU(register_cleanup) = register_cleanup;
536 break;
537 case LDPT_ADD_SYMBOLS:
538 TVU(add_symbols) = add_symbols;
539 break;
540 case LDPT_GET_INPUT_FILE:
541 TVU(get_input_file) = get_input_file;
542 break;
543 case LDPT_RELEASE_INPUT_FILE:
544 TVU(release_input_file) = release_input_file;
545 break;
546 case LDPT_GET_SYMBOLS:
547 TVU(get_symbols) = get_symbols;
548 break;
549 case LDPT_ADD_INPUT_FILE:
550 TVU(add_input_file) = add_input_file;
551 break;
552 case LDPT_ADD_INPUT_LIBRARY:
553 TVU(add_input_library) = add_input_library;
554 break;
555 case LDPT_SET_EXTRA_LIBRARY_PATH:
556 TVU(set_extra_library_path) = set_extra_library_path;
557 break;
558 default:
559 /* Added a new entry to the array without adding
560 a new case to set up its value is a bug. */
561 FAIL ();
562 }
563 #undef TVU
564 }
565 return tv_header_size;
566 }
567
568 /* Append the per-plugin args list and trailing LDPT_NULL to tv. */
569 static void
570 set_tv_plugin_args (plugin_t *plugin, struct ld_plugin_tv *tv)
571 {
572 plugin_arg_t *arg = plugin->args;
573 while (arg)
574 {
575 tv->tv_tag = LDPT_OPTION;
576 tv->tv_u.tv_string = arg->arg;
577 arg = arg->next;
578 tv++;
579 }
580 tv->tv_tag = LDPT_NULL;
581 tv->tv_u.tv_val = 0;
582 }
583
584 /* Load up and initialise all plugins after argument parsing. */
585 int plugin_load_plugins (void)
586 {
587 struct ld_plugin_tv *my_tv;
588 unsigned int max_args = 0;
589 plugin_t *curplug = plugins_list;
590
591 /* If there are no plugins, we need do nothing this run. */
592 if (!curplug)
593 return 0;
594
595 /* First pass over plugins to find max # args needed so that we
596 can size and allocate the tv array. */
597 while (curplug)
598 {
599 if (curplug->n_args > max_args)
600 max_args = curplug->n_args;
601 curplug = curplug->next;
602 }
603
604 /* Allocate tv array and initialise constant part. */
605 my_tv = xmalloc ((max_args + 1 + tv_header_size) * sizeof *my_tv);
606 set_tv_header (my_tv);
607
608 /* Pass over plugins again, activating them. */
609 curplug = plugins_list;
610 while (curplug)
611 {
612 enum ld_plugin_status rv;
613 ld_plugin_onload onloadfn = dlsym (curplug->dlhandle, "onload");
614 if (!onloadfn)
615 onloadfn = dlsym (curplug->dlhandle, "_onload");
616 if (!onloadfn)
617 return set_plugin_error (curplug->name);
618 set_tv_plugin_args (curplug, &my_tv[tv_header_size]);
619 called_plugin = curplug;
620 rv = (*onloadfn) (my_tv);
621 called_plugin = NULL;
622 if (rv != LDPS_OK)
623 return set_plugin_error (curplug->name);
624 curplug = curplug->next;
625 }
626
627 /* Since plugin(s) inited ok, assume they're going to want symbol
628 resolutions, which needs us to track which symbols are referenced
629 by non-IR files using the linker's notice callback. */
630 link_info.notice_all = TRUE;
631
632 return 0;
633 }
634
635 /* Call 'claim file' hook for all plugins. */
636 int
637 plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed)
638 {
639 plugin_t *curplug = plugins_list;
640 *claimed = FALSE;
641 if (no_more_claiming)
642 return 0;
643 while (curplug && !*claimed)
644 {
645 if (curplug->claim_file_handler)
646 {
647 enum ld_plugin_status rv;
648 called_plugin = curplug;
649 rv = (*curplug->claim_file_handler) (file, claimed);
650 called_plugin = NULL;
651 if (rv != LDPS_OK)
652 set_plugin_error (curplug->name);
653 }
654 curplug = curplug->next;
655 }
656 return plugin_error_p () ? -1 : 0;
657 }
658
659 /* Call 'all symbols read' hook for all plugins. */
660 int
661 plugin_call_all_symbols_read (void)
662 {
663 plugin_t *curplug = plugins_list;
664
665 /* Disable any further file-claiming. */
666 no_more_claiming = TRUE;
667
668 /* If --allow-multiple-definition is in effect, we need to disable it,
669 as the plugin infrastructure relies on the multiple_definition
670 callback to swap out the dummy IR-only BFDs for new real ones
671 when it starts opening the files added during this callback. */
672 plugin_cached_allow_multiple_defs = link_info.allow_multiple_definition;
673 link_info.allow_multiple_definition = FALSE;
674
675 while (curplug)
676 {
677 if (curplug->all_symbols_read_handler)
678 {
679 enum ld_plugin_status rv;
680 called_plugin = curplug;
681 rv = (*curplug->all_symbols_read_handler) ();
682 called_plugin = NULL;
683 if (rv != LDPS_OK)
684 set_plugin_error (curplug->name);
685 }
686 curplug = curplug->next;
687 }
688 return plugin_error_p () ? -1 : 0;
689 }
690
691 /* Call 'cleanup' hook for all plugins. */
692 int
693 plugin_call_cleanup (void)
694 {
695 plugin_t *curplug = plugins_list;
696 while (curplug)
697 {
698 if (curplug->cleanup_handler && !curplug->cleanup_done)
699 {
700 enum ld_plugin_status rv;
701 curplug->cleanup_done = TRUE;
702 called_plugin = curplug;
703 rv = (*curplug->cleanup_handler) ();
704 called_plugin = NULL;
705 if (rv != LDPS_OK)
706 set_plugin_error (curplug->name);
707 dlclose (curplug->dlhandle);
708 }
709 curplug = curplug->next;
710 }
711 return plugin_error_p () ? -1 : 0;
712 }
713
714 /* Lazily init the non_ironly hash table. */
715 static void
716 init_non_ironly_hash (void)
717 {
718 if (non_ironly_hash == NULL)
719 {
720 non_ironly_hash =
721 (struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table));
722 if (!bfd_hash_table_init_n (non_ironly_hash,
723 bfd_hash_newfunc,
724 sizeof (struct bfd_hash_entry),
725 61))
726 einfo (_("%P%F: bfd_hash_table_init failed: %E\n"));
727 }
728 }
729
730 /* To determine which symbols should be resolved LDPR_PREVAILING_DEF
731 and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as
732 the linker adds them to the linker hash table. If we see a symbol
733 being referenced from a non-IR file, we add it to the non_ironly hash
734 table. If we can't find it there at get_symbols time, we know that
735 it was referenced only by IR files. We have to notice_all symbols,
736 because we won't necessarily know until later which ones will be
737 contributed by IR files. */
738 bfd_boolean
739 plugin_notice (struct bfd_link_info *info ATTRIBUTE_UNUSED,
740 const char *name, bfd *abfd,
741 asection *section, bfd_vma value ATTRIBUTE_UNUSED)
742 {
743 bfd_boolean is_ref = bfd_is_und_section (section);
744 bfd_boolean is_dummy = is_ir_dummy_bfd (abfd);
745 init_non_ironly_hash ();
746 /* We only care about refs, not defs, indicated by section pointing
747 to the undefined section (according to the bfd linker notice callback
748 interface definition). */
749 if (is_ref && !is_dummy)
750 {
751 /* This is a ref from a non-IR file, so note the ref'd symbol
752 in the non-IR-only hash. */
753 if (!bfd_hash_lookup (non_ironly_hash, name, TRUE, TRUE))
754 einfo (_("%P%X: %s: hash table failure adding symbol %s"),
755 abfd->filename, name);
756 }
757 else if (!is_ref && is_dummy)
758 {
759 /* No further processing since this is a def from an IR dummy BFD. */
760 return FALSE;
761 }
762
763 /* Continue with cref/nocrossref/trace-sym processing. */
764 return TRUE;
765 }
766
767 /* When we add new object files to the link at all symbols read time,
768 these contain the real code and symbols generated from the IR files,
769 and so duplicate all the definitions already supplied by the dummy
770 IR-only BFDs that we created at claim files time. We use the linker's
771 multiple-definitions callback hook to fix up the clash, discarding
772 the symbol from the IR-only BFD in favour of the symbol from the
773 real BFD. We return true if this was not-really-a-clash because
774 we've fixed it up, or anyway if --allow-multiple-definition was in
775 effect (before we disabled it to ensure we got called back). */
776 bfd_boolean
777 plugin_multiple_definition (struct bfd_link_info *info, const char *name,
778 bfd *obfd, asection *osec ATTRIBUTE_UNUSED,
779 bfd_vma oval ATTRIBUTE_UNUSED,
780 bfd *nbfd, asection *nsec, bfd_vma nval)
781 {
782 if (is_ir_dummy_bfd (obfd))
783 {
784 struct bfd_link_hash_entry *blhe = bfd_link_hash_lookup (info->hash,
785 name, FALSE, FALSE, FALSE);
786 if (!blhe)
787 einfo (_("%P%X: %s: can't find IR symbol '%s'"), nbfd->filename,
788 name);
789 else if (blhe->type != bfd_link_hash_defined)
790 einfo (_("%P%x: %s: bad IR symbol type %d"), name, blhe->type);
791 /* Replace it with new details. */
792 blhe->u.def.section = nsec;
793 blhe->u.def.value = nval;
794 return TRUE;
795 }
796 return plugin_cached_allow_multiple_defs;
797 }
This page took 0.045445 seconds and 4 git commands to generate.