Merge copy_section and write_new_section into write_section.
[ksplice.git] / objmanip.c
blob2199333812aa6e21d823bd677505a15fdeb791cb
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 "kmodsrc/ksplice.h"
101 #include <stdint.h>
102 #include <stdarg.h>
103 #include <stdlib.h>
104 #include <stdio.h>
105 #include <limits.h>
107 struct asymbolp_vec isyms;
109 char **varargs;
110 int varargs_count;
111 char *modestr, *addstr_all = "", *addstr_sect_pre = "", *addstr_sect = "";
113 struct wsect *wanted_sections = NULL;
115 struct specsect special_sections[] = {
116 {".altinstructions", 1, ".altinstr_replacement",
117 2 * sizeof(void *) + 4},
118 {".smp_locks", 0, NULL, sizeof(void *)},
119 {".parainstructions", 0, NULL, sizeof(void *) + 4},
120 }, *const end_special_sections = *(&special_sections + 1);
122 #define mode(str) starts_with(modestr, str)
124 DECLARE_VEC_TYPE(unsigned long, addr_vec);
125 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
126 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
127 vec_init);
128 struct addr_vec_hash system_map;
130 void load_system_map()
132 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
133 assert(config_dir);
134 char file[PATH_MAX];
135 snprintf(file, sizeof(file), "%s/System.map", config_dir);
136 FILE *fp = fopen(file, "r");
137 assert(fp);
138 addr_vec_hash_init(&system_map);
139 unsigned long addr;
140 char type;
141 char sym[256];
142 while (fscanf(fp, "%lx %c %256s\n", &addr, &type, sym) == 3)
143 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
144 1) = addr;
145 fclose(fp);
148 int main(int argc, char **argv)
150 char *debug_name = malloc(strlen(argv[1]) + 4 + strlen(argv[2]) + 1);
151 sprintf(debug_name, "%s.pre%s", argv[1], argv[2]);
152 rename(argv[1], debug_name);
154 bfd_init();
155 bfd *ibfd = bfd_openr(debug_name, NULL);
156 assert(ibfd);
158 char **matching;
159 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
161 const char *output_target = bfd_get_target(ibfd);
162 bfd *obfd = bfd_openw(argv[1], output_target);
163 assert(obfd);
165 get_syms(ibfd, &isyms);
167 modestr = argv[2];
168 if (mode("keep")) {
169 addstr_all = argv[3];
170 addstr_sect = argv[4];
171 varargs = &argv[5];
172 varargs_count = argc - 5;
173 } else if (mode("patchlist")) {
174 addstr_all = argv[3];
175 addstr_sect_pre = argv[4];
176 addstr_sect = argv[5];
177 varargs = &argv[6];
178 varargs_count = argc - 6;
179 } else {
180 varargs = &argv[3];
181 varargs_count = argc - 3;
184 if (mode("keep") || mode("sizelist") || mode("rmsyms"))
185 load_system_map();
187 if (mode("keep")) {
188 while (1) {
189 struct wsect *tmp = wanted_sections;
190 bfd_map_over_sections(ibfd, mark_wanted_if_referenced,
191 NULL);
192 if (tmp == wanted_sections)
193 break;
197 asymbol **symp;
198 for (symp = isyms.data;
199 mode("sizelist") && symp < isyms.data + isyms.size; symp++) {
200 asymbol *sym = *symp;
201 if ((sym->flags & BSF_FUNCTION)
202 && sym->value == 0 && !(sym->flags & BSF_WEAK))
203 write_ksplice_size(ibfd, symp);
206 if (mode("patchlist")) {
207 char **symname;
208 for (symname = varargs; symname < varargs + varargs_count;
209 symname++)
210 write_ksplice_patch(ibfd, *symname);
213 asection *p;
214 for (p = ibfd->sections; p != NULL; p = p->next) {
215 if (is_special(p->name) || starts_with(p->name, ".ksplice"))
216 continue;
217 if (want_section(p->name, NULL) || mode("rmsyms"))
218 rm_some_relocs(ibfd, p);
221 struct specsect *ss;
222 if (mode("keep")) {
223 for (ss = special_sections; ss != end_special_sections; ss++)
224 rm_from_special(ibfd, ss);
227 copy_object(ibfd, obfd);
228 assert(bfd_close(obfd));
229 assert(bfd_close(ibfd));
230 return EXIT_SUCCESS;
233 void rm_some_relocs(bfd *ibfd, asection *isection)
235 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
236 struct arelentp_vec orig_relocs;
237 vec_move(&orig_relocs, &ss->relocs);
239 arelent **relocp;
240 for (relocp = orig_relocs.data;
241 relocp < orig_relocs.data + orig_relocs.size; ++relocp) {
242 int rm_reloc = 0;
243 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
245 if (mode("rmsyms") && match_varargs(sym_ptr->name))
246 rm_reloc = 1;
248 if (mode("keep"))
249 rm_reloc = 1;
251 if (mode("keep-primary") && want_section(sym_ptr->name, NULL))
252 rm_reloc = 0;
254 if (rm_reloc)
255 write_ksplice_reloc(ibfd, isection, *relocp, ss);
256 else
257 *vec_grow(&ss->relocs, 1) = *relocp;
261 struct supersect *make_section(bfd *abfd, struct asymbolp_vec *syms, char *name)
263 asection *sect = bfd_get_section_by_name(abfd, name);
264 if (sect != NULL)
265 return fetch_supersect(abfd, sect, syms);
266 else
267 return new_supersect(name);
270 void write_reloc(bfd *abfd, struct supersect *ss, void *addr, asymbol **symp,
271 bfd_vma offset)
273 bfd_reloc_code_real_type code;
274 switch (bfd_arch_bits_per_address(abfd)) {
275 case 32:
276 code = BFD_RELOC_32;
277 break;
278 case 64:
279 code = BFD_RELOC_64;
280 break;
281 default:
282 DIE;
285 arelent *reloc = malloc(sizeof(*reloc));
286 reloc->sym_ptr_ptr = symp;
287 reloc->address = addr - ss->contents.data;
288 reloc->howto = bfd_reloc_type_lookup(abfd, code);
289 /* FIXME: bfd_perform_relocation? bfd_install_relocation? */
290 reloc->addend = offset;
291 *(unsigned long *)addr = reloc->howto->partial_inplace ? offset : 0;
292 *vec_grow(&ss->relocs, 1) = reloc;
295 void write_string(bfd *ibfd, struct supersect *ss, void *addr,
296 const char *fmt, ...)
298 va_list ap;
299 va_start(ap, fmt);
300 int len = vsnprintf(NULL, 0, fmt, ap);
301 va_end(ap);
302 struct supersect *str_ss = make_section(ibfd, &isyms, ".ksplice_str");
303 char *buf = sect_grow(str_ss, len + 1, char);
304 va_start(ap, fmt);
305 vsnprintf(buf, len + 1, fmt, ap);
306 va_end(ap);
308 write_reloc(ibfd, ss, addr, &str_ss->symbol,
309 (void *)buf - str_ss->contents.data);
312 void write_system_map_array(bfd *ibfd, struct supersect *ss,
313 unsigned long **sym_addrs,
314 unsigned long *num_sym_addrs, asymbol *sym)
316 const char *system_map_name = dup_wolabel(sym->name);
317 const char **prefix;
318 for (prefix = (const char *[]){".text.", ".data.", ".bss.", NULL};
319 *prefix != NULL; prefix++) {
320 if (starts_with(system_map_name, *prefix))
321 system_map_name += strlen(*prefix);
323 struct addr_vec *addrs = addr_vec_hash_lookup(&system_map,
324 system_map_name, FALSE);
325 if (addrs != NULL) {
326 struct supersect *array_ss = make_section(ibfd, &isyms,
327 ".ksplice_array");
328 void *buf = sect_grow(array_ss, addrs->size,
329 typeof(*addrs->data));
330 memcpy(buf, addrs->data, addrs->size * sizeof(*addrs->data));
331 *num_sym_addrs = addrs->size;
332 write_reloc(ibfd, ss, sym_addrs, &array_ss->symbol,
333 buf - array_ss->contents.data);
334 } else {
335 *num_sym_addrs = 0;
336 *sym_addrs = NULL;
340 void write_ksplice_reloc(bfd *ibfd, asection *isection, arelent *orig_reloc,
341 struct supersect *ss)
343 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
345 char *new_symname = strdup(sym_ptr->name);
346 if (mode("keep-primary"))
347 want_section(sym_ptr->name, &new_symname);
349 reloc_howto_type *howto = orig_reloc->howto;
351 bfd_vma inplace = blot_section(ibfd, isection, orig_reloc->address,
352 howto);
354 struct supersect *kreloc_ss = make_section(ibfd, &isyms,
355 mode("rmsyms") ?
356 ".ksplice_init_relocs" :
357 ".ksplice_relocs");
358 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
359 struct ksplice_reloc);
361 write_string(ibfd, kreloc_ss, &kreloc->sym_name, "%s%s",
362 new_symname, addstr_all);
363 write_reloc(ibfd, kreloc_ss, &kreloc->blank_addr,
364 &ss->symbol, orig_reloc->address);
365 kreloc->blank_offset = (unsigned long)orig_reloc->address;
366 write_system_map_array(ibfd, kreloc_ss, &kreloc->sym_addrs,
367 &kreloc->num_sym_addrs, sym_ptr);
368 kreloc->pcrel = howto->pc_relative;
369 if (howto->partial_inplace)
370 kreloc->addend = inplace;
371 else
372 kreloc->addend = orig_reloc->addend;
373 kreloc->size = bfd_get_reloc_size(howto);
374 kreloc->dst_mask = howto->dst_mask;
375 kreloc->rightshift = howto->rightshift;
378 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
380 bfd_vma blot_section(bfd *abfd, asection *sect, int offset,
381 reloc_howto_type *howto)
383 struct supersect *ss = fetch_supersect(abfd, sect, &isyms);
384 void *address = ss->contents.data + offset;
385 switch (howto->size) {
386 case 0:
388 int8_t x = bfd_get_8(abfd, address);
389 bfd_vma newx = CANARY(x, 0x77);
390 bfd_put_8(abfd, newx, address);
391 return x & howto->src_mask;
393 case 1:
395 int16_t x = bfd_get_16(abfd, address);
396 bfd_vma newx = CANARY(x, 0x7777);
397 bfd_put_16(abfd, newx, address);
398 return x & howto->src_mask;
400 case 2:
402 int32_t x = bfd_get_32(abfd, address);
403 bfd_vma newx = CANARY(x, 0x77777777);
404 bfd_put_32(abfd, newx, address);
405 return x & howto->src_mask;
407 case 4:
409 int64_t x = bfd_get_64(abfd, address);
410 bfd_vma newx = CANARY(x, 0x7777777777777777ll);
411 bfd_put_64(abfd, newx, address);
412 return x & howto->src_mask;
414 default:
415 fprintf(stderr, "ksplice: Unsupported howto->size %d\n",
416 howto->size);
417 DIE;
421 void write_ksplice_size(bfd *ibfd, asymbol **symp)
423 asymbol *sym = *symp;
425 /* We call bfd_print_symbol in order to get access to
426 * the size associated with the function symbol, which
427 * is not otherwise available through the BFD API
429 char *buf = NULL;
430 size_t bufsize = 0;
431 FILE *fp = open_memstream(&buf, &bufsize);
432 bfd_print_symbol(ibfd, fp, sym, bfd_print_symbol_all);
433 fclose(fp);
434 assert(buf != NULL);
436 unsigned long symsize;
437 char *symname;
438 int len;
439 assert(sscanf(buf, "%*[^\t]\t%lx %as%n", &symsize, &symname, &len) >=
441 assert(buf[len] == '\0');
442 assert(strcmp(symname, sym->name) == 0);
443 free(symname);
444 free(buf);
446 struct supersect *ksize_ss = make_section(ibfd, &isyms,
447 ".ksplice_sizes");
448 struct ksplice_size *ksize = sect_grow(ksize_ss, 1,
449 struct ksplice_size);
451 write_string(ibfd, ksize_ss, &ksize->name, "%s", sym->name);
452 ksize->size = symsize;
453 write_reloc(ibfd, ksize_ss, &ksize->thismod_addr, symp, 0);
454 write_system_map_array(ibfd, ksize_ss, &ksize->sym_addrs,
455 &ksize->num_sym_addrs, sym);
458 void write_ksplice_patch(bfd *ibfd, char *symname)
460 struct supersect *kpatch_ss = make_section(ibfd, &isyms,
461 ".ksplice_patches");
462 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
463 struct ksplice_patch);
465 char newname[256];
466 snprintf(newname, sizeof(newname), "%s%s%s",
467 symname, addstr_all, addstr_sect);
468 asymbol **symp;
469 for (symp = isyms.data; symp < isyms.data + isyms.size; symp++) {
470 if (strcmp((*symp)->name, newname) == 0)
471 break;
473 assert(symp < isyms.data + isyms.size);
475 write_string(ibfd, kpatch_ss, &kpatch->oldstr, "%s%s%s",
476 symname, addstr_all, addstr_sect_pre);
477 write_string(ibfd, kpatch_ss, &kpatch->replstr, "%s", newname);
478 kpatch->oldaddr = 0;
479 write_reloc(ibfd, kpatch_ss, &kpatch->repladdr, symp, 0);
480 kpatch->saved = NULL;
483 void rm_from_special(bfd *ibfd, struct specsect *s)
485 asection *isection = bfd_get_section_by_name(ibfd, s->sectname);
486 if (isection == NULL)
487 return;
489 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
490 struct void_vec orig_contents;
491 vec_move(&orig_contents, &ss->contents);
492 size_t pad = align(orig_contents.size, 1 << ss->alignment) -
493 orig_contents.size;
494 memset(vec_grow(&orig_contents, pad), 0, pad);
495 struct arelentp_vec orig_relocs;
496 vec_move(&orig_relocs, &ss->relocs);
498 int entry_size = align(s->entry_size, 1 << ss->alignment);
499 int relocs_per_entry = s->odd_relocs ? 2 : 1;
500 assert((orig_contents.size / entry_size) * relocs_per_entry ==
501 orig_relocs.size);
503 void *orig_entry;
504 arelent **relocp;
505 for (orig_entry = orig_contents.data, relocp = orig_relocs.data;
506 orig_entry < orig_contents.data + orig_contents.size;
507 orig_entry += entry_size, relocp += relocs_per_entry) {
508 asymbol *sym = *(*relocp)->sym_ptr_ptr;
509 if (s->odd_relocs) {
510 asymbol *odd_sym = *(*(relocp + 1))->sym_ptr_ptr;
511 assert(strcmp(odd_sym->name, s->odd_relocname) == 0);
513 asection *p;
514 for (p = ibfd->sections; p != NULL; p = p->next) {
515 if (strcmp(sym->name, p->name) == 0
516 && !is_special(p->name)
517 && !want_section(p->name, NULL))
518 break;
520 if (p != NULL)
521 continue;
523 void *new_entry = vec_grow(&ss->contents, entry_size);
524 memcpy(new_entry, orig_entry, entry_size);
525 int modifier = (new_entry - ss->contents.data) -
526 (orig_entry - orig_contents.data);
527 arelent **new_relocp = vec_grow(&ss->relocs, 1);
528 *new_relocp = *relocp;
529 (*new_relocp)->address += modifier;
530 if (s->odd_relocs) {
531 new_relocp = vec_grow(&ss->relocs, 1);
532 *new_relocp = *(relocp + 1);
533 (*new_relocp)->address += modifier;
538 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
540 if (want_section(sect->name, NULL))
541 return;
542 if (!starts_with(sect->name, ".text")
543 && !starts_with(sect->name, ".rodata"))
544 return;
546 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
549 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
550 void *looking_for)
552 if (!want_section(looking_at->name, NULL))
553 return;
555 struct supersect *ss = fetch_supersect(abfd, looking_at, &isyms);
556 arelent **relocp;
557 for (relocp = ss->relocs.data;
558 relocp != ss->relocs.data + ss->relocs.size; ++relocp) {
559 asymbol *sym = *(*relocp)->sym_ptr_ptr;
560 if (sym->section == (asection *)looking_for) {
561 struct wsect *w = malloc(sizeof(*w));
562 w->name = strdup(((asection *)looking_for)->name);
563 w->next = wanted_sections;
564 wanted_sections = w;
569 /* Modified function from GNU Binutils objcopy.c */
570 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
572 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
574 bfd_vma start = bfd_get_start_address(ibfd);
576 flagword flags = bfd_get_file_flags(ibfd);
577 flags &= bfd_applicable_file_flags(obfd);
579 assert(bfd_set_start_address(obfd, start)
580 && bfd_set_file_flags(obfd, flags));
582 enum bfd_architecture iarch = bfd_get_arch(ibfd);
583 unsigned int imach = bfd_get_mach(ibfd);
584 assert(bfd_set_arch_mach(obfd, iarch, imach));
585 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
587 /* BFD mandates that all output sections be created and sizes set before
588 any output is done. Thus, we traverse all sections multiple times. */
589 bfd_map_over_sections(ibfd, setup_section, obfd);
591 assert(bfd_count_sections(obfd));
593 struct supersect *ss;
594 for (ss = new_supersects; ss != NULL; ss = ss->next)
595 setup_new_section(obfd, ss);
597 /* Mark symbols used in output relocations so that they
598 are kept, even if they are local labels or static symbols.
600 Note we iterate over the input sections examining their
601 relocations since the relocations for the output sections
602 haven't been set yet. mark_symbols_used_in_relocations will
603 ignore input sections which have no corresponding output
604 section. */
606 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, &isyms);
607 for (ss = new_supersects; ss != NULL; ss = ss->next)
608 ss_mark_symbols_used_in_relocations(ss);
609 struct asymbolp_vec osyms;
610 vec_init(&osyms);
611 filter_symbols(ibfd, obfd, &osyms, &isyms);
613 bfd_set_symtab(obfd, osyms.data, osyms.size);
615 /* This has to happen after the symbol table has been set. */
616 bfd_map_over_sections(obfd, write_section, NULL);
618 /* Allow the BFD backend to copy any private data it understands
619 from the input BFD to the output BFD. This is done last to
620 permit the routine to look at the filtered symbol table, which is
621 important for the ECOFF code at least. */
622 assert(bfd_copy_private_bfd_data(ibfd, obfd));
624 return TRUE;
627 /* Modified function from GNU Binutils objcopy.c */
628 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
630 bfd *obfd = obfdarg;
631 bfd_vma vma;
633 char *name = strdup(isection->name);
634 if (!want_section(isection->name, &name))
635 return;
637 asection *osection = bfd_make_section_anyway(obfd, name);
638 assert(osection != NULL);
640 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
641 osection->userdata = ss;
642 bfd_set_section_flags(obfd, osection, ss->flags);
643 ss->symbol = osection->symbol;
644 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
646 vma = bfd_section_vma(ibfd, isection);
647 assert(bfd_set_section_vma(obfd, osection, vma));
649 osection->lma = isection->lma;
650 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
651 osection->entsize = isection->entsize;
652 isection->output_section = osection;
653 isection->output_offset = 0;
654 return;
657 void setup_new_section(bfd *obfd, struct supersect *ss)
659 asection *osection = bfd_make_section_anyway(obfd, ss->name);
660 assert(osection != NULL);
661 bfd_set_section_flags(obfd, osection, ss->flags);
663 osection->userdata = ss;
664 ss->symbol = osection->symbol;
665 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
666 assert(bfd_set_section_vma(obfd, osection, 0));
668 osection->lma = 0;
669 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
670 osection->entsize = 0;
673 void write_section(bfd *obfd, asection *osection, void *arg)
675 struct supersect *ss = osection->userdata;
677 if (!want_section(ss->name, NULL) ||
678 (ss->flags & SEC_GROUP) != 0 ||
679 ss->contents.size == 0)
680 return;
682 bfd_set_reloc(obfd, osection,
683 ss->relocs.size == 0 ? NULL : ss->relocs.data,
684 ss->relocs.size);
686 if (ss->flags & SEC_HAS_CONTENTS)
687 assert(bfd_set_section_contents
688 (obfd, osection, ss->contents.data, 0,
689 ss->contents.size));
692 /* Modified function from GNU Binutils objcopy.c
694 * Mark all the symbols which will be used in output relocations with
695 * the BSF_KEEP flag so that those symbols will not be stripped.
697 * Ignore relocations which will not appear in the output file.
699 void mark_symbols_used_in_relocations(bfd *ibfd, asection *isection,
700 void *symbolsarg)
702 if (isection->output_section == NULL)
703 return;
705 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
706 ss_mark_symbols_used_in_relocations(ss);
709 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
711 /* Examine each symbol used in a relocation. If it's not one of the
712 special bfd section symbols, then mark it with BSF_KEEP. */
713 arelent **relocp;
714 for (relocp = ss->relocs.data;
715 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
716 asymbol *sym = *(*relocp)->sym_ptr_ptr;
717 if (sym != bfd_com_section_ptr->symbol
718 && sym != bfd_abs_section_ptr->symbol
719 && sym != bfd_und_section_ptr->symbol)
720 sym->flags |= BSF_KEEP;
724 /* Modified function from GNU Binutils objcopy.c
726 * Choose which symbol entries to copy.
727 * We don't copy in place, because that confuses the relocs.
728 * Return the number of symbols to print.
730 void filter_symbols(bfd *abfd, bfd *obfd, struct asymbolp_vec *osyms,
731 struct asymbolp_vec *isyms)
733 asymbol **symp;
734 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
735 asymbol *sym = *symp;
736 flagword flags = sym->flags;
738 if (mode("keep") && want_section(sym->section->name, NULL)) {
739 char *newname =
740 malloc(strlen(sym->name) + strlen(addstr_all) +
741 strlen(addstr_sect) + 1);
742 sprintf(newname, "%s%s%s", sym->name, addstr_all,
743 addstr_sect);
744 sym->name = newname;
747 int keep;
748 if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
749 || ((flags & BSF_SECTION_SYM) != 0
750 && ((*(sym->section)->symbol_ptr_ptr)->flags
751 & BSF_KEEP) != 0))
752 keep = 1;
753 else if ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
754 keep = 1;
755 else if (bfd_decode_symclass(sym) == 'I')
756 /* Global symbols in $idata sections need to be retained.
757 External users of the library containing the $idata
758 section may reference these symbols. */
759 keep = 1;
760 else if ((flags & BSF_GLOBAL) != 0
761 || (flags & BSF_WEAK) != 0
762 || bfd_is_com_section(sym->section))
763 keep = 1;
764 else if ((flags & BSF_DEBUGGING) != 0)
765 keep = 1;
766 else
767 keep = !bfd_is_local_label(abfd, sym);
769 if (!want_section(sym->section->name, NULL))
770 keep = 0;
772 if (mode("rmsyms") && match_varargs(sym->name))
773 keep = 0;
775 if (keep)
776 *vec_grow(osyms, 1) = sym;
779 asection *p;
780 for (p = obfd->sections; mode("keep") && p != NULL; p = p->next) {
781 if (starts_with(p->name, ".rodata") &&
782 !exists_sym_with_name(isyms, p->name)) {
783 asymbol *new = bfd_make_empty_symbol(obfd);
784 new->name = p->name;
785 new->value = 0x0;
786 new->flags = BSF_GLOBAL;
787 new->section = p;
788 *vec_grow(osyms, 1) = new;
793 int exists_sym_with_name(struct asymbolp_vec *syms, const char *desired)
795 asymbol **symp;
796 for (symp = syms->data; symp < syms->data + syms->size; symp++) {
797 if (strcmp(bfd_asymbol_name(*symp), desired) == 0)
798 return 1;
800 return 0;
803 int match_varargs(const char *str)
805 int i;
806 for (i = 0; i < varargs_count; i++) {
807 if (strcmp(str, varargs[i]) == 0)
808 return 1;
810 return 0;
813 int want_section(const char *name, char **newname)
815 static const char *static_want[] = {
816 ".altinstructions",
817 ".altinstr_replacement",
818 ".smp_locks",
819 ".parainstructions",
820 NULL
823 if (!mode("keep"))
824 return 1;
826 struct wsect *w = wanted_sections;
827 for (; w != NULL; w = w->next) {
828 if (strcmp(w->name, name) == 0)
829 goto success;
832 if (starts_with(name, ".ksplice"))
833 goto success;
834 if (mode("keep-helper") && starts_with(name, ".text"))
835 goto success;
836 if (match_varargs(name))
837 goto success;
839 int i;
840 for (i = 0; static_want[i] != NULL; i++) {
841 if (strcmp(name, static_want[i]) == 0)
842 return 1;
844 return 0;
846 success:
848 if (newname != NULL) {
849 *newname =
850 malloc(strlen(name) + strlen(addstr_all) +
851 strlen(addstr_sect) + 1);
852 sprintf(*newname, "%s%s%s", name, addstr_all, addstr_sect);
854 return 1;
857 struct specsect *is_special(const char *name)
859 struct specsect *ss;
860 for (ss = special_sections; ss != end_special_sections; ss++) {
861 if (strcmp(ss->sectname, name) == 0)
862 return ss;
864 return NULL;