]> git.ipfire.org Git - thirdparty/gcc.git/blob - lto-plugin/lto-plugin.c
Makefile.am (liblto_plugin_la_LIBADD): Link against the correct libiberty.
[thirdparty/gcc.git] / lto-plugin / lto-plugin.c
1 /* LTO plugin for gold.
2 Copyright (C) 2009 Free Software Foundation, Inc.
3 Contributed by Rafael Avila de Espindola (espindola@google.com).
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING3. If not see
17 <http://www.gnu.org/licenses/>. */
18
19 /* The plugin has only one external function: onload. Gold passes it an array of
20 function that the plugin uses to communicate back to gold.
21
22 With the functions provided by gold, the plugin can be notified when
23 gold first analyzes a file and pass a symbol table back to gold. The plugin
24 is also notified when all symbols have been read and it is time to generate
25 machine code for the necessary symbols.
26
27 More information at http://gcc.gnu.org/wiki/whopr/driver.
28
29 This plugin should be passed the lto-wrapper options and will forward them.
30 It also has 2 options of its own:
31 -debug: Print the command line used to run lto-wrapper.
32 -nop: Instead of running lto-wrapper, pass the original to the plugin. This
33 only works if the input files are hybrid. */
34
35 #include <assert.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <inttypes.h>
40 #include <ar.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <stdbool.h>
47 #include <libiberty.h>
48
49 /* The presence of gelf.h is checked by the toplevel configure script. */
50 #include <gelf.h>
51
52 #include "plugin-api.h"
53 #include "../gcc/lto/common.h"
54
55 /* The part of the symbol table the plugin has to keep track of. Note that we
56 must keep SYMS until all_symbols_read is called to give the linker time to
57 copy the symbol information. */
58
59 struct plugin_symtab
60 {
61 int nsyms;
62 uint32_t *slots;
63 struct ld_plugin_symbol *syms;
64 };
65
66 /* All that we have to remember about a file. */
67
68 struct plugin_file_info
69 {
70 char *name;
71 void *handle;
72 struct plugin_symtab symtab;
73 unsigned char temp;
74 };
75
76
77 static char *temp_obj_dir_name;
78 static ld_plugin_register_claim_file register_claim_file;
79 static ld_plugin_add_symbols add_symbols;
80 static ld_plugin_register_all_symbols_read register_all_symbols_read;
81 static ld_plugin_get_symbols get_symbols;
82 static ld_plugin_register_cleanup register_cleanup;
83 static ld_plugin_add_input_file add_input_file;
84 static ld_plugin_add_input_library add_input_library;
85
86 static struct plugin_file_info *claimed_files = NULL;
87 static unsigned int num_claimed_files = 0;
88
89 static char **output_files = NULL;
90 static unsigned int num_output_files = 0;
91
92 static char **lto_wrapper_argv;
93 static int lto_wrapper_num_args;
94
95 static char **pass_through_items = NULL;
96 static unsigned int num_pass_through_items;
97
98 static bool debug;
99 static bool nop;
100
101 /* Parse an entry of the IL symbol table. The data to be parsed is pointed
102 by P and the result is written in ENTRY. The slot number is stored in SLOT.
103 Returns the address of the next entry. */
104
105 static char *
106 parse_table_entry (char *p, struct ld_plugin_symbol *entry, uint32_t *slot)
107 {
108 unsigned char t;
109 enum ld_plugin_symbol_kind translate_kind[] =
110 {
111 LDPK_DEF,
112 LDPK_WEAKDEF,
113 LDPK_UNDEF,
114 LDPK_WEAKUNDEF,
115 LDPK_COMMON
116 };
117
118 enum ld_plugin_symbol_visibility translate_visibility[] =
119 {
120 LDPV_DEFAULT,
121 LDPV_PROTECTED,
122 LDPV_INTERNAL,
123 LDPV_HIDDEN
124 };
125
126 entry->name = strdup (p);
127 while (*p)
128 p++;
129 p++;
130
131 entry->version = NULL;
132
133 entry->comdat_key = p;
134 while (*p)
135 p++;
136 p++;
137
138 if (strlen (entry->comdat_key) == 0)
139 entry->comdat_key = NULL;
140 else
141 entry->comdat_key = strdup (entry->comdat_key);
142
143 t = *p;
144 assert (t <= 4);
145 entry->def = translate_kind[t];
146 p++;
147
148 t = *p;
149 assert (t <= 3);
150 entry->visibility = translate_visibility[t];
151 p++;
152
153 entry->size = *(uint64_t *) p;
154 p += 8;
155
156 *slot = *(uint32_t *) p;
157 p += 4;
158
159 entry->resolution = LDPR_UNKNOWN;
160
161 return p;
162 }
163
164 /* Return the section in ELF that is named NAME. */
165
166 static Elf_Scn *
167 get_section (Elf *elf, const char *name)
168 {
169 Elf_Scn *section = 0;
170 GElf_Ehdr header;
171 GElf_Ehdr *t = gelf_getehdr (elf, &header);
172 if (t == NULL)
173 return NULL;
174 assert (t == &header);
175
176 while ((section = elf_nextscn(elf, section)) != 0)
177 {
178 GElf_Shdr shdr;
179 GElf_Shdr *tshdr = gelf_getshdr (section, &shdr);
180 const char *t;
181 assert (tshdr == &shdr);
182 t = elf_strptr (elf, header.e_shstrndx, shdr.sh_name);
183 assert (t != NULL);
184 if (strcmp (t, name) == 0)
185 return section;
186 }
187 return NULL;
188 }
189
190 /* Returns the IL symbol table of file ELF. */
191
192 static Elf_Data *
193 get_symtab (Elf *elf)
194 {
195 Elf_Data *data = 0;
196 Elf_Scn *section = get_section (elf, ".gnu.lto_.symtab");
197 if (!section)
198 return NULL;
199
200 data = elf_getdata (section, data);
201 assert (data);
202 return data;
203 }
204
205 /* Translate the IL symbol table SYMTAB. Write the slots and symbols in OUT. */
206
207 static void
208 translate (Elf_Data *symtab, struct plugin_symtab *out)
209 {
210 uint32_t *slots = NULL;
211 char *data = symtab->d_buf;
212 char *end = data + symtab->d_size;
213 struct ld_plugin_symbol *syms = NULL;
214 int n = 0;
215
216 while (data < end)
217 {
218 n++;
219 syms = realloc (syms, n * sizeof (struct ld_plugin_symbol));
220 assert (syms);
221 slots = realloc (slots, n * sizeof (uint32_t));
222 assert (slots);
223 data = parse_table_entry (data, &syms[n - 1], &slots[n - 1]);
224 }
225
226 out->nsyms = n;
227 out->syms = syms;
228 out->slots = slots;
229 }
230
231 /* Free all memory that is no longer needed at the beginning of all_symbols_read. */
232
233 static void
234 free_1 (void)
235 {
236 unsigned int i;
237 for (i = 0; i < num_claimed_files; i++)
238 {
239 struct plugin_file_info *info = &claimed_files[i];
240 struct plugin_symtab *symtab = &info->symtab;
241 unsigned int j;
242 for (j = 0; j < symtab->nsyms; j++)
243 {
244 struct ld_plugin_symbol *s = &symtab->syms[j];
245 free (s->name);
246 if (s->comdat_key)
247 free (s->comdat_key);
248 }
249 free (symtab->syms);
250 symtab->syms = NULL;
251 }
252 }
253
254 /* Free all remaining memory. */
255
256 static void
257 free_2 (void)
258 {
259 unsigned int i;
260 for (i = 0; i < num_claimed_files; i++)
261 {
262 struct plugin_file_info *info = &claimed_files[i];
263 struct plugin_symtab *symtab = &info->symtab;
264 free (symtab->slots);
265 free (info->name);
266 }
267
268 for (i = 0; i < num_output_files; i++)
269 free (output_files[i]);
270 free (output_files);
271
272 free (claimed_files);
273 claimed_files = NULL;
274 num_claimed_files = 0;
275
276 free (temp_obj_dir_name);
277 temp_obj_dir_name = NULL;
278 }
279
280 /* Writes the relocations to disk. */
281
282 static void
283 write_resolution (void)
284 {
285 unsigned int i;
286 FILE *f;
287 /* FIXME: Disabled for now since we are not using the resolution file. */
288 return;
289
290
291 /* FIXME: This should be a temporary file. */
292 f = fopen ("resolution", "w");
293
294 fprintf (f, "%d\n", num_claimed_files);
295
296 for (i = 0; i < num_claimed_files; i++)
297 {
298 struct plugin_file_info *info = &claimed_files[i];
299 struct plugin_symtab *symtab = &info->symtab;
300 struct ld_plugin_symbol *syms = calloc (symtab->nsyms,
301 sizeof (struct ld_plugin_symbol));
302 unsigned j;
303
304 assert (syms);
305 get_symbols (info->handle, symtab->nsyms, syms);
306
307 fprintf (f, "%s %d\n", info->name, info->symtab.nsyms);
308
309 for (j = 0; j < info->symtab.nsyms; j++)
310 {
311 uint32_t slot = symtab->slots[j];
312 unsigned int resolution = syms[j].resolution;
313 fprintf (f, "%d %s\n", slot, lto_resolution_str[resolution]);
314 }
315 free (syms);
316 }
317 fclose (f);
318 }
319
320 /* Pass files generated by the lto-wrapper to the linker. FD is lto-wrapper's
321 stdout. */
322
323 static void
324 add_output_files (FILE *f)
325 {
326 char fname[1000]; /* FIXME: Is this big enough? */
327
328 for (;;)
329 {
330 size_t len;
331 char *s = fgets (fname, sizeof (fname), f);
332 if (!s)
333 break;
334
335 len = strlen (s);
336 assert (s[len - 1] == '\n');
337 s[len - 1] = '\0';
338
339 num_output_files++;
340 output_files = realloc (output_files, num_output_files * sizeof (char *));
341 output_files[num_output_files - 1] = strdup (s);
342 add_input_file (output_files[num_output_files - 1]);
343 }
344 }
345
346 /* Execute the lto-wrapper. ARGV[0] is the binary. The rest of ARGV is the
347 argument list. */
348
349 static void
350 exec_lto_wrapper (char *argv[])
351 {
352 int t;
353 int status;
354 char *at_args;
355 char *args_name;
356 FILE *args;
357 FILE *wrapper_output;
358 char *new_argv[3];
359 struct pex_obj *pex;
360 const char *errmsg;
361
362 /* Write argv to a file to avoid a command line that is too long. */
363 t = asprintf (&at_args, "@%s/arguments", temp_obj_dir_name);
364 assert (t >= 0);
365
366 args_name = at_args + 1;
367 args = fopen (args_name, "w");
368 assert (args);
369
370 t = writeargv (&argv[1], args);
371 assert (t == 0);
372 t = fclose (args);
373 assert (t == 0);
374
375 new_argv[0] = argv[0];
376 new_argv[1] = at_args;
377 new_argv[2] = NULL;
378
379 if (debug)
380 {
381 int i;
382 for (i = 0; new_argv[i]; i++)
383 fprintf (stderr, "%s ", new_argv[i]);
384 fprintf (stderr, "\n");
385 }
386
387
388 pex = pex_init (PEX_USE_PIPES, "lto-wrapper", NULL);
389 assert (pex != NULL);
390
391 errmsg = pex_run (pex, 0, new_argv[0], new_argv, NULL, NULL, &t);
392 assert (errmsg == NULL);
393 assert (t == 0);
394
395 wrapper_output = pex_read_output (pex, 0);
396 assert (wrapper_output);
397
398 add_output_files (wrapper_output);
399
400 t = pex_get_status (pex, 1, &status);
401 assert (t == 1);
402 assert (WIFEXITED (status) && WEXITSTATUS (status) == 0);
403
404 pex_free (pex);
405
406 t = unlink (args_name);
407 assert (t == 0);
408 free (at_args);
409 }
410
411 /* Pass the original files back to the linker. */
412
413 static void
414 use_original_files (void)
415 {
416 unsigned i;
417 for (i = 0; i < num_claimed_files; i++)
418 {
419 struct plugin_file_info *info = &claimed_files[i];
420 add_input_file (info->name);
421 }
422 }
423
424
425 /* Called by the linker once all symbols have been read. */
426
427 static enum ld_plugin_status
428 all_symbols_read_handler (void)
429 {
430 unsigned i;
431 unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 1;
432 char **lto_argv;
433 const char **lto_arg_ptr;
434 if (num_claimed_files == 0)
435 return LDPS_OK;
436
437 free_1 ();
438
439 if (nop)
440 {
441 use_original_files ();
442 return LDPS_OK;
443 }
444
445 lto_argv = (char **) calloc (sizeof (char *), num_lto_args);
446 lto_arg_ptr = (const char **) lto_argv;
447 assert (lto_wrapper_argv);
448
449 write_resolution ();
450
451 for (i = 0; i < lto_wrapper_num_args; i++)
452 *lto_arg_ptr++ = lto_wrapper_argv[i];
453
454 for (i = 0; i < num_claimed_files; i++)
455 {
456 struct plugin_file_info *info = &claimed_files[i];
457
458 *lto_arg_ptr++ = info->name;
459 }
460
461 *lto_arg_ptr++ = NULL;
462 exec_lto_wrapper (lto_argv);
463
464 free (lto_argv);
465
466 if (pass_through_items)
467 {
468 unsigned int i;
469 for (i = 0; i < num_pass_through_items; i++)
470 {
471 if (strncmp (pass_through_items[i], "-l", 2) == 0)
472 add_input_library (pass_through_items[i] + 2);
473 else
474 add_input_file (pass_through_items[i]);
475 free (pass_through_items[i]);
476 pass_through_items[i] = NULL;
477 }
478 free (pass_through_items);
479 pass_through_items = NULL;
480 }
481
482 return LDPS_OK;
483 }
484
485 /* Remove temporary files at the end of the link. */
486
487 static enum ld_plugin_status
488 cleanup_handler (void)
489 {
490 int t;
491 unsigned i;
492
493 for (i = 0; i < num_claimed_files; i++)
494 {
495 struct plugin_file_info *info = &claimed_files[i];
496 if (info->temp)
497 {
498 t = unlink (info->name);
499 assert (t == 0);
500 }
501 }
502 t = rmdir (temp_obj_dir_name);
503 assert (t == 0);
504
505 free_2 ();
506 return LDPS_OK;
507 }
508
509 /* Callback used by gold to check if the plugin will claim FILE. Writes
510 the result in CLAIMED. */
511
512 static enum ld_plugin_status
513 claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
514 {
515 enum ld_plugin_status status;
516 Elf *elf;
517 struct plugin_file_info lto_file;
518 Elf_Data *symtab;
519 int lto_file_fd;
520
521 if (file->offset != 0)
522 {
523 /* FIXME lto: lto1 should know how to handle archives. */
524 int fd;
525 off_t size = file->filesize;
526 off_t offset;
527
528 static int objnum = 0;
529 char *objname;
530 int t = asprintf (&objname, "%s/obj%d.o",
531 temp_obj_dir_name, objnum);
532 assert (t >= 0);
533 objnum++;
534
535 fd = open (objname, O_RDWR | O_CREAT, 0666);
536 assert (fd > 0);
537 offset = lseek (file->fd, file->offset, SEEK_SET);
538 assert (offset == file->offset);
539 while (size > 0)
540 {
541 ssize_t r, written;
542 char buf[1000];
543 off_t s = sizeof (buf) < size ? sizeof (buf) : size;
544 r = read (file->fd, buf, s);
545 written = write (fd, buf, r);
546 assert (written = r);
547 size -= r;
548 }
549 lto_file.name = objname;
550 lto_file_fd = fd;
551 lto_file.handle = file->handle;
552 lto_file.temp = 1;
553 }
554 else
555 {
556 lto_file.name = strdup (file->name);
557 lto_file_fd = file->fd;
558 lto_file.handle = file->handle;
559 lto_file.temp = 0;
560 }
561 elf = elf_begin (lto_file_fd, ELF_C_READ, NULL);
562
563 *claimed = 0;
564
565 if (!elf)
566 goto err;
567
568 symtab = get_symtab (elf);
569 if (!symtab)
570 goto err;
571
572 translate (symtab, &lto_file.symtab);
573
574 status = add_symbols (file->handle, lto_file.symtab.nsyms,
575 lto_file.symtab.syms);
576 assert (status == LDPS_OK);
577
578 *claimed = 1;
579 num_claimed_files++;
580 claimed_files =
581 realloc (claimed_files,
582 num_claimed_files * sizeof (struct plugin_file_info));
583 claimed_files[num_claimed_files - 1] = lto_file;
584
585 goto cleanup;
586
587 err:
588 if (file->offset != 0)
589 {
590 int t = unlink (lto_file.name);
591 assert (t == 0);
592 }
593 free (lto_file.name);
594
595 cleanup:
596 if (elf)
597 elf_end (elf);
598
599 return LDPS_OK;
600 }
601
602 /* Parse the plugin options. */
603
604 static void
605 process_option (const char *option)
606 {
607 if (strcmp (option, "-debug") == 0)
608 debug = 1;
609 else if (strcmp (option, "-nop") == 0)
610 nop = 1;
611 else if (!strncmp (option, "-pass-through=", strlen("-pass-through=")))
612 {
613 num_pass_through_items++;
614 pass_through_items = realloc (pass_through_items,
615 num_pass_through_items * sizeof (char *));
616 pass_through_items[num_pass_through_items - 1] =
617 strdup (option + strlen ("-pass-through="));
618 }
619 else
620 {
621 int size;
622 lto_wrapper_num_args += 1;
623 size = lto_wrapper_num_args * sizeof (char *);
624 lto_wrapper_argv = (char **) realloc (lto_wrapper_argv, size);
625 lto_wrapper_argv[lto_wrapper_num_args - 1] = strdup(option);
626 }
627 }
628
629 /* Called by gold after loading the plugin. TV is the transfer vector. */
630
631 enum ld_plugin_status
632 onload (struct ld_plugin_tv *tv)
633 {
634 struct ld_plugin_tv *p;
635 enum ld_plugin_status status;
636 char *t;
637
638 unsigned version = elf_version (EV_CURRENT);
639 assert (version != EV_NONE);
640
641 p = tv;
642 while (p->tv_tag)
643 {
644 switch (p->tv_tag)
645 {
646 case LDPT_REGISTER_CLAIM_FILE_HOOK:
647 register_claim_file = p->tv_u.tv_register_claim_file;
648 break;
649 case LDPT_ADD_SYMBOLS:
650 add_symbols = p->tv_u.tv_add_symbols;
651 break;
652 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
653 register_all_symbols_read = p->tv_u.tv_register_all_symbols_read;
654 break;
655 case LDPT_GET_SYMBOLS:
656 get_symbols = p->tv_u.tv_get_symbols;
657 break;
658 case LDPT_REGISTER_CLEANUP_HOOK:
659 register_cleanup = p->tv_u.tv_register_cleanup;
660 break;
661 case LDPT_ADD_INPUT_FILE:
662 add_input_file = p->tv_u.tv_add_input_file;
663 break;
664 case LDPT_ADD_INPUT_LIBRARY:
665 add_input_library = p->tv_u.tv_add_input_library;
666 break;
667 case LDPT_OPTION:
668 process_option (p->tv_u.tv_string);
669 break;
670 default:
671 break;
672 }
673 p++;
674 }
675
676 assert (register_claim_file);
677 assert (add_symbols);
678 status = register_claim_file (claim_file_handler);
679 assert (status == LDPS_OK);
680
681 if (register_cleanup)
682 {
683 status = register_cleanup (cleanup_handler);
684 assert (status == LDPS_OK);
685 }
686
687 if (register_all_symbols_read)
688 {
689 assert (get_symbols);
690 status = register_all_symbols_read (all_symbols_read_handler);
691 assert (status == LDPS_OK);
692 }
693
694 temp_obj_dir_name = strdup ("tmp_objectsXXXXXX");
695 t = mkdtemp (temp_obj_dir_name);
696 assert (t == temp_obj_dir_name);
697 return LDPS_OK;
698 }