Create relocations with bfd_install_relocation.
[ksplice.git] / objmanip.c
blob13de3b03a24b44ecdc0efe6397fe71bebb20a82d
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 reloc->addend = offset;
290 *(unsigned long *)addr = 0;
291 *vec_grow(&ss->new_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,
312 unsigned long **sym_addrs,
313 unsigned long *num_sym_addrs, asymbol *sym)
315 const char *system_map_name = dup_wolabel(sym->name);
316 const char **prefix;
317 for (prefix = (const char *[]){".text.", ".data.", ".bss.", NULL};
318 *prefix != NULL; prefix++) {
319 if (starts_with(system_map_name, *prefix))
320 system_map_name += strlen(*prefix);
322 struct addr_vec *addrs = addr_vec_hash_lookup(&system_map,
323 system_map_name, FALSE);
324 if (addrs != NULL) {
325 struct supersect *array_ss = make_section(ibfd, &isyms,
326 ".ksplice_array");
327 void *buf = sect_grow(array_ss, addrs->size,
328 typeof(*addrs->data));
329 memcpy(buf, addrs->data, addrs->size * sizeof(*addrs->data));
330 *num_sym_addrs = addrs->size;
331 write_reloc(ibfd, ss, sym_addrs, &array_ss->symbol,
332 buf - array_ss->contents.data);
333 } else {
334 *num_sym_addrs = 0;
335 *sym_addrs = NULL;
339 void write_ksplice_reloc(bfd *ibfd, asection *isection, arelent *orig_reloc,
340 struct supersect *ss)
342 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
344 char *new_symname = strdup(sym_ptr->name);
345 if (mode("keep-primary"))
346 want_section(sym_ptr->name, &new_symname);
348 reloc_howto_type *howto = orig_reloc->howto;
350 bfd_vma inplace = blot_section(ibfd, isection, orig_reloc->address,
351 howto);
353 struct supersect *kreloc_ss = make_section(ibfd, &isyms,
354 mode("rmsyms") ?
355 ".ksplice_init_relocs" :
356 ".ksplice_relocs");
357 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
358 struct ksplice_reloc);
360 write_string(ibfd, kreloc_ss, &kreloc->sym_name, "%s%s",
361 new_symname, addstr_all);
362 write_reloc(ibfd, kreloc_ss, &kreloc->blank_addr,
363 &ss->symbol, orig_reloc->address);
364 kreloc->blank_offset = (unsigned long)orig_reloc->address;
365 write_system_map_array(ibfd, kreloc_ss, &kreloc->sym_addrs,
366 &kreloc->num_sym_addrs, sym_ptr);
367 kreloc->pcrel = howto->pc_relative;
368 if (howto->partial_inplace)
369 kreloc->addend = inplace;
370 else
371 kreloc->addend = orig_reloc->addend;
372 kreloc->size = bfd_get_reloc_size(howto);
373 kreloc->dst_mask = howto->dst_mask;
374 kreloc->rightshift = howto->rightshift;
377 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
379 bfd_vma blot_section(bfd *abfd, asection *sect, int offset,
380 reloc_howto_type *howto)
382 struct supersect *ss = fetch_supersect(abfd, sect, &isyms);
383 void *address = ss->contents.data + offset;
384 switch (howto->size) {
385 case 0:
387 int8_t x = bfd_get_8(abfd, address);
388 bfd_vma newx = CANARY(x, 0x77);
389 bfd_put_8(abfd, newx, address);
390 return x & howto->src_mask;
392 case 1:
394 int16_t x = bfd_get_16(abfd, address);
395 bfd_vma newx = CANARY(x, 0x7777);
396 bfd_put_16(abfd, newx, address);
397 return x & howto->src_mask;
399 case 2:
401 int32_t x = bfd_get_32(abfd, address);
402 bfd_vma newx = CANARY(x, 0x77777777);
403 bfd_put_32(abfd, newx, address);
404 return x & howto->src_mask;
406 case 4:
408 int64_t x = bfd_get_64(abfd, address);
409 bfd_vma newx = CANARY(x, 0x7777777777777777ll);
410 bfd_put_64(abfd, newx, address);
411 return x & howto->src_mask;
413 default:
414 fprintf(stderr, "ksplice: Unsupported howto->size %d\n",
415 howto->size);
416 DIE;
420 void write_ksplice_size(bfd *ibfd, asymbol **symp)
422 asymbol *sym = *symp;
424 /* We call bfd_print_symbol in order to get access to
425 * the size associated with the function symbol, which
426 * is not otherwise available through the BFD API
428 char *buf = NULL;
429 size_t bufsize = 0;
430 FILE *fp = open_memstream(&buf, &bufsize);
431 bfd_print_symbol(ibfd, fp, sym, bfd_print_symbol_all);
432 fclose(fp);
433 assert(buf != NULL);
435 unsigned long symsize;
436 char *symname;
437 int len;
438 assert(sscanf(buf, "%*[^\t]\t%lx %as%n", &symsize, &symname, &len) >=
440 assert(buf[len] == '\0');
441 assert(strcmp(symname, sym->name) == 0);
442 free(symname);
443 free(buf);
445 struct supersect *ksize_ss = make_section(ibfd, &isyms,
446 ".ksplice_sizes");
447 struct ksplice_size *ksize = sect_grow(ksize_ss, 1,
448 struct ksplice_size);
450 write_string(ibfd, ksize_ss, &ksize->name, "%s", sym->name);
451 ksize->size = symsize;
452 write_reloc(ibfd, ksize_ss, &ksize->thismod_addr, symp, 0);
453 write_system_map_array(ibfd, ksize_ss, &ksize->sym_addrs,
454 &ksize->num_sym_addrs, sym);
457 void write_ksplice_patch(bfd *ibfd, char *symname)
459 struct supersect *kpatch_ss = make_section(ibfd, &isyms,
460 ".ksplice_patches");
461 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
462 struct ksplice_patch);
464 char newname[256];
465 snprintf(newname, sizeof(newname), "%s%s%s",
466 symname, addstr_all, addstr_sect);
467 asymbol **symp;
468 for (symp = isyms.data; symp < isyms.data + isyms.size; symp++) {
469 if (strcmp((*symp)->name, newname) == 0)
470 break;
472 assert(symp < isyms.data + isyms.size);
474 write_string(ibfd, kpatch_ss, &kpatch->oldstr, "%s%s%s",
475 symname, addstr_all, addstr_sect_pre);
476 write_string(ibfd, kpatch_ss, &kpatch->replstr, "%s", newname);
477 kpatch->oldaddr = 0;
478 write_reloc(ibfd, kpatch_ss, &kpatch->repladdr, symp, 0);
479 kpatch->saved = NULL;
482 void rm_from_special(bfd *ibfd, struct specsect *s)
484 asection *isection = bfd_get_section_by_name(ibfd, s->sectname);
485 if (isection == NULL)
486 return;
488 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
489 struct void_vec orig_contents;
490 vec_move(&orig_contents, &ss->contents);
491 size_t pad = align(orig_contents.size, 1 << ss->alignment) -
492 orig_contents.size;
493 memset(vec_grow(&orig_contents, pad), 0, pad);
494 struct arelentp_vec orig_relocs;
495 vec_move(&orig_relocs, &ss->relocs);
497 int entry_size = align(s->entry_size, 1 << ss->alignment);
498 int relocs_per_entry = s->odd_relocs ? 2 : 1;
499 assert((orig_contents.size / entry_size) * relocs_per_entry ==
500 orig_relocs.size);
502 void *orig_entry;
503 arelent **relocp;
504 for (orig_entry = orig_contents.data, relocp = orig_relocs.data;
505 orig_entry < orig_contents.data + orig_contents.size;
506 orig_entry += entry_size, relocp += relocs_per_entry) {
507 asymbol *sym = *(*relocp)->sym_ptr_ptr;
508 if (s->odd_relocs) {
509 asymbol *odd_sym = *(*(relocp + 1))->sym_ptr_ptr;
510 assert(strcmp(odd_sym->name, s->odd_relocname) == 0);
512 asection *p;
513 for (p = ibfd->sections; p != NULL; p = p->next) {
514 if (strcmp(sym->name, p->name) == 0
515 && !is_special(p->name)
516 && !want_section(p->name, NULL))
517 break;
519 if (p != NULL)
520 continue;
522 void *new_entry = vec_grow(&ss->contents, entry_size);
523 memcpy(new_entry, orig_entry, entry_size);
524 int modifier = (new_entry - ss->contents.data) -
525 (orig_entry - orig_contents.data);
526 arelent **new_relocp = vec_grow(&ss->relocs, 1);
527 *new_relocp = *relocp;
528 (*new_relocp)->address += modifier;
529 if (s->odd_relocs) {
530 new_relocp = vec_grow(&ss->relocs, 1);
531 *new_relocp = *(relocp + 1);
532 (*new_relocp)->address += modifier;
537 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
539 if (want_section(sect->name, NULL))
540 return;
541 if (!starts_with(sect->name, ".text")
542 && !starts_with(sect->name, ".rodata"))
543 return;
545 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
548 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
549 void *looking_for)
551 if (!want_section(looking_at->name, NULL))
552 return;
554 struct supersect *ss = fetch_supersect(abfd, looking_at, &isyms);
555 arelent **relocp;
556 for (relocp = ss->relocs.data;
557 relocp != ss->relocs.data + ss->relocs.size; ++relocp) {
558 asymbol *sym = *(*relocp)->sym_ptr_ptr;
559 if (sym->section == (asection *)looking_for) {
560 struct wsect *w = malloc(sizeof(*w));
561 w->name = strdup(((asection *)looking_for)->name);
562 w->next = wanted_sections;
563 wanted_sections = w;
568 /* Modified function from GNU Binutils objcopy.c */
569 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
571 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
573 bfd_vma start = bfd_get_start_address(ibfd);
575 flagword flags = bfd_get_file_flags(ibfd);
576 flags &= bfd_applicable_file_flags(obfd);
578 assert(bfd_set_start_address(obfd, start)
579 && bfd_set_file_flags(obfd, flags));
581 enum bfd_architecture iarch = bfd_get_arch(ibfd);
582 unsigned int imach = bfd_get_mach(ibfd);
583 assert(bfd_set_arch_mach(obfd, iarch, imach));
584 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
586 /* BFD mandates that all output sections be created and sizes set before
587 any output is done. Thus, we traverse all sections multiple times. */
588 bfd_map_over_sections(ibfd, setup_section, obfd);
590 assert(bfd_count_sections(obfd));
592 struct supersect *ss;
593 for (ss = new_supersects; ss != NULL; ss = ss->next)
594 setup_new_section(obfd, ss);
596 /* Mark symbols used in output relocations so that they
597 are kept, even if they are local labels or static symbols.
599 Note we iterate over the input sections examining their
600 relocations since the relocations for the output sections
601 haven't been set yet. mark_symbols_used_in_relocations will
602 ignore input sections which have no corresponding output
603 section. */
605 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, &isyms);
606 for (ss = new_supersects; ss != NULL; ss = ss->next)
607 ss_mark_symbols_used_in_relocations(ss);
608 struct asymbolp_vec osyms;
609 vec_init(&osyms);
610 filter_symbols(ibfd, obfd, &osyms, &isyms);
612 bfd_set_symtab(obfd, osyms.data, osyms.size);
614 /* This has to happen after the symbol table has been set. */
615 bfd_map_over_sections(obfd, write_section, NULL);
617 /* Allow the BFD backend to copy any private data it understands
618 from the input BFD to the output BFD. This is done last to
619 permit the routine to look at the filtered symbol table, which is
620 important for the ECOFF code at least. */
621 assert(bfd_copy_private_bfd_data(ibfd, obfd));
623 return TRUE;
626 /* Modified function from GNU Binutils objcopy.c */
627 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
629 bfd *obfd = obfdarg;
630 bfd_vma vma;
632 char *name = strdup(isection->name);
633 if (!want_section(isection->name, &name))
634 return;
636 asection *osection = bfd_make_section_anyway(obfd, name);
637 assert(osection != NULL);
639 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
640 osection->userdata = ss;
641 bfd_set_section_flags(obfd, osection, ss->flags);
642 ss->symbol = osection->symbol;
643 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
645 vma = bfd_section_vma(ibfd, isection);
646 assert(bfd_set_section_vma(obfd, osection, vma));
648 osection->lma = isection->lma;
649 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
650 osection->entsize = isection->entsize;
651 osection->output_section = osection;
652 osection->output_offset = 0;
653 isection->output_section = osection;
654 isection->output_offset = 0;
655 return;
658 void setup_new_section(bfd *obfd, struct supersect *ss)
660 asection *osection = bfd_make_section_anyway(obfd, ss->name);
661 assert(osection != NULL);
662 bfd_set_section_flags(obfd, osection, ss->flags);
664 osection->userdata = ss;
665 ss->symbol = osection->symbol;
666 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
667 assert(bfd_set_section_vma(obfd, osection, 0));
669 osection->lma = 0;
670 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
671 osection->entsize = 0;
672 osection->output_section = osection;
673 osection->output_offset = 0;
676 void write_section(bfd *obfd, asection *osection, void *arg)
678 struct supersect *ss = osection->userdata;
680 if (!want_section(ss->name, NULL) ||
681 (ss->flags & SEC_GROUP) != 0 ||
682 ss->contents.size == 0)
683 return;
685 arelent **relocp;
686 char *error_message;
687 for (relocp = ss->new_relocs.data;
688 relocp < ss->new_relocs.data + ss->new_relocs.size; ++relocp) {
689 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
690 0, osection, &error_message) !=
691 bfd_reloc_ok) {
692 fprintf(stderr, "ksplice: error installing reloc: %s",
693 error_message);
694 DIE;
697 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
698 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
700 bfd_set_reloc(obfd, osection,
701 ss->relocs.size == 0 ? NULL : ss->relocs.data,
702 ss->relocs.size);
704 if (ss->flags & SEC_HAS_CONTENTS)
705 assert(bfd_set_section_contents
706 (obfd, osection, ss->contents.data, 0,
707 ss->contents.size));
710 /* Modified function from GNU Binutils objcopy.c
712 * Mark all the symbols which will be used in output relocations with
713 * the BSF_KEEP flag so that those symbols will not be stripped.
715 * Ignore relocations which will not appear in the output file.
717 void mark_symbols_used_in_relocations(bfd *ibfd, asection *isection,
718 void *symbolsarg)
720 if (isection->output_section == NULL)
721 return;
723 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
724 ss_mark_symbols_used_in_relocations(ss);
727 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
729 /* Examine each symbol used in a relocation. If it's not one of the
730 special bfd section symbols, then mark it with BSF_KEEP. */
731 arelent **relocp;
732 for (relocp = ss->relocs.data;
733 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
734 asymbol *sym = *(*relocp)->sym_ptr_ptr;
735 if (sym != bfd_com_section_ptr->symbol
736 && sym != bfd_abs_section_ptr->symbol
737 && sym != bfd_und_section_ptr->symbol)
738 sym->flags |= BSF_KEEP;
742 /* Modified function from GNU Binutils objcopy.c
744 * Choose which symbol entries to copy.
745 * We don't copy in place, because that confuses the relocs.
746 * Return the number of symbols to print.
748 void filter_symbols(bfd *abfd, bfd *obfd, struct asymbolp_vec *osyms,
749 struct asymbolp_vec *isyms)
751 asymbol **symp;
752 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
753 asymbol *sym = *symp;
754 flagword flags = sym->flags;
756 if (mode("keep") && want_section(sym->section->name, NULL)) {
757 char *newname =
758 malloc(strlen(sym->name) + strlen(addstr_all) +
759 strlen(addstr_sect) + 1);
760 sprintf(newname, "%s%s%s", sym->name, addstr_all,
761 addstr_sect);
762 sym->name = newname;
765 int keep;
766 if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
767 || ((flags & BSF_SECTION_SYM) != 0
768 && ((*(sym->section)->symbol_ptr_ptr)->flags
769 & BSF_KEEP) != 0))
770 keep = 1;
771 else if ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
772 keep = 1;
773 else if (bfd_decode_symclass(sym) == 'I')
774 /* Global symbols in $idata sections need to be retained.
775 External users of the library containing the $idata
776 section may reference these symbols. */
777 keep = 1;
778 else if ((flags & BSF_GLOBAL) != 0
779 || (flags & BSF_WEAK) != 0
780 || bfd_is_com_section(sym->section))
781 keep = 1;
782 else if ((flags & BSF_DEBUGGING) != 0)
783 keep = 1;
784 else
785 keep = !bfd_is_local_label(abfd, sym);
787 if (!want_section(sym->section->name, NULL))
788 keep = 0;
790 if (mode("rmsyms") && match_varargs(sym->name))
791 keep = 0;
793 if (keep)
794 *vec_grow(osyms, 1) = sym;
797 asection *p;
798 for (p = obfd->sections; mode("keep") && p != NULL; p = p->next) {
799 if (starts_with(p->name, ".rodata") &&
800 !exists_sym_with_name(isyms, p->name)) {
801 asymbol *new = bfd_make_empty_symbol(obfd);
802 new->name = p->name;
803 new->value = 0x0;
804 new->flags = BSF_GLOBAL;
805 new->section = p;
806 *vec_grow(osyms, 1) = new;
811 int exists_sym_with_name(struct asymbolp_vec *syms, const char *desired)
813 asymbol **symp;
814 for (symp = syms->data; symp < syms->data + syms->size; symp++) {
815 if (strcmp(bfd_asymbol_name(*symp), desired) == 0)
816 return 1;
818 return 0;
821 int match_varargs(const char *str)
823 int i;
824 for (i = 0; i < varargs_count; i++) {
825 if (strcmp(str, varargs[i]) == 0)
826 return 1;
828 return 0;
831 int want_section(const char *name, char **newname)
833 static const char *static_want[] = {
834 ".altinstructions",
835 ".altinstr_replacement",
836 ".smp_locks",
837 ".parainstructions",
838 NULL
841 if (!mode("keep"))
842 return 1;
844 struct wsect *w = wanted_sections;
845 for (; w != NULL; w = w->next) {
846 if (strcmp(w->name, name) == 0)
847 goto success;
850 if (starts_with(name, ".ksplice"))
851 goto success;
852 if (mode("keep-helper") && starts_with(name, ".text"))
853 goto success;
854 if (match_varargs(name))
855 goto success;
857 int i;
858 for (i = 0; static_want[i] != NULL; i++) {
859 if (strcmp(name, static_want[i]) == 0)
860 return 1;
862 return 0;
864 success:
866 if (newname != NULL) {
867 *newname =
868 malloc(strlen(name) + strlen(addstr_all) +
869 strlen(addstr_sect) + 1);
870 sprintf(*newname, "%s%s%s", name, addstr_all, addstr_sect);
872 return 1;
875 struct specsect *is_special(const char *name)
877 struct specsect *ss;
878 for (ss = special_sections; ss != end_special_sections; ss++) {
879 if (strcmp(ss->sectname, name) == 0)
880 return ss;
882 return NULL;