Replace print_abort("out of memory") with the corresponding printk.
[ksplice.git] / objmanip.c
blobe43918ad494f3d2ced6cd90570ab3bdd98c68874
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 *vec_grow(&ss->new_relocs, 1) = reloc;
293 void write_string(bfd *ibfd, struct supersect *ss, void *addr,
294 const char *fmt, ...)
296 va_list ap;
297 va_start(ap, fmt);
298 int len = vsnprintf(NULL, 0, fmt, ap);
299 va_end(ap);
300 struct supersect *str_ss = make_section(ibfd, &isyms, ".ksplice_str");
301 char *buf = sect_grow(str_ss, len + 1, char);
302 va_start(ap, fmt);
303 vsnprintf(buf, len + 1, fmt, ap);
304 va_end(ap);
306 write_reloc(ibfd, ss, addr, &str_ss->symbol,
307 (void *)buf - str_ss->contents.data);
310 void write_system_map_array(bfd *ibfd, struct supersect *ss,
311 unsigned long **sym_addrs,
312 unsigned 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 reloc_howto_type *howto = orig_reloc->howto;
349 bfd_vma inplace = blot_section(ibfd, isection, orig_reloc->address,
350 howto);
352 struct supersect *kreloc_ss = make_section(ibfd, &isyms,
353 mode("rmsyms") ?
354 ".ksplice_init_relocs" :
355 ".ksplice_relocs");
356 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
357 struct ksplice_reloc);
359 write_string(ibfd, kreloc_ss, &kreloc->sym_name, "%s%s",
360 new_symname, addstr_all);
361 write_reloc(ibfd, kreloc_ss, &kreloc->blank_addr,
362 &ss->symbol, orig_reloc->address);
363 kreloc->blank_offset = (unsigned long)orig_reloc->address;
364 write_system_map_array(ibfd, kreloc_ss, &kreloc->sym_addrs,
365 &kreloc->num_sym_addrs, sym_ptr);
366 kreloc->pcrel = howto->pc_relative;
367 if (howto->partial_inplace)
368 kreloc->addend = inplace;
369 else
370 kreloc->addend = orig_reloc->addend;
371 kreloc->size = bfd_get_reloc_size(howto);
372 kreloc->dst_mask = howto->dst_mask;
373 kreloc->rightshift = howto->rightshift;
376 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
378 bfd_vma blot_section(bfd *abfd, asection *sect, int offset,
379 reloc_howto_type *howto)
381 struct supersect *ss = fetch_supersect(abfd, sect, &isyms);
382 void *address = ss->contents.data + offset;
383 switch (howto->size) {
384 case 0:
386 int8_t x = bfd_get_8(abfd, address);
387 bfd_vma newx = CANARY(x, 0x77);
388 bfd_put_8(abfd, newx, address);
389 return x & howto->src_mask;
391 case 1:
393 int16_t x = bfd_get_16(abfd, address);
394 bfd_vma newx = CANARY(x, 0x7777);
395 bfd_put_16(abfd, newx, address);
396 return x & howto->src_mask;
398 case 2:
400 int32_t x = bfd_get_32(abfd, address);
401 bfd_vma newx = CANARY(x, 0x77777777);
402 bfd_put_32(abfd, newx, address);
403 return x & howto->src_mask;
405 case 4:
407 int64_t x = bfd_get_64(abfd, address);
408 bfd_vma newx = CANARY(x, 0x7777777777777777ll);
409 bfd_put_64(abfd, newx, address);
410 return x & howto->src_mask;
412 default:
413 fprintf(stderr, "ksplice: Unsupported howto->size %d\n",
414 howto->size);
415 DIE;
419 void write_ksplice_size(bfd *ibfd, asymbol **symp)
421 asymbol *sym = *symp;
423 /* We call bfd_print_symbol in order to get access to
424 * the size associated with the function symbol, which
425 * is not otherwise available through the BFD API
427 char *buf = NULL;
428 size_t bufsize = 0;
429 FILE *fp = open_memstream(&buf, &bufsize);
430 bfd_print_symbol(ibfd, fp, sym, bfd_print_symbol_all);
431 fclose(fp);
432 assert(buf != NULL);
434 unsigned long symsize;
435 char *symname;
436 int len;
437 assert(sscanf(buf, "%*[^\t]\t%lx %as%n", &symsize, &symname, &len) >=
439 assert(buf[len] == '\0');
440 assert(strcmp(symname, sym->name) == 0);
441 free(symname);
442 free(buf);
444 struct supersect *ksize_ss = make_section(ibfd, &isyms,
445 ".ksplice_sizes");
446 struct ksplice_size *ksize = sect_grow(ksize_ss, 1,
447 struct ksplice_size);
449 write_string(ibfd, ksize_ss, &ksize->name, "%s", sym->name);
450 ksize->size = symsize;
451 write_reloc(ibfd, ksize_ss, &ksize->thismod_addr, symp, 0);
452 write_system_map_array(ibfd, ksize_ss, &ksize->sym_addrs,
453 &ksize->num_sym_addrs, sym);
456 void write_ksplice_patch(bfd *ibfd, char *symname)
458 struct supersect *kpatch_ss = make_section(ibfd, &isyms,
459 ".ksplice_patches");
460 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
461 struct ksplice_patch);
463 char newname[256];
464 snprintf(newname, sizeof(newname), "%s%s%s",
465 symname, addstr_all, addstr_sect);
466 asymbol **symp;
467 for (symp = isyms.data; symp < isyms.data + isyms.size; symp++) {
468 if (strcmp((*symp)->name, newname) == 0)
469 break;
471 assert(symp < isyms.data + isyms.size);
473 write_string(ibfd, kpatch_ss, &kpatch->oldstr, "%s%s%s",
474 symname, addstr_all, addstr_sect_pre);
475 write_string(ibfd, kpatch_ss, &kpatch->replstr, "%s", newname);
476 kpatch->oldaddr = 0;
477 write_reloc(ibfd, kpatch_ss, &kpatch->repladdr, symp, 0);
478 kpatch->saved = NULL;
481 void rm_from_special(bfd *ibfd, struct specsect *s)
483 asection *isection = bfd_get_section_by_name(ibfd, s->sectname);
484 if (isection == NULL)
485 return;
487 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
488 struct void_vec orig_contents;
489 vec_move(&orig_contents, &ss->contents);
490 size_t pad = align(orig_contents.size, 1 << ss->alignment) -
491 orig_contents.size;
492 memset(vec_grow(&orig_contents, pad), 0, pad);
493 struct arelentp_vec orig_relocs;
494 vec_move(&orig_relocs, &ss->relocs);
496 int entry_size = align(s->entry_size, 1 << ss->alignment);
497 int relocs_per_entry = s->odd_relocs ? 2 : 1;
498 assert((orig_contents.size / entry_size) * relocs_per_entry ==
499 orig_relocs.size);
501 void *orig_entry;
502 arelent **relocp;
503 for (orig_entry = orig_contents.data, relocp = orig_relocs.data;
504 orig_entry < orig_contents.data + orig_contents.size;
505 orig_entry += entry_size, relocp += relocs_per_entry) {
506 asymbol *sym = *(*relocp)->sym_ptr_ptr;
507 if (s->odd_relocs) {
508 asymbol *odd_sym = *(*(relocp + 1))->sym_ptr_ptr;
509 assert(strcmp(odd_sym->name, s->odd_relocname) == 0);
511 asection *p;
512 for (p = ibfd->sections; p != NULL; p = p->next) {
513 if (strcmp(sym->name, p->name) == 0
514 && !is_special(p->name)
515 && !want_section(p->name, NULL))
516 break;
518 if (p != NULL)
519 continue;
521 void *new_entry = vec_grow(&ss->contents, entry_size);
522 memcpy(new_entry, orig_entry, entry_size);
523 int modifier = (new_entry - ss->contents.data) -
524 (orig_entry - orig_contents.data);
525 arelent **new_relocp = vec_grow(&ss->relocs, 1);
526 *new_relocp = *relocp;
527 (*new_relocp)->address += modifier;
528 if (s->odd_relocs) {
529 new_relocp = vec_grow(&ss->relocs, 1);
530 *new_relocp = *(relocp + 1);
531 (*new_relocp)->address += modifier;
536 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
538 if (want_section(sect->name, NULL))
539 return;
540 if (!starts_with(sect->name, ".text")
541 && !starts_with(sect->name, ".rodata"))
542 return;
544 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
547 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
548 void *looking_for)
550 if (!want_section(looking_at->name, NULL))
551 return;
553 struct supersect *ss = fetch_supersect(abfd, looking_at, &isyms);
554 arelent **relocp;
555 for (relocp = ss->relocs.data;
556 relocp != ss->relocs.data + ss->relocs.size; ++relocp) {
557 asymbol *sym = *(*relocp)->sym_ptr_ptr;
558 if (sym->section == (asection *)looking_for) {
559 struct wsect *w = malloc(sizeof(*w));
560 w->name = strdup(((asection *)looking_for)->name);
561 w->next = wanted_sections;
562 wanted_sections = w;
567 /* Modified function from GNU Binutils objcopy.c */
568 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
570 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
572 bfd_vma start = bfd_get_start_address(ibfd);
574 flagword flags = bfd_get_file_flags(ibfd);
575 flags &= bfd_applicable_file_flags(obfd);
577 assert(bfd_set_start_address(obfd, start)
578 && bfd_set_file_flags(obfd, flags));
580 enum bfd_architecture iarch = bfd_get_arch(ibfd);
581 unsigned int imach = bfd_get_mach(ibfd);
582 assert(bfd_set_arch_mach(obfd, iarch, imach));
583 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
585 /* BFD mandates that all output sections be created and sizes set before
586 any output is done. Thus, we traverse all sections multiple times. */
587 bfd_map_over_sections(ibfd, setup_section, obfd);
589 assert(bfd_count_sections(obfd));
591 struct supersect *ss;
592 for (ss = new_supersects; ss != NULL; ss = ss->next)
593 setup_new_section(obfd, ss);
595 /* Mark symbols used in output relocations so that they
596 are kept, even if they are local labels or static symbols.
598 Note we iterate over the input sections examining their
599 relocations since the relocations for the output sections
600 haven't been set yet. mark_symbols_used_in_relocations will
601 ignore input sections which have no corresponding output
602 section. */
604 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, &isyms);
605 for (ss = new_supersects; ss != NULL; ss = ss->next)
606 ss_mark_symbols_used_in_relocations(ss);
607 struct asymbolp_vec osyms;
608 vec_init(&osyms);
609 filter_symbols(ibfd, obfd, &osyms, &isyms);
611 bfd_set_symtab(obfd, osyms.data, osyms.size);
613 /* This has to happen after the symbol table has been set. */
614 bfd_map_over_sections(obfd, write_section, NULL);
616 /* Allow the BFD backend to copy any private data it understands
617 from the input BFD to the output BFD. This is done last to
618 permit the routine to look at the filtered symbol table, which is
619 important for the ECOFF code at least. */
620 assert(bfd_copy_private_bfd_data(ibfd, obfd));
622 return TRUE;
625 /* Modified function from GNU Binutils objcopy.c */
626 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
628 bfd *obfd = obfdarg;
629 bfd_vma vma;
631 char *name = strdup(isection->name);
632 if (!want_section(isection->name, &name))
633 return;
635 asection *osection = bfd_make_section_anyway(obfd, name);
636 assert(osection != NULL);
638 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
639 osection->userdata = ss;
640 bfd_set_section_flags(obfd, osection, ss->flags);
641 ss->symbol = osection->symbol;
642 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
644 vma = bfd_section_vma(ibfd, isection);
645 assert(bfd_set_section_vma(obfd, osection, vma));
647 osection->lma = isection->lma;
648 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
649 osection->entsize = isection->entsize;
650 osection->output_section = osection;
651 osection->output_offset = 0;
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;
671 osection->output_section = osection;
672 osection->output_offset = 0;
675 void write_section(bfd *obfd, asection *osection, void *arg)
677 struct supersect *ss = osection->userdata;
679 if (!want_section(ss->name, NULL) ||
680 (ss->flags & SEC_GROUP) != 0 ||
681 ss->contents.size == 0)
682 return;
684 arelent **relocp;
685 char *error_message;
686 for (relocp = ss->new_relocs.data;
687 relocp < ss->new_relocs.data + ss->new_relocs.size; ++relocp) {
688 bfd_put(bfd_get_reloc_size((*relocp)->howto) * 8, obfd, 0,
689 ss->contents.data + (*relocp)->address);
690 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
691 0, osection, &error_message) !=
692 bfd_reloc_ok) {
693 fprintf(stderr, "ksplice: error installing reloc: %s",
694 error_message);
695 DIE;
698 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
699 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
701 bfd_set_reloc(obfd, osection,
702 ss->relocs.size == 0 ? NULL : ss->relocs.data,
703 ss->relocs.size);
705 if (ss->flags & SEC_HAS_CONTENTS)
706 assert(bfd_set_section_contents
707 (obfd, osection, ss->contents.data, 0,
708 ss->contents.size));
711 /* Modified function from GNU Binutils objcopy.c
713 * Mark all the symbols which will be used in output relocations with
714 * the BSF_KEEP flag so that those symbols will not be stripped.
716 * Ignore relocations which will not appear in the output file.
718 void mark_symbols_used_in_relocations(bfd *ibfd, asection *isection,
719 void *symbolsarg)
721 if (isection->output_section == NULL)
722 return;
724 struct supersect *ss = fetch_supersect(ibfd, isection, &isyms);
725 ss_mark_symbols_used_in_relocations(ss);
728 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
730 /* Examine each symbol used in a relocation. If it's not one of the
731 special bfd section symbols, then mark it with BSF_KEEP. */
732 arelent **relocp;
733 for (relocp = ss->relocs.data;
734 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
735 asymbol *sym = *(*relocp)->sym_ptr_ptr;
736 if (sym != bfd_com_section_ptr->symbol
737 && sym != bfd_abs_section_ptr->symbol
738 && sym != bfd_und_section_ptr->symbol)
739 sym->flags |= BSF_KEEP;
743 /* Modified function from GNU Binutils objcopy.c
745 * Choose which symbol entries to copy.
746 * We don't copy in place, because that confuses the relocs.
747 * Return the number of symbols to print.
749 void filter_symbols(bfd *abfd, bfd *obfd, struct asymbolp_vec *osyms,
750 struct asymbolp_vec *isyms)
752 asymbol **symp;
753 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
754 asymbol *sym = *symp;
755 flagword flags = sym->flags;
757 if (mode("keep") && want_section(sym->section->name, NULL)) {
758 char *newname =
759 malloc(strlen(sym->name) + strlen(addstr_all) +
760 strlen(addstr_sect) + 1);
761 sprintf(newname, "%s%s%s", sym->name, addstr_all,
762 addstr_sect);
763 sym->name = newname;
766 int keep;
767 if ((flags & BSF_KEEP) != 0 /* Used in relocation. */
768 || ((flags & BSF_SECTION_SYM) != 0
769 && ((*(sym->section)->symbol_ptr_ptr)->flags
770 & BSF_KEEP) != 0))
771 keep = 1;
772 else if ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
773 keep = 1;
774 else if (bfd_decode_symclass(sym) == 'I')
775 /* Global symbols in $idata sections need to be retained.
776 External users of the library containing the $idata
777 section may reference these symbols. */
778 keep = 1;
779 else if ((flags & BSF_GLOBAL) != 0
780 || (flags & BSF_WEAK) != 0
781 || bfd_is_com_section(sym->section))
782 keep = 1;
783 else if ((flags & BSF_DEBUGGING) != 0)
784 keep = 1;
785 else
786 keep = !bfd_is_local_label(abfd, sym);
788 if (!want_section(sym->section->name, NULL))
789 keep = 0;
791 if (mode("rmsyms") && match_varargs(sym->name))
792 keep = 0;
794 if (keep)
795 *vec_grow(osyms, 1) = sym;
798 asection *p;
799 for (p = obfd->sections; mode("keep") && p != NULL; p = p->next) {
800 if (starts_with(p->name, ".rodata") &&
801 !exists_sym_with_name(isyms, p->name)) {
802 asymbol *new = bfd_make_empty_symbol(obfd);
803 new->name = p->name;
804 new->value = 0x0;
805 new->flags = BSF_GLOBAL;
806 new->section = p;
807 *vec_grow(osyms, 1) = new;
812 int exists_sym_with_name(struct asymbolp_vec *syms, const char *desired)
814 asymbol **symp;
815 for (symp = syms->data; symp < syms->data + syms->size; symp++) {
816 if (strcmp(bfd_asymbol_name(*symp), desired) == 0)
817 return 1;
819 return 0;
822 int match_varargs(const char *str)
824 int i;
825 for (i = 0; i < varargs_count; i++) {
826 if (strcmp(str, varargs[i]) == 0)
827 return 1;
829 return 0;
832 int want_section(const char *name, char **newname)
834 static const char *static_want[] = {
835 ".altinstructions",
836 ".altinstr_replacement",
837 ".smp_locks",
838 ".parainstructions",
839 NULL
842 if (!mode("keep"))
843 return 1;
845 struct wsect *w = wanted_sections;
846 for (; w != NULL; w = w->next) {
847 if (strcmp(w->name, name) == 0)
848 goto success;
851 if (starts_with(name, ".ksplice"))
852 goto success;
853 if (mode("keep-helper") && starts_with(name, ".text"))
854 goto success;
855 if (match_varargs(name))
856 goto success;
858 int i;
859 for (i = 0; static_want[i] != NULL; i++) {
860 if (strcmp(name, static_want[i]) == 0)
861 return 1;
863 return 0;
865 success:
867 if (newname != NULL) {
868 *newname =
869 malloc(strlen(name) + strlen(addstr_all) +
870 strlen(addstr_sect) + 1);
871 sprintf(*newname, "%s%s%s", name, addstr_all, addstr_sect);
873 return 1;
876 struct specsect *is_special(const char *name)
878 struct specsect *ss;
879 for (ss = special_sections; ss != end_special_sections; ss++) {
880 if (strcmp(ss->sectname, name) == 0)
881 return ss;
883 return NULL;