Add supersect_move function.
[ksplice.git] / objmanip.c
blobc3fd9ab57d3b2af13c8ee0c3a42634f55fabc5ba
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 "kmodsrc/ksplice.h"
100 #include <stdint.h>
101 #include <stdarg.h>
102 #include <stdlib.h>
103 #include <stdio.h>
104 #include <limits.h>
106 struct wsect {
107 const char *name;
108 struct wsect *next;
111 struct specsect {
112 const char *sectname;
113 unsigned char odd_relocs;
114 const char *odd_relocname;
115 int entry_size;
118 void rm_some_relocs(struct supersect *ss);
119 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc);
120 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto);
121 void write_ksplice_size(struct superbfd *sbfd, asymbol **symp);
122 void write_ksplice_patch(struct superbfd *sbfd, const char *symname);
123 void rm_from_special(struct superbfd *sbfd, const struct specsect *s);
124 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored);
125 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
126 void *looking_for);
127 bfd_boolean copy_object(bfd *ibfd, bfd *obfd);
128 void setup_section(bfd *ibfd, asection *isection, void *obfdarg);
129 static void setup_new_section(bfd *obfd, struct supersect *ss);
130 static void write_section(bfd *obfd, asection *osection, void *arg);
131 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
132 void *ignored);
133 static void ss_mark_symbols_used_in_relocations(struct supersect *ss);
134 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
135 struct asymbolp_vec *isyms);
136 int match_varargs(const char *str);
137 int want_section(asection *sect);
138 const struct specsect *is_special(asection *sect);
139 struct supersect *make_section(struct superbfd *sbfd, const char *name);
140 void __attribute__((format(printf, 3, 4)))
141 write_string(struct supersect *ss, const char **addr, const char *fmt, ...);
142 void rm_some_exports(struct supersect *ss, struct supersect *crc_ss);
143 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
144 const char *export_type);
146 char **varargs;
147 int varargs_count;
148 const char *modestr, *addstr_all = "", *addstr_sect_pre = "", *addstr_sect = "";
150 struct wsect *wanted_sections = NULL;
152 const struct specsect special_sections[] = {
153 {".altinstructions", 1, ".altinstr_replacement",
154 2 * sizeof(void *) + 4},
155 {".smp_locks", 0, NULL, sizeof(void *)},
156 {".parainstructions", 0, NULL, sizeof(void *) + 4},
157 }, *const end_special_sections = *(&special_sections + 1);
159 #define mode(str) starts_with(modestr, str)
161 DECLARE_VEC_TYPE(unsigned long, addr_vec);
162 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
163 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
164 vec_init);
165 struct addr_vec_hash system_map;
167 void load_system_map()
169 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
170 assert(config_dir);
171 char *file;
172 assert(asprintf(&file, "%s/System.map", config_dir) >= 0);
173 FILE *fp = fopen(file, "r");
174 assert(fp);
175 addr_vec_hash_init(&system_map);
176 unsigned long addr;
177 char type;
178 char *sym;
179 while (fscanf(fp, "%lx %c %as\n", &addr, &type, &sym) == 3)
180 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
181 1) = addr;
182 fclose(fp);
185 int main(int argc, char *argv[])
187 char *export_name;
188 char *debug_name;
189 assert(asprintf(&debug_name, "%s.pre%s", argv[1], argv[2]) >= 0);
190 rename(argv[1], debug_name);
192 bfd_init();
193 bfd *ibfd = bfd_openr(debug_name, NULL);
194 assert(ibfd);
196 char **matching;
197 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
199 const char *output_target = bfd_get_target(ibfd);
200 bfd *obfd = bfd_openw(argv[1], output_target);
201 assert(obfd);
203 struct superbfd *isbfd = fetch_superbfd(ibfd);
205 modestr = argv[2];
206 if (mode("keep") || mode("sizelist")) {
207 addstr_all = argv[3];
208 addstr_sect = argv[4];
209 varargs = &argv[5];
210 varargs_count = argc - 5;
211 } else if (mode("patchlist")) {
212 addstr_all = argv[3];
213 addstr_sect_pre = argv[4];
214 addstr_sect = argv[5];
215 varargs = &argv[6];
216 varargs_count = argc - 6;
217 } else if (mode("export")) {
218 addstr_all = argv[3];
219 export_name = argv[4];
220 varargs = &argv[5];
221 varargs_count = argc - 5;
222 } else {
223 varargs = &argv[3];
224 varargs_count = argc - 3;
227 if (mode("keep") || mode("sizelist") || mode("rmsyms"))
228 load_system_map();
230 if (mode("keep")) {
231 while (1) {
232 const struct wsect *tmp = wanted_sections;
233 bfd_map_over_sections(ibfd, mark_wanted_if_referenced,
234 NULL);
235 if (tmp == wanted_sections)
236 break;
240 asymbol **symp;
241 for (symp = isbfd->syms.data;
242 mode("sizelist") && symp < isbfd->syms.data + isbfd->syms.size;
243 symp++) {
244 asymbol *sym = *symp;
245 if ((sym->flags & BSF_FUNCTION)
246 && sym->value == 0 && !(sym->flags & BSF_WEAK))
247 write_ksplice_size(isbfd, symp);
250 if (mode("patchlist")) {
251 char **symname;
252 for (symname = varargs; symname < varargs + varargs_count;
253 symname++)
254 write_ksplice_patch(isbfd, *symname);
257 asection *p;
258 for (p = ibfd->sections; p != NULL; p = p->next) {
259 struct supersect *ss = fetch_supersect(isbfd, p);
260 if (is_special(p) || starts_with(p->name, ".ksplice"))
261 continue;
262 if (want_section(p) || mode("rmsyms"))
263 rm_some_relocs(ss);
266 const struct specsect *ss;
267 if (mode("keep")) {
268 for (ss = special_sections; ss != end_special_sections; ss++)
269 rm_from_special(isbfd, ss);
272 if (mode("exportdel")) {
273 char **symname;
274 assert(mode("exportdel___ksymtab"));
275 for (symname = varargs; symname < varargs + varargs_count;
276 symname++)
277 write_ksplice_export(isbfd, *symname,
278 modestr +
279 strlen("exportdel___ksymtab"));
280 } else if (mode("export")) {
281 assert(starts_with(export_name, "__ksymtab"));
282 asection *sym_sect = bfd_get_section_by_name(ibfd, export_name);
283 assert(sym_sect != NULL);
284 char *export_crc_name;
285 assert(asprintf(&export_crc_name, "__kcrctab%s", export_name +
286 strlen("__ksymtab")) >= 0);
287 asection *crc_sect = bfd_get_section_by_name(ibfd,
288 export_crc_name);
289 struct supersect *sym_ss, *crc_ss = NULL;
290 sym_ss = fetch_supersect(isbfd, sym_sect);
291 if (crc_sect != NULL)
292 crc_ss = fetch_supersect(isbfd, crc_sect);
293 rm_some_exports(sym_ss, crc_ss);
296 copy_object(ibfd, obfd);
297 assert(bfd_close(obfd));
298 assert(bfd_close(ibfd));
299 return EXIT_SUCCESS;
302 void rm_some_exports(struct supersect *ss, struct supersect *crc_ss)
304 struct void_vec orig_contents;
305 struct arelentp_vec orig_relocs;
306 vec_move(&orig_contents, &ss->contents);
307 vec_move(&orig_relocs, &ss->relocs);
309 struct void_vec orig_crc_contents;
310 struct arelentp_vec orig_crc_relocs;
311 if (crc_ss != NULL) {
312 vec_move(&orig_crc_contents, &crc_ss->contents);
313 vec_move(&orig_crc_relocs, &crc_ss->relocs);
315 void *orig_entry, *new_entry, *orig_crc_entry, *new_crc_entry;
316 arelent **relocp, **new_relocp, **crc_relocp, **new_crc_relocp;
317 long mod, crc_mod;
318 int entry_size = sizeof(struct kernel_symbol);
319 int crc_entry_size = sizeof(unsigned long);
320 int relocs_per_entry = 2;
321 int crc_relocs_per_entry = 1;
322 assert(orig_contents.size * relocs_per_entry ==
323 orig_relocs.size * entry_size);
324 if (crc_ss != NULL) {
325 assert(orig_contents.size * crc_entry_size ==
326 orig_crc_contents.size * entry_size);
327 assert(orig_crc_contents.size * crc_relocs_per_entry ==
328 orig_crc_relocs.size * crc_entry_size);
330 for (orig_entry = orig_contents.data, relocp = orig_relocs.data,
331 orig_crc_entry = orig_crc_contents.data,
332 crc_relocp = orig_crc_relocs.data;
333 orig_entry < orig_contents.data + orig_contents.size;
334 orig_entry += entry_size, relocp += relocs_per_entry,
335 orig_crc_entry += crc_entry_size,
336 crc_relocp += crc_relocs_per_entry) {
337 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
338 if (match_varargs(sym_ptr->name)) {
339 new_entry = vec_grow(&ss->contents, entry_size);
340 memcpy(new_entry, orig_entry, entry_size);
341 struct kernel_symbol *sym =
342 (struct kernel_symbol *)new_entry;
343 mod = ((new_entry - ss->contents.data) -
344 (orig_entry - orig_contents.data));
345 new_relocp = vec_grow(&ss->relocs, 1);
346 *new_relocp = *relocp;
347 (*new_relocp)->address += mod;
348 /* Replace name with a mangled name */
349 write_ksplice_export(ss->parent, sym_ptr->name, modestr
350 + strlen("export__ksymtab"));
351 write_string(ss, (const char **)&sym->name,
352 "DISABLED_%s_%s", sym_ptr->name,
353 addstr_all);
355 if (crc_ss != NULL) {
356 new_crc_entry = vec_grow(&crc_ss->contents,
357 crc_entry_size);
358 memcpy(new_crc_entry, orig_crc_entry,
359 crc_entry_size);
360 crc_mod = ((new_crc_entry -
361 crc_ss->contents.data) -
362 (orig_crc_entry -
363 orig_crc_contents.data));
364 new_crc_relocp = vec_grow(&crc_ss->relocs,
365 crc_relocs_per_entry);
366 *new_crc_relocp = *crc_relocp;
367 (*new_crc_relocp)->address += crc_mod;
373 void rm_some_relocs(struct supersect *ss)
375 struct arelentp_vec orig_relocs;
376 vec_move(&orig_relocs, &ss->relocs);
378 arelent **relocp;
379 for (relocp = orig_relocs.data;
380 relocp < orig_relocs.data + orig_relocs.size; relocp++) {
381 int rm_reloc = 0;
382 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
384 if (mode("rmsyms") && match_varargs(sym_ptr->name))
385 rm_reloc = 1;
387 if (mode("keep"))
388 rm_reloc = 1;
390 if (mode("keep-primary") && want_section(sym_ptr->section))
391 rm_reloc = 0;
393 if (rm_reloc)
394 write_ksplice_reloc(ss, *relocp);
395 else
396 *vec_grow(&ss->relocs, 1) = *relocp;
400 struct supersect *make_section(struct superbfd *sbfd, const char *name)
402 asection *sect = bfd_get_section_by_name(sbfd->abfd, name);
403 if (sect != NULL)
404 return fetch_supersect(sbfd, sect);
405 else
406 return new_supersect(sbfd, name);
409 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
410 bfd_vma offset)
412 bfd_reloc_code_real_type code;
413 switch (bfd_arch_bits_per_address(ss->parent->abfd)) {
414 case 32:
415 code = BFD_RELOC_32;
416 break;
417 case 64:
418 code = BFD_RELOC_64;
419 break;
420 default:
421 DIE;
424 arelent *reloc = malloc(sizeof(*reloc));
425 reloc->sym_ptr_ptr = symp;
426 reloc->address = addr - ss->contents.data;
427 reloc->howto = bfd_reloc_type_lookup(ss->parent->abfd, code);
428 reloc->addend = offset;
429 *vec_grow(&ss->new_relocs, 1) = reloc;
432 void write_string(struct supersect *ss, const char **addr, const char *fmt, ...)
434 va_list ap;
435 va_start(ap, fmt);
436 int len = vsnprintf(NULL, 0, fmt, ap);
437 va_end(ap);
438 struct supersect *str_ss = make_section(ss->parent, ".ksplice_str");
439 char *buf = sect_grow(str_ss, len + 1, char);
440 va_start(ap, fmt);
441 vsnprintf(buf, len + 1, fmt, ap);
442 va_end(ap);
444 write_reloc(ss, addr, &str_ss->symbol,
445 (void *)buf - str_ss->contents.data);
448 void write_system_map_array(struct superbfd *sbfd, struct supersect *ss,
449 const unsigned long **sym_addrs,
450 unsigned long *num_sym_addrs, asymbol *sym)
452 const char *system_map_name = sym->name;
453 const char **prefix;
454 for (prefix = (const char *[]){".text.", ".data.", ".bss.", NULL};
455 *prefix != NULL; prefix++) {
456 if (starts_with(system_map_name, *prefix))
457 system_map_name += strlen(*prefix);
459 struct addr_vec *addrs = addr_vec_hash_lookup(&system_map,
460 system_map_name, FALSE);
461 if (addrs != NULL) {
462 struct supersect *array_ss = make_section(sbfd,
463 ".ksplice_array");
464 void *buf = sect_grow(array_ss, addrs->size,
465 typeof(*addrs->data));
466 memcpy(buf, addrs->data, addrs->size * sizeof(*addrs->data));
467 *num_sym_addrs = addrs->size;
468 write_reloc(ss, sym_addrs, &array_ss->symbol,
469 buf - array_ss->contents.data);
470 } else {
471 *num_sym_addrs = 0;
472 *sym_addrs = NULL;
476 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc)
478 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
480 reloc_howto_type *howto = orig_reloc->howto;
482 bfd_vma addend = get_reloc_offset(ss, orig_reloc, 0);
483 blot_section(ss, orig_reloc->address, howto);
485 struct supersect *kreloc_ss = make_section(ss->parent,
486 mode("rmsyms") ?
487 ".ksplice_init_relocs" :
488 ".ksplice_relocs");
489 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
490 struct ksplice_reloc);
492 write_string(kreloc_ss, &kreloc->sym_name, "%s%s",
493 sym_ptr->name, addstr_all);
494 write_reloc(kreloc_ss, &kreloc->blank_addr,
495 &ss->symbol, orig_reloc->address);
496 kreloc->blank_offset = (unsigned long)orig_reloc->address;
497 write_system_map_array(ss->parent, kreloc_ss, &kreloc->sym_addrs,
498 &kreloc->num_sym_addrs, sym_ptr);
499 kreloc->pcrel = howto->pc_relative;
500 kreloc->addend = addend;
501 kreloc->size = bfd_get_reloc_size(howto);
502 kreloc->dst_mask = howto->dst_mask;
503 kreloc->rightshift = howto->rightshift;
506 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
508 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto)
510 int bits = bfd_get_reloc_size(howto) * 8;
511 void *address = ss->contents.data + offset;
512 bfd_vma x = bfd_get(bits, ss->parent->abfd, address);
513 x = (x & ~howto->dst_mask) |
514 ((bfd_vma)0x7777777777777777LL & howto->dst_mask);
515 bfd_put(bits, ss->parent->abfd, x, address);
518 void write_ksplice_size(struct superbfd *sbfd, asymbol **symp)
520 asymbol *sym = *symp;
522 /* We call bfd_print_symbol in order to get access to
523 * the size associated with the function symbol, which
524 * is not otherwise available through the BFD API
526 char *buf = NULL;
527 size_t bufsize = 0;
528 FILE *fp = open_memstream(&buf, &bufsize);
529 bfd_print_symbol(sbfd->abfd, fp, sym, bfd_print_symbol_all);
530 fclose(fp);
531 assert(buf != NULL);
533 unsigned long symsize;
534 char *symname;
535 int len;
536 assert(sscanf(buf, "%*[^\t]\t%lx %as%n", &symsize, &symname, &len) >=
538 assert(buf[len] == '\0');
539 assert(strcmp(symname, sym->name) == 0);
540 free(symname);
541 free(buf);
543 struct supersect *ksize_ss = make_section(sbfd, ".ksplice_sizes");
544 struct ksplice_size *ksize = sect_grow(ksize_ss, 1,
545 struct ksplice_size);
547 write_string(ksize_ss, &ksize->name, "%s%s%s",
548 sym->name, addstr_all, addstr_sect);
549 ksize->size = symsize;
550 ksize->flags = 0;
551 if (match_varargs(sym->name) && (sym->flags & BSF_FUNCTION))
552 ksize->flags |= KSPLICE_SIZE_DELETED;
553 write_reloc(ksize_ss, &ksize->thismod_addr, symp, 0);
554 write_system_map_array(sbfd, ksize_ss, &ksize->sym_addrs,
555 &ksize->num_sym_addrs, sym);
558 void write_ksplice_patch(struct superbfd *sbfd, const char *symname)
560 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
561 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
562 struct ksplice_patch);
564 asymbol **symp;
565 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
566 symp++) {
567 if (strcmp((*symp)->name, symname) == 0)
568 break;
570 assert(symp < sbfd->syms.data + sbfd->syms.size);
572 write_string(kpatch_ss, &kpatch->oldstr, "%s%s%s",
573 symname, addstr_all, addstr_sect_pre);
574 kpatch->oldaddr = 0;
575 write_reloc(kpatch_ss, &kpatch->repladdr, symp, 0);
578 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
579 const char *export_type)
581 struct supersect *export_ss = make_section(sbfd, ".ksplice_exports");
582 struct ksplice_export *export = sect_grow(export_ss, 1,
583 struct ksplice_export);
585 write_string(export_ss, &export->type, "%s", export_type);
586 if (mode("exportdel")) {
587 write_string(export_ss, &export->name, "%s", symname);
588 write_string(export_ss, &export->new_name,
589 "DISABLED_%s_%s", symname, addstr_all);
590 } else {
591 write_string(export_ss, &export->new_name, "%s", symname);
592 write_string(export_ss, &export->name, "DISABLED_%s_%s",
593 symname, addstr_all);
597 void rm_from_special(struct superbfd *sbfd, const struct specsect *s)
599 asection *isection = bfd_get_section_by_name(sbfd->abfd, s->sectname);
600 if (isection == NULL)
601 return;
603 struct supersect *ss = fetch_supersect(sbfd, isection);
604 struct void_vec orig_contents;
605 vec_move(&orig_contents, &ss->contents);
606 size_t pad = align(orig_contents.size, 1 << ss->alignment) -
607 orig_contents.size;
608 memset(vec_grow(&orig_contents, pad), 0, pad);
609 struct arelentp_vec orig_relocs;
610 vec_move(&orig_relocs, &ss->relocs);
612 int entry_size = align(s->entry_size, 1 << ss->alignment);
613 int relocs_per_entry = s->odd_relocs ? 2 : 1;
614 assert(orig_contents.size * relocs_per_entry ==
615 orig_relocs.size * entry_size);
617 const void *orig_entry;
618 arelent **relocp;
619 for (orig_entry = orig_contents.data, relocp = orig_relocs.data;
620 orig_entry < orig_contents.data + orig_contents.size;
621 orig_entry += entry_size, relocp += relocs_per_entry) {
622 asymbol *sym = *(*relocp)->sym_ptr_ptr;
623 if (s->odd_relocs) {
624 asymbol *odd_sym = *(*(relocp + 1))->sym_ptr_ptr;
625 assert(strcmp(odd_sym->name, s->odd_relocname) == 0);
627 asection *p;
628 for (p = sbfd->abfd->sections; p != NULL; p = p->next) {
629 if (strcmp(sym->name, p->name) == 0
630 && !is_special(p) && !want_section(p))
631 break;
633 if (p != NULL)
634 continue;
636 void *new_entry = vec_grow(&ss->contents, entry_size);
637 memcpy(new_entry, orig_entry, entry_size);
638 int modifier = (new_entry - ss->contents.data) -
639 (orig_entry - orig_contents.data);
640 arelent **new_relocp = vec_grow(&ss->relocs, 1);
641 *new_relocp = *relocp;
642 (*new_relocp)->address += modifier;
643 if (s->odd_relocs) {
644 new_relocp = vec_grow(&ss->relocs, 1);
645 *new_relocp = *(relocp + 1);
646 (*new_relocp)->address += modifier;
651 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
653 if (want_section(sect))
654 return;
655 if (!starts_with(sect->name, ".text")
656 && !starts_with(sect->name, ".rodata"))
657 return;
659 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
662 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
663 void *looking_for)
665 if (!want_section(looking_at) || is_special(looking_at))
666 return;
668 struct superbfd *sbfd = fetch_superbfd(abfd);
669 struct supersect *ss = fetch_supersect(sbfd, looking_at);
670 arelent **relocp;
671 for (relocp = ss->relocs.data;
672 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
673 asymbol *sym = *(*relocp)->sym_ptr_ptr;
674 if (sym->section == (asection *)looking_for &&
675 (!starts_with(sym->section->name, ".text") ||
676 get_reloc_offset(ss, *relocp, 1) != 0)) {
677 struct wsect *w = malloc(sizeof(*w));
678 w->name = ((asection *)looking_for)->name;
679 w->next = wanted_sections;
680 wanted_sections = w;
681 break;
686 /* Modified function from GNU Binutils objcopy.c */
687 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
689 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
691 bfd_vma start = bfd_get_start_address(ibfd);
693 flagword flags = bfd_get_file_flags(ibfd);
694 flags &= bfd_applicable_file_flags(obfd);
696 assert(bfd_set_start_address(obfd, start)
697 && bfd_set_file_flags(obfd, flags));
699 enum bfd_architecture iarch = bfd_get_arch(ibfd);
700 unsigned int imach = bfd_get_mach(ibfd);
701 assert(bfd_set_arch_mach(obfd, iarch, imach));
702 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
704 /* BFD mandates that all output sections be created and sizes set before
705 any output is done. Thus, we traverse all sections multiple times. */
706 bfd_map_over_sections(ibfd, setup_section, obfd);
708 struct supersect *ss;
709 for (ss = new_supersects; ss != NULL; ss = ss->next)
710 setup_new_section(obfd, ss);
712 /* Mark symbols used in output relocations so that they
713 are kept, even if they are local labels or static symbols.
715 Note we iterate over the input sections examining their
716 relocations since the relocations for the output sections
717 haven't been set yet. mark_symbols_used_in_relocations will
718 ignore input sections which have no corresponding output
719 section. */
721 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, NULL);
722 for (ss = new_supersects; ss != NULL; ss = ss->next)
723 ss_mark_symbols_used_in_relocations(ss);
724 struct asymbolp_vec osyms;
725 vec_init(&osyms);
726 filter_symbols(ibfd, obfd, &osyms, &fetch_superbfd(ibfd)->syms);
728 bfd_set_symtab(obfd, osyms.data, osyms.size);
730 /* This has to happen after the symbol table has been set. */
731 bfd_map_over_sections(obfd, write_section, NULL);
733 /* Allow the BFD backend to copy any private data it understands
734 from the input BFD to the output BFD. This is done last to
735 permit the routine to look at the filtered symbol table, which is
736 important for the ECOFF code at least. */
737 assert(bfd_copy_private_bfd_data(ibfd, obfd));
739 return TRUE;
742 /* Modified function from GNU Binutils objcopy.c */
743 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
745 bfd *obfd = obfdarg;
746 bfd_vma vma;
748 if (!want_section(isection))
749 return;
751 asection *osection = bfd_make_section_anyway(obfd, isection->name);
752 assert(osection != NULL);
754 struct superbfd *isbfd = fetch_superbfd(ibfd);
755 struct supersect *ss = fetch_supersect(isbfd, isection);
756 osection->userdata = ss;
757 bfd_set_section_flags(obfd, osection, ss->flags);
758 ss->symbol = osection->symbol;
759 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
761 vma = bfd_section_vma(ibfd, isection);
762 assert(bfd_set_section_vma(obfd, osection, vma));
764 osection->lma = isection->lma;
765 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
766 osection->entsize = isection->entsize;
767 osection->output_section = osection;
768 osection->output_offset = 0;
769 isection->output_section = osection;
770 isection->output_offset = 0;
771 return;
774 void setup_new_section(bfd *obfd, struct supersect *ss)
776 asection *osection = bfd_make_section_anyway(obfd, ss->name);
777 assert(osection != NULL);
778 bfd_set_section_flags(obfd, osection, ss->flags);
780 osection->userdata = ss;
781 ss->symbol = osection->symbol;
782 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
783 assert(bfd_set_section_vma(obfd, osection, 0));
785 osection->lma = 0;
786 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
787 osection->entsize = 0;
788 osection->output_section = osection;
789 osection->output_offset = 0;
792 void write_section(bfd *obfd, asection *osection, void *arg)
794 struct supersect *ss = osection->userdata;
796 if (!want_section(osection) || (ss->flags & SEC_GROUP) != 0 ||
797 ss->contents.size == 0)
798 return;
800 arelent **relocp;
801 char *error_message;
802 for (relocp = ss->new_relocs.data;
803 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
804 bfd_put(bfd_get_reloc_size((*relocp)->howto) * 8, obfd, 0,
805 ss->contents.data + (*relocp)->address);
806 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
807 0, osection, &error_message) !=
808 bfd_reloc_ok) {
809 fprintf(stderr, "ksplice: error installing reloc: %s",
810 error_message);
811 DIE;
814 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
815 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
817 bfd_set_reloc(obfd, osection,
818 ss->relocs.size == 0 ? NULL : ss->relocs.data,
819 ss->relocs.size);
821 if (ss->flags & SEC_HAS_CONTENTS)
822 assert(bfd_set_section_contents
823 (obfd, osection, ss->contents.data, 0,
824 ss->contents.size));
827 /* Modified function from GNU Binutils objcopy.c
829 * Mark all the symbols which will be used in output relocations with
830 * the BSF_KEEP flag so that those symbols will not be stripped.
832 * Ignore relocations which will not appear in the output file.
834 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
835 void *ignored)
837 struct superbfd *sbfd = fetch_superbfd(abfd);
838 if (isection->output_section == NULL)
839 return;
841 struct supersect *ss = fetch_supersect(sbfd, isection);
842 ss_mark_symbols_used_in_relocations(ss);
845 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
847 /* Examine each symbol used in a relocation. If it's not one of the
848 special bfd section symbols, then mark it with BSF_KEEP. */
849 arelent **relocp;
850 for (relocp = ss->relocs.data;
851 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
852 asymbol *sym = *(*relocp)->sym_ptr_ptr;
853 if (!(bfd_is_const_section(sym->section) &&
854 sym == sym->section->symbol))
855 sym->flags |= BSF_KEEP;
859 /* Modified function from GNU Binutils objcopy.c
861 * Choose which symbol entries to copy.
862 * We don't copy in place, because that confuses the relocs.
863 * Return the number of symbols to print.
865 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
866 struct asymbolp_vec *isyms)
868 asymbol **symp;
869 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
870 asymbol *sym = *symp;
872 int keep;
874 if (mode("keep") && (sym->flags & BSF_GLOBAL) != 0)
875 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
877 if (mode("globalize-new") && match_varargs(sym->name))
878 sym->flags = (sym->flags & ~BSF_LOCAL) | BSF_GLOBAL;
880 if ((sym->flags & BSF_KEEP) != 0 /* Used in relocation. */
881 || ((sym->flags & BSF_SECTION_SYM) != 0
882 && ((*(sym->section)->symbol_ptr_ptr)->flags
883 & BSF_KEEP) != 0))
884 keep = 1;
885 else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
886 keep = 1;
887 else if (bfd_decode_symclass(sym) == 'I')
888 /* Global symbols in $idata sections need to be retained.
889 External users of the library containing the $idata
890 section may reference these symbols. */
891 keep = 1;
892 else if ((sym->flags & BSF_GLOBAL) != 0
893 || (sym->flags & BSF_WEAK) != 0
894 || bfd_is_com_section(sym->section))
895 keep = 1;
896 else if ((sym->flags & BSF_DEBUGGING) != 0)
897 keep = 1;
898 else
899 keep = !bfd_is_local_label(ibfd, sym);
901 if (!want_section(sym->section))
902 keep = 0;
904 if (mode("rmsyms") && match_varargs(sym->name))
905 keep = 0;
907 if (keep)
908 *vec_grow(osyms, 1) = sym;
912 int match_varargs(const char *str)
914 int i;
915 for (i = 0; i < varargs_count; i++) {
916 if (strcmp(str, varargs[i]) == 0)
917 return 1;
919 return 0;
922 int want_section(asection *sect)
924 static const char *static_want[] = {
925 ".altinstructions",
926 ".altinstr_replacement",
927 ".smp_locks",
928 ".parainstructions",
929 NULL
931 const char *name = sect->name;
933 if (!mode("keep"))
934 return 1;
936 if (mode("keep-primary") && bfd_is_abs_section(sect))
937 return 1;
938 const struct wsect *w = wanted_sections;
939 for (; w != NULL; w = w->next) {
940 if (strcmp(w->name, name) == 0)
941 return 1;
944 if (starts_with(name, ".ksplice"))
945 return 1;
946 if (mode("keep-helper") && starts_with(name, ".text"))
947 return 1;
948 if (mode("keep-primary") && starts_with(name, "__ksymtab"))
949 return 1;
950 if (mode("keep-primary") && starts_with(name, "__kcrctab"))
951 return 1;
952 if (match_varargs(name))
953 return 1;
955 int i;
956 for (i = 0; static_want[i] != NULL; i++) {
957 if (strcmp(name, static_want[i]) == 0)
958 return 1;
960 return 0;
963 const struct specsect *is_special(asection *sect)
965 const struct specsect *ss;
966 for (ss = special_sections; ss != end_special_sections; ss++) {
967 if (strcmp(ss->sectname, sect->name) == 0)
968 return ss;
970 return NULL;