New hash table interface for objcommon.h, based on BFD hash tables.
[ksplice.git] / objmanip.c
bloba5e2b204a65a9dd0f09238b660e2509397832977
1 /* This file is based in part on objcopy.c from GNU Binutils v2.17.
3 * Copyright (C) 1991-2006 Free Software Foundation, Inc.
4 * Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 * 02110-1301, USA.
20 /* objmanip performs various object file manipulations for Ksplice. Its first
21 * argument is always an object file, which is modified in-place during
22 * objmanip's execution. (objmanip's code is similar to objcopy from GNU
23 * binutils because every manipulation that objmanip performs is essentially a
24 * "copy" operation with certain changes which make the new version different
25 * from the old version). objmanip has four modes of operation:
27 * (1) keep mode
29 * This mode is the first objmanip step in processing the target object files.
31 * This mode can be broken down into two submodes, called "keep-primary" (which
32 * is used to prepare the primary kernel module) and "keep-helper" (which is
33 * used to prepare the helper kernel module):
35 * (a) keep-primary: "objmanip file.o keep-primary ADDSTR sect_1 ... sect_n"
37 * In this submode, only certain sections are kept; all other sections are
38 * discarded. Specifically, the following sections are kept: the listed
39 * sections (sect_1 ... sect_n), certain sections referenced by the listed
40 * sections, and certain special sections. The sections that are kept have
41 * ADDSTR added to the end of their names.
43 * The sections that are kept have most of their ELF relocations removed.
44 * (Relocations that point to sections that are being kept are not removed; all
45 * other relocations are removed). Information about each of the removed ELF
46 * relocations is printed to STDOUT (ksplice-create will save this information
47 * into Ksplice-specific ELF sections for the primary kernel module to use
48 * later).
50 * Each line of the STDOUT output represents a single place within the ELF
51 * object file at which a relocation has been removed. Each line contains the
52 * following fields, separated by spaces: an ELF symbol name, the name of a
53 * section previously containing a relocation pointing to that symbol, the
54 * offset (within that section) of the former relocation to that symbol, a bit
55 * representing whether that ELF relocation is PC-relative, and the ELF addend
56 * value for that relocation.
58 * (b) keep-helper: "objmanip file.o keep-helper ADDSTR"
60 * In this submode, essentially all sections are kept and have ADDSTR added to
61 * the end of their names.
63 * The sections that are kept have all of their ELF relocations removed.
64 * Information about each of the removed ELF relocations is printed to STDOUT
65 * (ksplice-create will save this information into Ksplice-specific ELF
66 * sections for the helper kernel module to use later).
68 * The fields of the STDOUT output are the same as with keep-primary.
70 * (2) globalize mode: "objmanip file.o globalize GLOBALIZESTR"
72 * This mode is the second objmanip step in processing the target object files.
73 * In this mode, all symbols whose names end in GLOBALIZESTR will be
74 * duplicated, with the duplicate symbols differing slightly from the original
75 * symbols. The duplicate symbols will have the string "_global" added to the
76 * end of their symbol names, and they will be global ELF symbols, regardless
77 * of whether the corresponding original symbol was global.
79 * (3) sizelist mode: "objmanip file.o sizelist"
81 * After the target object files have been linked into a single collection
82 * object file, this mode is used in order to obtain a list of all of the
83 * functions in the collection object file. Each line of the STDOUT output
84 * contains an ELF section name and that section's size, as presented by BFD's
85 * bfd_print_symbol function.
87 * (4) rmsyms mode: "objmanip file.o rmsyms sym_1 ... sym_n"
89 * This mode is the final objmanip step in preparing the Ksplice kernel
90 * modules. In this mode, any ELF relocations involving the listed symbols
91 * (sym_1 ... sym_n) are removed, and information about each of the removed
92 * relocations is printed to STDOUT.
94 * The fields of the STDOUT output are the same as with keep-primary.
97 #include "objcommon.h"
98 #include "objmanip.h"
99 #include <stdint.h>
100 #include <stdarg.h>
102 struct asymbolp_vec isyms;
104 char **varargs;
105 int varargs_count;
106 char *modestr, *addstr_all = "", *addstr_sect = "", *globalizestr;
108 struct wsect *wanted_sections = NULL;
110 struct specsect special_sections[] = {
111 {".altinstructions", 1, ".altinstr_replacement",
112 2 * sizeof(void *) + 4},
113 {".smp_locks", 0, NULL, sizeof(void *)},
114 {".parainstructions", 0, NULL, sizeof(void *) + 4},
115 }, *const end_special_sections = *(&special_sections + 1);
117 #define mode(str) starts_with(modestr, str)
119 int main(int argc, char **argv)
121 char *debug_name = malloc(strlen(argv[1]) + 4 + strlen(argv[2]) + 1);
122 sprintf(debug_name, "%s.pre%s", argv[1], argv[2]);
123 rename(argv[1], debug_name);
125 bfd_init();
126 bfd *ibfd = bfd_openr(debug_name, NULL);
127 assert(ibfd);
129 char **matching;
130 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
132 const char *output_target = bfd_get_target(ibfd);
133 bfd *obfd = bfd_openw(argv[1], output_target);
134 assert(obfd);
136 get_syms(ibfd, &isyms);
138 modestr = argv[2];
139 if (mode("keep")) {
140 addstr_all = argv[3];
141 addstr_sect = argv[4];
142 varargs = &argv[5];
143 varargs_count = argc - 5;
144 } else if (mode("globalize")) {
145 globalizestr = argv[3];
146 varargs = &argv[4];
147 varargs_count = argc - 4;
148 } else {
149 varargs = &argv[3];
150 varargs_count = argc - 3;
153 if (mode("keep")) {
154 while (1) {
155 struct wsect *tmp = wanted_sections;
156 bfd_map_over_sections(ibfd, mark_wanted_if_referenced,
157 NULL);
158 if (tmp == wanted_sections)
159 break;
163 asymbol **symp;
164 for (symp = isyms.data;
165 mode("sizelist") && symp < isyms.data + isyms.size; symp++) {
166 asymbol *sym = *symp;
167 if ((sym->flags & BSF_FUNCTION)
168 && sym->value == 0 && !(sym->flags & BSF_WEAK)) {
169 /* We call bfd_print_symbol in order to get access to
170 * the size associated with the function symbol, which
171 * is not otherwise available through the BFD API
173 bfd_print_symbol(ibfd, stdout, sym,
174 bfd_print_symbol_all);
175 printf("\n");
179 asection *p;
180 for (p = ibfd->sections; p != NULL; p = p->next) {
181 if (is_special(p->name) || starts_with(p->name, ".ksplice"))
182 continue;
183 if (want_section(p->name, NULL) || mode("rmsyms"))
184 rm_some_relocs(ibfd, p);
187 struct specsect *ss;
188 if (mode("keep")) {
189 for (ss = special_sections; ss != end_special_sections; ss++)
190 rm_from_special(ibfd, ss);
193 copy_object(ibfd, obfd);
194 assert(bfd_close(obfd));
195 assert(bfd_close(ibfd));
196 return EXIT_SUCCESS;
199 void rm_some_relocs(bfd *ibfd, asection *isection)
201 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
202 struct arelentp_vec orig_relocs;
203 vec_move(&orig_relocs, &ss->relocs);
205 arelent **relocp;
206 for (relocp = orig_relocs.data;
207 relocp < orig_relocs.data + orig_relocs.size; ++relocp) {
208 int rm_reloc = 0;
209 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
211 if (mode("rmsyms") && match_varargs(sym_ptr->name))
212 rm_reloc = 1;
214 if (mode("keep"))
215 rm_reloc = 1;
217 if (mode("keep-primary") && want_section(sym_ptr->name, NULL))
218 rm_reloc = 0;
220 if (rm_reloc)
221 print_reloc(ibfd, isection, *relocp, ss);
222 else
223 *vec_grow(&ss->relocs, 1) = *relocp;
227 struct supersect *make_section(bfd *abfd, struct asymbolp_vec *syms, char *name)
229 asection *sect = bfd_get_section_by_name(abfd, name);
230 if (sect != NULL)
231 return fetch_supersect(abfd, sect, syms);
232 else
233 return new_supersect(name);
236 void write_reloc(bfd *abfd, struct supersect *ss, void *addr, asymbol **symp,
237 bfd_vma offset)
239 bfd_reloc_code_real_type code;
240 switch (bfd_arch_bits_per_address(abfd)) {
241 case 32:
242 code = BFD_RELOC_32;
243 break;
244 case 64:
245 code = BFD_RELOC_64;
246 break;
247 default:
248 DIE;
251 arelent *reloc = malloc(sizeof(*reloc));
252 reloc->sym_ptr_ptr = symp;
253 reloc->address = addr - ss->contents.data;
254 reloc->howto = bfd_reloc_type_lookup(abfd, code);
255 /* FIXME: bfd_perform_relocation? bfd_install_relocation? */
256 reloc->addend = offset;
257 *(long *)addr = reloc->howto->partial_inplace ? offset : 0;
258 *vec_grow(&ss->relocs, 1) = reloc;
261 void write_string(bfd *ibfd, struct supersect *ss, void *addr,
262 const char *fmt, ...)
264 va_list ap;
265 va_start(ap, fmt);
266 int len = vsnprintf(NULL, 0, fmt, ap);
267 va_end(ap);
268 struct supersect *str_ss = make_section(ibfd, &isyms, ".ksplice_str");
269 char *buf = sect_grow(str_ss, len + 1, char);
270 va_start(ap, fmt);
271 vsnprintf(buf, len + 1, fmt, ap);
272 va_end(ap);
274 write_reloc(ibfd, ss, addr, &str_ss->symbol,
275 (void *)buf - str_ss->contents.data);
278 void print_reloc(bfd *ibfd, asection *isection, arelent *orig_reloc,
279 struct supersect *ss)
281 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
283 char *new_sectname = strdup(isection->name);
284 if (mode("keep"))
285 want_section(isection->name, &new_sectname);
287 char *new_symname = strdup(sym_ptr->name);
288 if (mode("keep-primary"))
289 want_section(sym_ptr->name, &new_symname);
291 int addend = orig_reloc->addend;
292 reloc_howto_type *howto = orig_reloc->howto;
293 int size = bfd_get_reloc_size(howto);
294 int addend2 = blot_section(ibfd, isection, orig_reloc->address, size);
295 assert(addend == 0 || addend2 == 0);
296 if (addend == 0)
297 addend = addend2;
299 printf("%s%s ", new_symname, addstr_all);
300 printf("%s%s%s ", canonical_sym(new_sectname), addstr_all, addstr_sect);
301 printf("%08x ", (int)orig_reloc->address);
302 printf("%d %08x %d\n", howto->pc_relative, addend, size);
305 int blot_section(bfd *abfd, asection *sect, int offset, int size)
307 struct supersect *ss = fetch_supersect(abfd, sect, &isyms);
308 void *address = ss->contents.data + offset;
309 int tmp;
310 if (size == 4) {
311 tmp = *(int *)address;
312 *((int *)address) = 0x77777777;
313 } else if (size == 8) {
314 tmp = *(long long *)address;
315 *((long long *)address) = 0x7777777777777777ll;
316 } else {
317 fprintf(stderr, "ksplice: Unsupported size %d\n", size);
318 DIE;
320 return tmp;
323 const char *canonical_sym(const char *sect_wlabel)
325 const char *sect = sect_wlabel;
326 if (!mode("sizelist"))
327 sect = dup_wolabel(sect_wlabel);
329 if (starts_with(sect, ".rodata"))
330 return sect;
332 asymbol **symp;
333 for (symp = isyms.data; symp < isyms.data + isyms.size; symp++) {
334 asymbol *sym = *symp;
335 const char *cur_sectname = sym->section->name;
336 if (!mode("sizelist"))
337 cur_sectname = dup_wolabel(cur_sectname);
339 if (strlen(sym->name) != 0 &&
340 !starts_with(sym->name, ".text") &&
341 strcmp(cur_sectname, sect) == 0 && sym->value == 0)
342 return sym->name;
344 printf("ksplice: Failed to canonicalize %s\n", sect);
345 DIE;
348 void rm_from_special(bfd *ibfd, struct specsect *s)
350 asection *isection = bfd_get_section_by_name(ibfd, s->sectname);
351 if (isection == NULL)
352 return;
354 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
355 struct void_vec orig_contents;
356 vec_move(&orig_contents, &ss->contents);
357 size_t pad = align(orig_contents.size, 1 << ss->alignment) -
358 orig_contents.size;
359 memset(vec_grow(&orig_contents, pad), 0, pad);
360 struct arelentp_vec orig_relocs;
361 vec_move(&orig_relocs, &ss->relocs);
363 int entry_size = align(s->entry_size, 1 << ss->alignment);
364 int relocs_per_entry = s->odd_relocs ? 2 : 1;
365 assert((orig_contents.size / entry_size) * relocs_per_entry ==
366 orig_relocs.size);
368 void *orig_entry;
369 arelent **relocp;
370 for (orig_entry = orig_contents.data, relocp = orig_relocs.data;
371 orig_entry < orig_contents.data + orig_contents.size;
372 orig_entry += entry_size, relocp += relocs_per_entry) {
373 asymbol *sym = *(*relocp)->sym_ptr_ptr;
374 if (s->odd_relocs) {
375 asymbol *odd_sym = *(*(relocp + 1))->sym_ptr_ptr;
376 assert(strcmp(odd_sym->name, s->odd_relocname) == 0);
378 asection *p;
379 for (p = ibfd->sections; p != NULL; p = p->next) {
380 if (strcmp(sym->name, p->name) == 0
381 && !is_special(p->name)
382 && !want_section(p->name, NULL))
383 break;
385 if (p != NULL)
386 continue;
388 void *new_entry = vec_grow(&ss->contents, entry_size);
389 memcpy(new_entry, orig_entry, entry_size);
390 int modifier = (new_entry - ss->contents.data) -
391 (orig_entry - orig_contents.data);
392 arelent **new_relocp = vec_grow(&ss->relocs, 1);
393 *new_relocp = *relocp;
394 (*new_relocp)->address += modifier;
395 if (s->odd_relocs) {
396 new_relocp = vec_grow(&ss->relocs, 1);
397 *new_relocp = *(relocp + 1);
398 (*new_relocp)->address += modifier;
403 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
405 if (want_section(sect->name, NULL))
406 return;
407 if (!starts_with(sect->name, ".text")
408 && !starts_with(sect->name, ".rodata"))
409 return;
411 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
414 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
415 void *looking_for)
417 if (!want_section(looking_at->name, NULL))
418 return;
420 struct supersect *ss = fetch_supersect(abfd, looking_at, &isyms);
421 arelent **relocp;
422 for (relocp = ss->relocs.data;
423 relocp != ss->relocs.data + ss->relocs.size; ++relocp) {
424 asymbol *sym = *(*relocp)->sym_ptr_ptr;
425 if (sym->section == (asection *)looking_for) {
426 struct wsect *w = malloc(sizeof(*w));
427 w->name = strdup(((asection *)looking_for)->name);
428 w->next = wanted_sections;
429 wanted_sections = w;
434 /* Modified function from GNU Binutils objcopy.c */
435 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
437 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
439 bfd_vma start = bfd_get_start_address(ibfd);
441 flagword flags = bfd_get_file_flags(ibfd);
442 flags &= bfd_applicable_file_flags(obfd);
444 assert(bfd_set_start_address(obfd, start)
445 && bfd_set_file_flags(obfd, flags));
447 enum bfd_architecture iarch = bfd_get_arch(ibfd);
448 unsigned int imach = bfd_get_mach(ibfd);
449 assert(bfd_set_arch_mach(obfd, iarch, imach));
450 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
452 /* BFD mandates that all output sections be created and sizes set before
453 any output is done. Thus, we traverse all sections multiple times. */
454 bfd_map_over_sections(ibfd, setup_section, obfd);
456 assert(bfd_count_sections(obfd));
458 struct supersect *ss;
459 for (ss = new_supersects; ss != NULL; ss = ss->next)
460 setup_new_section(obfd, ss);
462 /* Mark symbols used in output relocations so that they
463 are kept, even if they are local labels or static symbols.
465 Note we iterate over the input sections examining their
466 relocations since the relocations for the output sections
467 haven't been set yet. mark_symbols_used_in_relocations will
468 ignore input sections which have no corresponding output
469 section. */
471 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, &isyms);
472 for (ss = new_supersects; ss != NULL; ss = ss->next)
473 ss_mark_symbols_used_in_relocations(ss);
474 struct asymbolp_vec osyms;
475 vec_init(&osyms);
476 filter_symbols(ibfd, obfd, &osyms, &isyms);
478 bfd_set_symtab(obfd, osyms.data, osyms.size);
480 /* This has to happen after the symbol table has been set. */
481 bfd_map_over_sections(ibfd, copy_section, obfd);
482 for (ss = new_supersects; ss != NULL; ss = ss->next)
483 write_new_section(obfd, ss);
485 /* Allow the BFD backend to copy any private data it understands
486 from the input BFD to the output BFD. This is done last to
487 permit the routine to look at the filtered symbol table, which is
488 important for the ECOFF code at least. */
489 assert(bfd_copy_private_bfd_data(ibfd, obfd));
491 return TRUE;
494 /* Modified function from GNU Binutils objcopy.c */
495 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
497 bfd *obfd = obfdarg;
498 bfd_vma vma;
500 char *name = strdup(isection->name);
501 if (!want_section(isection->name, &name))
502 return;
504 asection *osection = bfd_make_section_anyway(obfd, name);
505 assert(osection != NULL);
507 flagword flags = bfd_get_section_flags(ibfd, isection);
508 bfd_set_section_flags(obfd, osection, flags);
510 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
511 osection->userdata = ss;
512 ss->symbol = osection->symbol;
513 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
515 vma = bfd_section_vma(ibfd, isection);
516 assert(bfd_set_section_vma(obfd, osection, vma));
518 osection->lma = isection->lma;
519 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
520 osection->entsize = isection->entsize;
521 isection->output_section = osection;
522 isection->output_offset = 0;
523 return;
526 void setup_new_section(bfd *obfd, struct supersect *ss)
528 asection *osection = bfd_make_section_anyway(obfd, ss->name);
529 assert(osection != NULL);
530 bfd_set_section_flags(obfd, osection,
531 SEC_ALLOC | SEC_HAS_CONTENTS | SEC_RELOC);
533 osection->userdata = ss;
534 ss->symbol = osection->symbol;
535 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
536 assert(bfd_set_section_vma(obfd, osection, 0));
538 osection->lma = 0;
539 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
540 osection->entsize = 0;
543 /* Modified function from GNU Binutils objcopy.c */
544 void copy_section(bfd *ibfd, asection *isection, void *obfdarg)
546 bfd *obfd = obfdarg;
548 char *name = strdup(isection->name);
549 if (!want_section(isection->name, &name))
550 return;
552 flagword flags = bfd_get_section_flags(ibfd, isection);
553 if ((flags & SEC_GROUP) != 0)
554 return;
556 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
557 asection *osection = isection->output_section;
558 if (ss->contents.size == 0 || osection == 0)
559 return;
561 bfd_set_reloc(obfd, osection,
562 ss->relocs.size == 0 ? NULL : ss->relocs.data,
563 ss->relocs.size);
565 if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS
566 && bfd_get_section_flags(obfd, osection) & SEC_HAS_CONTENTS)
567 assert(bfd_set_section_contents
568 (obfd, osection, ss->contents.data, 0,
569 ss->contents.size));
572 void write_new_section(bfd *obfd, struct supersect *ss)
574 asection *osection = bfd_get_section_by_name(obfd, ss->name);
576 if (ss->contents.size == 0 || osection == 0)
577 return;
579 bfd_set_reloc(obfd, osection,
580 ss->relocs.size == 0 ? NULL : ss->relocs.data,
581 ss->relocs.size);
583 if (bfd_get_section_flags(obfd, osection) & SEC_HAS_CONTENTS)
584 assert(bfd_set_section_contents
585 (obfd, osection, ss->contents.data, 0,
586 ss->contents.size));
589 /* Modified function from GNU Binutils objcopy.c
591 * Mark all the symbols which will be used in output relocations with
592 * the BSF_KEEP flag so that those symbols will not be stripped.
594 * Ignore relocations which will not appear in the output file.
596 void mark_symbols_used_in_relocations(bfd *ibfd, asection *isection,
597 void *symbolsarg)
599 if (isection->output_section == NULL)
600 return;
602 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
603 ss_mark_symbols_used_in_relocations(ss);
606 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
608 /* Examine each symbol used in a relocation. If it's not one of the
609 special bfd section symbols, then mark it with BSF_KEEP. */
610 arelent **relocp;
611 for (relocp = ss->relocs.data;
612 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
613 asymbol *sym = *(*relocp)->sym_ptr_ptr;
614 if (sym != bfd_com_section_ptr->symbol
615 && sym != bfd_abs_section_ptr->symbol
616 && sym != bfd_und_section_ptr->symbol)
617 sym->flags |= BSF_KEEP;
621 /* Modified function from GNU Binutils objcopy.c
623 * Choose which symbol entries to copy.
624 * We don't copy in place, because that confuses the relocs.
625 * Return the number of symbols to print.
627 void filter_symbols(bfd *abfd, bfd *obfd, struct asymbolp_vec *osyms,
628 struct asymbolp_vec *isyms)
630 asymbol **symp;
631 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
632 asymbol *sym = *symp;
633 flagword flags = sym->flags;
635 if (mode("keep") && want_section(sym->section->name, NULL)) {
636 char *newname =
637 malloc(strlen(sym->name) + strlen(addstr_all) +
638 strlen(addstr_sect) + 1);
639 sprintf(newname, "%s%s%s", sym->name, addstr_all,
640 addstr_sect);
641 sym->name = newname;
644 int keep;
645 if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
646 || ((flags & BSF_SECTION_SYM) != 0
647 && ((*(sym->section)->symbol_ptr_ptr)->flags
648 & BSF_KEEP) != 0))
649 keep = 1;
650 else if ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
651 keep = 1;
652 else if (bfd_decode_symclass(sym) == 'I')
653 /* Global symbols in $idata sections need to be retained.
654 External users of the library containing the $idata
655 section may reference these symbols. */
656 keep = 1;
657 else if ((flags & BSF_GLOBAL) != 0
658 || (flags & BSF_WEAK) != 0
659 || bfd_is_com_section(sym->section))
660 keep = 1;
661 else if ((flags & BSF_DEBUGGING) != 0)
662 keep = 1;
663 else
664 keep = !bfd_is_local_label(abfd, sym);
666 if (!want_section(sym->section->name, NULL))
667 keep = 0;
669 if (mode("rmsyms") && match_varargs(sym->name))
670 keep = 0;
672 if (keep)
673 *vec_grow(osyms, 1) = sym;
675 if (keep && mode("globalize")
676 && ends_with(sym->name, globalizestr)) {
677 asymbol *new = bfd_make_empty_symbol(obfd);
678 char *tmp =
679 malloc(strlen(sym->name) + strlen("_global") + 1);
680 sprintf(tmp, "%s_global", sym->name);
681 new->name = tmp;
682 new->value = sym->value;
683 new->flags = BSF_GLOBAL;
684 new->section = sym->section;
685 *vec_grow(osyms, 1) = new;
689 asection *p;
690 for (p = obfd->sections; mode("keep") && p != NULL; p = p->next) {
691 if (starts_with(p->name, ".rodata") &&
692 !exists_sym_with_name(isyms, p->name)) {
693 asymbol *new = bfd_make_empty_symbol(obfd);
694 new->name = p->name;
695 new->value = 0x0;
696 new->flags = BSF_GLOBAL;
697 new->section = p;
698 *vec_grow(osyms, 1) = new;
703 int exists_sym_with_name(struct asymbolp_vec *syms, const char *desired)
705 asymbol **symp;
706 for (symp = syms->data; symp < syms->data + syms->size; symp++) {
707 if (strcmp(bfd_asymbol_name(*symp), desired) == 0)
708 return 1;
710 return 0;
713 int match_varargs(const char *str)
715 int i;
716 for (i = 0; i < varargs_count; i++) {
717 if (strcmp(str, varargs[i]) == 0)
718 return 1;
719 if (starts_with(str, varargs[i]) &&
720 strcmp(str + strlen(varargs[i]), "_global") == 0)
721 return 1;
723 return 0;
726 int want_section(const char *name, char **newname)
728 static const char *static_want[] = {
729 ".altinstructions",
730 ".altinstr_replacement",
731 ".smp_locks",
732 ".parainstructions",
733 NULL
736 if (!mode("keep"))
737 return 1;
739 struct wsect *w = wanted_sections;
740 for (; w != NULL; w = w->next) {
741 if (strcmp(w->name, name) == 0)
742 goto success;
745 if (starts_with(name, ".ksplice"))
746 goto success;
747 if (mode("keep-helper") && starts_with(name, ".text"))
748 goto success;
749 if (match_varargs(name))
750 goto success;
752 int i;
753 for (i = 0; static_want[i] != NULL; i++) {
754 if (strcmp(name, static_want[i]) == 0)
755 return 1;
757 return 0;
759 success:
761 if (newname != NULL) {
762 *newname =
763 malloc(strlen(name) + strlen(addstr_all) +
764 strlen(addstr_sect) + 1);
765 sprintf(*newname, "%s%s%s", name, addstr_all, addstr_sect);
767 return 1;
770 struct specsect *is_special(const char *name)
772 struct specsect *ss;
773 for (ss = special_sections; ss != end_special_sections; ss++) {
774 if (strcmp(ss->sectname, name) == 0)
775 return ss;
777 return NULL;