Remove now-unused label_map parsing code.
[ksplice.git] / objmanip.c
blob320f6a90d00ec54a233ab74621bfe072c8e6c4cb
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) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
5 * Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
6 * Tim Abbott <tabbott@mit.edu>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License, version 2.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 * 02110-1301, USA.
22 /* objmanip performs various object file manipulations for Ksplice. Its first
23 * two arguments are always an input object file and an output object file.
25 * - keep-primary: "objmanip <post.o> <out.o> keep-primary <pre.o> <kid>"
27 * This mode prepares the object file to be installed as a ksplice update. The
28 * kid argument is the ksplice id string for the ksplice update being built.
30 * - keep-helper: "objmanip <pre.o> <out.o> keep-helper"
32 * This mode prepares the object file to be used for run-pre matching. This
33 * involves replacing all ELF relocations with ksplice relocations and
34 * writing ksplice_section structures for each ELF text or data section.
36 * - rmsyms mode: "objmanip <in.o> <out.o> rmsyms
38 * In this mode, any ELF relocations involving the list of symbol names given on
39 * standard input are replaced with ksplice relocations. This is used only
40 * for KSPLICE_STANDALONE.
42 * - finalize mode: "objmanip <in.o> <out.o> finalize"
44 * In this mode, any ELF relocations to undefined symbols are replaced with
45 * ksplice relocations.
48 /* Always define KSPLICE_STANDALONE, even if you're using integrated Ksplice.
49 objmanip won't compile without it. */
50 #define KSPLICE_STANDALONE
52 #define _GNU_SOURCE
53 #include "objcommon.h"
54 #include "kmodsrc/ksplice.h"
55 #include <stdint.h>
56 #include <stdarg.h>
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <limits.h>
61 #define symbol_init(sym) *(sym) = (asymbol *)NULL
62 DEFINE_HASH_TYPE(asymbol *, symbol_hash, symbol_hash_init, symbol_hash_free,
63 symbol_hash_lookup, symbol_init);
65 struct export {
66 const char *name;
67 asection *sect;
69 DECLARE_VEC_TYPE(struct export, export_vec);
71 DECLARE_VEC_TYPE(const char *, str_vec);
73 struct wsect {
74 asection *sect;
75 struct wsect *next;
78 struct table_section {
79 const char *sectname;
80 int entry_size;
83 struct export_desc {
84 const char *sectname;
85 struct str_vec names;
87 DECLARE_VEC_TYPE(struct export_desc, export_desc_vec);
89 #define bool_init(b) *(b) = false
90 DEFINE_HASH_TYPE(bool, bool_hash, bool_hash_init, bool_hash_free,
91 bool_hash_lookup, bool_init);
93 #define ulong_init(x) *(x) = 0
94 DEFINE_HASH_TYPE(unsigned long, ulong_hash, ulong_hash_init,
95 ulong_hash_free, ulong_hash_lookup, ulong_init);
97 void foreach_nonmatching(struct superbfd *oldsbfd, struct superbfd *newsbfd,
98 void (*s_fn)(struct superbfd *, asection *));
99 void foreach_new_section(struct superbfd *oldsbfd, struct superbfd *newsbfd,
100 void (*s_fn)(struct superbfd *, asection *));
101 void print_changed_section(struct superbfd *sbfd, asection *sect);
102 void print_new_section(struct superbfd *sbfd, asection *sect);
103 void print_deleted_section(struct superbfd *sbfd, asection *sect);
104 struct export_vec *get_export_syms(struct superbfd *sbfd);
105 void compare_exported_symbols(struct superbfd *oldsbfd,
106 struct superbfd *newsbfd, char *addstr);
107 bool relocs_equal(struct superbfd *oldsbfd, asection *oldp,
108 struct superbfd *newsbfd, asection *newp);
109 static void handle_section_symbol_renames(struct superbfd *oldsbfd,
110 struct superbfd *newsbfd);
112 void rm_some_relocs(struct supersect *ss);
113 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc);
114 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto);
115 void write_ksplice_section(struct superbfd *sbfd, asymbol **symp);
116 void write_ksplice_patch(struct superbfd *sbfd, const char *sectname);
117 void write_ksplice_deleted_patch(struct superbfd *sbfd, const char *label);
118 void filter_table_section(struct superbfd *sbfd, const struct table_section *s);
119 void filter_ex_table_section(struct superbfd *sbfd);
120 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored);
121 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
122 void *looking_for);
123 bfd_boolean copy_object(bfd *ibfd, bfd *obfd);
124 void setup_section(bfd *ibfd, asection *isection, void *obfdarg);
125 static void setup_new_section(bfd *obfd, struct supersect *ss);
126 static void write_section(bfd *obfd, asection *osection, void *arg);
127 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
128 void *ignored);
129 static void ss_mark_symbols_used_in_relocations(struct supersect *ss);
130 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
131 struct asymbolp_vec *isyms);
132 static bool deleted_table_section_symbol(bfd *abfd, asymbol *sym);
133 void read_str_set(struct str_vec *strs);
134 bool str_in_set(const char *str, const struct str_vec *strs);
135 bool want_section(asection *sect);
136 bool is_table_section(asection *sect);
137 struct supersect *make_section(struct superbfd *sbfd, const char *name);
138 void __attribute__((format(printf, 3, 4)))
139 write_string(struct supersect *ss, const char **addr, const char *fmt, ...);
140 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed);
141 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
142 const char *export_type, bool del);
143 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
144 bfd_vma offset);
145 arelent *create_reloc(struct supersect *ss, const void *addr, asymbol **symp,
146 bfd_vma offset);
148 struct str_vec sections, newsects, delsects, rmsyms;
149 struct export_desc_vec exports;
151 const char *modestr, *kid;
153 struct wsect *wanted_sections = NULL;
155 const struct table_section table_sections[] = {
156 {".altinstructions", 2 * sizeof(void *) + 4},
157 {".smp_locks", sizeof(void *)},
158 {".parainstructions", sizeof(void *) + 4},
159 }, *const end_table_sections = *(&table_sections + 1);
161 #define mode(str) starts_with(modestr, str)
163 DECLARE_VEC_TYPE(unsigned long, addr_vec);
164 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
165 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
166 vec_init);
167 struct addr_vec_hash system_map;
169 struct bool_hash system_map_written;
170 struct ulong_hash ksplice_symbol_offset;
171 struct ulong_hash ksplice_string_offset;
173 void load_system_map()
175 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
176 assert(config_dir);
177 char *file;
178 assert(asprintf(&file, "%s/System.map", config_dir) >= 0);
179 FILE *fp = fopen(file, "r");
180 assert(fp);
181 addr_vec_hash_init(&system_map);
182 unsigned long addr;
183 char type;
184 char *sym;
185 while (fscanf(fp, "%lx %c %as\n", &addr, &type, &sym) == 3)
186 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
187 1) = addr;
188 fclose(fp);
191 bool needed_data_section(struct superbfd *sbfd, asection *isection)
193 struct supersect *ss = fetch_supersect(sbfd, isection);
194 if (starts_with(isection->name, ".rodata"))
195 return true;
196 if (starts_with(isection->name, ".data")) {
197 /* Ignore .data.percpu sections */
198 if (starts_with(isection->name, ".data.percpu"))
199 return false;
200 return ss->relocs.size != 0;
202 return false;
205 int main(int argc, char *argv[])
207 bfd_init();
208 bfd *ibfd = bfd_openr(argv[1], NULL);
209 assert(ibfd);
211 char **matching;
212 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
214 const char *output_target = bfd_get_target(ibfd);
215 bfd *obfd = bfd_openw(argv[2], output_target);
216 assert(obfd);
218 struct superbfd *isbfd = fetch_superbfd(ibfd);
220 bool_hash_init(&system_map_written);
221 ulong_hash_init(&ksplice_symbol_offset);
222 ulong_hash_init(&ksplice_string_offset);
224 modestr = argv[3];
225 if (mode("keep-primary")) {
226 struct bfd *prebfd = bfd_openr(argv[4], NULL);
227 kid = argv[5];
229 assert(prebfd != NULL);
230 assert(bfd_check_format_matches(prebfd, bfd_object, &matching));
232 struct superbfd *presbfd = fetch_superbfd(prebfd);
234 handle_section_symbol_renames(presbfd, isbfd);
235 print_label_map(isbfd);
236 printf("\n");
237 vec_init(&sections);
238 foreach_nonmatching(presbfd, isbfd, print_changed_section);
239 printf("\n");
240 vec_init(&newsects);
241 foreach_new_section(presbfd, isbfd, print_new_section);
242 printf("\n");
243 vec_init(&delsects);
244 foreach_new_section(isbfd, presbfd, print_deleted_section);
245 vec_init(&exports);
246 compare_exported_symbols(presbfd, isbfd, "");
247 compare_exported_symbols(isbfd, presbfd, "del_");
248 printf("\n");
250 assert(bfd_close(prebfd));
251 } else if (mode("rmsyms")) {
252 read_str_set(&rmsyms);
255 if (mode("keep-primary")) {
256 /* Create export_desc structures for all export sections */
257 asection *sect;
258 for (sect = isbfd->abfd->sections; sect != NULL;
259 sect = sect->next) {
260 struct export_desc *ed;
261 if (!starts_with(sect->name, "__ksymtab") ||
262 ends_with(sect->name, "_strings"))
263 continue;
264 for (ed = exports.data;
265 ed < exports.data + exports.size; ed++) {
266 if (strcmp(ed->sectname, sect->name) == 0)
267 break;
269 if (ed < exports.data + exports.size)
270 continue;
271 ed = vec_grow(&exports, 1);
272 ed->sectname = sect->name;
273 vec_init(&ed->names);
277 if (mode("keep") || mode("rmsyms"))
278 load_system_map();
280 if (mode("keep")) {
281 while (1) {
282 const struct wsect *tmp = wanted_sections;
283 bfd_map_over_sections(ibfd, mark_wanted_if_referenced,
284 NULL);
285 if (tmp == wanted_sections)
286 break;
289 asection *sect;
290 for (sect = ibfd->sections; sect != NULL; sect = sect->next) {
291 asymbol **symp = canonical_symbolp(isbfd, sect->symbol);
292 if (symp == NULL)
293 continue;
294 asymbol *sym = *symp;
295 if (!want_section(sect))
296 continue;
297 if (starts_with(sect->name, ".rodata.str"))
298 continue;
299 if ((sym->flags & BSF_WEAK) != 0)
300 continue;
301 if ((sym->flags & BSF_FUNCTION) != 0 ||
302 needed_data_section(isbfd, sect))
303 write_ksplice_section(isbfd, symp);
307 if (mode("keep-primary")) {
308 asection *sect;
309 for (sect = isbfd->abfd->sections; sect != NULL;
310 sect = sect->next) {
311 if (str_in_set(sect->name, &sections) ||
312 (starts_with(sect->name, ".text") &&
313 want_section(sect) &&
314 !str_in_set(sect->name, &newsects)))
315 write_ksplice_patch(isbfd, sect->name);
318 const char **label;
319 for (label = delsects.data;
320 label < delsects.data + delsects.size; label++)
321 write_ksplice_deleted_patch(isbfd, *label);
323 const struct export_desc *ed;
324 for (ed = exports.data; ed < exports.data + exports.size;
325 ed++) {
326 if (starts_with(ed->sectname, "del___ksymtab")) {
327 const char *export_type =
328 ed->sectname + strlen("del___ksymtab");
329 const char **symname;
330 for (symname = ed->names.data;
331 symname < ed->names.data + ed->names.size;
332 symname++)
333 write_ksplice_export(isbfd, *symname,
334 export_type, true);
335 } else {
336 rm_some_exports(isbfd, ed);
341 asection *p;
342 for (p = ibfd->sections; p != NULL; p = p->next) {
343 struct supersect *ss = fetch_supersect(isbfd, p);
344 if (is_table_section(p) || starts_with(p->name, ".ksplice") ||
345 strcmp(p->name, ".fixup") == 0)
346 continue;
347 if (want_section(p) || mode("rmsyms"))
348 rm_some_relocs(ss);
351 const struct table_section *ss;
352 if (mode("keep")) {
353 for (ss = table_sections; ss != end_table_sections; ss++)
354 filter_table_section(isbfd, ss);
355 filter_ex_table_section(isbfd);
358 copy_object(ibfd, obfd);
359 assert(bfd_close(obfd));
360 assert(bfd_close(ibfd));
361 return EXIT_SUCCESS;
364 struct export_vec *get_export_syms(struct superbfd *sbfd)
366 asection *sect;
367 struct export_vec *exports;
368 exports = malloc(sizeof(*exports));
369 assert(exports != NULL);
370 vec_init(exports);
372 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
373 if (!starts_with(sect->name, "__ksymtab") ||
374 ends_with(sect->name, "_strings"))
375 continue;
376 struct supersect *ss = fetch_supersect(sbfd, sect);
377 struct kernel_symbol *sym;
378 assert(ss->contents.size * 2 == ss->relocs.size *
379 sizeof(struct kernel_symbol));
380 for (sym = ss->contents.data;
381 (void *)sym < ss->contents.data + ss->contents.size;
382 sym++) {
383 struct export *exp = vec_grow(exports, 1);
384 exp->name =
385 read_string(ss, (const char *const *)&sym->name);
386 exp->sect = sect;
389 return exports;
392 void compare_exported_symbols(struct superbfd *oldsbfd,
393 struct superbfd *newsbfd, char *addstr)
395 struct export_vec *new_exports, *old_exports;
396 new_exports = get_export_syms(newsbfd);
397 if (new_exports == NULL)
398 return;
399 old_exports = get_export_syms(oldsbfd);
400 struct export *old, *new;
401 asection *last_sect = NULL;
402 struct export_desc *ed;
403 for (new = new_exports->data; new < new_exports->data +
404 new_exports->size; new++) {
405 bool found = false;
406 if (old_exports != NULL) {
407 for (old = old_exports->data; old < old_exports->data +
408 old_exports->size; old++) {
409 if (strcmp(new->name, old->name) == 0 &&
410 strcmp(new->sect->name, old->sect->name)
411 == 0) {
412 found = true;
413 break;
417 if (!found) {
418 if (last_sect != new->sect) {
419 last_sect = new->sect;
420 ed = vec_grow(&exports, 1);
421 char *sectname;
422 assert(asprintf(&sectname, "%s%s", addstr,
423 new->sect->name) >= 0);
424 ed->sectname = sectname;
425 vec_init(&ed->names);
426 printf("\n%s", sectname);
428 *vec_grow(&ed->names, 1) = new->name;
429 printf(" %s", new->name);
434 void foreach_new_section(struct superbfd *oldsbfd, struct superbfd *newsbfd,
435 void (*s_fn)(struct superbfd *, asection *))
437 asection *oldsect, *newsect;
438 struct supersect *old_ss, *new_ss;
439 for (newsect = newsbfd->abfd->sections; newsect != NULL;
440 newsect = newsect->next) {
441 if (starts_with(newsect->name, ".rodata.str") ||
442 is_special(newsect))
443 continue;
444 for (oldsect = oldsbfd->abfd->sections; oldsect != NULL;
445 oldsect = oldsect->next) {
446 if (strcmp(newsect->name, oldsect->name) != 0 &&
447 strcmp(label_lookup(newsbfd, newsect->symbol),
448 label_lookup(oldsbfd, oldsect->symbol))
449 != 0)
450 continue;
451 if (!starts_with(newsect->name, ".rodata"))
452 break;
453 new_ss = fetch_supersect(oldsbfd, oldsect);
454 old_ss = fetch_supersect(oldsbfd, oldsect);
455 if (old_ss->contents.size != new_ss->contents.size ||
456 memcmp(old_ss->contents.data, new_ss->contents.data,
457 old_ss->contents.size) != 0)
458 oldsect = NULL;
459 break;
461 if (oldsect == NULL)
462 s_fn(newsbfd, newsect);
466 void foreach_nonmatching(struct superbfd *oldsbfd, struct superbfd *newsbfd,
467 void (*s_fn)(struct superbfd *, asection *))
469 asection *newp, *oldp;
470 struct supersect *old_ss, *new_ss;
471 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
472 if (!starts_with(newp->name, ".text"))
473 continue;
474 new_ss = fetch_supersect(newsbfd, newp);
475 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
476 if (oldp == NULL)
477 continue;
478 old_ss = fetch_supersect(oldsbfd, oldp);
479 if (new_ss->contents.size == old_ss->contents.size &&
480 memcmp(new_ss->contents.data, old_ss->contents.data,
481 new_ss->contents.size) == 0 &&
482 relocs_equal(oldsbfd, oldp, newsbfd, newp))
483 continue;
484 s_fn(newsbfd, newp);
488 static void handle_section_symbol_renames(struct superbfd *oldsbfd,
489 struct superbfd *newsbfd)
491 asection *newp, *oldp;
492 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
493 if (!starts_with(newp->name, ".text") &&
494 !starts_with(newp->name, ".data") &&
495 !starts_with(newp->name, ".rodata") &&
496 !starts_with(newp->name, ".bss"))
497 continue;
498 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
499 if (oldp == NULL)
500 continue;
502 const char *old_label = label_lookup(oldsbfd, oldp->symbol);
503 const char *new_label = label_lookup(newsbfd, newp->symbol);
505 if (strcmp(old_label, new_label) == 0)
506 continue;
507 label_map_set(newsbfd, new_label, old_label);
512 * relocs_equal checks to see whether the old section and the new section
513 * reference different read-only data in their relocations -- if a hard-coded
514 * string has been changed between the old file and the new file, relocs_equal
515 * will detect the difference.
517 bool relocs_equal(struct superbfd *oldsbfd, asection *oldp,
518 struct superbfd *newsbfd, asection *newp)
520 int i;
521 struct supersect *old_ss, *new_ss;
523 old_ss = fetch_supersect(oldsbfd, oldp);
524 new_ss = fetch_supersect(newsbfd, newp);
526 if (old_ss->relocs.size != new_ss->relocs.size)
527 return false;
529 for (i = 0; i < old_ss->relocs.size; i++) {
530 struct supersect *ro_old_ss, *ro_new_ss;
532 asymbol *old_sym = *old_ss->relocs.data[i]->sym_ptr_ptr;
533 asymbol *new_sym = *new_ss->relocs.data[i]->sym_ptr_ptr;
535 ro_old_ss = fetch_supersect(oldsbfd, old_sym->section);
536 ro_new_ss = fetch_supersect(newsbfd, new_sym->section);
538 bfd_vma old_offset =
539 get_reloc_offset(old_ss, old_ss->relocs.data[i], true);
540 bfd_vma new_offset =
541 get_reloc_offset(new_ss, new_ss->relocs.data[i], true);
543 if (strcmp(ro_old_ss->name, ro_new_ss->name) != 0)
544 return false;
546 if (!starts_with(ro_old_ss->name, ".rodata")) {
547 /* for non-rodata, we just compare that the two
548 relocations are to the same offset within the same
549 section. */
550 if (old_sym->value + old_offset !=
551 new_sym->value + new_offset)
552 return false;
553 continue;
556 if (starts_with(ro_old_ss->name, ".rodata.str") &&
557 /* check it's not an out-of-range relocation to a string;
558 we'll just compare entire sections for them */
559 !(old_offset >= ro_old_ss->contents.size ||
560 new_offset >= ro_new_ss->contents.size)) {
561 if (strcmp
562 (ro_old_ss->contents.data + old_sym->value +
563 old_offset,
564 ro_new_ss->contents.data + new_sym->value +
565 new_offset) != 0)
566 return false;
567 continue;
570 if (ro_old_ss->contents.size != ro_new_ss->contents.size)
571 return false;
573 if (memcmp(ro_old_ss->contents.data, ro_new_ss->contents.data,
574 ro_old_ss->contents.size) != 0)
575 return false;
578 return true;
581 void print_changed_section(struct superbfd *sbfd, asection *sect)
583 *vec_grow(&sections, 1) = sect->name;
584 printf("%s ", sect->name);
587 void print_new_section(struct superbfd *sbfd, asection *sect)
589 *vec_grow(&newsects, 1) = sect->name;
590 printf("%s ", sect->name);
593 void print_deleted_section(struct superbfd *sbfd, asection *sect)
595 if (!starts_with(sect->name, ".text"))
596 return;
597 const char *label = label_lookup(sbfd, sect->symbol);
598 *vec_grow(&delsects, 1) = label;
599 printf("%s ", label);
602 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed)
604 assert(starts_with(ed->sectname, "__ksymtab"));
605 const char *export_type = ed->sectname + strlen("__ksymtab");
606 asection *sym_sect = bfd_get_section_by_name(isbfd->abfd, ed->sectname);
607 assert(sym_sect != NULL);
608 char *export_crc_name;
609 assert(asprintf(&export_crc_name, "__kcrctab%s", export_type) >= 0);
610 asection *crc_sect = bfd_get_section_by_name(isbfd->abfd,
611 export_crc_name);
612 struct supersect *ss, *crc_ss = NULL;
613 ss = fetch_supersect(isbfd, sym_sect);
614 if (crc_sect != NULL)
615 crc_ss = fetch_supersect(isbfd, crc_sect);
617 if (crc_ss != NULL)
618 assert(ss->contents.size * sizeof(unsigned long) ==
619 crc_ss->contents.size * sizeof(struct kernel_symbol));
621 struct supersect orig_ss, orig_crc_ss;
622 supersect_move(&orig_ss, ss);
623 if (crc_ss != NULL)
624 supersect_move(&orig_crc_ss, crc_ss);
626 struct kernel_symbol *orig_ksym;
627 unsigned long *orig_crc;
628 for (orig_ksym = orig_ss.contents.data,
629 orig_crc = orig_crc_ss.contents.data;
630 (void *)orig_ksym < orig_ss.contents.data + orig_ss.contents.size;
631 orig_ksym++, orig_crc++) {
632 asymbol *sym;
633 read_reloc(&orig_ss, &orig_ksym->value,
634 sizeof(orig_ksym->value), &sym);
635 if (!str_in_set(sym->name, &ed->names))
636 continue;
638 struct kernel_symbol *ksym = sect_grow(ss, 1, typeof(*ksym));
639 sect_copy(ss, &ksym->value, &orig_ss, &orig_ksym->value, 1);
640 /* Replace name with a mangled name */
641 write_ksplice_export(ss->parent, sym->name, export_type, false);
642 write_string(ss, (const char **)&ksym->name,
643 "DISABLED_%s_%s", sym->name, kid);
645 if (crc_ss != NULL)
646 sect_copy(crc_ss,
647 sect_grow(crc_ss, 1, typeof(*orig_crc)),
648 &orig_crc_ss, orig_crc, 1);
652 void rm_some_relocs(struct supersect *ss)
654 struct arelentp_vec orig_relocs;
655 vec_move(&orig_relocs, &ss->relocs);
657 arelent **relocp;
658 for (relocp = orig_relocs.data;
659 relocp < orig_relocs.data + orig_relocs.size; relocp++) {
660 bool rm_reloc = false;
661 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
663 if (mode("rmsyms") && str_in_set(sym_ptr->name, &rmsyms) &&
664 bfd_is_und_section(sym_ptr->section))
665 rm_reloc = true;
667 if (mode("keep"))
668 rm_reloc = true;
670 if (mode("keep-primary") && want_section(sym_ptr->section) &&
671 (str_in_set(sym_ptr->section->name, &newsects) ||
672 bfd_is_const_section(sym_ptr->section) ||
673 starts_with(sym_ptr->section->name, ".rodata.str")))
674 rm_reloc = false;
676 if (mode("finalize") && bfd_is_und_section(sym_ptr->section))
677 rm_reloc = true;
679 if (rm_reloc)
680 write_ksplice_reloc(ss, *relocp);
681 else
682 *vec_grow(&ss->relocs, 1) = *relocp;
686 struct supersect *make_section(struct superbfd *sbfd, const char *name)
688 asection *sect = bfd_get_section_by_name(sbfd->abfd, name);
689 if (sect != NULL)
690 return fetch_supersect(sbfd, sect);
691 else
692 return new_supersect(sbfd, name);
695 arelent *create_reloc(struct supersect *ss, const void *addr, asymbol **symp,
696 bfd_vma offset)
698 bfd_reloc_code_real_type code;
699 switch (bfd_arch_bits_per_address(ss->parent->abfd)) {
700 case 32:
701 code = BFD_RELOC_32;
702 break;
703 case 64:
704 code = BFD_RELOC_64;
705 break;
706 default:
707 DIE;
710 arelent *reloc = malloc(sizeof(*reloc));
711 reloc->sym_ptr_ptr = symp;
712 reloc->address = addr - ss->contents.data;
713 reloc->howto = bfd_reloc_type_lookup(ss->parent->abfd, code);
714 reloc->addend = offset;
715 return reloc;
718 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
719 bfd_vma offset)
721 arelent *new_reloc = create_reloc(ss, addr, symp, offset), **relocp;
722 for (relocp = ss->relocs.data;
723 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
724 if ((*relocp)->address == new_reloc->address) {
725 memmove(relocp,
726 relocp + 1,
727 (void *)(ss->relocs.data + ss->relocs.size) -
728 (void *)(relocp + 1));
729 ss->relocs.size--;
730 relocp--;
733 *vec_grow(&ss->new_relocs, 1) = new_reloc;
736 void write_string(struct supersect *ss, const char **addr, const char *fmt, ...)
738 va_list ap;
739 struct supersect *str_ss = make_section(ss->parent, ".ksplice_str");
740 char *str;
741 va_start(ap, fmt);
742 int len = vasprintf(&str, fmt, ap);
743 assert(len >= 0);
744 va_end(ap);
746 unsigned long *str_offp = ulong_hash_lookup(&ksplice_string_offset, str,
747 FALSE);
748 if (str_offp == NULL) {
749 char *buf = sect_grow(str_ss, len + 1, char);
750 memcpy(buf, str, len + 1);
751 str_offp = ulong_hash_lookup(&ksplice_string_offset, str, TRUE);
752 *str_offp = (void *)buf - str_ss->contents.data;
755 write_reloc(ss, addr, &str_ss->symbol, *str_offp);
758 void lookup_system_map(struct addr_vec *addrs, const char *name, long offset)
760 struct addr_vec *map_addrs =
761 addr_vec_hash_lookup(&system_map, name, FALSE);
762 if (map_addrs == NULL)
763 return;
765 unsigned long *addr, *map_addr;
766 for (map_addr = map_addrs->data;
767 map_addr < map_addrs->data + map_addrs->size; map_addr++) {
768 for (addr = addrs->data; addr < addrs->data + addrs->size;
769 addr++) {
770 if (*addr == *map_addr + offset)
771 break;
773 if (addr < addrs->data + addrs->size)
774 continue;
775 *vec_grow(addrs, 1) = *map_addr + offset;
779 void write_system_map_array(struct superbfd *sbfd, struct supersect *ss,
780 const unsigned long **sym_addrs,
781 unsigned long *num_sym_addrs, asymbol *sym)
783 struct addr_vec addrs;
784 vec_init(&addrs);
786 if (bfd_is_abs_section(sym->section)) {
787 *vec_grow(&addrs, 1) = sym->value;
788 } else if (bfd_is_und_section(sym->section)) {
789 lookup_system_map(&addrs, sym->name, 0);
790 } else if (!bfd_is_const_section(sym->section)) {
791 asymbol **gsymp;
792 for (gsymp = sbfd->syms.data;
793 gsymp < sbfd->syms.data + sbfd->syms.size; gsymp++) {
794 asymbol *gsym = *gsymp;
795 if ((gsym->flags & BSF_DEBUGGING) == 0 &&
796 gsym->section == sym->section)
797 lookup_system_map(&addrs, gsym->name,
798 sym->value - gsym->value);
802 *num_sym_addrs = addrs.size;
803 if (addrs.size != 0) {
804 struct supersect *array_ss = make_section(sbfd,
805 ".ksplice_array");
806 void *buf = sect_grow(array_ss, addrs.size,
807 typeof(*addrs.data));
808 memcpy(buf, addrs.data, addrs.size * sizeof(*addrs.data));
809 write_reloc(ss, sym_addrs, &array_ss->symbol,
810 buf - array_ss->contents.data);
811 } else {
812 *sym_addrs = NULL;
815 vec_free(&addrs);
818 void write_ksplice_system_map(struct superbfd *sbfd, asymbol *sym,
819 const char *addstr_sect)
821 struct supersect *smap_ss = make_section(sbfd, ".ksplice_system_map");
822 struct ksplice_system_map *smap;
823 const char *label = label_lookup(sbfd, sym);
825 bool *done = bool_hash_lookup(&system_map_written, label, TRUE);
826 if (*done)
827 return;
828 *done = true;
830 smap = sect_grow(smap_ss, 1, struct ksplice_system_map);
832 write_system_map_array(sbfd, smap_ss, &smap->candidates,
833 &smap->nr_candidates, sym);
834 write_string(smap_ss, &smap->label, "%s%s", label, addstr_sect);
837 void write_ksplice_symbol(struct supersect *ss,
838 const struct ksplice_symbol *const *addr,
839 asymbol *sym, const char *addstr_sect)
841 struct supersect *ksymbol_ss = make_section(ss->parent,
842 ".ksplice_symbols");
843 struct ksplice_symbol *ksymbol;
844 unsigned long *ksymbol_offp;
845 const char *label = label_lookup(ss->parent, sym);
846 char *output;
847 assert(asprintf(&output, "%s%s", label, addstr_sect) >= 0);
849 ksymbol_offp = ulong_hash_lookup(&ksplice_symbol_offset, output, FALSE);
850 if (ksymbol_offp != NULL) {
851 write_reloc(ss, addr, &ksymbol_ss->symbol, *ksymbol_offp);
852 return;
854 ksymbol = sect_grow(ksymbol_ss, 1, struct ksplice_symbol);
855 ksymbol_offp = ulong_hash_lookup(&ksplice_symbol_offset, output, TRUE);
856 *ksymbol_offp = (void *)ksymbol - ksymbol_ss->contents.data;
858 if (bfd_is_und_section(sym->section) || (sym->flags & BSF_GLOBAL) != 0) {
859 write_string(ksymbol_ss, &ksymbol->name, "%s", sym->name);
860 } else if (bfd_is_const_section(sym->section)) {
861 ksymbol->name = NULL;
862 } else {
863 asymbol *gsym = canonical_symbol(ss->parent, sym);
865 if (gsym == NULL)
866 ksymbol->name = NULL;
867 else
868 write_string(ksymbol_ss, &ksymbol->name, "%s",
869 gsym->name);
872 write_string(ksymbol_ss, &ksymbol->label, "%s%s", label, addstr_sect);
874 write_ksplice_system_map(ksymbol_ss->parent, sym, addstr_sect);
876 write_reloc(ss, addr, &ksymbol_ss->symbol, *ksymbol_offp);
879 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc)
881 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
882 reloc_howto_type *howto = orig_reloc->howto;
883 bfd_vma addend = get_reloc_offset(ss, orig_reloc, false);
885 if (mode("finalize") && starts_with(ss->name, ".ksplice_patches")) {
886 unsigned long *repladdr =
887 ss->contents.data + orig_reloc->address;
888 *repladdr = 0;
889 return;
892 blot_section(ss, orig_reloc->address, howto);
894 struct supersect *kreloc_ss = make_section(ss->parent,
895 mode("rmsyms") ?
896 ".ksplice_init_relocs" :
897 ".ksplice_relocs");
898 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
899 struct ksplice_reloc);
901 write_reloc(kreloc_ss, &kreloc->blank_addr,
902 &ss->symbol, orig_reloc->address);
903 kreloc->blank_offset = (unsigned long)orig_reloc->address;
904 write_ksplice_symbol(kreloc_ss, &kreloc->symbol, sym_ptr, "");
905 kreloc->pcrel = howto->pc_relative;
906 kreloc->addend = addend;
907 kreloc->size = bfd_get_reloc_size(howto);
908 kreloc->dst_mask = howto->dst_mask;
909 kreloc->rightshift = howto->rightshift;
910 kreloc->signed_addend =
911 (howto->complain_on_overflow == complain_overflow_signed) ||
912 (howto->complain_on_overflow == complain_overflow_bitfield);
915 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
917 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto)
919 int bits = bfd_get_reloc_size(howto) * 8;
920 void *address = ss->contents.data + offset;
921 bfd_vma x = bfd_get(bits, ss->parent->abfd, address);
922 x = (x & ~howto->dst_mask) |
923 ((bfd_vma)KSPLICE_CANARY & howto->dst_mask);
924 bfd_put(bits, ss->parent->abfd, x, address);
927 void write_ksplice_section(struct superbfd *sbfd, asymbol **symp)
929 asymbol *sym = *symp;
930 struct supersect *ksect_ss = make_section(sbfd, ".ksplice_sections");
931 struct ksplice_section *ksect = sect_grow(ksect_ss, 1,
932 struct ksplice_section);
934 write_ksplice_symbol(ksect_ss, &ksect->symbol, sym,
935 mode("keep-primary") ? "(post)" : "");
936 ksect->size = bfd_get_section_size(sym->section);
937 ksect->flags = 0;
938 if (starts_with(sym->section->name, ".rodata"))
939 ksect->flags |= KSPLICE_SECTION_RODATA;
940 if (starts_with(sym->section->name, ".data"))
941 ksect->flags |= KSPLICE_SECTION_DATA;
942 if (starts_with(sym->section->name, ".text") ||
943 starts_with(sym->section->name, ".exit.text"))
944 ksect->flags |= KSPLICE_SECTION_TEXT;
945 assert(ksect->flags != 0);
946 write_reloc(ksect_ss, &ksect->address, symp, 0);
949 void write_ksplice_patch(struct superbfd *sbfd, const char *sectname)
951 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
952 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
953 struct ksplice_patch);
954 asection *sect = bfd_get_section_by_name(sbfd->abfd, sectname);
955 assert(sect != NULL);
957 write_string(kpatch_ss, &kpatch->label, "%s",
958 label_lookup(sbfd, sect->symbol));
959 write_reloc(kpatch_ss, &kpatch->repladdr, &sect->symbol, 0);
962 void write_ksplice_deleted_patch(struct superbfd *sbfd, const char *label)
964 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
965 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
966 struct ksplice_patch);
968 write_string(kpatch_ss, &kpatch->label, "%s", label);
969 const char *orig_label = lookup_orig_label(sbfd, label);
970 if (orig_label == NULL)
971 return;
972 asymbol **symp;
973 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
974 symp++) {
975 asymbol *sym = *symp;
976 if (bfd_is_und_section(sym->section) &&
977 strcmp(orig_label, sym->name) == 0)
978 break;
980 if (symp >= sbfd->syms.data + sbfd->syms.size)
981 DIE;
982 write_reloc(kpatch_ss, &kpatch->repladdr, symp, 0);
985 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
986 const char *export_type, bool del)
988 struct supersect *export_ss = make_section(sbfd, ".ksplice_exports");
989 struct ksplice_export *exp = sect_grow(export_ss, 1,
990 struct ksplice_export);
992 if (del) {
993 write_string(export_ss, &exp->name, "%s", symname);
994 write_string(export_ss, &exp->new_name, "DISABLED_%s_%s",
995 symname, kid);
996 } else {
997 write_string(export_ss, &exp->new_name, "%s", symname);
998 write_string(export_ss, &exp->name, "DISABLED_%s_%s", symname,
999 kid);
1003 void filter_table_section(struct superbfd *sbfd, const struct table_section *s)
1005 asection *isection = bfd_get_section_by_name(sbfd->abfd, s->sectname);
1006 if (isection == NULL)
1007 return;
1009 struct supersect *ss = fetch_supersect(sbfd, isection), orig_ss;
1010 supersect_move(&orig_ss, ss);
1012 const void *orig_entry;
1013 for (orig_entry = orig_ss.contents.data;
1014 orig_entry < orig_ss.contents.data + orig_ss.contents.size;
1015 orig_entry += align(s->entry_size, 1 << ss->alignment)) {
1016 asymbol *sym;
1017 read_reloc(&orig_ss, orig_entry, sizeof(void *), &sym);
1019 asection *p;
1020 for (p = sbfd->abfd->sections; p != NULL; p = p->next) {
1021 if (sym->section == p
1022 && !is_table_section(p) && !want_section(p))
1023 break;
1025 if (p != NULL)
1026 continue;
1028 sect_copy(ss, sect_do_grow(ss, 1, s->entry_size,
1029 1 << ss->alignment),
1030 &orig_ss, orig_entry, s->entry_size);
1034 struct fixup_entry {
1035 bfd_vma offset;
1036 bool used;
1037 bfd_vma ex_offset;
1039 DECLARE_VEC_TYPE(struct fixup_entry, fixup_entry_vec);
1041 int compare_fixups(const void *aptr, const void *bptr)
1043 const struct fixup_entry *a = aptr, *b = bptr;
1044 if (a->offset < b->offset)
1045 return -1;
1046 else if (a->offset > b->offset)
1047 return 1;
1048 else
1049 return (int)a->used - (int)b->used;
1052 void filter_ex_table_section(struct superbfd *sbfd)
1054 asection *isection = bfd_get_section_by_name(sbfd->abfd, "__ex_table");
1055 if (isection == NULL)
1056 return;
1057 asection *fixup_sect = bfd_get_section_by_name(sbfd->abfd, ".fixup");
1059 struct supersect *ss = fetch_supersect(sbfd, isection), orig_ss;
1060 supersect_move(&orig_ss, ss);
1062 struct supersect *fixup_ss = NULL;
1063 if (fixup_sect != NULL)
1064 fixup_ss = fetch_supersect(sbfd, fixup_sect);
1066 struct fixup_entry_vec fixups;
1067 vec_init(&fixups);
1069 const struct exception_table_entry *orig_entry;
1070 for (orig_entry = orig_ss.contents.data;
1071 (void *)orig_entry < orig_ss.contents.data + orig_ss.contents.size;
1072 orig_entry++) {
1073 asymbol *sym, *fixup_sym;
1074 read_reloc(&orig_ss, &orig_entry->insn,
1075 sizeof(orig_entry->insn), &sym);
1077 struct fixup_entry *f;
1078 bfd_vma fixup_offset = read_reloc(&orig_ss, &orig_entry->fixup,
1079 sizeof(orig_entry->fixup),
1080 &fixup_sym);
1081 if (fixup_sym->section == fixup_sect) {
1082 assert(fixup_offset < fixup_ss->contents.size);
1083 f = vec_grow(&fixups, 1);
1084 f->offset = fixup_offset;
1085 f->used = false;
1088 asection *p;
1089 for (p = sbfd->abfd->sections; p != NULL; p = p->next) {
1090 if (sym->section == p
1091 && !is_table_section(p) && !want_section(p))
1092 break;
1094 if (p != NULL)
1095 continue;
1097 if (fixup_sym->section == fixup_sect) {
1098 f->used = true;
1099 f->ex_offset = ss->contents.size +
1100 offsetof(struct exception_table_entry, fixup);
1102 sect_copy(ss, sect_grow(ss, 1, struct exception_table_entry),
1103 &orig_ss, orig_entry, 1);
1106 if (fixup_sect == NULL)
1107 return;
1109 struct supersect orig_fixup_ss;
1110 supersect_move(&orig_fixup_ss, fixup_ss);
1112 qsort(fixups.data, fixups.size, sizeof(*fixups.data), compare_fixups);
1113 *vec_grow(&fixups, 1) = (struct fixup_entry)
1114 { .offset = orig_fixup_ss.contents.size, .used = false };
1116 struct fixup_entry *f;
1117 for (f = fixups.data; f < fixups.data + fixups.size - 1; f++) {
1118 if (!f->used)
1119 continue;
1120 write_reloc(ss, ss->contents.data + f->ex_offset,
1121 &fixup_ss->symbol, fixup_ss->contents.size);
1122 sect_copy(fixup_ss,
1123 sect_grow(fixup_ss, (f + 1)->offset - f->offset,
1124 unsigned char),
1125 &orig_fixup_ss,
1126 orig_fixup_ss.contents.data + f->offset,
1127 (f + 1)->offset - f->offset);
1131 void mark_wanted_if_referenced(bfd *abfd, asection *sect, void *ignored)
1133 if (want_section(sect))
1134 return;
1135 if (!starts_with(sect->name, ".text")
1136 && !starts_with(sect->name, ".exit.text")
1137 && !starts_with(sect->name, ".rodata")
1138 && !(starts_with(sect->name, ".data") && mode("keep-helper")))
1139 return;
1141 if (mode("keep-helper")) {
1142 struct superbfd *sbfd = fetch_superbfd(abfd);
1143 asymbol **symp;
1144 for (symp = sbfd->syms.data;
1145 symp < sbfd->syms.data + sbfd->syms.size; symp++) {
1146 asymbol *sym = *symp;
1147 if (sym->section == sect &&
1148 (sym->flags & BSF_GLOBAL) != 0) {
1149 struct wsect *w = malloc(sizeof(*w));
1150 w->sect = sect;
1151 w->next = wanted_sections;
1152 wanted_sections = w;
1153 return;
1158 bfd_map_over_sections(abfd, check_for_ref_to_section, sect);
1161 void check_for_ref_to_section(bfd *abfd, asection *looking_at,
1162 void *looking_for)
1164 if (!want_section(looking_at) || is_table_section(looking_at))
1165 return;
1167 struct superbfd *sbfd = fetch_superbfd(abfd);
1168 struct supersect *ss = fetch_supersect(sbfd, looking_at);
1169 arelent **relocp;
1170 for (relocp = ss->relocs.data;
1171 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1172 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1173 if (sym->section == (asection *)looking_for &&
1174 (!starts_with(sym->section->name, ".text") ||
1175 (get_reloc_offset(ss, *relocp, true) != 0 &&
1176 strcmp(looking_at->name, ".fixup") != 0))) {
1177 struct wsect *w = malloc(sizeof(*w));
1178 w->sect = looking_for;
1179 w->next = wanted_sections;
1180 wanted_sections = w;
1181 break;
1186 /* Modified function from GNU Binutils objcopy.c */
1187 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
1189 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
1191 bfd_vma start = bfd_get_start_address(ibfd);
1193 flagword flags = bfd_get_file_flags(ibfd);
1194 flags &= bfd_applicable_file_flags(obfd);
1196 assert(bfd_set_start_address(obfd, start)
1197 && bfd_set_file_flags(obfd, flags));
1199 enum bfd_architecture iarch = bfd_get_arch(ibfd);
1200 unsigned int imach = bfd_get_mach(ibfd);
1201 assert(bfd_set_arch_mach(obfd, iarch, imach));
1202 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
1204 /* BFD mandates that all output sections be created and sizes set before
1205 any output is done. Thus, we traverse all sections multiple times. */
1206 bfd_map_over_sections(ibfd, setup_section, obfd);
1208 struct supersect *new_supersects = fetch_superbfd(ibfd)->new_supersects;
1209 struct supersect *ss;
1210 for (ss = new_supersects; ss != NULL; ss = ss->next)
1211 setup_new_section(obfd, ss);
1213 /* Mark symbols used in output relocations so that they
1214 are kept, even if they are local labels or static symbols.
1216 Note we iterate over the input sections examining their
1217 relocations since the relocations for the output sections
1218 haven't been set yet. mark_symbols_used_in_relocations will
1219 ignore input sections which have no corresponding output
1220 section. */
1222 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, NULL);
1223 for (ss = new_supersects; ss != NULL; ss = ss->next)
1224 ss_mark_symbols_used_in_relocations(ss);
1225 struct asymbolp_vec osyms;
1226 vec_init(&osyms);
1227 filter_symbols(ibfd, obfd, &osyms, &fetch_superbfd(ibfd)->syms);
1229 bfd_set_symtab(obfd, osyms.data, osyms.size);
1231 /* This has to happen after the symbol table has been set. */
1232 bfd_map_over_sections(obfd, write_section, NULL);
1234 /* Allow the BFD backend to copy any private data it understands
1235 from the input BFD to the output BFD. This is done last to
1236 permit the routine to look at the filtered symbol table, which is
1237 important for the ECOFF code at least. */
1238 assert(bfd_copy_private_bfd_data(ibfd, obfd));
1240 return TRUE;
1243 /* Modified function from GNU Binutils objcopy.c */
1244 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
1246 bfd *obfd = obfdarg;
1247 bfd_vma vma;
1249 if (!want_section(isection))
1250 return;
1252 asection *osection = bfd_make_section_anyway(obfd, isection->name);
1253 assert(osection != NULL);
1255 struct superbfd *isbfd = fetch_superbfd(ibfd);
1256 struct supersect *ss = fetch_supersect(isbfd, isection);
1257 osection->userdata = ss;
1258 bfd_set_section_flags(obfd, osection, ss->flags);
1259 ss->symbol = osection->symbol;
1260 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
1262 vma = bfd_section_vma(ibfd, isection);
1263 assert(bfd_set_section_vma(obfd, osection, vma));
1265 osection->lma = isection->lma;
1266 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
1267 osection->entsize = isection->entsize;
1268 osection->output_section = osection;
1269 osection->output_offset = 0;
1270 isection->output_section = osection;
1271 isection->output_offset = 0;
1272 return;
1275 void setup_new_section(bfd *obfd, struct supersect *ss)
1277 asection *osection = bfd_make_section_anyway(obfd, ss->name);
1278 assert(osection != NULL);
1279 bfd_set_section_flags(obfd, osection, ss->flags);
1281 osection->userdata = ss;
1282 ss->symbol = osection->symbol;
1283 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
1284 assert(bfd_set_section_vma(obfd, osection, 0));
1286 osection->lma = 0;
1287 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
1288 osection->entsize = 0;
1289 osection->output_section = osection;
1290 osection->output_offset = 0;
1293 void write_section(bfd *obfd, asection *osection, void *arg)
1295 struct supersect *ss = osection->userdata;
1297 if ((ss->flags & SEC_GROUP) != 0 || ss->contents.size == 0)
1298 return;
1300 arelent **relocp;
1301 char *error_message;
1302 for (relocp = ss->new_relocs.data;
1303 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
1304 bfd_vma val;
1305 if (bfd_get_arch(obfd) == bfd_arch_arm)
1306 val = osection->use_rela_p ? 0 : (*relocp)->addend;
1307 else
1308 val = 0;
1309 bfd_put(bfd_get_reloc_size((*relocp)->howto) * 8, obfd, val,
1310 ss->contents.data + (*relocp)->address);
1311 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
1312 0, osection, &error_message) !=
1313 bfd_reloc_ok) {
1314 fprintf(stderr, "ksplice: error installing reloc: %s",
1315 error_message);
1316 DIE;
1319 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
1320 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
1322 bfd_set_reloc(obfd, osection,
1323 ss->relocs.size == 0 ? NULL : ss->relocs.data,
1324 ss->relocs.size);
1326 if (ss->flags & SEC_HAS_CONTENTS)
1327 assert(bfd_set_section_contents
1328 (obfd, osection, ss->contents.data, 0,
1329 ss->contents.size));
1332 /* Modified function from GNU Binutils objcopy.c
1334 * Mark all the symbols which will be used in output relocations with
1335 * the BSF_KEEP flag so that those symbols will not be stripped.
1337 * Ignore relocations which will not appear in the output file.
1339 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
1340 void *ignored)
1342 struct superbfd *sbfd = fetch_superbfd(abfd);
1343 if (isection->output_section == NULL)
1344 return;
1346 struct supersect *ss = fetch_supersect(sbfd, isection);
1347 ss_mark_symbols_used_in_relocations(ss);
1350 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
1352 /* Examine each symbol used in a relocation. If it's not one of the
1353 special bfd section symbols, then mark it with BSF_KEEP. */
1354 arelent **relocp;
1355 for (relocp = ss->relocs.data;
1356 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1357 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1358 if (!(bfd_is_const_section(sym->section) &&
1359 sym == sym->section->symbol))
1360 sym->flags |= BSF_KEEP;
1362 for (relocp = ss->new_relocs.data;
1363 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
1364 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1365 if (!(bfd_is_const_section(sym->section) &&
1366 sym == sym->section->symbol))
1367 sym->flags |= BSF_KEEP;
1371 static bool deleted_table_section_symbol(bfd *abfd, asymbol *sym)
1373 struct superbfd *sbfd = fetch_superbfd(abfd);
1374 struct supersect *ss = fetch_supersect(sbfd, sym->section);
1376 if (bfd_is_const_section(sym->section))
1377 return false;
1379 asymbol **symp;
1380 for (symp = ss->syms.data; symp < ss->syms.data + ss->syms.size; symp++) {
1381 if (sym == *symp)
1382 break;
1384 return symp >= ss->syms.data + ss->syms.size;
1387 /* Modified function from GNU Binutils objcopy.c
1389 * Choose which symbol entries to copy.
1390 * We don't copy in place, because that confuses the relocs.
1391 * Return the number of symbols to print.
1393 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
1394 struct asymbolp_vec *isyms)
1396 asymbol **symp;
1397 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
1398 asymbol *sym = *symp;
1400 bool keep = false;
1402 if (mode("keep") && (sym->flags & BSF_GLOBAL) != 0 &&
1403 !(mode("keep-primary") &&
1404 str_in_set(sym->section->name, &newsects)))
1405 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
1407 if (mode("finalize") && (sym->flags & BSF_GLOBAL) != 0)
1408 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
1410 if ((sym->flags & BSF_KEEP) != 0 /* Used in relocation. */
1411 || ((sym->flags & BSF_SECTION_SYM) != 0 &&
1412 want_section(fetch_superbfd(ibfd), sym->section)))
1413 keep = true;
1414 else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 &&
1415 want_section(sym->section))
1416 keep = true;
1417 else if (mode("keep-primary") &&
1418 starts_with(sym->section->name, "__ksymtab"))
1419 keep = true;
1421 if (deleted_table_section_symbol(ibfd, sym))
1422 keep = false;
1424 if (bfd_is_com_section(sym->section))
1425 keep = false;
1427 if (mode("rmsyms"))
1428 keep = !str_in_set(sym->name, &rmsyms);
1430 if (keep)
1431 *vec_grow(osyms, 1) = sym;
1435 void read_str_set(struct str_vec *strs)
1437 char *buf = NULL;
1438 size_t n = 0;
1439 assert(getline(&buf, &n, stdin) >= 0);
1440 vec_init(strs);
1441 char *saveptr;
1442 while (1) {
1443 char *str = strtok_r(buf, " \n", &saveptr);
1444 buf = NULL;
1445 if (str == NULL)
1446 break;
1447 *vec_grow(strs, 1) = str;
1451 bool str_in_set(const char *str, const struct str_vec *strs)
1453 const char **strp;
1454 for (strp = strs->data; strp < strs->data + strs->size; strp++) {
1455 if (strcmp(str, *strp) == 0)
1456 return true;
1458 return false;
1461 bool want_section(asection *sect)
1463 if (!mode("keep"))
1464 return true;
1466 if (mode("keep-primary") && bfd_is_abs_section(sect))
1467 return true;
1468 const struct wsect *w = wanted_sections;
1469 for (; w != NULL; w = w->next) {
1470 if (w->sect == sect)
1471 return true;
1474 if (starts_with(sect->name, ".ksplice"))
1475 return true;
1476 if (mode("keep-helper") && starts_with(sect->name, ".text"))
1477 return true;
1478 if (mode("keep-helper") && starts_with(sect->name, ".exit.text")
1479 && bfd_get_section_by_name(sect->owner, ".exitcall.exit") == NULL)
1480 return true;
1481 if (mode("keep-primary") && str_in_set(sect->name, &sections))
1482 return true;
1483 if (mode("keep-primary") && str_in_set(sect->name, &newsects))
1484 return true;
1486 if (mode("keep-helper") && starts_with(sect->name, "__ksymtab"))
1487 return false;
1488 if (mode("keep-helper") && starts_with(sect->name, "__kcrctab"))
1489 return false;
1491 if (is_special(sect))
1492 return true;
1494 return false;
1497 bool is_table_section(asection *sect)
1499 const struct table_section *ss;
1500 for (ss = table_sections; ss != end_table_sections; ss++) {
1501 if (strcmp(ss->sectname, sect->name) == 0)
1502 return true;
1504 if (strcmp(sect->name, "__ex_table") == 0)
1505 return true;
1506 return false;