1 |
145 |
khays |
/* Plugin control for the GNU linker.
|
2 |
|
|
Copyright 2010, 2011 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 |
|
|
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
|
36 |
|
|
#include <windows.h>
|
37 |
|
|
#endif
|
38 |
|
|
|
39 |
|
|
/* Report plugin symbols. */
|
40 |
|
|
bfd_boolean report_plugin_symbols;
|
41 |
|
|
|
42 |
|
|
/* The suffix to append to the name of the real (claimed) object file
|
43 |
|
|
when generating a dummy BFD to hold the IR symbols sent from the
|
44 |
|
|
plugin. For cosmetic use only; appears in maps, crefs etc. */
|
45 |
|
|
#define IRONLY_SUFFIX " (symbol from plugin)"
|
46 |
|
|
|
47 |
|
|
/* Stores a single argument passed to a plugin. */
|
48 |
|
|
typedef struct plugin_arg
|
49 |
|
|
{
|
50 |
|
|
struct plugin_arg *next;
|
51 |
|
|
const char *arg;
|
52 |
|
|
} plugin_arg_t;
|
53 |
|
|
|
54 |
|
|
/* Holds all details of a single plugin. */
|
55 |
|
|
typedef struct plugin
|
56 |
|
|
{
|
57 |
|
|
/* Next on the list of plugins, or NULL at end of chain. */
|
58 |
|
|
struct plugin *next;
|
59 |
|
|
/* The argument string given to --plugin. */
|
60 |
|
|
const char *name;
|
61 |
|
|
/* The shared library handle returned by dlopen. */
|
62 |
|
|
void *dlhandle;
|
63 |
|
|
/* The list of argument string given to --plugin-opt. */
|
64 |
|
|
plugin_arg_t *args;
|
65 |
|
|
/* Number of args in the list, for convenience. */
|
66 |
|
|
size_t n_args;
|
67 |
|
|
/* The plugin's event handlers. */
|
68 |
|
|
ld_plugin_claim_file_handler claim_file_handler;
|
69 |
|
|
ld_plugin_all_symbols_read_handler all_symbols_read_handler;
|
70 |
|
|
ld_plugin_cleanup_handler cleanup_handler;
|
71 |
|
|
/* TRUE if the cleanup handlers have been called. */
|
72 |
|
|
bfd_boolean cleanup_done;
|
73 |
|
|
} plugin_t;
|
74 |
|
|
|
75 |
|
|
/* The master list of all plugins. */
|
76 |
|
|
static plugin_t *plugins_list = NULL;
|
77 |
|
|
|
78 |
|
|
/* We keep a tail pointer for easy linking on the end. */
|
79 |
|
|
static plugin_t **plugins_tail_chain_ptr = &plugins_list;
|
80 |
|
|
|
81 |
|
|
/* The last plugin added to the list, for receiving args. */
|
82 |
|
|
static plugin_t *last_plugin = NULL;
|
83 |
|
|
|
84 |
|
|
/* The tail of the arg chain of the last plugin added to the list. */
|
85 |
|
|
static plugin_arg_t **last_plugin_args_tail_chain_ptr = NULL;
|
86 |
|
|
|
87 |
|
|
/* The plugin which is currently having a callback executed. */
|
88 |
|
|
static plugin_t *called_plugin = NULL;
|
89 |
|
|
|
90 |
|
|
/* Last plugin to cause an error, if any. */
|
91 |
|
|
static const char *error_plugin = NULL;
|
92 |
|
|
|
93 |
|
|
/* State of linker "notice" interface before we poked at it. */
|
94 |
|
|
static bfd_boolean orig_notice_all;
|
95 |
|
|
|
96 |
|
|
/* Original linker callbacks, and the plugin version. */
|
97 |
|
|
static const struct bfd_link_callbacks *orig_callbacks;
|
98 |
|
|
static struct bfd_link_callbacks plugin_callbacks;
|
99 |
|
|
|
100 |
|
|
/* Set at all symbols read time, to avoid recursively offering the plugin
|
101 |
|
|
its own newly-added input files and libs to claim. */
|
102 |
|
|
bfd_boolean no_more_claiming = FALSE;
|
103 |
|
|
|
104 |
|
|
/* List of tags to set in the constant leading part of the tv array. */
|
105 |
|
|
static const enum ld_plugin_tag tv_header_tags[] =
|
106 |
|
|
{
|
107 |
|
|
LDPT_MESSAGE,
|
108 |
|
|
LDPT_API_VERSION,
|
109 |
|
|
LDPT_GNU_LD_VERSION,
|
110 |
|
|
LDPT_LINKER_OUTPUT,
|
111 |
|
|
LDPT_OUTPUT_NAME,
|
112 |
|
|
LDPT_REGISTER_CLAIM_FILE_HOOK,
|
113 |
|
|
LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
|
114 |
|
|
LDPT_REGISTER_CLEANUP_HOOK,
|
115 |
|
|
LDPT_ADD_SYMBOLS,
|
116 |
|
|
LDPT_GET_INPUT_FILE,
|
117 |
|
|
LDPT_RELEASE_INPUT_FILE,
|
118 |
|
|
LDPT_GET_SYMBOLS,
|
119 |
163 |
khays |
LDPT_GET_SYMBOLS_V2,
|
120 |
145 |
khays |
LDPT_ADD_INPUT_FILE,
|
121 |
|
|
LDPT_ADD_INPUT_LIBRARY,
|
122 |
|
|
LDPT_SET_EXTRA_LIBRARY_PATH
|
123 |
|
|
};
|
124 |
|
|
|
125 |
|
|
/* 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);
|
127 |
|
|
|
128 |
|
|
/* Forward references. */
|
129 |
|
|
static bfd_boolean plugin_notice (struct bfd_link_info *,
|
130 |
|
|
struct bfd_link_hash_entry *, bfd *,
|
131 |
|
|
asection *, bfd_vma, flagword, const char *);
|
132 |
|
|
|
133 |
|
|
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
|
134 |
|
|
|
135 |
|
|
#define RTLD_NOW 0 /* Dummy value. */
|
136 |
|
|
|
137 |
|
|
static void *
|
138 |
|
|
dlopen (const char *file, int mode ATTRIBUTE_UNUSED)
|
139 |
|
|
{
|
140 |
|
|
return LoadLibrary (file);
|
141 |
|
|
}
|
142 |
|
|
|
143 |
|
|
static void *
|
144 |
|
|
dlsym (void *handle, const char *name)
|
145 |
|
|
{
|
146 |
|
|
return GetProcAddress (handle, name);
|
147 |
|
|
}
|
148 |
|
|
|
149 |
|
|
static int
|
150 |
|
|
dlclose (void *handle)
|
151 |
|
|
{
|
152 |
|
|
FreeLibrary (handle);
|
153 |
|
|
return 0;
|
154 |
|
|
}
|
155 |
|
|
|
156 |
|
|
#endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */
|
157 |
|
|
|
158 |
|
|
/* Helper function for exiting with error status. */
|
159 |
|
|
static int
|
160 |
|
|
set_plugin_error (const char *plugin)
|
161 |
|
|
{
|
162 |
|
|
error_plugin = plugin;
|
163 |
|
|
return -1;
|
164 |
|
|
}
|
165 |
|
|
|
166 |
|
|
/* Test if an error occurred. */
|
167 |
|
|
static bfd_boolean
|
168 |
|
|
plugin_error_p (void)
|
169 |
|
|
{
|
170 |
|
|
return error_plugin != NULL;
|
171 |
|
|
}
|
172 |
|
|
|
173 |
|
|
/* Return name of plugin which caused an error if any. */
|
174 |
|
|
const char *
|
175 |
|
|
plugin_error_plugin (void)
|
176 |
|
|
{
|
177 |
|
|
return error_plugin ? error_plugin : _("<no plugin>");
|
178 |
|
|
}
|
179 |
|
|
|
180 |
|
|
/* Handle -plugin arg: find and load plugin, or return error. */
|
181 |
|
|
int
|
182 |
|
|
plugin_opt_plugin (const char *plugin)
|
183 |
|
|
{
|
184 |
|
|
plugin_t *newplug;
|
185 |
|
|
|
186 |
|
|
newplug = xmalloc (sizeof *newplug);
|
187 |
|
|
memset (newplug, 0, sizeof *newplug);
|
188 |
|
|
newplug->name = plugin;
|
189 |
|
|
newplug->dlhandle = dlopen (plugin, RTLD_NOW);
|
190 |
|
|
if (!newplug->dlhandle)
|
191 |
|
|
return set_plugin_error (plugin);
|
192 |
|
|
|
193 |
|
|
/* Chain on end, so when we run list it is in command-line order. */
|
194 |
|
|
*plugins_tail_chain_ptr = newplug;
|
195 |
|
|
plugins_tail_chain_ptr = &newplug->next;
|
196 |
|
|
|
197 |
|
|
/* Record it as current plugin for receiving args. */
|
198 |
|
|
last_plugin = newplug;
|
199 |
|
|
last_plugin_args_tail_chain_ptr = &newplug->args;
|
200 |
|
|
return 0;
|
201 |
|
|
}
|
202 |
|
|
|
203 |
|
|
/* Accumulate option arguments for last-loaded plugin, or return
|
204 |
|
|
error if none. */
|
205 |
|
|
int
|
206 |
|
|
plugin_opt_plugin_arg (const char *arg)
|
207 |
|
|
{
|
208 |
|
|
plugin_arg_t *newarg;
|
209 |
|
|
|
210 |
|
|
if (!last_plugin)
|
211 |
|
|
return set_plugin_error (_("<no plugin>"));
|
212 |
|
|
|
213 |
|
|
newarg = xmalloc (sizeof *newarg);
|
214 |
|
|
newarg->arg = arg;
|
215 |
|
|
newarg->next = NULL;
|
216 |
|
|
|
217 |
|
|
/* Chain on end to preserve command-line order. */
|
218 |
|
|
*last_plugin_args_tail_chain_ptr = newarg;
|
219 |
|
|
last_plugin_args_tail_chain_ptr = &newarg->next;
|
220 |
|
|
last_plugin->n_args++;
|
221 |
|
|
return 0;
|
222 |
|
|
}
|
223 |
|
|
|
224 |
|
|
/* Create a dummy BFD. */
|
225 |
|
|
bfd *
|
226 |
|
|
plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
|
227 |
|
|
{
|
228 |
|
|
bfd *abfd;
|
229 |
|
|
|
230 |
|
|
bfd_use_reserved_id = 1;
|
231 |
|
|
abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL),
|
232 |
|
|
srctemplate);
|
233 |
|
|
if (abfd != NULL)
|
234 |
|
|
{
|
235 |
|
|
abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN;
|
236 |
|
|
bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
|
237 |
|
|
bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate));
|
238 |
|
|
if (bfd_make_writable (abfd)
|
239 |
|
|
&& bfd_copy_private_bfd_data (srctemplate, abfd))
|
240 |
|
|
{
|
241 |
|
|
flagword flags;
|
242 |
|
|
|
243 |
157 |
khays |
/* Create section to own the symbols. */
|
244 |
145 |
khays |
flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
|
245 |
|
|
| SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE);
|
246 |
|
|
if (bfd_make_section_anyway_with_flags (abfd, ".text", flags))
|
247 |
|
|
return abfd;
|
248 |
|
|
}
|
249 |
|
|
}
|
250 |
|
|
einfo (_("could not create dummy IR bfd: %F%E\n"));
|
251 |
|
|
return NULL;
|
252 |
|
|
}
|
253 |
|
|
|
254 |
|
|
/* Check if the BFD passed in is an IR dummy object file. */
|
255 |
|
|
static bfd_boolean
|
256 |
|
|
is_ir_dummy_bfd (const bfd *abfd)
|
257 |
|
|
{
|
258 |
|
|
/* ABFD can sometimes legitimately be NULL, e.g. when called from one
|
259 |
|
|
of the linker callbacks for a symbol in the *ABS* or *UND* sections.
|
260 |
|
|
Likewise, the usrdata field may be NULL if ABFD was added by the
|
261 |
|
|
backend without a corresponding input statement, as happens e.g.
|
262 |
|
|
when processing DT_NEEDED dependencies. */
|
263 |
|
|
return (abfd
|
264 |
|
|
&& abfd->usrdata
|
265 |
|
|
&& ((lang_input_statement_type *)(abfd->usrdata))->claimed);
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
/* Helpers to convert between BFD and GOLD symbol formats. */
|
269 |
|
|
static enum ld_plugin_status
|
270 |
|
|
asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
|
271 |
|
|
const struct ld_plugin_symbol *ldsym)
|
272 |
|
|
{
|
273 |
|
|
flagword flags = BSF_NO_FLAGS;
|
274 |
|
|
struct bfd_section *section;
|
275 |
|
|
|
276 |
|
|
asym->the_bfd = abfd;
|
277 |
|
|
asym->name = (ldsym->version
|
278 |
|
|
? concat (ldsym->name, "@", ldsym->version, (const char *) NULL)
|
279 |
|
|
: ldsym->name);
|
280 |
|
|
asym->value = 0;
|
281 |
|
|
switch (ldsym->def)
|
282 |
|
|
{
|
283 |
|
|
case LDPK_WEAKDEF:
|
284 |
|
|
flags = BSF_WEAK;
|
285 |
|
|
/* FALLTHRU */
|
286 |
|
|
case LDPK_DEF:
|
287 |
|
|
flags |= BSF_GLOBAL;
|
288 |
157 |
khays |
if (ldsym->comdat_key)
|
289 |
|
|
{
|
290 |
|
|
char *name = concat (".gnu.linkonce.t.", ldsym->comdat_key,
|
291 |
|
|
(const char *) NULL);
|
292 |
|
|
section = bfd_get_section_by_name (abfd, name);
|
293 |
|
|
if (section != NULL)
|
294 |
|
|
free (name);
|
295 |
|
|
else
|
296 |
|
|
{
|
297 |
|
|
flagword sflags;
|
298 |
|
|
|
299 |
|
|
sflags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
|
300 |
|
|
| SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE
|
301 |
|
|
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD);
|
302 |
|
|
section = bfd_make_section_anyway_with_flags (abfd, name, sflags);
|
303 |
|
|
if (section == NULL)
|
304 |
|
|
return LDPS_ERR;
|
305 |
|
|
}
|
306 |
|
|
}
|
307 |
|
|
else
|
308 |
|
|
section = bfd_get_section_by_name (abfd, ".text");
|
309 |
145 |
khays |
break;
|
310 |
|
|
|
311 |
|
|
case LDPK_WEAKUNDEF:
|
312 |
|
|
flags = BSF_WEAK;
|
313 |
|
|
/* FALLTHRU */
|
314 |
|
|
case LDPK_UNDEF:
|
315 |
|
|
section = bfd_und_section_ptr;
|
316 |
|
|
break;
|
317 |
|
|
|
318 |
|
|
case LDPK_COMMON:
|
319 |
|
|
flags = BSF_GLOBAL;
|
320 |
|
|
section = bfd_com_section_ptr;
|
321 |
|
|
asym->value = ldsym->size;
|
322 |
|
|
/* For ELF targets, set alignment of common symbol to 1. */
|
323 |
|
|
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
|
324 |
|
|
{
|
325 |
|
|
((elf_symbol_type *) asym)->internal_elf_sym.st_shndx = SHN_COMMON;
|
326 |
|
|
((elf_symbol_type *) asym)->internal_elf_sym.st_value = 1;
|
327 |
|
|
}
|
328 |
|
|
break;
|
329 |
|
|
|
330 |
|
|
default:
|
331 |
|
|
return LDPS_ERR;
|
332 |
|
|
}
|
333 |
|
|
asym->flags = flags;
|
334 |
|
|
asym->section = section;
|
335 |
|
|
|
336 |
|
|
/* Visibility only applies on ELF targets. */
|
337 |
|
|
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
|
338 |
|
|
{
|
339 |
|
|
elf_symbol_type *elfsym = elf_symbol_from (abfd, asym);
|
340 |
|
|
unsigned char visibility;
|
341 |
|
|
|
342 |
|
|
if (!elfsym)
|
343 |
|
|
einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!\n"), asym->name);
|
344 |
|
|
switch (ldsym->visibility)
|
345 |
|
|
{
|
346 |
|
|
default:
|
347 |
|
|
einfo (_("%P%F: unknown ELF symbol visibility: %d!\n"),
|
348 |
|
|
ldsym->visibility);
|
349 |
|
|
case LDPV_DEFAULT:
|
350 |
|
|
visibility = STV_DEFAULT;
|
351 |
|
|
break;
|
352 |
|
|
case LDPV_PROTECTED:
|
353 |
|
|
visibility = STV_PROTECTED;
|
354 |
|
|
break;
|
355 |
|
|
case LDPV_INTERNAL:
|
356 |
|
|
visibility = STV_INTERNAL;
|
357 |
|
|
break;
|
358 |
|
|
case LDPV_HIDDEN:
|
359 |
|
|
visibility = STV_HIDDEN;
|
360 |
|
|
break;
|
361 |
|
|
}
|
362 |
|
|
elfsym->internal_elf_sym.st_other
|
363 |
|
|
= (visibility | (elfsym->internal_elf_sym.st_other
|
364 |
|
|
& ~ELF_ST_VISIBILITY (-1)));
|
365 |
|
|
}
|
366 |
|
|
|
367 |
|
|
return LDPS_OK;
|
368 |
|
|
}
|
369 |
|
|
|
370 |
|
|
/* Register a claim-file handler. */
|
371 |
|
|
static enum ld_plugin_status
|
372 |
|
|
register_claim_file (ld_plugin_claim_file_handler handler)
|
373 |
|
|
{
|
374 |
|
|
ASSERT (called_plugin);
|
375 |
|
|
called_plugin->claim_file_handler = handler;
|
376 |
|
|
return LDPS_OK;
|
377 |
|
|
}
|
378 |
|
|
|
379 |
|
|
/* Register an all-symbols-read handler. */
|
380 |
|
|
static enum ld_plugin_status
|
381 |
|
|
register_all_symbols_read (ld_plugin_all_symbols_read_handler handler)
|
382 |
|
|
{
|
383 |
|
|
ASSERT (called_plugin);
|
384 |
|
|
called_plugin->all_symbols_read_handler = handler;
|
385 |
|
|
return LDPS_OK;
|
386 |
|
|
}
|
387 |
|
|
|
388 |
|
|
/* Register a cleanup handler. */
|
389 |
|
|
static enum ld_plugin_status
|
390 |
|
|
register_cleanup (ld_plugin_cleanup_handler handler)
|
391 |
|
|
{
|
392 |
|
|
ASSERT (called_plugin);
|
393 |
|
|
called_plugin->cleanup_handler = handler;
|
394 |
|
|
return LDPS_OK;
|
395 |
|
|
}
|
396 |
|
|
|
397 |
|
|
/* Add symbols from a plugin-claimed input file. */
|
398 |
|
|
static enum ld_plugin_status
|
399 |
|
|
add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms)
|
400 |
|
|
{
|
401 |
|
|
asymbol **symptrs;
|
402 |
|
|
bfd *abfd = handle;
|
403 |
|
|
int n;
|
404 |
157 |
khays |
|
405 |
145 |
khays |
ASSERT (called_plugin);
|
406 |
|
|
symptrs = xmalloc (nsyms * sizeof *symptrs);
|
407 |
|
|
for (n = 0; n < nsyms; n++)
|
408 |
|
|
{
|
409 |
|
|
enum ld_plugin_status rv;
|
410 |
157 |
khays |
asymbol *bfdsym;
|
411 |
|
|
|
412 |
|
|
bfdsym = bfd_make_empty_symbol (abfd);
|
413 |
145 |
khays |
symptrs[n] = bfdsym;
|
414 |
|
|
rv = asymbol_from_plugin_symbol (abfd, bfdsym, syms + n);
|
415 |
|
|
if (rv != LDPS_OK)
|
416 |
|
|
return rv;
|
417 |
|
|
}
|
418 |
|
|
bfd_set_symtab (abfd, symptrs, nsyms);
|
419 |
|
|
return LDPS_OK;
|
420 |
|
|
}
|
421 |
|
|
|
422 |
|
|
/* Get the input file information with an open (possibly re-opened)
|
423 |
|
|
file descriptor. */
|
424 |
|
|
static enum ld_plugin_status
|
425 |
|
|
get_input_file (const void *handle, struct ld_plugin_input_file *file)
|
426 |
|
|
{
|
427 |
|
|
ASSERT (called_plugin);
|
428 |
|
|
handle = handle;
|
429 |
|
|
file = file;
|
430 |
|
|
return LDPS_ERR;
|
431 |
|
|
}
|
432 |
|
|
|
433 |
|
|
/* Release the input file. */
|
434 |
|
|
static enum ld_plugin_status
|
435 |
|
|
release_input_file (const void *handle)
|
436 |
|
|
{
|
437 |
|
|
ASSERT (called_plugin);
|
438 |
|
|
handle = handle;
|
439 |
|
|
return LDPS_ERR;
|
440 |
|
|
}
|
441 |
|
|
|
442 |
|
|
/* Return TRUE if a defined symbol might be reachable from outside the
|
443 |
|
|
universe of claimed objects. */
|
444 |
|
|
static inline bfd_boolean
|
445 |
163 |
khays |
is_visible_from_outside (struct ld_plugin_symbol *lsym,
|
446 |
145 |
khays |
struct bfd_link_hash_entry *blhe)
|
447 |
|
|
{
|
448 |
|
|
struct bfd_sym_chain *sym;
|
449 |
|
|
|
450 |
|
|
if (link_info.relocatable)
|
451 |
|
|
return TRUE;
|
452 |
163 |
khays |
if (link_info.export_dynamic || !link_info.executable)
|
453 |
145 |
khays |
{
|
454 |
163 |
khays |
/* Check if symbol is hidden by version script. */
|
455 |
|
|
if (bfd_hide_sym_by_version (link_info.version_info,
|
456 |
|
|
blhe->root.string))
|
457 |
|
|
return FALSE;
|
458 |
145 |
khays |
/* Only ELF symbols really have visibility. */
|
459 |
|
|
if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
|
460 |
|
|
{
|
461 |
|
|
struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe;
|
462 |
|
|
int vis = ELF_ST_VISIBILITY (el->other);
|
463 |
|
|
return vis == STV_DEFAULT || vis == STV_PROTECTED;
|
464 |
|
|
}
|
465 |
|
|
/* On non-ELF targets, we can safely make inferences by considering
|
466 |
|
|
what visibility the plugin would have liked to apply when it first
|
467 |
|
|
sent us the symbol. During ELF symbol processing, visibility only
|
468 |
|
|
ever becomes more restrictive, not less, when symbols are merged,
|
469 |
|
|
so this is a conservative estimate; it may give false positives,
|
470 |
|
|
declaring something visible from outside when it in fact would
|
471 |
|
|
not have been, but this will only lead to missed optimisation
|
472 |
|
|
opportunities during LTRANS at worst; it will not give false
|
473 |
|
|
negatives, which can lead to the disastrous conclusion that the
|
474 |
|
|
related symbol is IRONLY. (See GCC PR46319 for an example.) */
|
475 |
|
|
return (lsym->visibility == LDPV_DEFAULT
|
476 |
|
|
|| lsym->visibility == LDPV_PROTECTED);
|
477 |
|
|
}
|
478 |
|
|
|
479 |
|
|
for (sym = &entry_symbol; sym != NULL; sym = sym->next)
|
480 |
|
|
if (sym->name
|
481 |
|
|
&& strcmp (sym->name, blhe->root.string) == 0)
|
482 |
|
|
return TRUE;
|
483 |
|
|
|
484 |
|
|
return FALSE;
|
485 |
|
|
}
|
486 |
|
|
|
487 |
|
|
/* Get the symbol resolution info for a plugin-claimed input file. */
|
488 |
|
|
static enum ld_plugin_status
|
489 |
163 |
khays |
get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms,
|
490 |
|
|
int def_ironly_exp)
|
491 |
145 |
khays |
{
|
492 |
|
|
const bfd *abfd = handle;
|
493 |
|
|
int n;
|
494 |
163 |
khays |
|
495 |
145 |
khays |
ASSERT (called_plugin);
|
496 |
|
|
for (n = 0; n < nsyms; n++)
|
497 |
|
|
{
|
498 |
|
|
struct bfd_link_hash_entry *blhe;
|
499 |
|
|
asection *owner_sec;
|
500 |
163 |
khays |
int res;
|
501 |
|
|
|
502 |
145 |
khays |
if (syms[n].def != LDPK_UNDEF)
|
503 |
|
|
blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
|
504 |
|
|
FALSE, FALSE, TRUE);
|
505 |
|
|
else
|
506 |
|
|
blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info,
|
507 |
|
|
syms[n].name, FALSE, FALSE, TRUE);
|
508 |
|
|
if (!blhe)
|
509 |
|
|
{
|
510 |
163 |
khays |
res = LDPR_UNKNOWN;
|
511 |
145 |
khays |
goto report_symbol;
|
512 |
|
|
}
|
513 |
|
|
|
514 |
|
|
/* Determine resolution from blhe type and symbol's original type. */
|
515 |
|
|
if (blhe->type == bfd_link_hash_undefined
|
516 |
|
|
|| blhe->type == bfd_link_hash_undefweak)
|
517 |
|
|
{
|
518 |
163 |
khays |
res = LDPR_UNDEF;
|
519 |
145 |
khays |
goto report_symbol;
|
520 |
|
|
}
|
521 |
|
|
if (blhe->type != bfd_link_hash_defined
|
522 |
|
|
&& blhe->type != bfd_link_hash_defweak
|
523 |
|
|
&& blhe->type != bfd_link_hash_common)
|
524 |
|
|
{
|
525 |
|
|
/* We should not have a new, indirect or warning symbol here. */
|
526 |
|
|
einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)\n",
|
527 |
|
|
called_plugin->name, blhe->type);
|
528 |
|
|
}
|
529 |
|
|
|
530 |
|
|
/* Find out which section owns the symbol. Since it's not undef,
|
531 |
|
|
it must have an owner; if it's not a common symbol, both defs
|
532 |
|
|
and weakdefs keep it in the same place. */
|
533 |
|
|
owner_sec = (blhe->type == bfd_link_hash_common
|
534 |
|
|
? blhe->u.c.p->section
|
535 |
|
|
: blhe->u.def.section);
|
536 |
|
|
|
537 |
|
|
|
538 |
|
|
/* If it was originally undefined or common, then it has been
|
539 |
|
|
resolved; determine how. */
|
540 |
|
|
if (syms[n].def == LDPK_UNDEF
|
541 |
|
|
|| syms[n].def == LDPK_WEAKUNDEF
|
542 |
|
|
|| syms[n].def == LDPK_COMMON)
|
543 |
|
|
{
|
544 |
|
|
if (owner_sec->owner == link_info.output_bfd)
|
545 |
163 |
khays |
res = LDPR_RESOLVED_EXEC;
|
546 |
145 |
khays |
else if (owner_sec->owner == abfd)
|
547 |
163 |
khays |
res = LDPR_PREVAILING_DEF_IRONLY;
|
548 |
145 |
khays |
else if (is_ir_dummy_bfd (owner_sec->owner))
|
549 |
163 |
khays |
res = LDPR_RESOLVED_IR;
|
550 |
145 |
khays |
else if (owner_sec->owner != NULL
|
551 |
|
|
&& (owner_sec->owner->flags & DYNAMIC) != 0)
|
552 |
163 |
khays |
res = LDPR_RESOLVED_DYN;
|
553 |
145 |
khays |
else
|
554 |
163 |
khays |
res = LDPR_RESOLVED_EXEC;
|
555 |
145 |
khays |
}
|
556 |
|
|
|
557 |
|
|
/* Was originally def, or weakdef. Does it prevail? If the
|
558 |
|
|
owner is the original dummy bfd that supplied it, then this
|
559 |
|
|
is the definition that has prevailed. */
|
560 |
163 |
khays |
else if (owner_sec->owner == link_info.output_bfd)
|
561 |
|
|
res = LDPR_PREEMPTED_REG;
|
562 |
145 |
khays |
else if (owner_sec->owner == abfd)
|
563 |
163 |
khays |
res = LDPR_PREVAILING_DEF_IRONLY;
|
564 |
|
|
|
565 |
|
|
/* Was originally def, weakdef, or common, but has been pre-empted. */
|
566 |
|
|
else if (is_ir_dummy_bfd (owner_sec->owner))
|
567 |
|
|
res = LDPR_PREEMPTED_IR;
|
568 |
|
|
else
|
569 |
|
|
res = LDPR_PREEMPTED_REG;
|
570 |
|
|
|
571 |
|
|
if (res == LDPR_PREVAILING_DEF_IRONLY)
|
572 |
145 |
khays |
{
|
573 |
163 |
khays |
/* We need to know if the sym is referenced from non-IR files. Or
|
574 |
|
|
even potentially-referenced, perhaps in a future final link if
|
575 |
|
|
this is a partial one, perhaps dynamically at load-time if the
|
576 |
|
|
symbol is externally visible. */
|
577 |
|
|
if (blhe->non_ir_ref)
|
578 |
|
|
res = LDPR_PREVAILING_DEF;
|
579 |
|
|
else if (is_visible_from_outside (&syms[n], blhe))
|
580 |
|
|
res = def_ironly_exp;
|
581 |
145 |
khays |
}
|
582 |
|
|
|
583 |
|
|
report_symbol:
|
584 |
163 |
khays |
syms[n].resolution = res;
|
585 |
145 |
khays |
if (report_plugin_symbols)
|
586 |
|
|
einfo (_("%P: %B: symbol `%s' "
|
587 |
|
|
"definition: %d, visibility: %d, resolution: %d\n"),
|
588 |
|
|
abfd, syms[n].name,
|
589 |
163 |
khays |
syms[n].def, syms[n].visibility, res);
|
590 |
145 |
khays |
}
|
591 |
|
|
return LDPS_OK;
|
592 |
|
|
}
|
593 |
|
|
|
594 |
163 |
khays |
static enum ld_plugin_status
|
595 |
|
|
get_symbols_v1 (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
|
596 |
|
|
{
|
597 |
|
|
return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF);
|
598 |
|
|
}
|
599 |
|
|
|
600 |
|
|
static enum ld_plugin_status
|
601 |
|
|
get_symbols_v2 (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
|
602 |
|
|
{
|
603 |
|
|
return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF_IRONLY_EXP);
|
604 |
|
|
}
|
605 |
|
|
|
606 |
145 |
khays |
/* Add a new (real) input file generated by a plugin. */
|
607 |
|
|
static enum ld_plugin_status
|
608 |
|
|
add_input_file (const char *pathname)
|
609 |
|
|
{
|
610 |
|
|
ASSERT (called_plugin);
|
611 |
|
|
if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum,
|
612 |
|
|
NULL))
|
613 |
|
|
return LDPS_ERR;
|
614 |
|
|
return LDPS_OK;
|
615 |
|
|
}
|
616 |
|
|
|
617 |
|
|
/* Add a new (real) library required by a plugin. */
|
618 |
|
|
static enum ld_plugin_status
|
619 |
|
|
add_input_library (const char *pathname)
|
620 |
|
|
{
|
621 |
|
|
ASSERT (called_plugin);
|
622 |
|
|
if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum,
|
623 |
|
|
NULL))
|
624 |
|
|
return LDPS_ERR;
|
625 |
|
|
return LDPS_OK;
|
626 |
|
|
}
|
627 |
|
|
|
628 |
|
|
/* Set the extra library path to be used by libraries added via
|
629 |
|
|
add_input_library. */
|
630 |
|
|
static enum ld_plugin_status
|
631 |
|
|
set_extra_library_path (const char *path)
|
632 |
|
|
{
|
633 |
|
|
ASSERT (called_plugin);
|
634 |
|
|
ldfile_add_library_path (xstrdup (path), FALSE);
|
635 |
|
|
return LDPS_OK;
|
636 |
|
|
}
|
637 |
|
|
|
638 |
|
|
/* Issue a diagnostic message from a plugin. */
|
639 |
|
|
static enum ld_plugin_status
|
640 |
|
|
message (int level, const char *format, ...)
|
641 |
|
|
{
|
642 |
|
|
va_list args;
|
643 |
|
|
va_start (args, format);
|
644 |
|
|
|
645 |
|
|
switch (level)
|
646 |
|
|
{
|
647 |
|
|
case LDPL_INFO:
|
648 |
|
|
vfinfo (stdout, format, args, FALSE);
|
649 |
|
|
putchar ('\n');
|
650 |
|
|
break;
|
651 |
|
|
case LDPL_WARNING:
|
652 |
|
|
vfinfo (stdout, format, args, TRUE);
|
653 |
|
|
putchar ('\n');
|
654 |
|
|
break;
|
655 |
|
|
case LDPL_FATAL:
|
656 |
|
|
case LDPL_ERROR:
|
657 |
|
|
default:
|
658 |
|
|
{
|
659 |
|
|
char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ",
|
660 |
|
|
format, "\n", (const char *) NULL));
|
661 |
|
|
fflush (stdout);
|
662 |
|
|
vfinfo (stderr, newfmt, args, TRUE);
|
663 |
|
|
fflush (stderr);
|
664 |
|
|
}
|
665 |
|
|
break;
|
666 |
|
|
}
|
667 |
|
|
|
668 |
|
|
va_end (args);
|
669 |
|
|
return LDPS_OK;
|
670 |
|
|
}
|
671 |
|
|
|
672 |
|
|
/* Helper to size leading part of tv array and set it up. */
|
673 |
163 |
khays |
static void
|
674 |
145 |
khays |
set_tv_header (struct ld_plugin_tv *tv)
|
675 |
|
|
{
|
676 |
|
|
size_t i;
|
677 |
|
|
|
678 |
|
|
/* Version info. */
|
679 |
|
|
static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL);
|
680 |
|
|
static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100;
|
681 |
|
|
|
682 |
|
|
for (i = 0; i < tv_header_size; i++)
|
683 |
|
|
{
|
684 |
|
|
tv[i].tv_tag = tv_header_tags[i];
|
685 |
|
|
#define TVU(x) tv[i].tv_u.tv_ ## x
|
686 |
|
|
switch (tv[i].tv_tag)
|
687 |
|
|
{
|
688 |
|
|
case LDPT_MESSAGE:
|
689 |
|
|
TVU(message) = message;
|
690 |
|
|
break;
|
691 |
|
|
case LDPT_API_VERSION:
|
692 |
|
|
TVU(val) = LD_PLUGIN_API_VERSION;
|
693 |
|
|
break;
|
694 |
|
|
case LDPT_GNU_LD_VERSION:
|
695 |
|
|
TVU(val) = major * 100 + minor;
|
696 |
|
|
break;
|
697 |
|
|
case LDPT_LINKER_OUTPUT:
|
698 |
|
|
TVU(val) = (link_info.relocatable
|
699 |
|
|
? LDPO_REL
|
700 |
163 |
khays |
: link_info.executable ? LDPO_EXEC : LDPO_DYN);
|
701 |
145 |
khays |
break;
|
702 |
|
|
case LDPT_OUTPUT_NAME:
|
703 |
|
|
TVU(string) = output_filename;
|
704 |
|
|
break;
|
705 |
|
|
case LDPT_REGISTER_CLAIM_FILE_HOOK:
|
706 |
|
|
TVU(register_claim_file) = register_claim_file;
|
707 |
|
|
break;
|
708 |
|
|
case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
|
709 |
|
|
TVU(register_all_symbols_read) = register_all_symbols_read;
|
710 |
|
|
break;
|
711 |
|
|
case LDPT_REGISTER_CLEANUP_HOOK:
|
712 |
|
|
TVU(register_cleanup) = register_cleanup;
|
713 |
|
|
break;
|
714 |
|
|
case LDPT_ADD_SYMBOLS:
|
715 |
|
|
TVU(add_symbols) = add_symbols;
|
716 |
|
|
break;
|
717 |
|
|
case LDPT_GET_INPUT_FILE:
|
718 |
|
|
TVU(get_input_file) = get_input_file;
|
719 |
|
|
break;
|
720 |
|
|
case LDPT_RELEASE_INPUT_FILE:
|
721 |
|
|
TVU(release_input_file) = release_input_file;
|
722 |
|
|
break;
|
723 |
|
|
case LDPT_GET_SYMBOLS:
|
724 |
163 |
khays |
TVU(get_symbols) = get_symbols_v1;
|
725 |
145 |
khays |
break;
|
726 |
163 |
khays |
case LDPT_GET_SYMBOLS_V2:
|
727 |
|
|
TVU(get_symbols) = get_symbols_v2;
|
728 |
|
|
break;
|
729 |
145 |
khays |
case LDPT_ADD_INPUT_FILE:
|
730 |
|
|
TVU(add_input_file) = add_input_file;
|
731 |
|
|
break;
|
732 |
|
|
case LDPT_ADD_INPUT_LIBRARY:
|
733 |
|
|
TVU(add_input_library) = add_input_library;
|
734 |
|
|
break;
|
735 |
|
|
case LDPT_SET_EXTRA_LIBRARY_PATH:
|
736 |
|
|
TVU(set_extra_library_path) = set_extra_library_path;
|
737 |
|
|
break;
|
738 |
|
|
default:
|
739 |
|
|
/* Added a new entry to the array without adding
|
740 |
|
|
a new case to set up its value is a bug. */
|
741 |
|
|
FAIL ();
|
742 |
|
|
}
|
743 |
|
|
#undef TVU
|
744 |
|
|
}
|
745 |
|
|
}
|
746 |
|
|
|
747 |
|
|
/* Append the per-plugin args list and trailing LDPT_NULL to tv. */
|
748 |
|
|
static void
|
749 |
|
|
set_tv_plugin_args (plugin_t *plugin, struct ld_plugin_tv *tv)
|
750 |
|
|
{
|
751 |
|
|
plugin_arg_t *arg = plugin->args;
|
752 |
|
|
while (arg)
|
753 |
|
|
{
|
754 |
|
|
tv->tv_tag = LDPT_OPTION;
|
755 |
|
|
tv->tv_u.tv_string = arg->arg;
|
756 |
|
|
arg = arg->next;
|
757 |
|
|
tv++;
|
758 |
|
|
}
|
759 |
|
|
tv->tv_tag = LDPT_NULL;
|
760 |
|
|
tv->tv_u.tv_val = 0;
|
761 |
|
|
}
|
762 |
|
|
|
763 |
|
|
/* Return true if any plugins are active this run. Only valid
|
764 |
|
|
after options have been processed. */
|
765 |
|
|
bfd_boolean
|
766 |
|
|
plugin_active_plugins_p (void)
|
767 |
|
|
{
|
768 |
|
|
return plugins_list != NULL;
|
769 |
|
|
}
|
770 |
|
|
|
771 |
|
|
/* Load up and initialise all plugins after argument parsing. */
|
772 |
|
|
int
|
773 |
|
|
plugin_load_plugins (void)
|
774 |
|
|
{
|
775 |
|
|
struct ld_plugin_tv *my_tv;
|
776 |
|
|
unsigned int max_args = 0;
|
777 |
|
|
plugin_t *curplug = plugins_list;
|
778 |
|
|
|
779 |
|
|
/* If there are no plugins, we need do nothing this run. */
|
780 |
|
|
if (!curplug)
|
781 |
|
|
return 0;
|
782 |
|
|
|
783 |
|
|
/* First pass over plugins to find max # args needed so that we
|
784 |
|
|
can size and allocate the tv array. */
|
785 |
|
|
while (curplug)
|
786 |
|
|
{
|
787 |
|
|
if (curplug->n_args > max_args)
|
788 |
|
|
max_args = curplug->n_args;
|
789 |
|
|
curplug = curplug->next;
|
790 |
|
|
}
|
791 |
|
|
|
792 |
|
|
/* Allocate tv array and initialise constant part. */
|
793 |
|
|
my_tv = xmalloc ((max_args + 1 + tv_header_size) * sizeof *my_tv);
|
794 |
|
|
set_tv_header (my_tv);
|
795 |
|
|
|
796 |
|
|
/* Pass over plugins again, activating them. */
|
797 |
|
|
curplug = plugins_list;
|
798 |
|
|
while (curplug)
|
799 |
|
|
{
|
800 |
|
|
enum ld_plugin_status rv;
|
801 |
|
|
ld_plugin_onload onloadfn = dlsym (curplug->dlhandle, "onload");
|
802 |
|
|
if (!onloadfn)
|
803 |
|
|
onloadfn = dlsym (curplug->dlhandle, "_onload");
|
804 |
|
|
if (!onloadfn)
|
805 |
|
|
return set_plugin_error (curplug->name);
|
806 |
|
|
set_tv_plugin_args (curplug, &my_tv[tv_header_size]);
|
807 |
|
|
called_plugin = curplug;
|
808 |
|
|
rv = (*onloadfn) (my_tv);
|
809 |
|
|
called_plugin = NULL;
|
810 |
|
|
if (rv != LDPS_OK)
|
811 |
|
|
return set_plugin_error (curplug->name);
|
812 |
|
|
curplug = curplug->next;
|
813 |
|
|
}
|
814 |
|
|
|
815 |
|
|
/* Since plugin(s) inited ok, assume they're going to want symbol
|
816 |
|
|
resolutions, which needs us to track which symbols are referenced
|
817 |
|
|
by non-IR files using the linker's notice callback. */
|
818 |
|
|
orig_notice_all = link_info.notice_all;
|
819 |
|
|
orig_callbacks = link_info.callbacks;
|
820 |
|
|
plugin_callbacks = *orig_callbacks;
|
821 |
|
|
plugin_callbacks.notice = &plugin_notice;
|
822 |
|
|
link_info.notice_all = TRUE;
|
823 |
|
|
link_info.callbacks = &plugin_callbacks;
|
824 |
|
|
|
825 |
|
|
return 0;
|
826 |
|
|
}
|
827 |
|
|
|
828 |
|
|
/* Call 'claim file' hook for all plugins. */
|
829 |
|
|
static int
|
830 |
|
|
plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed)
|
831 |
|
|
{
|
832 |
|
|
plugin_t *curplug = plugins_list;
|
833 |
|
|
*claimed = FALSE;
|
834 |
|
|
if (no_more_claiming)
|
835 |
|
|
return 0;
|
836 |
|
|
while (curplug && !*claimed)
|
837 |
|
|
{
|
838 |
|
|
if (curplug->claim_file_handler)
|
839 |
|
|
{
|
840 |
|
|
enum ld_plugin_status rv;
|
841 |
|
|
called_plugin = curplug;
|
842 |
|
|
rv = (*curplug->claim_file_handler) (file, claimed);
|
843 |
|
|
called_plugin = NULL;
|
844 |
|
|
if (rv != LDPS_OK)
|
845 |
|
|
set_plugin_error (curplug->name);
|
846 |
|
|
}
|
847 |
|
|
curplug = curplug->next;
|
848 |
|
|
}
|
849 |
|
|
return plugin_error_p () ? -1 : 0;
|
850 |
|
|
}
|
851 |
|
|
|
852 |
|
|
void
|
853 |
|
|
plugin_maybe_claim (struct ld_plugin_input_file *file,
|
854 |
|
|
lang_input_statement_type *entry)
|
855 |
|
|
{
|
856 |
|
|
int claimed = 0;
|
857 |
|
|
|
858 |
|
|
/* We create a dummy BFD, initially empty, to house whatever symbols
|
859 |
|
|
the plugin may want to add. */
|
860 |
|
|
file->handle = plugin_get_ir_dummy_bfd (entry->the_bfd->filename,
|
861 |
|
|
entry->the_bfd);
|
862 |
|
|
if (plugin_call_claim_file (file, &claimed))
|
863 |
|
|
einfo (_("%P%F: %s: plugin reported error claiming file\n"),
|
864 |
|
|
plugin_error_plugin ());
|
865 |
|
|
/* fd belongs to us, not the plugin; but we don't need it. */
|
866 |
|
|
close (file->fd);
|
867 |
|
|
if (claimed)
|
868 |
|
|
{
|
869 |
|
|
/* Discard the real file's BFD and substitute the dummy one. */
|
870 |
|
|
|
871 |
|
|
/* BFD archive handling caches elements so we can't call
|
872 |
|
|
bfd_close for archives. */
|
873 |
|
|
if (entry->the_bfd->my_archive == NULL)
|
874 |
|
|
bfd_close (entry->the_bfd);
|
875 |
|
|
entry->the_bfd = file->handle;
|
876 |
|
|
entry->claimed = TRUE;
|
877 |
|
|
bfd_make_readable (entry->the_bfd);
|
878 |
|
|
}
|
879 |
|
|
else
|
880 |
|
|
{
|
881 |
|
|
/* If plugin didn't claim the file, we don't need the dummy bfd.
|
882 |
|
|
Can't avoid speculatively creating it, alas. */
|
883 |
|
|
bfd_close_all_done (file->handle);
|
884 |
|
|
entry->claimed = FALSE;
|
885 |
|
|
}
|
886 |
|
|
}
|
887 |
|
|
|
888 |
|
|
/* Call 'all symbols read' hook for all plugins. */
|
889 |
|
|
int
|
890 |
|
|
plugin_call_all_symbols_read (void)
|
891 |
|
|
{
|
892 |
|
|
plugin_t *curplug = plugins_list;
|
893 |
|
|
|
894 |
|
|
/* Disable any further file-claiming. */
|
895 |
|
|
no_more_claiming = TRUE;
|
896 |
|
|
|
897 |
|
|
while (curplug)
|
898 |
|
|
{
|
899 |
|
|
if (curplug->all_symbols_read_handler)
|
900 |
|
|
{
|
901 |
|
|
enum ld_plugin_status rv;
|
902 |
|
|
called_plugin = curplug;
|
903 |
|
|
rv = (*curplug->all_symbols_read_handler) ();
|
904 |
|
|
called_plugin = NULL;
|
905 |
|
|
if (rv != LDPS_OK)
|
906 |
|
|
set_plugin_error (curplug->name);
|
907 |
|
|
}
|
908 |
|
|
curplug = curplug->next;
|
909 |
|
|
}
|
910 |
|
|
return plugin_error_p () ? -1 : 0;
|
911 |
|
|
}
|
912 |
|
|
|
913 |
|
|
/* Call 'cleanup' hook for all plugins at exit. */
|
914 |
|
|
void
|
915 |
|
|
plugin_call_cleanup (void)
|
916 |
|
|
{
|
917 |
|
|
plugin_t *curplug = plugins_list;
|
918 |
|
|
while (curplug)
|
919 |
|
|
{
|
920 |
|
|
if (curplug->cleanup_handler && !curplug->cleanup_done)
|
921 |
|
|
{
|
922 |
|
|
enum ld_plugin_status rv;
|
923 |
|
|
curplug->cleanup_done = TRUE;
|
924 |
|
|
called_plugin = curplug;
|
925 |
|
|
rv = (*curplug->cleanup_handler) ();
|
926 |
|
|
called_plugin = NULL;
|
927 |
|
|
if (rv != LDPS_OK)
|
928 |
|
|
set_plugin_error (curplug->name);
|
929 |
|
|
dlclose (curplug->dlhandle);
|
930 |
|
|
}
|
931 |
|
|
curplug = curplug->next;
|
932 |
|
|
}
|
933 |
|
|
if (plugin_error_p ())
|
934 |
|
|
info_msg (_("%P: %s: error in plugin cleanup (ignored)\n"),
|
935 |
|
|
plugin_error_plugin ());
|
936 |
|
|
}
|
937 |
|
|
|
938 |
|
|
/* To determine which symbols should be resolved LDPR_PREVAILING_DEF
|
939 |
|
|
and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as
|
940 |
|
|
the linker adds them to the linker hash table. Mark those
|
941 |
|
|
referenced from a non-IR file with non_ir_ref. We have to
|
942 |
|
|
notice_all symbols, because we won't necessarily know until later
|
943 |
|
|
which ones will be contributed by IR files. */
|
944 |
|
|
static bfd_boolean
|
945 |
|
|
plugin_notice (struct bfd_link_info *info,
|
946 |
|
|
struct bfd_link_hash_entry *h,
|
947 |
|
|
bfd *abfd,
|
948 |
|
|
asection *section,
|
949 |
|
|
bfd_vma value,
|
950 |
|
|
flagword flags,
|
951 |
|
|
const char *string)
|
952 |
|
|
{
|
953 |
|
|
if (h != NULL)
|
954 |
|
|
{
|
955 |
|
|
bfd *sym_bfd;
|
956 |
|
|
|
957 |
|
|
/* No further processing if this def/ref is from an IR dummy BFD. */
|
958 |
|
|
if (is_ir_dummy_bfd (abfd))
|
959 |
|
|
return TRUE;
|
960 |
|
|
|
961 |
|
|
/* Making an indirect symbol counts as a reference unless this
|
962 |
|
|
is a brand new symbol. */
|
963 |
|
|
if (bfd_is_ind_section (section)
|
964 |
|
|
|| (flags & BSF_INDIRECT) != 0)
|
965 |
|
|
{
|
966 |
|
|
if (h->type != bfd_link_hash_new)
|
967 |
|
|
{
|
968 |
|
|
struct bfd_link_hash_entry *inh;
|
969 |
|
|
|
970 |
|
|
h->non_ir_ref = TRUE;
|
971 |
|
|
inh = bfd_wrapped_link_hash_lookup (abfd, info, string, FALSE,
|
972 |
|
|
FALSE, FALSE);
|
973 |
|
|
if (inh != NULL)
|
974 |
|
|
inh->non_ir_ref = TRUE;
|
975 |
|
|
}
|
976 |
|
|
}
|
977 |
|
|
|
978 |
|
|
/* Nothing to do here for warning symbols. */
|
979 |
|
|
else if ((flags & BSF_WARNING) != 0)
|
980 |
|
|
;
|
981 |
|
|
|
982 |
|
|
/* Nothing to do here for constructor symbols. */
|
983 |
|
|
else if ((flags & BSF_CONSTRUCTOR) != 0)
|
984 |
|
|
;
|
985 |
|
|
|
986 |
|
|
/* If this is a ref, set non_ir_ref. */
|
987 |
|
|
else if (bfd_is_und_section (section))
|
988 |
|
|
h->non_ir_ref = TRUE;
|
989 |
|
|
|
990 |
|
|
/* Otherwise, it must be a new def. Ensure any symbol defined
|
991 |
|
|
in an IR dummy BFD takes on a new value from a real BFD.
|
992 |
|
|
Weak symbols are not normally overridden by a new weak
|
993 |
|
|
definition, and strong symbols will normally cause multiple
|
994 |
|
|
definition errors. Avoid this by making the symbol appear
|
995 |
|
|
to be undefined. */
|
996 |
|
|
else if (((h->type == bfd_link_hash_defweak
|
997 |
|
|
|| h->type == bfd_link_hash_defined)
|
998 |
|
|
&& is_ir_dummy_bfd (sym_bfd = h->u.def.section->owner))
|
999 |
|
|
|| (h->type == bfd_link_hash_common
|
1000 |
|
|
&& is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner)))
|
1001 |
|
|
{
|
1002 |
|
|
h->type = bfd_link_hash_undefweak;
|
1003 |
|
|
h->u.undef.abfd = sym_bfd;
|
1004 |
|
|
}
|
1005 |
|
|
}
|
1006 |
|
|
|
1007 |
|
|
/* Continue with cref/nocrossref/trace-sym processing. */
|
1008 |
|
|
if (h == NULL
|
1009 |
|
|
|| orig_notice_all
|
1010 |
|
|
|| (info->notice_hash != NULL
|
1011 |
|
|
&& bfd_hash_lookup (info->notice_hash, h->root.string,
|
1012 |
|
|
FALSE, FALSE) != NULL))
|
1013 |
|
|
return (*orig_callbacks->notice) (info, h,
|
1014 |
|
|
abfd, section, value, flags, string);
|
1015 |
|
|
return TRUE;
|
1016 |
|
|
}
|
1017 |
163 |
khays |
|
1018 |
|
|
/* Return true if bfd is a dynamic library that should be reloaded. */
|
1019 |
|
|
|
1020 |
|
|
bfd_boolean
|
1021 |
|
|
plugin_should_reload (bfd *abfd)
|
1022 |
|
|
{
|
1023 |
|
|
return ((abfd->flags & DYNAMIC) != 0
|
1024 |
|
|
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
1025 |
|
|
&& bfd_get_format (abfd) == bfd_object
|
1026 |
|
|
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0);
|
1027 |
|
|
}
|