Rev 5199 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5199 | serge | 1 | /* Plugin control for the GNU linker. |
6324 | serge | 2 | Copyright (C) 2010-2015 Free Software Foundation, Inc. |
5199 | serge | 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" |
||
6324 | serge | 24 | #include "libbfd.h" |
5199 | serge | 25 | #include "bfdlink.h" |
26 | #include "bfdver.h" |
||
27 | #include "ld.h" |
||
28 | #include "ldmain.h" |
||
29 | #include "ldmisc.h" |
||
30 | #include "ldexp.h" |
||
31 | #include "ldlang.h" |
||
32 | #include "ldfile.h" |
||
6324 | serge | 33 | #include "../bfd/plugin.h" |
5199 | serge | 34 | #include "plugin.h" |
35 | #include "plugin-api.h" |
||
36 | #include "elf-bfd.h" |
||
37 | #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) |
||
38 | #include |
||
39 | #endif |
||
40 | |||
41 | /* Report plugin symbols. */ |
||
42 | bfd_boolean report_plugin_symbols; |
||
43 | |||
44 | /* The suffix to append to the name of the real (claimed) object file |
||
45 | when generating a dummy BFD to hold the IR symbols sent from the |
||
46 | plugin. For cosmetic use only; appears in maps, crefs etc. */ |
||
47 | #define IRONLY_SUFFIX " (symbol from plugin)" |
||
48 | |||
49 | /* Stores a single argument passed to a plugin. */ |
||
50 | typedef struct plugin_arg |
||
51 | { |
||
52 | struct plugin_arg *next; |
||
53 | const char *arg; |
||
54 | } plugin_arg_t; |
||
55 | |||
56 | /* Holds all details of a single plugin. */ |
||
57 | typedef struct plugin |
||
58 | { |
||
59 | /* Next on the list of plugins, or NULL at end of chain. */ |
||
60 | struct plugin *next; |
||
61 | /* The argument string given to --plugin. */ |
||
62 | const char *name; |
||
63 | /* The shared library handle returned by dlopen. */ |
||
64 | void *dlhandle; |
||
65 | /* The list of argument string given to --plugin-opt. */ |
||
66 | plugin_arg_t *args; |
||
67 | /* Number of args in the list, for convenience. */ |
||
68 | size_t n_args; |
||
69 | /* The plugin's event handlers. */ |
||
70 | ld_plugin_claim_file_handler claim_file_handler; |
||
71 | ld_plugin_all_symbols_read_handler all_symbols_read_handler; |
||
72 | ld_plugin_cleanup_handler cleanup_handler; |
||
73 | /* TRUE if the cleanup handlers have been called. */ |
||
74 | bfd_boolean cleanup_done; |
||
75 | } plugin_t; |
||
76 | |||
6324 | serge | 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; |
||
96 | |||
5199 | serge | 97 | /* The master list of all plugins. */ |
98 | static plugin_t *plugins_list = NULL; |
||
99 | |||
100 | /* We keep a tail pointer for easy linking on the end. */ |
||
101 | static plugin_t **plugins_tail_chain_ptr = &plugins_list; |
||
102 | |||
103 | /* The last plugin added to the list, for receiving args. */ |
||
104 | static plugin_t *last_plugin = NULL; |
||
105 | |||
106 | /* The tail of the arg chain of the last plugin added to the list. */ |
||
107 | static plugin_arg_t **last_plugin_args_tail_chain_ptr = NULL; |
||
108 | |||
109 | /* The plugin which is currently having a callback executed. */ |
||
110 | static plugin_t *called_plugin = NULL; |
||
111 | |||
112 | /* Last plugin to cause an error, if any. */ |
||
113 | static const char *error_plugin = NULL; |
||
114 | |||
115 | /* State of linker "notice" interface before we poked at it. */ |
||
116 | static bfd_boolean orig_notice_all; |
||
117 | |||
118 | /* Original linker callbacks, and the plugin version. */ |
||
119 | static const struct bfd_link_callbacks *orig_callbacks; |
||
120 | static struct bfd_link_callbacks plugin_callbacks; |
||
121 | |||
122 | /* Set at all symbols read time, to avoid recursively offering the plugin |
||
123 | its own newly-added input files and libs to claim. */ |
||
124 | bfd_boolean no_more_claiming = FALSE; |
||
125 | |||
126 | /* List of tags to set in the constant leading part of the tv array. */ |
||
127 | static const enum ld_plugin_tag tv_header_tags[] = |
||
128 | { |
||
129 | LDPT_MESSAGE, |
||
130 | LDPT_API_VERSION, |
||
131 | LDPT_GNU_LD_VERSION, |
||
132 | LDPT_LINKER_OUTPUT, |
||
133 | LDPT_OUTPUT_NAME, |
||
134 | LDPT_REGISTER_CLAIM_FILE_HOOK, |
||
135 | LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, |
||
136 | LDPT_REGISTER_CLEANUP_HOOK, |
||
137 | LDPT_ADD_SYMBOLS, |
||
138 | LDPT_GET_INPUT_FILE, |
||
6324 | serge | 139 | LDPT_GET_VIEW, |
5199 | serge | 140 | LDPT_RELEASE_INPUT_FILE, |
141 | LDPT_GET_SYMBOLS, |
||
142 | LDPT_GET_SYMBOLS_V2, |
||
143 | LDPT_ADD_INPUT_FILE, |
||
144 | LDPT_ADD_INPUT_LIBRARY, |
||
145 | LDPT_SET_EXTRA_LIBRARY_PATH |
||
146 | }; |
||
147 | |||
148 | /* How many entries in the constant leading part of the tv array. */ |
||
149 | static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags); |
||
150 | |||
151 | /* Forward references. */ |
||
152 | static bfd_boolean plugin_notice (struct bfd_link_info *, |
||
6324 | serge | 153 | struct bfd_link_hash_entry *, |
154 | struct bfd_link_hash_entry *, |
||
155 | bfd *, asection *, bfd_vma, flagword); |
||
5199 | serge | 156 | |
6324 | serge | 157 | static const bfd_target * plugin_object_p (bfd *); |
158 | |||
5199 | serge | 159 | #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) |
160 | |||
161 | #define RTLD_NOW 0 /* Dummy value. */ |
||
162 | |||
163 | static void * |
||
164 | dlopen (const char *file, int mode ATTRIBUTE_UNUSED) |
||
165 | { |
||
166 | return LoadLibrary (file); |
||
167 | } |
||
168 | |||
169 | static void * |
||
170 | dlsym (void *handle, const char *name) |
||
171 | { |
||
172 | return GetProcAddress (handle, name); |
||
173 | } |
||
174 | |||
175 | static int |
||
176 | dlclose (void *handle) |
||
177 | { |
||
178 | FreeLibrary (handle); |
||
179 | return 0; |
||
180 | } |
||
181 | |||
182 | #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */ |
||
183 | |||
184 | #ifndef HAVE_DLFCN_H |
||
185 | static const char * |
||
186 | dlerror (void) |
||
187 | { |
||
188 | return ""; |
||
189 | } |
||
190 | #endif |
||
191 | |||
192 | /* Helper function for exiting with error status. */ |
||
193 | static int |
||
194 | set_plugin_error (const char *plugin) |
||
195 | { |
||
196 | error_plugin = plugin; |
||
197 | return -1; |
||
198 | } |
||
199 | |||
200 | /* Test if an error occurred. */ |
||
201 | static bfd_boolean |
||
202 | plugin_error_p (void) |
||
203 | { |
||
204 | return error_plugin != NULL; |
||
205 | } |
||
206 | |||
207 | /* Return name of plugin which caused an error if any. */ |
||
208 | const char * |
||
209 | plugin_error_plugin (void) |
||
210 | { |
||
211 | return error_plugin ? error_plugin : _(" |
||
212 | } |
||
213 | |||
214 | /* Handle -plugin arg: find and load plugin, or return error. */ |
||
215 | void |
||
216 | plugin_opt_plugin (const char *plugin) |
||
217 | { |
||
218 | plugin_t *newplug; |
||
219 | |||
220 | newplug = xmalloc (sizeof *newplug); |
||
221 | memset (newplug, 0, sizeof *newplug); |
||
222 | newplug->name = plugin; |
||
223 | newplug->dlhandle = dlopen (plugin, RTLD_NOW); |
||
224 | if (!newplug->dlhandle) |
||
225 | einfo (_("%P%F: %s: error loading plugin: %s\n"), plugin, dlerror ()); |
||
226 | |||
227 | /* Chain on end, so when we run list it is in command-line order. */ |
||
228 | *plugins_tail_chain_ptr = newplug; |
||
229 | plugins_tail_chain_ptr = &newplug->next; |
||
230 | |||
231 | /* Record it as current plugin for receiving args. */ |
||
232 | last_plugin = newplug; |
||
233 | last_plugin_args_tail_chain_ptr = &newplug->args; |
||
234 | } |
||
235 | |||
236 | /* Accumulate option arguments for last-loaded plugin, or return |
||
237 | error if none. */ |
||
238 | int |
||
239 | plugin_opt_plugin_arg (const char *arg) |
||
240 | { |
||
241 | plugin_arg_t *newarg; |
||
242 | |||
243 | if (!last_plugin) |
||
244 | return set_plugin_error (_(" |
||
245 | |||
6324 | serge | 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; |
||
255 | } |
||
256 | |||
5199 | serge | 257 | newarg = xmalloc (sizeof *newarg); |
258 | newarg->arg = arg; |
||
259 | newarg->next = NULL; |
||
260 | |||
261 | /* Chain on end to preserve command-line order. */ |
||
262 | *last_plugin_args_tail_chain_ptr = newarg; |
||
263 | last_plugin_args_tail_chain_ptr = &newarg->next; |
||
264 | last_plugin->n_args++; |
||
265 | return 0; |
||
266 | } |
||
267 | |||
6324 | serge | 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 |
||
272 | add_symbols hook has been called so that it can be read when linking. */ |
||
273 | static bfd * |
||
5199 | serge | 274 | plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) |
275 | { |
||
276 | bfd *abfd; |
||
6324 | serge | 277 | bfd_boolean bfd_plugin_target; |
5199 | serge | 278 | |
279 | bfd_use_reserved_id = 1; |
||
6324 | serge | 280 | bfd_plugin_target = bfd_plugin_target_p (srctemplate->xvec); |
5199 | serge | 281 | abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL), |
6324 | serge | 282 | bfd_plugin_target ? link_info.output_bfd : srctemplate); |
5199 | serge | 283 | if (abfd != NULL) |
284 | { |
||
285 | abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN; |
||
6324 | serge | 286 | if (!bfd_make_writable (abfd)) |
287 | goto report_error; |
||
288 | if (!bfd_plugin_target) |
||
289 | { |
||
5199 | serge | 290 | bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); |
291 | bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); |
||
6324 | serge | 292 | if (!bfd_copy_private_bfd_data (srctemplate, abfd)) |
293 | goto report_error; |
||
294 | } |
||
5199 | serge | 295 | { |
296 | flagword flags; |
||
297 | |||
298 | /* Create section to own the symbols. */ |
||
299 | flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY |
||
300 | | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE); |
||
301 | if (bfd_make_section_anyway_with_flags (abfd, ".text", flags)) |
||
302 | return abfd; |
||
303 | } |
||
304 | } |
||
6324 | serge | 305 | report_error: |
5199 | serge | 306 | einfo (_("could not create dummy IR bfd: %F%E\n")); |
307 | return NULL; |
||
308 | } |
||
309 | |||
310 | /* Check if the BFD passed in is an IR dummy object file. */ |
||
6324 | serge | 311 | static inline bfd_boolean |
5199 | serge | 312 | is_ir_dummy_bfd (const bfd *abfd) |
313 | { |
||
314 | /* ABFD can sometimes legitimately be NULL, e.g. when called from one |
||
6324 | serge | 315 | of the linker callbacks for a symbol in the *ABS* or *UND* sections. */ |
316 | return abfd != NULL && (abfd->flags & BFD_PLUGIN) != 0; |
||
5199 | serge | 317 | } |
318 | |||
319 | /* Helpers to convert between BFD and GOLD symbol formats. */ |
||
320 | static enum ld_plugin_status |
||
321 | asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, |
||
322 | const struct ld_plugin_symbol *ldsym) |
||
323 | { |
||
324 | flagword flags = BSF_NO_FLAGS; |
||
325 | struct bfd_section *section; |
||
326 | |||
327 | asym->the_bfd = abfd; |
||
328 | asym->name = (ldsym->version |
||
329 | ? concat (ldsym->name, "@", ldsym->version, (const char *) NULL) |
||
330 | : ldsym->name); |
||
331 | asym->value = 0; |
||
332 | switch (ldsym->def) |
||
333 | { |
||
334 | case LDPK_WEAKDEF: |
||
335 | flags = BSF_WEAK; |
||
336 | /* FALLTHRU */ |
||
337 | case LDPK_DEF: |
||
338 | flags |= BSF_GLOBAL; |
||
339 | if (ldsym->comdat_key) |
||
340 | { |
||
341 | char *name = concat (".gnu.linkonce.t.", ldsym->comdat_key, |
||
342 | (const char *) NULL); |
||
343 | section = bfd_get_section_by_name (abfd, name); |
||
344 | if (section != NULL) |
||
345 | free (name); |
||
346 | else |
||
347 | { |
||
348 | flagword sflags; |
||
349 | |||
350 | sflags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY |
||
351 | | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE |
||
352 | | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD); |
||
353 | section = bfd_make_section_anyway_with_flags (abfd, name, sflags); |
||
354 | if (section == NULL) |
||
355 | return LDPS_ERR; |
||
356 | } |
||
357 | } |
||
358 | else |
||
359 | section = bfd_get_section_by_name (abfd, ".text"); |
||
360 | break; |
||
361 | |||
362 | case LDPK_WEAKUNDEF: |
||
363 | flags = BSF_WEAK; |
||
364 | /* FALLTHRU */ |
||
365 | case LDPK_UNDEF: |
||
366 | section = bfd_und_section_ptr; |
||
367 | break; |
||
368 | |||
369 | case LDPK_COMMON: |
||
370 | flags = BSF_GLOBAL; |
||
371 | section = bfd_com_section_ptr; |
||
372 | asym->value = ldsym->size; |
||
373 | /* For ELF targets, set alignment of common symbol to 1. */ |
||
374 | if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
||
375 | { |
||
376 | ((elf_symbol_type *) asym)->internal_elf_sym.st_shndx = SHN_COMMON; |
||
377 | ((elf_symbol_type *) asym)->internal_elf_sym.st_value = 1; |
||
378 | } |
||
379 | break; |
||
380 | |||
381 | default: |
||
382 | return LDPS_ERR; |
||
383 | } |
||
384 | asym->flags = flags; |
||
385 | asym->section = section; |
||
386 | |||
387 | /* Visibility only applies on ELF targets. */ |
||
388 | if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
||
389 | { |
||
390 | elf_symbol_type *elfsym = elf_symbol_from (abfd, asym); |
||
391 | unsigned char visibility; |
||
392 | |||
393 | if (!elfsym) |
||
394 | einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!\n"), asym->name); |
||
395 | switch (ldsym->visibility) |
||
396 | { |
||
397 | default: |
||
398 | einfo (_("%P%F: unknown ELF symbol visibility: %d!\n"), |
||
399 | ldsym->visibility); |
||
400 | case LDPV_DEFAULT: |
||
401 | visibility = STV_DEFAULT; |
||
402 | break; |
||
403 | case LDPV_PROTECTED: |
||
404 | visibility = STV_PROTECTED; |
||
405 | break; |
||
406 | case LDPV_INTERNAL: |
||
407 | visibility = STV_INTERNAL; |
||
408 | break; |
||
409 | case LDPV_HIDDEN: |
||
410 | visibility = STV_HIDDEN; |
||
411 | break; |
||
412 | } |
||
413 | elfsym->internal_elf_sym.st_other |
||
414 | = (visibility | (elfsym->internal_elf_sym.st_other |
||
415 | & ~ELF_ST_VISIBILITY (-1))); |
||
416 | } |
||
417 | |||
418 | return LDPS_OK; |
||
419 | } |
||
420 | |||
421 | /* Register a claim-file handler. */ |
||
422 | static enum ld_plugin_status |
||
423 | register_claim_file (ld_plugin_claim_file_handler handler) |
||
424 | { |
||
425 | ASSERT (called_plugin); |
||
426 | called_plugin->claim_file_handler = handler; |
||
427 | return LDPS_OK; |
||
428 | } |
||
429 | |||
430 | /* Register an all-symbols-read handler. */ |
||
431 | static enum ld_plugin_status |
||
432 | register_all_symbols_read (ld_plugin_all_symbols_read_handler handler) |
||
433 | { |
||
434 | ASSERT (called_plugin); |
||
435 | called_plugin->all_symbols_read_handler = handler; |
||
436 | return LDPS_OK; |
||
437 | } |
||
438 | |||
439 | /* Register a cleanup handler. */ |
||
440 | static enum ld_plugin_status |
||
441 | register_cleanup (ld_plugin_cleanup_handler handler) |
||
442 | { |
||
443 | ASSERT (called_plugin); |
||
444 | called_plugin->cleanup_handler = handler; |
||
445 | return LDPS_OK; |
||
446 | } |
||
447 | |||
448 | /* Add symbols from a plugin-claimed input file. */ |
||
449 | static enum ld_plugin_status |
||
450 | add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms) |
||
451 | { |
||
452 | asymbol **symptrs; |
||
6324 | serge | 453 | plugin_input_file_t *input = handle; |
454 | bfd *abfd = input->abfd; |
||
5199 | serge | 455 | int n; |
456 | |||
457 | ASSERT (called_plugin); |
||
458 | symptrs = xmalloc (nsyms * sizeof *symptrs); |
||
459 | for (n = 0; n < nsyms; n++) |
||
460 | { |
||
461 | enum ld_plugin_status rv; |
||
462 | asymbol *bfdsym; |
||
463 | |||
464 | bfdsym = bfd_make_empty_symbol (abfd); |
||
465 | symptrs[n] = bfdsym; |
||
466 | rv = asymbol_from_plugin_symbol (abfd, bfdsym, syms + n); |
||
467 | if (rv != LDPS_OK) |
||
468 | return rv; |
||
469 | } |
||
470 | bfd_set_symtab (abfd, symptrs, nsyms); |
||
471 | return LDPS_OK; |
||
472 | } |
||
473 | |||
474 | /* Get the input file information with an open (possibly re-opened) |
||
475 | file descriptor. */ |
||
476 | static enum ld_plugin_status |
||
6324 | serge | 477 | get_input_file (const void *handle, struct ld_plugin_input_file *file) |
5199 | serge | 478 | { |
6324 | serge | 479 | const plugin_input_file_t *input = handle; |
480 | |||
5199 | serge | 481 | ASSERT (called_plugin); |
6324 | serge | 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 |
||
493 | get_view (const void *handle, const void **viewp) |
||
494 | { |
||
495 | ASSERT (called_plugin); |
||
5199 | serge | 496 | return LDPS_ERR; |
497 | } |
||
498 | |||
499 | /* Release the input file. */ |
||
500 | static enum ld_plugin_status |
||
6324 | serge | 501 | release_input_file (const void *handle) |
5199 | serge | 502 | { |
503 | ASSERT (called_plugin); |
||
504 | return LDPS_ERR; |
||
505 | } |
||
506 | |||
507 | /* Return TRUE if a defined symbol might be reachable from outside the |
||
508 | universe of claimed objects. */ |
||
509 | static inline bfd_boolean |
||
510 | is_visible_from_outside (struct ld_plugin_symbol *lsym, |
||
511 | struct bfd_link_hash_entry *blhe) |
||
512 | { |
||
513 | struct bfd_sym_chain *sym; |
||
514 | |||
6324 | serge | 515 | if (bfd_link_relocatable (&link_info)) |
5199 | serge | 516 | return TRUE; |
6324 | serge | 517 | if (link_info.export_dynamic || bfd_link_dll (&link_info)) |
5199 | serge | 518 | { |
519 | /* Check if symbol is hidden by version script. */ |
||
520 | if (bfd_hide_sym_by_version (link_info.version_info, |
||
521 | blhe->root.string)) |
||
522 | return FALSE; |
||
523 | /* Only ELF symbols really have visibility. */ |
||
524 | if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour) |
||
525 | { |
||
526 | struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe; |
||
527 | int vis = ELF_ST_VISIBILITY (el->other); |
||
528 | return vis == STV_DEFAULT || vis == STV_PROTECTED; |
||
529 | } |
||
530 | /* On non-ELF targets, we can safely make inferences by considering |
||
531 | what visibility the plugin would have liked to apply when it first |
||
532 | sent us the symbol. During ELF symbol processing, visibility only |
||
533 | ever becomes more restrictive, not less, when symbols are merged, |
||
534 | so this is a conservative estimate; it may give false positives, |
||
535 | declaring something visible from outside when it in fact would |
||
536 | not have been, but this will only lead to missed optimisation |
||
537 | opportunities during LTRANS at worst; it will not give false |
||
538 | negatives, which can lead to the disastrous conclusion that the |
||
539 | related symbol is IRONLY. (See GCC PR46319 for an example.) */ |
||
540 | return (lsym->visibility == LDPV_DEFAULT |
||
541 | || lsym->visibility == LDPV_PROTECTED); |
||
542 | } |
||
543 | |||
544 | for (sym = &entry_symbol; sym != NULL; sym = sym->next) |
||
545 | if (sym->name |
||
546 | && strcmp (sym->name, blhe->root.string) == 0) |
||
547 | return TRUE; |
||
548 | |||
549 | return FALSE; |
||
550 | } |
||
551 | |||
552 | /* Get the symbol resolution info for a plugin-claimed input file. */ |
||
553 | static enum ld_plugin_status |
||
554 | get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, |
||
555 | int def_ironly_exp) |
||
556 | { |
||
6324 | serge | 557 | const plugin_input_file_t *input = handle; |
558 | const bfd *abfd = (const bfd *) input->abfd; |
||
5199 | serge | 559 | int n; |
560 | |||
561 | ASSERT (called_plugin); |
||
562 | for (n = 0; n < nsyms; n++) |
||
563 | { |
||
564 | struct bfd_link_hash_entry *blhe; |
||
565 | asection *owner_sec; |
||
566 | int res; |
||
567 | |||
568 | if (syms[n].def != LDPK_UNDEF) |
||
569 | blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name, |
||
570 | FALSE, FALSE, TRUE); |
||
571 | else |
||
572 | blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, |
||
573 | syms[n].name, FALSE, FALSE, TRUE); |
||
574 | if (!blhe) |
||
575 | { |
||
576 | res = LDPR_UNKNOWN; |
||
577 | goto report_symbol; |
||
578 | } |
||
579 | |||
580 | /* Determine resolution from blhe type and symbol's original type. */ |
||
581 | if (blhe->type == bfd_link_hash_undefined |
||
582 | || blhe->type == bfd_link_hash_undefweak) |
||
583 | { |
||
584 | res = LDPR_UNDEF; |
||
585 | goto report_symbol; |
||
586 | } |
||
587 | if (blhe->type != bfd_link_hash_defined |
||
588 | && blhe->type != bfd_link_hash_defweak |
||
589 | && blhe->type != bfd_link_hash_common) |
||
590 | { |
||
591 | /* We should not have a new, indirect or warning symbol here. */ |
||
592 | einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)\n", |
||
593 | called_plugin->name, blhe->type); |
||
594 | } |
||
595 | |||
596 | /* Find out which section owns the symbol. Since it's not undef, |
||
597 | it must have an owner; if it's not a common symbol, both defs |
||
598 | and weakdefs keep it in the same place. */ |
||
599 | owner_sec = (blhe->type == bfd_link_hash_common |
||
600 | ? blhe->u.c.p->section |
||
601 | : blhe->u.def.section); |
||
602 | |||
603 | |||
604 | /* If it was originally undefined or common, then it has been |
||
605 | resolved; determine how. */ |
||
606 | if (syms[n].def == LDPK_UNDEF |
||
607 | || syms[n].def == LDPK_WEAKUNDEF |
||
608 | || syms[n].def == LDPK_COMMON) |
||
609 | { |
||
610 | if (owner_sec->owner == link_info.output_bfd) |
||
611 | res = LDPR_RESOLVED_EXEC; |
||
612 | else if (owner_sec->owner == abfd) |
||
613 | res = LDPR_PREVAILING_DEF_IRONLY; |
||
614 | else if (is_ir_dummy_bfd (owner_sec->owner)) |
||
615 | res = LDPR_RESOLVED_IR; |
||
616 | else if (owner_sec->owner != NULL |
||
617 | && (owner_sec->owner->flags & DYNAMIC) != 0) |
||
618 | res = LDPR_RESOLVED_DYN; |
||
619 | else |
||
620 | res = LDPR_RESOLVED_EXEC; |
||
621 | } |
||
622 | |||
623 | /* Was originally def, or weakdef. Does it prevail? If the |
||
624 | owner is the original dummy bfd that supplied it, then this |
||
625 | is the definition that has prevailed. */ |
||
626 | else if (owner_sec->owner == link_info.output_bfd) |
||
627 | res = LDPR_PREEMPTED_REG; |
||
628 | else if (owner_sec->owner == abfd) |
||
629 | res = LDPR_PREVAILING_DEF_IRONLY; |
||
630 | |||
631 | /* Was originally def, weakdef, or common, but has been pre-empted. */ |
||
632 | else if (is_ir_dummy_bfd (owner_sec->owner)) |
||
633 | res = LDPR_PREEMPTED_IR; |
||
634 | else |
||
635 | res = LDPR_PREEMPTED_REG; |
||
636 | |||
637 | if (res == LDPR_PREVAILING_DEF_IRONLY) |
||
638 | { |
||
639 | /* We need to know if the sym is referenced from non-IR files. Or |
||
640 | even potentially-referenced, perhaps in a future final link if |
||
641 | this is a partial one, perhaps dynamically at load-time if the |
||
642 | symbol is externally visible. */ |
||
643 | if (blhe->non_ir_ref) |
||
644 | res = LDPR_PREVAILING_DEF; |
||
645 | else if (is_visible_from_outside (&syms[n], blhe)) |
||
646 | res = def_ironly_exp; |
||
647 | } |
||
648 | |||
649 | report_symbol: |
||
650 | syms[n].resolution = res; |
||
651 | if (report_plugin_symbols) |
||
652 | einfo (_("%P: %B: symbol `%s' " |
||
653 | "definition: %d, visibility: %d, resolution: %d\n"), |
||
654 | abfd, syms[n].name, |
||
655 | syms[n].def, syms[n].visibility, res); |
||
656 | } |
||
657 | return LDPS_OK; |
||
658 | } |
||
659 | |||
660 | static enum ld_plugin_status |
||
661 | get_symbols_v1 (const void *handle, int nsyms, struct ld_plugin_symbol *syms) |
||
662 | { |
||
663 | return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF); |
||
664 | } |
||
665 | |||
666 | static enum ld_plugin_status |
||
667 | get_symbols_v2 (const void *handle, int nsyms, struct ld_plugin_symbol *syms) |
||
668 | { |
||
669 | return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF_IRONLY_EXP); |
||
670 | } |
||
671 | |||
672 | /* Add a new (real) input file generated by a plugin. */ |
||
673 | static enum ld_plugin_status |
||
674 | add_input_file (const char *pathname) |
||
675 | { |
||
6324 | serge | 676 | lang_input_statement_type *is; |
677 | |||
5199 | serge | 678 | ASSERT (called_plugin); |
6324 | serge | 679 | is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum, |
680 | NULL); |
||
681 | if (!is) |
||
5199 | serge | 682 | return LDPS_ERR; |
6324 | serge | 683 | is->flags.lto_output = 1; |
5199 | serge | 684 | return LDPS_OK; |
685 | } |
||
686 | |||
687 | /* Add a new (real) library required by a plugin. */ |
||
688 | static enum ld_plugin_status |
||
689 | add_input_library (const char *pathname) |
||
690 | { |
||
6324 | serge | 691 | lang_input_statement_type *is; |
692 | |||
5199 | serge | 693 | ASSERT (called_plugin); |
6324 | serge | 694 | is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum, |
695 | NULL); |
||
696 | if (!is) |
||
5199 | serge | 697 | return LDPS_ERR; |
6324 | serge | 698 | is->flags.lto_output = 1; |
5199 | serge | 699 | return LDPS_OK; |
700 | } |
||
701 | |||
702 | /* Set the extra library path to be used by libraries added via |
||
703 | add_input_library. */ |
||
704 | static enum ld_plugin_status |
||
705 | set_extra_library_path (const char *path) |
||
706 | { |
||
707 | ASSERT (called_plugin); |
||
708 | ldfile_add_library_path (xstrdup (path), FALSE); |
||
709 | return LDPS_OK; |
||
710 | } |
||
711 | |||
712 | /* Issue a diagnostic message from a plugin. */ |
||
713 | static enum ld_plugin_status |
||
714 | message (int level, const char *format, ...) |
||
715 | { |
||
716 | va_list args; |
||
717 | va_start (args, format); |
||
718 | |||
719 | switch (level) |
||
720 | { |
||
721 | case LDPL_INFO: |
||
722 | vfinfo (stdout, format, args, FALSE); |
||
723 | putchar ('\n'); |
||
724 | break; |
||
725 | case LDPL_WARNING: |
||
6324 | serge | 726 | { |
727 | char *newfmt = ACONCAT (("%P: warning: ", format, "\n", |
||
728 | (const char *) NULL)); |
||
729 | vfinfo (stdout, newfmt, args, TRUE); |
||
730 | } |
||
5199 | serge | 731 | break; |
732 | case LDPL_FATAL: |
||
733 | case LDPL_ERROR: |
||
734 | default: |
||
735 | { |
||
6324 | serge | 736 | char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F" : "%P%X", |
737 | ": error: ", format, "\n", |
||
738 | (const char *) NULL)); |
||
5199 | serge | 739 | fflush (stdout); |
740 | vfinfo (stderr, newfmt, args, TRUE); |
||
741 | fflush (stderr); |
||
742 | } |
||
743 | break; |
||
744 | } |
||
745 | |||
746 | va_end (args); |
||
747 | return LDPS_OK; |
||
748 | } |
||
749 | |||
750 | /* Helper to size leading part of tv array and set it up. */ |
||
751 | static void |
||
752 | set_tv_header (struct ld_plugin_tv *tv) |
||
753 | { |
||
754 | size_t i; |
||
755 | |||
756 | /* Version info. */ |
||
757 | static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL); |
||
758 | static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100; |
||
759 | |||
760 | for (i = 0; i < tv_header_size; i++) |
||
761 | { |
||
762 | tv[i].tv_tag = tv_header_tags[i]; |
||
763 | #define TVU(x) tv[i].tv_u.tv_ ## x |
||
764 | switch (tv[i].tv_tag) |
||
765 | { |
||
766 | case LDPT_MESSAGE: |
||
767 | TVU(message) = message; |
||
768 | break; |
||
769 | case LDPT_API_VERSION: |
||
770 | TVU(val) = LD_PLUGIN_API_VERSION; |
||
771 | break; |
||
772 | case LDPT_GNU_LD_VERSION: |
||
773 | TVU(val) = major * 100 + minor; |
||
774 | break; |
||
775 | case LDPT_LINKER_OUTPUT: |
||
6324 | serge | 776 | TVU(val) = (bfd_link_relocatable (&link_info) ? LDPO_REL |
777 | : bfd_link_pde (&link_info) ? LDPO_EXEC |
||
778 | : bfd_link_pie (&link_info) ? LDPO_PIE |
||
779 | : LDPO_DYN); |
||
5199 | serge | 780 | break; |
781 | case LDPT_OUTPUT_NAME: |
||
782 | TVU(string) = output_filename; |
||
783 | break; |
||
784 | case LDPT_REGISTER_CLAIM_FILE_HOOK: |
||
785 | TVU(register_claim_file) = register_claim_file; |
||
786 | break; |
||
787 | case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: |
||
788 | TVU(register_all_symbols_read) = register_all_symbols_read; |
||
789 | break; |
||
790 | case LDPT_REGISTER_CLEANUP_HOOK: |
||
791 | TVU(register_cleanup) = register_cleanup; |
||
792 | break; |
||
793 | case LDPT_ADD_SYMBOLS: |
||
794 | TVU(add_symbols) = add_symbols; |
||
795 | break; |
||
796 | case LDPT_GET_INPUT_FILE: |
||
797 | TVU(get_input_file) = get_input_file; |
||
798 | break; |
||
6324 | serge | 799 | case LDPT_GET_VIEW: |
800 | TVU(get_view) = get_view; |
||
801 | break; |
||
5199 | serge | 802 | case LDPT_RELEASE_INPUT_FILE: |
803 | TVU(release_input_file) = release_input_file; |
||
804 | break; |
||
805 | case LDPT_GET_SYMBOLS: |
||
806 | TVU(get_symbols) = get_symbols_v1; |
||
807 | break; |
||
808 | case LDPT_GET_SYMBOLS_V2: |
||
809 | TVU(get_symbols) = get_symbols_v2; |
||
810 | break; |
||
811 | case LDPT_ADD_INPUT_FILE: |
||
812 | TVU(add_input_file) = add_input_file; |
||
813 | break; |
||
814 | case LDPT_ADD_INPUT_LIBRARY: |
||
815 | TVU(add_input_library) = add_input_library; |
||
816 | break; |
||
817 | case LDPT_SET_EXTRA_LIBRARY_PATH: |
||
818 | TVU(set_extra_library_path) = set_extra_library_path; |
||
819 | break; |
||
820 | default: |
||
821 | /* Added a new entry to the array without adding |
||
822 | a new case to set up its value is a bug. */ |
||
823 | FAIL (); |
||
824 | } |
||
825 | #undef TVU |
||
826 | } |
||
827 | } |
||
828 | |||
829 | /* Append the per-plugin args list and trailing LDPT_NULL to tv. */ |
||
830 | static void |
||
831 | set_tv_plugin_args (plugin_t *plugin, struct ld_plugin_tv *tv) |
||
832 | { |
||
833 | plugin_arg_t *arg = plugin->args; |
||
834 | while (arg) |
||
835 | { |
||
836 | tv->tv_tag = LDPT_OPTION; |
||
837 | tv->tv_u.tv_string = arg->arg; |
||
838 | arg = arg->next; |
||
839 | tv++; |
||
840 | } |
||
841 | tv->tv_tag = LDPT_NULL; |
||
842 | tv->tv_u.tv_val = 0; |
||
843 | } |
||
844 | |||
845 | /* Load up and initialise all plugins after argument parsing. */ |
||
846 | void |
||
847 | plugin_load_plugins (void) |
||
848 | { |
||
849 | struct ld_plugin_tv *my_tv; |
||
850 | unsigned int max_args = 0; |
||
851 | plugin_t *curplug = plugins_list; |
||
852 | |||
853 | /* If there are no plugins, we need do nothing this run. */ |
||
854 | if (!curplug) |
||
855 | return; |
||
856 | |||
857 | /* First pass over plugins to find max # args needed so that we |
||
858 | can size and allocate the tv array. */ |
||
859 | while (curplug) |
||
860 | { |
||
861 | if (curplug->n_args > max_args) |
||
862 | max_args = curplug->n_args; |
||
863 | curplug = curplug->next; |
||
864 | } |
||
865 | |||
866 | /* Allocate tv array and initialise constant part. */ |
||
867 | my_tv = xmalloc ((max_args + 1 + tv_header_size) * sizeof *my_tv); |
||
868 | set_tv_header (my_tv); |
||
869 | |||
870 | /* Pass over plugins again, activating them. */ |
||
871 | curplug = plugins_list; |
||
872 | while (curplug) |
||
873 | { |
||
874 | enum ld_plugin_status rv; |
||
875 | ld_plugin_onload onloadfn; |
||
876 | |||
877 | onloadfn = (ld_plugin_onload) dlsym (curplug->dlhandle, "onload"); |
||
878 | if (!onloadfn) |
||
879 | onloadfn = (ld_plugin_onload) dlsym (curplug->dlhandle, "_onload"); |
||
880 | if (!onloadfn) |
||
881 | einfo (_("%P%F: %s: error loading plugin: %s\n"), |
||
882 | curplug->name, dlerror ()); |
||
883 | set_tv_plugin_args (curplug, &my_tv[tv_header_size]); |
||
884 | called_plugin = curplug; |
||
885 | rv = (*onloadfn) (my_tv); |
||
886 | called_plugin = NULL; |
||
887 | if (rv != LDPS_OK) |
||
888 | einfo (_("%P%F: %s: plugin error: %d\n"), curplug->name, rv); |
||
889 | curplug = curplug->next; |
||
890 | } |
||
891 | |||
892 | /* Since plugin(s) inited ok, assume they're going to want symbol |
||
893 | resolutions, which needs us to track which symbols are referenced |
||
894 | by non-IR files using the linker's notice callback. */ |
||
895 | orig_notice_all = link_info.notice_all; |
||
896 | orig_callbacks = link_info.callbacks; |
||
897 | plugin_callbacks = *orig_callbacks; |
||
898 | plugin_callbacks.notice = &plugin_notice; |
||
899 | link_info.notice_all = TRUE; |
||
6324 | serge | 900 | link_info.lto_plugin_active = TRUE; |
5199 | serge | 901 | link_info.callbacks = &plugin_callbacks; |
6324 | serge | 902 | |
903 | register_ld_plugin_object_p (plugin_object_p); |
||
904 | |||
905 | #if HAVE_MMAP && HAVE_GETPAGESIZE |
||
906 | plugin_pagesize = getpagesize (); |
||
907 | #endif |
||
5199 | serge | 908 | } |
909 | |||
910 | /* Call 'claim file' hook for all plugins. */ |
||
911 | static int |
||
912 | plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed) |
||
913 | { |
||
914 | plugin_t *curplug = plugins_list; |
||
915 | *claimed = FALSE; |
||
916 | if (no_more_claiming) |
||
917 | return 0; |
||
918 | while (curplug && !*claimed) |
||
919 | { |
||
920 | if (curplug->claim_file_handler) |
||
921 | { |
||
922 | enum ld_plugin_status rv; |
||
923 | called_plugin = curplug; |
||
924 | rv = (*curplug->claim_file_handler) (file, claimed); |
||
925 | called_plugin = NULL; |
||
926 | if (rv != LDPS_OK) |
||
927 | set_plugin_error (curplug->name); |
||
928 | } |
||
929 | curplug = curplug->next; |
||
930 | } |
||
931 | return plugin_error_p () ? -1 : 0; |
||
932 | } |
||
933 | |||
6324 | serge | 934 | /* Duplicates a character string with memory attached to ABFD. */ |
935 | |||
936 | static char * |
||
937 | plugin_strdup (bfd *abfd, const char *str) |
||
5199 | serge | 938 | { |
6324 | serge | 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 | } |
||
5199 | serge | 949 | |
6324 | serge | 950 | static const bfd_target * |
951 | plugin_object_p (bfd *ibfd) |
||
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) |
||
979 | return NULL; |
||
980 | |||
5199 | serge | 981 | /* We create a dummy BFD, initially empty, to house whatever symbols |
982 | the plugin may want to add. */ |
||
6324 | serge | 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; |
||
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 | |||
1025 | claimed = 0; |
||
1026 | |||
1027 | if (plugin_call_claim_file (&file, &claimed)) |
||
5199 | serge | 1028 | einfo (_("%P%F: %s: plugin reported error claiming file\n"), |
1029 | plugin_error_plugin ()); |
||
6324 | serge | 1030 | |
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 |
||
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; |
||
1043 | } |
||
1044 | |||
5199 | serge | 1045 | if (claimed) |
1046 | { |
||
6324 | serge | 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 | { |
||
1082 | bfd *abfd = entry->the_bfd->plugin_dummy_bfd; |
||
1083 | |||
5199 | serge | 1084 | /* Discard the real file's BFD and substitute the dummy one. */ |
1085 | |||
1086 | /* BFD archive handling caches elements so we can't call |
||
1087 | bfd_close for archives. */ |
||
1088 | if (entry->the_bfd->my_archive == NULL) |
||
1089 | bfd_close (entry->the_bfd); |
||
6324 | serge | 1090 | entry->the_bfd = abfd; |
1091 | entry->flags.claimed = 1; |
||
5199 | serge | 1092 | } |
1093 | } |
||
1094 | |||
1095 | /* Call 'all symbols read' hook for all plugins. */ |
||
1096 | int |
||
1097 | plugin_call_all_symbols_read (void) |
||
1098 | { |
||
1099 | plugin_t *curplug = plugins_list; |
||
1100 | |||
1101 | /* Disable any further file-claiming. */ |
||
1102 | no_more_claiming = TRUE; |
||
1103 | |||
1104 | while (curplug) |
||
1105 | { |
||
1106 | if (curplug->all_symbols_read_handler) |
||
1107 | { |
||
1108 | enum ld_plugin_status rv; |
||
1109 | called_plugin = curplug; |
||
1110 | rv = (*curplug->all_symbols_read_handler) (); |
||
1111 | called_plugin = NULL; |
||
1112 | if (rv != LDPS_OK) |
||
1113 | set_plugin_error (curplug->name); |
||
1114 | } |
||
1115 | curplug = curplug->next; |
||
1116 | } |
||
1117 | return plugin_error_p () ? -1 : 0; |
||
1118 | } |
||
1119 | |||
1120 | /* Call 'cleanup' hook for all plugins at exit. */ |
||
1121 | void |
||
1122 | plugin_call_cleanup (void) |
||
1123 | { |
||
1124 | plugin_t *curplug = plugins_list; |
||
1125 | while (curplug) |
||
1126 | { |
||
1127 | if (curplug->cleanup_handler && !curplug->cleanup_done) |
||
1128 | { |
||
1129 | enum ld_plugin_status rv; |
||
1130 | curplug->cleanup_done = TRUE; |
||
1131 | called_plugin = curplug; |
||
1132 | rv = (*curplug->cleanup_handler) (); |
||
1133 | called_plugin = NULL; |
||
1134 | if (rv != LDPS_OK) |
||
1135 | info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"), |
||
1136 | curplug->name, rv); |
||
1137 | dlclose (curplug->dlhandle); |
||
1138 | } |
||
1139 | curplug = curplug->next; |
||
1140 | } |
||
1141 | } |
||
1142 | |||
1143 | /* To determine which symbols should be resolved LDPR_PREVAILING_DEF |
||
1144 | and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as |
||
1145 | the linker adds them to the linker hash table. Mark those |
||
1146 | referenced from a non-IR file with non_ir_ref. We have to |
||
1147 | notice_all symbols, because we won't necessarily know until later |
||
1148 | which ones will be contributed by IR files. */ |
||
1149 | static bfd_boolean |
||
1150 | plugin_notice (struct bfd_link_info *info, |
||
1151 | struct bfd_link_hash_entry *h, |
||
6324 | serge | 1152 | struct bfd_link_hash_entry *inh, |
5199 | serge | 1153 | bfd *abfd, |
1154 | asection *section, |
||
1155 | bfd_vma value, |
||
6324 | serge | 1156 | flagword flags) |
5199 | serge | 1157 | { |
6324 | serge | 1158 | struct bfd_link_hash_entry *orig_h = h; |
1159 | |||
5199 | serge | 1160 | if (h != NULL) |
1161 | { |
||
1162 | bfd *sym_bfd; |
||
1163 | |||
6324 | serge | 1164 | if (h->type == bfd_link_hash_warning) |
1165 | h = h->u.i.link; |
||
1166 | |||
5199 | serge | 1167 | /* Nothing to do here if this def/ref is from an IR dummy BFD. */ |
1168 | if (is_ir_dummy_bfd (abfd)) |
||
1169 | ; |
||
1170 | |||
1171 | /* Making an indirect symbol counts as a reference unless this |
||
1172 | is a brand new symbol. */ |
||
1173 | else if (bfd_is_ind_section (section) |
||
1174 | || (flags & BSF_INDIRECT) != 0) |
||
1175 | { |
||
6324 | serge | 1176 | /* ??? Some of this is questionable. See comments in |
1177 | _bfd_generic_link_add_one_symbol for case IND. */ |
||
5199 | serge | 1178 | if (h->type != bfd_link_hash_new) |
1179 | { |
||
1180 | h->non_ir_ref = TRUE; |
||
1181 | inh->non_ir_ref = TRUE; |
||
1182 | } |
||
6324 | serge | 1183 | else if (inh->type == bfd_link_hash_new) |
1184 | inh->non_ir_ref = TRUE; |
||
5199 | serge | 1185 | } |
1186 | |||
1187 | /* Nothing to do here for warning symbols. */ |
||
1188 | else if ((flags & BSF_WARNING) != 0) |
||
1189 | ; |
||
1190 | |||
1191 | /* Nothing to do here for constructor symbols. */ |
||
1192 | else if ((flags & BSF_CONSTRUCTOR) != 0) |
||
1193 | ; |
||
1194 | |||
1195 | /* If this is a ref, set non_ir_ref. */ |
||
1196 | else if (bfd_is_und_section (section)) |
||
1197 | { |
||
1198 | /* Replace the undefined dummy bfd with the real one. */ |
||
1199 | if ((h->type == bfd_link_hash_undefined |
||
1200 | || h->type == bfd_link_hash_undefweak) |
||
1201 | && (h->u.undef.abfd == NULL |
||
1202 | || (h->u.undef.abfd->flags & BFD_PLUGIN) != 0)) |
||
1203 | h->u.undef.abfd = abfd; |
||
1204 | h->non_ir_ref = TRUE; |
||
1205 | } |
||
1206 | |||
1207 | /* Otherwise, it must be a new def. Ensure any symbol defined |
||
1208 | in an IR dummy BFD takes on a new value from a real BFD. |
||
1209 | Weak symbols are not normally overridden by a new weak |
||
1210 | definition, and strong symbols will normally cause multiple |
||
1211 | definition errors. Avoid this by making the symbol appear |
||
1212 | to be undefined. */ |
||
1213 | else if (((h->type == bfd_link_hash_defweak |
||
1214 | || h->type == bfd_link_hash_defined) |
||
1215 | && is_ir_dummy_bfd (sym_bfd = h->u.def.section->owner)) |
||
1216 | || (h->type == bfd_link_hash_common |
||
1217 | && is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner))) |
||
1218 | { |
||
1219 | h->type = bfd_link_hash_undefweak; |
||
1220 | h->u.undef.abfd = sym_bfd; |
||
1221 | } |
||
1222 | } |
||
1223 | |||
1224 | /* Continue with cref/nocrossref/trace-sym processing. */ |
||
6324 | serge | 1225 | if (orig_h == NULL |
5199 | serge | 1226 | || orig_notice_all |
1227 | || (info->notice_hash != NULL |
||
6324 | serge | 1228 | && bfd_hash_lookup (info->notice_hash, orig_h->root.string, |
5199 | serge | 1229 | FALSE, FALSE) != NULL)) |
6324 | serge | 1230 | return (*orig_callbacks->notice) (info, orig_h, inh, |
1231 | abfd, section, value, flags); |
||
5199 | serge | 1232 | return TRUE; |
1233 | }>>>> |