Make handle_myst_reloc get a module_pack.
[ksplice.git] / objmanip.c
blob5736a8c5cb0204f65ecb7873ed550e3410e5dddb
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 #define _GNU_SOURCE
98 #include "objcommon.h"
99 #include "objmanip.h"
100 #include <stdint.h>
101 #include <stdarg.h>
102 #include <stdlib.h>
103 #include <stdio.h>
104 #include <limits.h>
106 struct asymbolp_vec isyms;
108 char **varargs;
109 int varargs_count;
110 char *modestr, *addstr_all = "", *addstr_sect_pre = "", *addstr_sect = "";
112 struct wsect *wanted_sections = NULL;
114 struct specsect special_sections[] = {
115 {".altinstructions", 1, ".altinstr_replacement",
116 2 * sizeof(void *) + 4},
117 {".smp_locks", 0, NULL, sizeof(void *)},
118 {".parainstructions", 0, NULL, sizeof(void *) + 4},
119 }, *const end_special_sections = *(&special_sections + 1);
121 #define mode(str) starts_with(modestr, str)
123 DECLARE_VEC_TYPE(long, addr_vec);
124 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
125 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
126 vec_init);
127 struct addr_vec_hash system_map;
129 void load_system_map()
131 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
132 assert(config_dir);
133 char file[PATH_MAX];
134 snprintf(file, sizeof(file), "%s/System.map", config_dir);
135 FILE *fp = fopen(file, "r");
136 assert(fp);
137 addr_vec_hash_init(&system_map);
138 long addr;
139 char type;
140 char sym[256];
141 while (fscanf(fp, "%lx %c %256s\n", &addr, &type, sym) == 3)
142 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
143 1) = addr;
144 fclose(fp);
147 int main(int argc, char **argv)
149 char *debug_name = malloc(strlen(argv[1]) + 4 + strlen(argv[2]) + 1);
150 sprintf(debug_name, "%s.pre%s", argv[1], argv[2]);
151 rename(argv[1], debug_name);
153 bfd_init();
154 bfd *ibfd = bfd_openr(debug_name, NULL);
155 assert(ibfd);
157 char **matching;
158 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
160 const char *output_target = bfd_get_target(ibfd);
161 bfd *obfd = bfd_openw(argv[1], output_target);
162 assert(obfd);
164 get_syms(ibfd, &isyms);
166 modestr = argv[2];
167 if (mode("keep")) {
168 addstr_all = argv[3];
169 addstr_sect = argv[4];
170 varargs = &argv[5];
171 varargs_count = argc - 5;
172 } else if (mode("patchlist")) {
173 addstr_all = argv[3];
174 addstr_sect_pre = argv[4];
175 addstr_sect = argv[5];
176 varargs = &argv[6];
177 varargs_count = argc - 6;
178 } else {
179 varargs = &argv[3];
180 varargs_count = argc - 3;
183 if (mode("keep") || mode("sizelist") || mode("rmsyms"))
184 load_system_map();
186 if (mode("keep")) {
187 while (1) {
188 struct wsect *tmp = wanted_sections;
189 bfd_map_over_sections(ibfd, mark_wanted_if_referenced,
190 NULL);
191 if (tmp == wanted_sections)
192 break;
196 asymbol **symp;
197 for (symp = isyms.data;
198 mode("sizelist") && symp < isyms.data + isyms.size; symp++) {
199 asymbol *sym = *symp;
200 if ((sym->flags & BSF_FUNCTION)
201 && sym->value == 0 && !(sym->flags & BSF_WEAK))
202 write_ksplice_size(ibfd, symp);
205 if (mode("patchlist")) {
206 char **symname;
207 for (symname = varargs; symname < varargs + varargs_count;
208 symname++)
209 write_ksplice_patch(ibfd, *symname);
212 asection *p;
213 for (p = ibfd->sections; p != NULL; p = p->next) {
214 if (is_special(p->name) || starts_with(p->name, ".ksplice"))
215 continue;
216 if (want_section(p->name, NULL) || mode("rmsyms"))
217 rm_some_relocs(ibfd, p);
220 struct specsect *ss;
221 if (mode("keep")) {
222 for (ss = special_sections; ss != end_special_sections; ss++)
223 rm_from_special(ibfd, ss);
226 copy_object(ibfd, obfd);
227 assert(bfd_close(obfd));
228 assert(bfd_close(ibfd));
229 return EXIT_SUCCESS;
232 void rm_some_relocs(bfd *ibfd, asection *isection)
234 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
235 struct arelentp_vec orig_relocs;
236 vec_move(&orig_relocs, &ss->relocs);
238 arelent **relocp;
239 for (relocp = orig_relocs.data;
240 relocp < orig_relocs.data + orig_relocs.size; ++relocp) {
241 int rm_reloc = 0;
242 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
244 if (mode("rmsyms") && match_varargs(sym_ptr->name))
245 rm_reloc = 1;
247 if (mode("keep"))
248 rm_reloc = 1;
250 if (mode("keep-primary") && want_section(sym_ptr->name, NULL))
251 rm_reloc = 0;
253 if (rm_reloc)
254 write_ksplice_reloc(ibfd, isection, *relocp, ss);
255 else
256 *vec_grow(&ss->relocs, 1) = *relocp;
260 struct supersect *make_section(bfd *abfd, struct asymbolp_vec *syms, char *name)
262 asection *sect = bfd_get_section_by_name(abfd, name);
263 if (sect != NULL)
264 return fetch_supersect(abfd, sect, syms);
265 else
266 return new_supersect(name);
269 void write_reloc(bfd *abfd, struct supersect *ss, void *addr, asymbol **symp,
270 bfd_vma offset)
272 bfd_reloc_code_real_type code;
273 switch (bfd_arch_bits_per_address(abfd)) {
274 case 32:
275 code = BFD_RELOC_32;
276 break;
277 case 64:
278 code = BFD_RELOC_64;
279 break;
280 default:
281 DIE;
284 arelent *reloc = malloc(sizeof(*reloc));
285 reloc->sym_ptr_ptr = symp;
286 reloc->address = addr - ss->contents.data;
287 reloc->howto = bfd_reloc_type_lookup(abfd, code);
288 /* FIXME: bfd_perform_relocation? bfd_install_relocation? */
289 reloc->addend = offset;
290 *(long *)addr = reloc->howto->partial_inplace ? offset : 0;
291 *vec_grow(&ss->relocs, 1) = reloc;
294 void write_string(bfd *ibfd, struct supersect *ss, void *addr,
295 const char *fmt, ...)
297 va_list ap;
298 va_start(ap, fmt);
299 int len = vsnprintf(NULL, 0, fmt, ap);
300 va_end(ap);
301 struct supersect *str_ss = make_section(ibfd, &isyms, ".ksplice_str");
302 char *buf = sect_grow(str_ss, len + 1, char);
303 va_start(ap, fmt);
304 vsnprintf(buf, len + 1, fmt, ap);
305 va_end(ap);
307 write_reloc(ibfd, ss, addr, &str_ss->symbol,
308 (void *)buf - str_ss->contents.data);
311 void write_system_map_array(bfd *ibfd, struct supersect *ss, long **sym_addrs,
312 long *num_sym_addrs, asymbol *sym)
314 const char *system_map_name = dup_wolabel(sym->name);
315 const char **prefix;
316 for (prefix = (const char *[]){".text.", ".data.", ".bss.", NULL};
317 *prefix != NULL; prefix++) {
318 if (starts_with(system_map_name, *prefix))
319 system_map_name += strlen(*prefix);
321 struct addr_vec *addrs = addr_vec_hash_lookup(&system_map,
322 system_map_name, FALSE);
323 if (addrs != NULL) {
324 struct supersect *array_ss = make_section(ibfd, &isyms,
325 ".ksplice_array");
326 void *buf = sect_grow(array_ss, addrs->size,
327 typeof(*addrs->data));
328 memcpy(buf, addrs->data, addrs->size * sizeof(*addrs->data));
329 *num_sym_addrs = addrs->size;
330 write_reloc(ibfd, ss, sym_addrs, &array_ss->symbol,
331 buf - array_ss->contents.data);
332 } else {
333 *num_sym_addrs = 0;
334 *sym_addrs = NULL;
338 void write_ksplice_reloc(bfd *ibfd, asection *isection, arelent *orig_reloc,
339 struct supersect *ss)
341 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
343 char *new_symname = strdup(sym_ptr->name);
344 if (mode("keep-primary"))
345 want_section(sym_ptr->name, &new_symname);
347 int addend = orig_reloc->addend;
348 reloc_howto_type *howto = orig_reloc->howto;
349 int size = bfd_get_reloc_size(howto);
350 int addend2 = blot_section(ibfd, isection, orig_reloc->address, size);
351 assert(addend == 0 || addend2 == 0);
352 if (addend == 0)
353 addend = addend2;
355 struct supersect *kreloc_ss = make_section(ibfd, &isyms,
356 mode("rmsyms") ?
357 ".ksplice_init_relocs" :
358 ".ksplice_relocs");
359 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
360 struct ksplice_reloc);
362 write_string(ibfd, kreloc_ss, &kreloc->sym_name, "%s%s",
363 new_symname, addstr_all);
364 write_reloc(ibfd, kreloc_ss, &kreloc->blank_addr,
365 &ss->symbol, orig_reloc->address);
366 kreloc->blank_offset = (long)orig_reloc->address;
367 write_system_map_array(ibfd, kreloc_ss, &kreloc->sym_addrs,
368 &kreloc->num_sym_addrs, sym_ptr);
369 kreloc->pcrel = howto->pc_relative;
370 kreloc->addend = addend;
371 kreloc->size = size;
374 int blot_section(bfd *abfd, asection *sect, int offset, int size)
376 struct supersect *ss = fetch_supersect(abfd, sect, &isyms);
377 void *address = ss->contents.data + offset;
378 int tmp;
379 if (size == 4) {
380 tmp = *(int *)address;
381 *((int *)address) = 0x77777777;
382 } else if (size == 8) {
383 tmp = *(long long *)address;
384 *((long long *)address) = 0x7777777777777777ll;
385 } else {
386 fprintf(stderr, "ksplice: Unsupported size %d\n", size);
387 DIE;
389 return tmp;
392 void write_ksplice_size(bfd *ibfd, asymbol **symp)
394 asymbol *sym = *symp;
396 /* We call bfd_print_symbol in order to get access to
397 * the size associated with the function symbol, which
398 * is not otherwise available through the BFD API
400 char *buf = NULL;
401 size_t bufsize = 0;
402 FILE *fp = open_memstream(&buf, &bufsize);
403 bfd_print_symbol(ibfd, fp, sym, bfd_print_symbol_all);
404 fclose(fp);
405 assert(buf != NULL);
407 unsigned long symsize;
408 char *symname;
409 int len;
410 assert(sscanf(buf, "%*[^\t]\t%lx %as%n", &symsize, &symname, &len) >=
412 assert(buf[len] == '\0');
413 assert(strcmp(symname, sym->name) == 0);
414 free(symname);
415 free(buf);
417 struct supersect *ksize_ss = make_section(ibfd, &isyms,
418 ".ksplice_sizes");
419 struct ksplice_size *ksize = sect_grow(ksize_ss, 1,
420 struct ksplice_size);
422 write_string(ibfd, ksize_ss, &ksize->name, "%s", sym->name);
423 ksize->size = symsize;
424 write_reloc(ibfd, ksize_ss, &ksize->thismod_addr, symp, 0);
425 write_system_map_array(ibfd, ksize_ss, &ksize->sym_addrs,
426 &ksize->num_sym_addrs, sym);
429 void write_ksplice_patch(bfd *ibfd, char *symname)
431 struct supersect *kpatch_ss = make_section(ibfd, &isyms,
432 ".ksplice_patches");
433 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
434 struct ksplice_patch);
436 char newname[256];
437 snprintf(newname, sizeof(newname), "%s%s%s",
438 symname, addstr_all, addstr_sect);
439 asymbol **symp;
440 for (symp = isyms.data; symp < isyms.data + isyms.size; symp++) {
441 if (strcmp((*symp)->name, newname) == 0)
442 break;
444 assert(symp < isyms.data + isyms.size);
446 write_string(ibfd, kpatch_ss, &kpatch->oldstr, "%s%s%s",
447 symname, addstr_all, addstr_sect_pre);
448 write_string(ibfd, kpatch_ss, &kpatch->replstr, "%s", newname);
449 kpatch->oldaddr = 0;
450 write_reloc(ibfd, kpatch_ss, &kpatch->repladdr, symp, 0);
451 kpatch->saved = NULL;
454 void rm_from_special(bfd *ibfd, struct specsect *s)
456 asection *isection = bfd_get_section_by_name(ibfd, s->sectname);
457 if (isection == NULL)
458 return;
460 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
461 struct void_vec orig_contents;
462 vec_move(&orig_contents, &ss->contents);
463 size_t pad = align(orig_contents.size, 1 << ss->alignment) -
464 orig_contents.size;
465 memset(vec_grow(&orig_contents, pad), 0, pad);
466 struct arelentp_vec orig_relocs;
467 vec_move(&orig_relocs, &ss->relocs);
469 int entry_size = align(s->entry_size, 1 << ss->alignment);
470 int relocs_per_entry = s->odd_relocs ? 2 : 1;
471 assert((orig_contents.size / entry_size) * relocs_per_entry ==
472 orig_relocs.size);
474 void *orig_entry;
475 arelent **relocp;
476 for (orig_entry = orig_contents.data, relocp = orig_relocs.data;
477 orig_entry < orig_contents.data + orig_contents.size;
478 orig_entry += entry_size, relocp += relocs_per_entry) {
479 asymbol *sym = *(*relocp)->sym_ptr_ptr;
480 if (s->odd_relocs) {
481 asymbol *odd_sym = *(*(relocp + 1))->sym_ptr_ptr;
482 assert(strcmp(odd_sym->name, s->odd_relocname) == 0);
484 asection *p;
485 for (p = ibfd->sections; p != NULL; p = p->next) {
486 if (strcmp(sym->name, p->name) == 0
487 && !is_special(p->name)
488 && !want_section(p->name, NULL))
489 break;
491 if (p != NULL)
492 continue;
494 void *new_entry = vec_grow(&ss->contents, entry_size);
495 memcpy(new_entry, orig_entry, entry_size);
496 int modifier = (new_entry - ss->contents.data) -
497 (orig_entry - orig_contents.data);
498 arelent **new_relocp = vec_grow(&ss->relocs, 1);
499 *new_relocp = *relocp;
500 (*new_relocp)->address += modifier;
501 if (s->odd_relocs) {
502 new_relocp = vec_grow(&ss->relocs, 1);
503 *new_relocp = *(relocp + 1);
504 (*new_relocp)->address += modifier;
509 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
511 if (want_section(sect->name, NULL))
512 return;
513 if (!starts_with(sect->name, ".text")
514 && !starts_with(sect->name, ".rodata"))
515 return;
517 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
520 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
521 void *looking_for)
523 if (!want_section(looking_at->name, NULL))
524 return;
526 struct supersect *ss = fetch_supersect(abfd, looking_at, &isyms);
527 arelent **relocp;
528 for (relocp = ss->relocs.data;
529 relocp != ss->relocs.data + ss->relocs.size; ++relocp) {
530 asymbol *sym = *(*relocp)->sym_ptr_ptr;
531 if (sym->section == (asection *)looking_for) {
532 struct wsect *w = malloc(sizeof(*w));
533 w->name = strdup(((asection *)looking_for)->name);
534 w->next = wanted_sections;
535 wanted_sections = w;
540 /* Modified function from GNU Binutils objcopy.c */
541 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
543 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
545 bfd_vma start = bfd_get_start_address(ibfd);
547 flagword flags = bfd_get_file_flags(ibfd);
548 flags &= bfd_applicable_file_flags(obfd);
550 assert(bfd_set_start_address(obfd, start)
551 && bfd_set_file_flags(obfd, flags));
553 enum bfd_architecture iarch = bfd_get_arch(ibfd);
554 unsigned int imach = bfd_get_mach(ibfd);
555 assert(bfd_set_arch_mach(obfd, iarch, imach));
556 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
558 /* BFD mandates that all output sections be created and sizes set before
559 any output is done. Thus, we traverse all sections multiple times. */
560 bfd_map_over_sections(ibfd, setup_section, obfd);
562 assert(bfd_count_sections(obfd));
564 struct supersect *ss;
565 for (ss = new_supersects; ss != NULL; ss = ss->next)
566 setup_new_section(obfd, ss);
568 /* Mark symbols used in output relocations so that they
569 are kept, even if they are local labels or static symbols.
571 Note we iterate over the input sections examining their
572 relocations since the relocations for the output sections
573 haven't been set yet. mark_symbols_used_in_relocations will
574 ignore input sections which have no corresponding output
575 section. */
577 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, &isyms);
578 for (ss = new_supersects; ss != NULL; ss = ss->next)
579 ss_mark_symbols_used_in_relocations(ss);
580 struct asymbolp_vec osyms;
581 vec_init(&osyms);
582 filter_symbols(ibfd, obfd, &osyms, &isyms);
584 bfd_set_symtab(obfd, osyms.data, osyms.size);
586 /* This has to happen after the symbol table has been set. */
587 bfd_map_over_sections(ibfd, copy_section, obfd);
588 for (ss = new_supersects; ss != NULL; ss = ss->next)
589 write_new_section(obfd, ss);
591 /* Allow the BFD backend to copy any private data it understands
592 from the input BFD to the output BFD. This is done last to
593 permit the routine to look at the filtered symbol table, which is
594 important for the ECOFF code at least. */
595 assert(bfd_copy_private_bfd_data(ibfd, obfd));
597 return TRUE;
600 /* Modified function from GNU Binutils objcopy.c */
601 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
603 bfd *obfd = obfdarg;
604 bfd_vma vma;
606 char *name = strdup(isection->name);
607 if (!want_section(isection->name, &name))
608 return;
610 asection *osection = bfd_make_section_anyway(obfd, name);
611 assert(osection != NULL);
613 flagword flags = bfd_get_section_flags(ibfd, isection);
614 bfd_set_section_flags(obfd, osection, flags);
616 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
617 osection->userdata = ss;
618 ss->symbol = osection->symbol;
619 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
621 vma = bfd_section_vma(ibfd, isection);
622 assert(bfd_set_section_vma(obfd, osection, vma));
624 osection->lma = isection->lma;
625 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
626 osection->entsize = isection->entsize;
627 isection->output_section = osection;
628 isection->output_offset = 0;
629 return;
632 void setup_new_section(bfd *obfd, struct supersect *ss)
634 asection *osection = bfd_make_section_anyway(obfd, ss->name);
635 assert(osection != NULL);
636 bfd_set_section_flags(obfd, osection,
637 SEC_ALLOC | SEC_HAS_CONTENTS | SEC_RELOC);
639 osection->userdata = ss;
640 ss->symbol = osection->symbol;
641 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
642 assert(bfd_set_section_vma(obfd, osection, 0));
644 osection->lma = 0;
645 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
646 osection->entsize = 0;
649 /* Modified function from GNU Binutils objcopy.c */
650 void copy_section(bfd *ibfd, asection *isection, void *obfdarg)
652 bfd *obfd = obfdarg;
654 char *name = strdup(isection->name);
655 if (!want_section(isection->name, &name))
656 return;
658 flagword flags = bfd_get_section_flags(ibfd, isection);
659 if ((flags & SEC_GROUP) != 0)
660 return;
662 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
663 asection *osection = isection->output_section;
664 if (ss->contents.size == 0 || osection == 0)
665 return;
667 bfd_set_reloc(obfd, osection,
668 ss->relocs.size == 0 ? NULL : ss->relocs.data,
669 ss->relocs.size);
671 if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS
672 && bfd_get_section_flags(obfd, osection) & SEC_HAS_CONTENTS)
673 assert(bfd_set_section_contents
674 (obfd, osection, ss->contents.data, 0,
675 ss->contents.size));
678 void write_new_section(bfd *obfd, struct supersect *ss)
680 asection *osection = bfd_get_section_by_name(obfd, ss->name);
682 if (ss->contents.size == 0 || osection == 0)
683 return;
685 bfd_set_reloc(obfd, osection,
686 ss->relocs.size == 0 ? NULL : ss->relocs.data,
687 ss->relocs.size);
689 if (bfd_get_section_flags(obfd, osection) & SEC_HAS_CONTENTS)
690 assert(bfd_set_section_contents
691 (obfd, osection, ss->contents.data, 0,
692 ss->contents.size));
695 /* Modified function from GNU Binutils objcopy.c
697 * Mark all the symbols which will be used in output relocations with
698 * the BSF_KEEP flag so that those symbols will not be stripped.
700 * Ignore relocations which will not appear in the output file.
702 void mark_symbols_used_in_relocations(bfd *ibfd, asection *isection,
703 void *symbolsarg)
705 if (isection->output_section == NULL)
706 return;
708 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
709 ss_mark_symbols_used_in_relocations(ss);
712 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
714 /* Examine each symbol used in a relocation. If it's not one of the
715 special bfd section symbols, then mark it with BSF_KEEP. */
716 arelent **relocp;
717 for (relocp = ss->relocs.data;
718 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
719 asymbol *sym = *(*relocp)->sym_ptr_ptr;
720 if (sym != bfd_com_section_ptr->symbol
721 && sym != bfd_abs_section_ptr->symbol
722 && sym != bfd_und_section_ptr->symbol)
723 sym->flags |= BSF_KEEP;
727 /* Modified function from GNU Binutils objcopy.c
729 * Choose which symbol entries to copy.
730 * We don't copy in place, because that confuses the relocs.
731 * Return the number of symbols to print.
733 void filter_symbols(bfd *abfd, bfd *obfd, struct asymbolp_vec *osyms,
734 struct asymbolp_vec *isyms)
736 asymbol **symp;
737 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
738 asymbol *sym = *symp;
739 flagword flags = sym->flags;
741 if (mode("keep") && want_section(sym->section->name, NULL)) {
742 char *newname =
743 malloc(strlen(sym->name) + strlen(addstr_all) +
744 strlen(addstr_sect) + 1);
745 sprintf(newname, "%s%s%s", sym->name, addstr_all,
746 addstr_sect);
747 sym->name = newname;
750 int keep;
751 if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
752 || ((flags & BSF_SECTION_SYM) != 0
753 && ((*(sym->section)->symbol_ptr_ptr)->flags
754 & BSF_KEEP) != 0))
755 keep = 1;
756 else if ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
757 keep = 1;
758 else if (bfd_decode_symclass(sym) == 'I')
759 /* Global symbols in $idata sections need to be retained.
760 External users of the library containing the $idata
761 section may reference these symbols. */
762 keep = 1;
763 else if ((flags & BSF_GLOBAL) != 0
764 || (flags & BSF_WEAK) != 0
765 || bfd_is_com_section(sym->section))
766 keep = 1;
767 else if ((flags & BSF_DEBUGGING) != 0)
768 keep = 1;
769 else
770 keep = !bfd_is_local_label(abfd, sym);
772 if (!want_section(sym->section->name, NULL))
773 keep = 0;
775 if (mode("rmsyms") && match_varargs(sym->name))
776 keep = 0;
778 if (keep)
779 *vec_grow(osyms, 1) = sym;
782 asection *p;
783 for (p = obfd->sections; mode("keep") && p != NULL; p = p->next) {
784 if (starts_with(p->name, ".rodata") &&
785 !exists_sym_with_name(isyms, p->name)) {
786 asymbol *new = bfd_make_empty_symbol(obfd);
787 new->name = p->name;
788 new->value = 0x0;
789 new->flags = BSF_GLOBAL;
790 new->section = p;
791 *vec_grow(osyms, 1) = new;
796 int exists_sym_with_name(struct asymbolp_vec *syms, const char *desired)
798 asymbol **symp;
799 for (symp = syms->data; symp < syms->data + syms->size; symp++) {
800 if (strcmp(bfd_asymbol_name(*symp), desired) == 0)
801 return 1;
803 return 0;
806 int match_varargs(const char *str)
808 int i;
809 for (i = 0; i < varargs_count; i++) {
810 if (strcmp(str, varargs[i]) == 0)
811 return 1;
813 return 0;
816 int want_section(const char *name, char **newname)
818 static const char *static_want[] = {
819 ".altinstructions",
820 ".altinstr_replacement",
821 ".smp_locks",
822 ".parainstructions",
823 NULL
826 if (!mode("keep"))
827 return 1;
829 struct wsect *w = wanted_sections;
830 for (; w != NULL; w = w->next) {
831 if (strcmp(w->name, name) == 0)
832 goto success;
835 if (starts_with(name, ".ksplice"))
836 goto success;
837 if (mode("keep-helper") && starts_with(name, ".text"))
838 goto success;
839 if (match_varargs(name))
840 goto success;
842 int i;
843 for (i = 0; static_want[i] != NULL; i++) {
844 if (strcmp(name, static_want[i]) == 0)
845 return 1;
847 return 0;
849 success:
851 if (newname != NULL) {
852 *newname =
853 malloc(strlen(name) + strlen(addstr_all) +
854 strlen(addstr_sect) + 1);
855 sprintf(*newname, "%s%s%s", name, addstr_all, addstr_sect);
857 return 1;
860 struct specsect *is_special(const char *name)
862 struct specsect *ss;
863 for (ss = special_sections; ss != end_special_sections; ss++) {
864 if (strcmp(ss->sectname, name) == 0)
865 return ss;
867 return NULL;