Handle special sections using spans.
[ksplice.git] / objmanip.c
blob0c841edffdcdb45d3e68982999c051f2242f93a1
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 "kmodsrc/offsets.h"
56 #include <stdint.h>
57 #include <stdarg.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <limits.h>
62 #define symbol_init(sym) *(sym) = (asymbol *)NULL
63 DEFINE_HASH_TYPE(asymbol *, symbol_hash, symbol_hash_init, symbol_hash_free,
64 symbol_hash_lookup, symbol_init);
66 struct export {
67 const char *name;
68 asection *sect;
70 DECLARE_VEC_TYPE(struct export, export_vec);
72 DECLARE_VEC_TYPE(const char *, str_vec);
74 struct wsect {
75 asection *sect;
76 struct wsect *next;
79 struct export_desc {
80 const char *sectname;
81 struct str_vec names;
83 DECLARE_VEC_TYPE(struct export_desc, export_desc_vec);
85 #define bool_init(b) *(b) = false
86 DEFINE_HASH_TYPE(bool, bool_hash, bool_hash_init, bool_hash_free,
87 bool_hash_lookup, bool_init);
89 #define ulong_init(x) *(x) = 0
90 DEFINE_HASH_TYPE(unsigned long, ulong_hash, ulong_hash_init,
91 ulong_hash_free, ulong_hash_lookup, ulong_init);
93 void do_keep_primary(struct superbfd *isbfd, const char *pre);
94 void do_keep_helper(struct superbfd *isbfd);
95 void do_finalize(struct superbfd *isbfd);
96 void do_rmsyms(struct superbfd *isbfd);
98 struct export_vec *get_export_syms(struct superbfd *sbfd);
99 void compare_exported_symbols(struct superbfd *oldsbfd,
100 struct superbfd *newsbfd, char *addstr);
101 bool relocs_equal(struct supersect *old_ss, struct supersect *new_ss);
102 static bool part_of_reloc(struct supersect *ss, unsigned long addr);
103 static bool nonrelocs_equal(struct supersect *old_ss, struct supersect *new_ss);
104 static void handle_section_symbol_renames(struct superbfd *oldsbfd,
105 struct superbfd *newsbfd);
107 enum supersect_type supersect_type(struct supersect *ss);
108 void initialize_supersect_types(struct superbfd *sbfd);
109 static void initialize_spans(struct superbfd *sbfd);
110 static void initialize_string_spans(struct superbfd *sbfd, asection *sect);
111 struct span *reloc_target_span(struct supersect *ss, arelent *reloc);
112 struct span *reloc_address_span(struct supersect *ss, arelent *reloc);
113 void remove_unkept_spans(struct superbfd *sbfd);
114 void compute_span_shifts(struct superbfd *sbfd);
115 static struct span *new_span(struct superbfd *sbfd, asection *sect,
116 bfd_vma start, bfd_vma size);
117 bool is_table_section(const char *name, bool consider_other);
119 void rm_relocs(struct superbfd *isbfd);
120 void rm_some_relocs(struct supersect *ss);
121 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc);
122 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto);
123 void write_ksplice_section(struct superbfd *sbfd, asymbol **symp,
124 struct span *span);
125 void write_ksplice_patch(struct superbfd *sbfd, const char *sectname);
126 void write_ksplice_deleted_patch(struct superbfd *sbfd, const char *name,
127 const char *label);
128 void filter_table_sections(struct superbfd *isbfd);
129 void filter_table_section(struct superbfd *sbfd, const struct table_section *s);
130 void keep_referenced_sections(struct superbfd *sbfd);
131 bfd_boolean copy_object(bfd *ibfd, bfd *obfd);
132 void setup_section(bfd *ibfd, asection *isection, void *obfdarg);
133 static void setup_new_section(bfd *obfd, struct supersect *ss);
134 static void write_section(bfd *obfd, asection *osection, void *arg);
135 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
136 void *ignored);
137 static void ss_mark_symbols_used_in_relocations(struct supersect *ss);
138 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
139 struct asymbolp_vec *isyms);
140 static bool deleted_table_section_symbol(bfd *abfd, asymbol *sym);
141 void read_str_set(struct str_vec *strs);
142 bool str_in_set(const char *str, const struct str_vec *strs);
143 struct supersect *make_section(struct superbfd *sbfd, const char *name);
144 void __attribute__((format(printf, 3, 4)))
145 write_string(struct supersect *ss, const char **addr, const char *fmt, ...);
146 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed);
147 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
148 const char *export_type, bool del);
149 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
150 bfd_vma offset);
151 arelent *create_reloc(struct supersect *ss, const void *addr, asymbol **symp,
152 bfd_vma offset);
153 static void match_global_symbol_sections(struct superbfd *oldsbfd,
154 struct superbfd *newsbfd);
155 static void match_sections_by_name(struct superbfd *oldsbfd,
156 struct superbfd *newsbfd);
157 static void match_sections_by_contents(struct superbfd *oldsbfd,
158 struct superbfd *newsbfd);
159 static void match_sections_by_label(struct superbfd *oldsbfd,
160 struct superbfd *newsbfd);
161 static void mark_new_sections(struct superbfd *sbfd);
162 static void handle_deleted_sections(struct superbfd *oldsbfd,
163 struct superbfd *newsbfd);
164 static void compare_matched_sections(struct superbfd *sbfd);
165 static void update_nonzero_offsets(struct superbfd *sbfd);
166 static void handle_nonzero_offset_relocs(struct supersect *ss);
168 static const char *label_lookup(struct superbfd *sbfd, asymbol *sym);
169 static void print_label_map(struct superbfd *sbfd);
170 static void label_map_set(struct superbfd *sbfd, const char *oldlabel,
171 const char *label);
172 static void init_label_map(struct superbfd *sbfd);
174 int verbose = 0;
175 #define debug_(sbfd, level, fmt, ...) \
176 do { \
177 if (verbose >= (level)) \
178 printf("%s: " fmt, (sbfd)->abfd->filename, \
179 ## __VA_ARGS__); \
180 } while (0)
181 #define debug0(sbfd, fmt, ...) debug_(sbfd, 0, fmt, ## __VA_ARGS__)
182 #define debug1(sbfd, fmt, ...) debug_(sbfd, 1, fmt, ## __VA_ARGS__)
183 #define err(sbfd, fmt, ...) \
184 do { \
185 fprintf(stderr, "%s: " fmt, (sbfd)->abfd->filename, \
186 ## __VA_ARGS__); \
187 } while (0)
189 struct str_vec delsects, rmsyms;
190 struct export_desc_vec exports;
191 bool changed;
193 struct ksplice_config *config;
195 const char *modestr, *kid;
197 struct superbfd *offsets_sbfd = NULL;
199 #define mode(str) starts_with(modestr, str)
201 DECLARE_VEC_TYPE(unsigned long, addr_vec);
202 DEFINE_HASH_TYPE(struct addr_vec, addr_vec_hash,
203 addr_vec_hash_init, addr_vec_hash_free, addr_vec_hash_lookup,
204 vec_init);
205 struct addr_vec_hash system_map;
207 struct bool_hash system_map_written;
208 struct ulong_hash ksplice_symbol_offset;
209 struct ulong_hash ksplice_string_offset;
211 void load_system_map()
213 const char *config_dir = getenv("KSPLICE_CONFIG_DIR");
214 assert(config_dir);
215 char *file;
216 assert(asprintf(&file, "%s/System.map", config_dir) >= 0);
217 FILE *fp = fopen(file, "r");
218 assert(fp);
219 addr_vec_hash_init(&system_map);
220 unsigned long addr;
221 char type;
222 char *sym;
223 while (fscanf(fp, "%lx %c %as\n", &addr, &type, &sym) == 3)
224 *vec_grow(addr_vec_hash_lookup(&system_map, sym, TRUE),
225 1) = addr;
226 fclose(fp);
229 void load_offsets()
231 char *kmodsrc = getenv("KSPLICE_KMODSRC"), *offsets_file;
232 assert(kmodsrc != NULL);
233 assert(asprintf(&offsets_file, "%s/offsets.o", kmodsrc) >= 0);
234 bfd *offsets_bfd = bfd_openr(offsets_file, NULL);
235 assert(offsets_bfd != NULL);
236 char **matching;
237 assert(bfd_check_format_matches(offsets_bfd, bfd_object, &matching));
238 offsets_sbfd = fetch_superbfd(offsets_bfd);
240 asection *config_sect = bfd_get_section_by_name(offsets_sbfd->abfd,
241 ".ksplice_config");
242 struct supersect *config_ss =
243 fetch_supersect(offsets_sbfd, config_sect);
245 config = config_ss->contents.data;
248 bool matchable_data_section(struct supersect *ss)
250 if (ss->type == SS_TYPE_STRING)
251 return true;
252 if (ss->type == SS_TYPE_RODATA)
253 return true;
254 if (ss->type == SS_TYPE_DATA && ss->relocs.size != 0)
255 return true;
256 return false;
259 bool unchangeable_section(struct supersect *ss)
261 if (ss->type == SS_TYPE_DATA)
262 return true;
263 if (ss->type == SS_TYPE_IGNORED && !starts_with(ss->name, ".debug"))
264 return true;
265 return false;
268 int main(int argc, char *argv[])
270 if (getenv("KSPLICE_VERBOSE") != NULL)
271 verbose = atoi(getenv("KSPLICE_VERBOSE"));
273 bfd_init();
274 bfd *ibfd = bfd_openr(argv[1], NULL);
275 assert(ibfd);
277 char **matching;
278 assert(bfd_check_format_matches(ibfd, bfd_object, &matching));
280 const char *output_target = bfd_get_target(ibfd);
281 bfd *obfd = bfd_openw(argv[2], output_target);
282 assert(obfd);
284 struct superbfd *isbfd = fetch_superbfd(ibfd);
285 init_label_map(isbfd);
287 bool_hash_init(&system_map_written);
288 ulong_hash_init(&ksplice_symbol_offset);
289 ulong_hash_init(&ksplice_string_offset);
291 modestr = argv[3];
292 if (mode("keep-primary")) {
293 kid = argv[5];
294 do_keep_primary(isbfd, argv[4]);
295 } else if (mode("keep-helper")) {
296 do_keep_helper(isbfd);
297 } else if (mode("finalize")) {
298 do_finalize(isbfd);
299 } else if (mode("rmsyms")) {
300 do_rmsyms(isbfd);
303 copy_object(ibfd, obfd);
305 if (offsets_sbfd != NULL)
306 assert(bfd_close(offsets_sbfd->abfd));
307 assert(bfd_close(obfd));
308 assert(bfd_close(ibfd));
309 return EXIT_SUCCESS;
312 void do_keep_primary(struct superbfd *isbfd, const char *pre)
314 struct bfd *prebfd = bfd_openr(pre, NULL);
315 assert(prebfd != NULL);
316 char **matching;
317 assert(bfd_check_format_matches(prebfd, bfd_object, &matching));
319 struct superbfd *presbfd = fetch_superbfd(prebfd);
320 init_label_map(presbfd);
321 load_system_map();
322 load_offsets();
323 initialize_supersect_types(isbfd);
324 initialize_supersect_types(presbfd);
326 match_global_symbol_sections(presbfd, isbfd);
327 debug1(isbfd, "Matched global\n");
328 match_sections_by_name(presbfd, isbfd);
329 debug1(isbfd, "Matched by name\n");
330 match_sections_by_label(presbfd, isbfd);
331 debug1(isbfd, "Matched by label\n");
332 match_sections_by_contents(presbfd, isbfd);
333 debug1(isbfd, "Matched by contents\n");
335 do {
336 changed = false;
337 compare_matched_sections(isbfd);
338 update_nonzero_offsets(isbfd);
339 mark_new_sections(isbfd);
340 } while (changed);
341 vec_init(&delsects);
343 handle_deleted_sections(presbfd, isbfd);
344 handle_section_symbol_renames(presbfd, isbfd);
346 vec_init(&exports);
347 compare_exported_symbols(presbfd, isbfd, "");
348 compare_exported_symbols(isbfd, presbfd, "del_");
350 initialize_spans(isbfd);
351 initialize_spans(presbfd);
352 asection *sect;
353 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
354 struct supersect *ss = fetch_supersect(isbfd, sect);
355 if (ss->type != SS_TYPE_STRING)
356 continue;
357 asection *oldsect = bfd_get_section_by_name(prebfd, sect->name);
358 if (oldsect == NULL)
359 continue;
360 struct supersect *old_ss = fetch_supersect(presbfd, oldsect);
361 struct span *span, *old_span;
362 for (span = ss->spans.data;
363 span < ss->spans.data + ss->spans.size; span++) {
364 span->new = true;
365 for (old_span = old_ss->spans.data;
366 old_span < old_ss->spans.data + old_ss->spans.size;
367 old_span++) {
368 if (strcmp((char *)ss->contents.data +
369 span->start,
370 (char *)old_ss->contents.data +
371 old_span->start) == 0) {
372 if (!span->new)
373 DIE;
374 span->label = old_span->label;
375 span->new = false;
380 assert(bfd_close(prebfd));
382 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
383 struct supersect *ss = fetch_supersect(isbfd, sect);
384 ss->keep = false;
385 if (ss->type == SS_TYPE_STRING || ss->type == SS_TYPE_SPECIAL ||
386 ss->type == SS_TYPE_EXPORT)
387 ss->keep = true;
388 if (ss->new || ss->patch)
389 ss->keep = true;
392 print_label_map(isbfd);
394 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
395 struct supersect *ss = fetch_supersect(isbfd, sect);
396 if (ss->patch)
397 debug0(isbfd, "Patching section: %s\n", sect->name);
400 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
401 struct supersect *ss = fetch_supersect(isbfd, sect);
402 if (ss->new)
403 debug0(isbfd, "New section: %s\n", sect->name);
406 const char **sectname;
407 for (sectname = delsects.data;
408 sectname < delsects.data + delsects.size; sectname++)
409 debug0(isbfd, "Deleted section: %s\n", *sectname);
411 const struct export_desc *ed;
412 for (ed = exports.data; ed < exports.data + exports.size; ed++) {
413 const char **symname;
414 bool del = starts_with(ed->sectname, "del___ksymtab");
415 const char *export_type = ed->sectname + strlen("__ksymtab");
416 if (del)
417 export_type += strlen("_del");
418 for (symname = ed->names.data;
419 symname < ed->names.data + ed->names.size; symname++)
420 debug0(isbfd, "Export %s (%s): %s\n",
421 del ? "deletion" : "addition",
422 export_type, *symname);
425 struct span *span;
426 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
427 struct supersect *ss = fetch_supersect(isbfd, sect);
428 for (span = ss->spans.data;
429 span < ss->spans.data + ss->spans.size; span++)
430 span->keep = ss->keep;
433 filter_table_sections(isbfd);
434 compute_span_shifts(isbfd);
436 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
437 struct supersect *ss = fetch_supersect(isbfd, sect);
438 if (!ss->patch && !ss->new)
439 continue;
440 asymbol **symp = canonical_symbolp(isbfd, sect->symbol);
441 if (symp == NULL)
442 DIE;
444 struct span *span;
445 for (span = ss->spans.data;
446 span < ss->spans.data + ss->spans.size; span++)
447 write_ksplice_section(isbfd, symp, span);
449 if (ss->patch)
450 write_ksplice_patch(isbfd, sect->name);
453 for (ed = exports.data; ed < exports.data + exports.size; ed++) {
454 if (starts_with(ed->sectname, "del___ksymtab")) {
455 const char *export_type =
456 ed->sectname + strlen("del___ksymtab");
457 const char **symname;
458 for (symname = ed->names.data;
459 symname < ed->names.data + ed->names.size;
460 symname++)
461 write_ksplice_export(isbfd, *symname,
462 export_type, true);
463 } else {
464 rm_some_exports(isbfd, ed);
468 rm_relocs(isbfd);
469 remove_unkept_spans(isbfd);
472 void do_keep_helper(struct superbfd *isbfd)
474 load_system_map();
475 load_offsets();
476 initialize_supersect_types(isbfd);
477 initialize_spans(isbfd);
479 asection *sect;
480 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
481 struct supersect *ss = fetch_supersect(isbfd, sect);
482 ss->keep = false;
483 if (ss->type == SS_TYPE_SPECIAL || ss->type == SS_TYPE_TEXT)
484 ss->keep = true;
487 asymbol **symp;
488 for (symp = isbfd->syms.data;
489 symp < isbfd->syms.data + isbfd->syms.size; symp++) {
490 asymbol *sym = *symp;
491 if (!bfd_is_const_section(sym->section) &&
492 (sym->flags & BSF_GLOBAL) != 0) {
493 struct supersect *sym_ss =
494 fetch_supersect(isbfd, sym->section);
495 if (sym_ss->type != SS_TYPE_IGNORED)
496 sym_ss->keep = true;
500 struct span *span;
501 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
502 struct supersect *ss = fetch_supersect(isbfd, sect);
503 for (span = ss->spans.data;
504 span < ss->spans.data + ss->spans.size; span++)
505 span->keep = ss->keep;
508 do {
509 changed = false;
510 keep_referenced_sections(isbfd);
511 } while (changed);
513 filter_table_sections(isbfd);
514 compute_span_shifts(isbfd);
516 for (sect = isbfd->abfd->sections; sect != NULL; sect = sect->next) {
517 struct supersect *ss = fetch_supersect(isbfd, sect);
518 asymbol **symp = canonical_symbolp(isbfd, sect->symbol);
519 if (symp == NULL)
520 continue;
521 asymbol *sym = *symp;
522 if ((sym->flags & BSF_WEAK) != 0)
523 continue;
524 if (bfd_get_section_size(sect) == 0)
525 continue;
526 if (!ss->keep)
527 continue;
528 if (ss->type != SS_TYPE_TEXT && !matchable_data_section(ss))
529 continue;
531 struct span *span;
532 for (span = ss->spans.data;
533 span < ss->spans.data + ss->spans.size; span++) {
534 if (span->keep)
535 write_ksplice_section(isbfd, symp, span);
539 rm_relocs(isbfd);
540 remove_unkept_spans(isbfd);
543 void do_finalize(struct superbfd *isbfd)
545 load_system_map();
546 load_offsets();
547 initialize_supersect_types(isbfd);
548 initialize_spans(isbfd);
549 rm_relocs(isbfd);
552 void do_rmsyms(struct superbfd *isbfd)
554 read_str_set(&rmsyms);
555 load_system_map();
556 load_offsets();
557 initialize_supersect_types(isbfd);
558 initialize_spans(isbfd);
559 rm_relocs(isbfd);
562 struct export_vec *get_export_syms(struct superbfd *sbfd)
564 asection *sect;
565 struct export_vec *exports;
566 exports = malloc(sizeof(*exports));
567 assert(exports != NULL);
568 vec_init(exports);
570 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
571 if (!starts_with(sect->name, "__ksymtab") ||
572 ends_with(sect->name, "_strings"))
573 continue;
574 struct supersect *ss = fetch_supersect(sbfd, sect);
575 struct kernel_symbol *sym;
576 assert(ss->contents.size * 2 == ss->relocs.size *
577 sizeof(struct kernel_symbol));
578 for (sym = ss->contents.data;
579 (void *)sym < ss->contents.data + ss->contents.size;
580 sym++) {
581 struct export *exp = vec_grow(exports, 1);
582 exp->name =
583 read_string(ss, (const char *const *)&sym->name);
584 exp->sect = sect;
587 return exports;
590 void compare_exported_symbols(struct superbfd *oldsbfd,
591 struct superbfd *newsbfd, char *addstr)
593 struct export_vec *new_exports, *old_exports;
594 new_exports = get_export_syms(newsbfd);
595 if (new_exports == NULL)
596 return;
597 old_exports = get_export_syms(oldsbfd);
598 struct export *old, *new;
599 asection *last_sect = NULL;
600 struct export_desc *ed = NULL;
601 for (new = new_exports->data; new < new_exports->data +
602 new_exports->size; new++) {
603 bool found = false;
604 if (old_exports != NULL) {
605 for (old = old_exports->data; old < old_exports->data +
606 old_exports->size; old++) {
607 if (strcmp(new->name, old->name) == 0 &&
608 strcmp(new->sect->name, old->sect->name)
609 == 0) {
610 found = true;
611 break;
615 if (last_sect != new->sect) {
616 last_sect = new->sect;
617 ed = vec_grow(&exports, 1);
618 char *sectname;
619 assert(asprintf(&sectname, "%s%s", addstr,
620 new->sect->name) >= 0);
621 ed->sectname = sectname;
622 vec_init(&ed->names);
624 if (!found)
625 *vec_grow(&ed->names, 1) = new->name;
629 void match_sections(struct supersect *oldss, struct supersect *newss)
631 if (oldss->match == newss && newss->match == oldss)
632 return;
633 if (oldss->match != NULL) {
634 err(newss->parent, "Matching conflict: old %s: %s != %s\n",
635 oldss->name, oldss->match->name, newss->name);
636 DIE;
638 if (newss->match != NULL) {
639 err(newss->parent, "Matching conflict: new %s: %s != %s\n",
640 newss->name, newss->match->name, oldss->name);
641 DIE;
643 oldss->match = newss;
644 newss->match = oldss;
645 debug1(newss->parent, "Matched old %s to new %s\n",
646 oldss->name, newss->name);
649 static void match_global_symbol_sections(struct superbfd *oldsbfd,
650 struct superbfd *newsbfd)
652 asymbol **oldsymp, **newsymp;
653 for (oldsymp = oldsbfd->syms.data;
654 oldsymp < oldsbfd->syms.data + oldsbfd->syms.size; oldsymp++) {
655 asymbol *oldsym = *oldsymp;
656 if ((oldsym->flags & BSF_GLOBAL) == 0 ||
657 bfd_is_const_section(oldsym->section))
658 continue;
659 for (newsymp = newsbfd->syms.data;
660 newsymp < newsbfd->syms.data + newsbfd->syms.size;
661 newsymp++) {
662 asymbol *newsym = *newsymp;
663 if ((newsym->flags & BSF_GLOBAL) == 0 ||
664 bfd_is_const_section(oldsym->section))
665 continue;
666 if (strcmp(oldsym->name, newsym->name) != 0)
667 continue;
668 struct supersect *oldss =
669 fetch_supersect(oldsbfd, oldsym->section);
670 struct supersect *newss =
671 fetch_supersect(newsbfd, newsym->section);
672 match_sections(oldss, newss);
677 static void match_sections_by_name(struct superbfd *oldsbfd,
678 struct superbfd *newsbfd)
680 asection *newp, *oldp;
681 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
682 struct supersect *newss = fetch_supersect(newsbfd, newp);
683 oldp = bfd_get_section_by_name(oldsbfd->abfd, newp->name);
684 if (oldp == NULL || newss->type == SS_TYPE_STRING ||
685 newss->type == SS_TYPE_SPECIAL ||
686 newss->type == SS_TYPE_EXPORT)
687 continue;
688 if (static_local_symbol(newsbfd,
689 canonical_symbol(newsbfd,
690 newp->symbol)))
691 continue;
693 struct supersect *oldss = fetch_supersect(oldsbfd, oldp);
694 match_sections(oldss, newss);
698 static void match_sections_by_label(struct superbfd *oldsbfd,
699 struct superbfd *newsbfd)
701 asection *oldsect, *newsect;
702 struct supersect *oldss, *newss;
703 for (newsect = newsbfd->abfd->sections; newsect != NULL;
704 newsect = newsect->next) {
705 newss = fetch_supersect(newsbfd, newsect);
706 if (newss->type == SS_TYPE_STRING ||
707 newss->type == SS_TYPE_SPECIAL ||
708 newss->type == SS_TYPE_EXPORT)
709 continue;
710 for (oldsect = oldsbfd->abfd->sections; oldsect != NULL;
711 oldsect = oldsect->next) {
712 if (strcmp(label_lookup(newsbfd, newsect->symbol),
713 label_lookup(oldsbfd, oldsect->symbol)) != 0)
714 continue;
715 oldss = fetch_supersect(oldsbfd, oldsect);
716 match_sections(oldss, newss);
721 static void match_sections_by_contents(struct superbfd *oldsbfd,
722 struct superbfd *newsbfd)
724 asection *oldsect, *newsect;
725 struct supersect *oldss, *newss;
726 for (newsect = newsbfd->abfd->sections; newsect != NULL;
727 newsect = newsect->next) {
728 newss = fetch_supersect(newsbfd, newsect);
729 if (newss->type != SS_TYPE_RODATA)
730 continue;
731 for (oldsect = oldsbfd->abfd->sections; oldsect != NULL;
732 oldsect = oldsect->next) {
733 oldss = fetch_supersect(oldsbfd, oldsect);
734 if (oldss->type != SS_TYPE_RODATA)
735 continue;
736 if (oldss->relocs.size != 0 || newss->relocs.size != 0)
737 continue;
738 if (oldss->contents.size != newss->contents.size)
739 continue;
740 if (memcmp(oldss->contents.data, newss->contents.data,
741 oldss->contents.size) != 0)
742 continue;
743 match_sections(oldss, newss);
748 static void mark_new_sections(struct superbfd *sbfd)
750 asection *sect;
751 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
752 struct supersect *ss = fetch_supersect(sbfd, sect);
753 if (ss->type == SS_TYPE_STRING || ss->type == SS_TYPE_SPECIAL ||
754 ss->type == SS_TYPE_IGNORED || ss->type == SS_TYPE_EXPORT)
755 continue;
756 if (ss->match == NULL)
757 ss->new = true;
761 static void handle_deleted_sections(struct superbfd *oldsbfd,
762 struct superbfd *newsbfd)
764 asection *sect;
765 for (sect = oldsbfd->abfd->sections; sect != NULL; sect = sect->next) {
766 struct supersect *ss = fetch_supersect(oldsbfd, sect);
767 if (ss->type != SS_TYPE_TEXT)
768 continue;
769 if (ss->match != NULL)
770 continue;
771 const char *label = label_lookup(oldsbfd, sect->symbol);
772 *vec_grow(&delsects, 1) = label;
773 asymbol *csym = canonical_symbol(oldsbfd, sect->symbol);
774 write_ksplice_deleted_patch(newsbfd, csym->name, label);
778 static void handle_nonzero_offset_relocs(struct supersect *ss)
780 int i;
781 for (i = 0; i < ss->relocs.size; i++) {
782 asymbol *sym = *ss->relocs.data[i]->sym_ptr_ptr;
783 bfd_vma offset = get_reloc_offset(ss, ss->relocs.data[i], true);
784 if (sym->value + offset == 0)
785 continue;
786 if (bfd_is_const_section(sym->section))
787 continue;
788 struct supersect *sym_ss = fetch_supersect(ss->parent,
789 sym->section);
790 if (sym_ss->type != SS_TYPE_TEXT)
791 continue;
792 if (!sym_ss->patch) {
793 changed = true;
794 debug1(ss->parent,
795 "Changing %s because a relocation from sect %s "
796 "has a nonzero offset %lx+%lx into it\n",
797 sym_ss->name, ss->name,
798 (unsigned long)sym->value,
799 (unsigned long)offset);
801 sym_ss->patch = true;
805 static void update_nonzero_offsets(struct superbfd *sbfd)
807 asection *sect;
808 struct supersect *ss;
810 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
811 ss = fetch_supersect(sbfd, sect);
812 if (ss->new || ss->patch)
813 handle_nonzero_offset_relocs(ss);
817 static void compare_matched_sections(struct superbfd *newsbfd)
819 asection *newp;
820 struct supersect *old_ss, *new_ss;
821 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
822 new_ss = fetch_supersect(newsbfd, newp);
823 if (new_ss->match == NULL)
824 continue;
825 old_ss = new_ss->match;
827 if (nonrelocs_equal(old_ss, new_ss) &&
828 relocs_equal(old_ss, new_ss))
829 continue;
831 char *reason;
832 if (new_ss->contents.size != old_ss->contents.size)
833 reason = "differing sizes";
834 else if (memcmp(new_ss->contents.data, old_ss->contents.data,
835 new_ss->contents.size) != 0)
836 reason = "differing contents";
837 else
838 reason = "differing relocations";
839 if (new_ss->type == SS_TYPE_TEXT) {
840 if (new_ss->patch)
841 continue;
842 new_ss->patch = true;
843 debug1(newsbfd, "Changing %s due to %s\n", new_ss->name,
844 reason);
845 } else {
846 debug1(newsbfd, "Unmatching %s and %s due to %s\n",
847 old_ss->name, new_ss->name, reason);
848 new_ss->match = NULL;
849 old_ss->match = NULL;
851 changed = true;
852 if (unchangeable_section(new_ss))
853 err(newsbfd, "warning: ignoring change to nonpatchable "
854 "section %s\n", new_ss->name);
858 static void handle_section_symbol_renames(struct superbfd *oldsbfd,
859 struct superbfd *newsbfd)
861 asection *newp, *oldp;
862 for (newp = newsbfd->abfd->sections; newp != NULL; newp = newp->next) {
863 struct supersect *newss = fetch_supersect(newsbfd, newp);
864 if (newss->match == NULL)
865 continue;
866 oldp = bfd_get_section_by_name(oldsbfd->abfd,
867 newss->match->name);
868 if (oldp == NULL)
869 continue;
871 const char *old_label = label_lookup(oldsbfd, oldp->symbol);
872 const char *new_label = label_lookup(newsbfd, newp->symbol);
874 if (strcmp(old_label, new_label) == 0)
875 continue;
876 label_map_set(newsbfd, new_label, old_label);
880 static bool part_of_reloc(struct supersect *ss, unsigned long addr)
882 arelent **relocp;
883 for (relocp = ss->relocs.data;
884 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
885 arelent *reloc = *relocp;
886 if (addr >= reloc->address &&
887 addr < reloc->address + reloc->howto->size)
888 return true;
890 return false;
893 static bool nonrelocs_equal(struct supersect *old_ss, struct supersect *new_ss)
895 int i;
896 if (old_ss->contents.size != new_ss->contents.size)
897 return false;
898 const unsigned char *old = old_ss->contents.data;
899 const unsigned char *new = new_ss->contents.data;
900 for (i = 0; i < old_ss->contents.size; i++) {
901 if (old[i] != new[i] &&
902 !(part_of_reloc(old_ss, i) && part_of_reloc(new_ss, i)))
903 return false;
905 return true;
909 * relocs_equal checks to see whether the old section and the new section
910 * reference different read-only data in their relocations -- if a hard-coded
911 * string has been changed between the old file and the new file, relocs_equal
912 * will detect the difference.
914 bool relocs_equal(struct supersect *old_ss, struct supersect *new_ss)
916 int i;
917 struct superbfd *oldsbfd = old_ss->parent;
918 struct superbfd *newsbfd = new_ss->parent;
920 if (old_ss->relocs.size != new_ss->relocs.size) {
921 debug1(newsbfd, "Different reloc count between %s and %s\n",
922 old_ss->name, new_ss->name);
923 return false;
926 for (i = 0; i < old_ss->relocs.size; i++) {
927 struct supersect *ro_old_ss, *ro_new_ss;
929 if (old_ss->relocs.data[i]->address !=
930 new_ss->relocs.data[i]->address)
931 return false;
933 asymbol *old_sym = *old_ss->relocs.data[i]->sym_ptr_ptr;
934 asymbol *new_sym = *new_ss->relocs.data[i]->sym_ptr_ptr;
936 bfd_vma old_offset =
937 get_reloc_offset(old_ss, old_ss->relocs.data[i], true);
938 bfd_vma new_offset =
939 get_reloc_offset(new_ss, new_ss->relocs.data[i], true);
941 if (bfd_is_und_section(old_sym->section) ||
942 bfd_is_und_section(new_sym->section)) {
943 if (!bfd_is_und_section(new_sym->section) &&
944 fetch_supersect(newsbfd, new_sym->section)->type
945 == SS_TYPE_TEXT && old_offset != 0)
946 return false;
948 if (!bfd_is_und_section(old_sym->section) &&
949 fetch_supersect(oldsbfd, old_sym->section)->type
950 == SS_TYPE_TEXT && new_offset != 0)
951 return false;
953 if (strcmp(old_sym->name, new_sym->name) == 0 &&
954 old_offset == new_offset)
955 continue;
956 return false;
959 if (bfd_is_const_section(old_sym->section) ||
960 bfd_is_const_section(new_sym->section))
961 DIE;
963 ro_old_ss = fetch_supersect(oldsbfd, old_sym->section);
964 ro_new_ss = fetch_supersect(newsbfd, new_sym->section);
966 if (ro_old_ss->type == SS_TYPE_STRING &&
967 /* check it's not an out-of-range relocation to a string;
968 we'll just compare entire sections for them */
969 !(old_offset >= ro_old_ss->contents.size ||
970 new_offset >= ro_new_ss->contents.size)) {
971 if (strcmp(ro_old_ss->contents.data + old_sym->value +
972 old_offset,
973 ro_new_ss->contents.data + new_sym->value +
974 new_offset) != 0) {
975 debug0(newsbfd, "Section %s/%s has string "
976 "difference \"%s\"/\"%s\"\n",
977 old_ss->name, new_ss->name,
978 (const char *)(ro_old_ss->contents.data +
979 old_sym->value +
980 old_offset),
981 (const char *)(ro_new_ss->contents.data +
982 new_sym->value +
983 new_offset));
984 debug1(newsbfd,
985 "Strings differ between %s and %s\n",
986 old_ss->name, new_ss->name);
987 return false;
989 continue;
992 if (ro_old_ss->match != ro_new_ss ||
993 ro_new_ss->match != ro_old_ss) {
994 debug1(newsbfd, "Nonmatching relocs from %s to %s/%s\n",
995 new_ss->name, ro_new_ss->name, ro_old_ss->name);
996 return false;
999 if (old_sym->value + old_offset != new_sym->value + new_offset) {
1000 debug1(newsbfd, "Offsets to %s/%s differ between %s "
1001 "and %s: %lx+%lx/%lx+%lx\n", ro_old_ss->name,
1002 ro_new_ss->name, old_ss->name, new_ss->name,
1003 (unsigned long)old_sym->value,
1004 (unsigned long)old_offset,
1005 (unsigned long)new_sym->value,
1006 (unsigned long)new_offset);
1007 return false;
1010 if ((old_sym->value + old_offset != 0 ||
1011 new_sym->value + new_offset != 0) && ro_new_ss->patch) {
1012 debug1(newsbfd, "Relocation from %s to nonzero offsets "
1013 "%lx+%lx/%lx+%lx in changed section %s\n",
1014 new_ss->name,
1015 (unsigned long)old_sym->value,
1016 (unsigned long)old_offset,
1017 (unsigned long)new_sym->value,
1018 (unsigned long)new_offset,
1019 new_sym->section->name);
1020 return false;
1024 return true;
1027 void rm_some_exports(struct superbfd *isbfd, const struct export_desc *ed)
1029 assert(starts_with(ed->sectname, "__ksymtab"));
1030 const char *export_type = ed->sectname + strlen("__ksymtab");
1031 asection *sym_sect = bfd_get_section_by_name(isbfd->abfd, ed->sectname);
1032 assert(sym_sect != NULL);
1033 char *export_crc_name;
1034 assert(asprintf(&export_crc_name, "__kcrctab%s", export_type) >= 0);
1035 asection *crc_sect = bfd_get_section_by_name(isbfd->abfd,
1036 export_crc_name);
1037 struct supersect *ss, *crc_ss = NULL;
1038 ss = fetch_supersect(isbfd, sym_sect);
1039 if (crc_sect != NULL)
1040 crc_ss = fetch_supersect(isbfd, crc_sect);
1042 if (crc_ss != NULL)
1043 assert(ss->contents.size * sizeof(unsigned long) ==
1044 crc_ss->contents.size * sizeof(struct kernel_symbol));
1046 struct supersect orig_ss, orig_crc_ss;
1047 supersect_move(&orig_ss, ss);
1048 if (crc_ss != NULL)
1049 supersect_move(&orig_crc_ss, crc_ss);
1051 struct kernel_symbol *orig_ksym;
1052 unsigned long *orig_crc;
1053 for (orig_ksym = orig_ss.contents.data,
1054 orig_crc = orig_crc_ss.contents.data;
1055 (void *)orig_ksym < orig_ss.contents.data + orig_ss.contents.size;
1056 orig_ksym++, orig_crc++) {
1057 asymbol *sym;
1058 read_reloc(&orig_ss, &orig_ksym->value,
1059 sizeof(orig_ksym->value), &sym);
1060 if (!str_in_set(sym->name, &ed->names))
1061 continue;
1063 struct kernel_symbol *ksym = sect_grow(ss, 1, typeof(*ksym));
1064 sect_copy(ss, &ksym->value, &orig_ss, &orig_ksym->value, 1);
1065 /* Replace name with a mangled name */
1066 write_ksplice_export(ss->parent, sym->name, export_type, false);
1067 write_string(ss, (const char **)&ksym->name,
1068 "DISABLED_%s_%s", sym->name, kid);
1070 if (crc_ss != NULL)
1071 sect_copy(crc_ss,
1072 sect_grow(crc_ss, 1, typeof(*orig_crc)),
1073 &orig_crc_ss, orig_crc, 1);
1077 void rm_relocs(struct superbfd *isbfd)
1079 asection *p;
1080 for (p = isbfd->abfd->sections; p != NULL; p = p->next) {
1081 struct supersect *ss = fetch_supersect(isbfd, p);
1082 if ((mode("keep") && ss->type == SS_TYPE_SPECIAL) ||
1083 ss->type == SS_TYPE_KSPLICE)
1084 continue;
1085 if (ss->keep || mode("rmsyms"))
1086 rm_some_relocs(ss);
1088 if (mode("finalize")) {
1089 p = bfd_get_section_by_name(isbfd->abfd, ".ksplice_patches");
1090 if (p != NULL) {
1091 struct supersect *ss = fetch_supersect(isbfd, p);
1092 rm_some_relocs(ss);
1097 void rm_some_relocs(struct supersect *ss)
1099 struct arelentp_vec orig_relocs;
1100 vec_move(&orig_relocs, &ss->relocs);
1102 arelent **relocp;
1103 for (relocp = orig_relocs.data;
1104 relocp < orig_relocs.data + orig_relocs.size; relocp++) {
1105 bool rm_reloc = false;
1106 asymbol *sym_ptr = *(*relocp)->sym_ptr_ptr;
1108 if (mode("rmsyms") && str_in_set(sym_ptr->name, &rmsyms) &&
1109 bfd_is_und_section(sym_ptr->section))
1110 rm_reloc = true;
1112 if (mode("keep"))
1113 rm_reloc = true;
1115 if (mode("keep-primary") &&
1116 (bfd_is_const_section(sym_ptr->section) ||
1117 fetch_supersect(ss->parent, sym_ptr->section)->new ||
1118 reloc_target_span(ss, *relocp)->new ||
1119 !reloc_address_span(ss, *relocp)->keep))
1120 rm_reloc = false;
1122 if (mode("finalize") && bfd_is_und_section(sym_ptr->section))
1123 rm_reloc = true;
1125 if (rm_reloc)
1126 write_ksplice_reloc(ss, *relocp);
1127 else
1128 *vec_grow(&ss->relocs, 1) = *relocp;
1132 struct supersect *make_section(struct superbfd *sbfd, const char *name)
1134 asection *sect = bfd_get_section_by_name(sbfd->abfd, name);
1135 if (sect != NULL)
1136 return fetch_supersect(sbfd, sect);
1137 else
1138 return new_supersect(sbfd, name);
1141 arelent *create_reloc(struct supersect *ss, const void *addr, asymbol **symp,
1142 bfd_vma offset)
1144 bfd_reloc_code_real_type code;
1145 switch (bfd_arch_bits_per_address(ss->parent->abfd)) {
1146 case 32:
1147 code = BFD_RELOC_32;
1148 break;
1149 case 64:
1150 code = BFD_RELOC_64;
1151 break;
1152 default:
1153 DIE;
1156 arelent *reloc = malloc(sizeof(*reloc));
1157 reloc->sym_ptr_ptr = symp;
1158 reloc->address = addr_offset(ss, addr);
1159 reloc->howto = bfd_reloc_type_lookup(ss->parent->abfd, code);
1160 reloc->addend = offset;
1161 return reloc;
1164 void write_reloc(struct supersect *ss, const void *addr, asymbol **symp,
1165 bfd_vma offset)
1167 arelent *new_reloc = create_reloc(ss, addr, symp, offset), **relocp;
1168 for (relocp = ss->relocs.data;
1169 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1170 if ((*relocp)->address == new_reloc->address) {
1171 memmove(relocp,
1172 relocp + 1,
1173 (void *)(ss->relocs.data + ss->relocs.size) -
1174 (void *)(relocp + 1));
1175 ss->relocs.size--;
1176 relocp--;
1179 *vec_grow(&ss->new_relocs, 1) = new_reloc;
1182 void write_string(struct supersect *ss, const char **addr, const char *fmt, ...)
1184 va_list ap;
1185 struct supersect *str_ss = make_section(ss->parent, ".ksplice_str");
1186 char *str;
1187 va_start(ap, fmt);
1188 int len = vasprintf(&str, fmt, ap);
1189 assert(len >= 0);
1190 va_end(ap);
1192 unsigned long *str_offp = ulong_hash_lookup(&ksplice_string_offset, str,
1193 FALSE);
1194 if (str_offp == NULL) {
1195 char *buf = sect_grow(str_ss, len + 1, char);
1196 memcpy(buf, str, len + 1);
1197 str_offp = ulong_hash_lookup(&ksplice_string_offset, str, TRUE);
1198 *str_offp = addr_offset(str_ss, buf);
1201 write_reloc(ss, addr, &str_ss->symbol, *str_offp);
1204 void lookup_system_map(struct addr_vec *addrs, const char *name, long offset)
1206 struct addr_vec *map_addrs =
1207 addr_vec_hash_lookup(&system_map, name, FALSE);
1208 if (map_addrs == NULL)
1209 return;
1211 unsigned long *addr, *map_addr;
1212 for (map_addr = map_addrs->data;
1213 map_addr < map_addrs->data + map_addrs->size; map_addr++) {
1214 for (addr = addrs->data; addr < addrs->data + addrs->size;
1215 addr++) {
1216 if (*addr == *map_addr + offset)
1217 break;
1219 if (addr < addrs->data + addrs->size)
1220 continue;
1221 *vec_grow(addrs, 1) = *map_addr + offset;
1225 void write_system_map_array(struct superbfd *sbfd, struct supersect *ss,
1226 const unsigned long **sym_addrs,
1227 unsigned long *num_sym_addrs, asymbol *sym)
1229 struct addr_vec addrs;
1230 vec_init(&addrs);
1232 if (bfd_is_abs_section(sym->section)) {
1233 *vec_grow(&addrs, 1) = sym->value;
1234 } else if (bfd_is_und_section(sym->section)) {
1235 lookup_system_map(&addrs, sym->name, 0);
1236 } else if (!bfd_is_const_section(sym->section)) {
1237 asymbol **gsymp;
1238 for (gsymp = sbfd->syms.data;
1239 gsymp < sbfd->syms.data + sbfd->syms.size; gsymp++) {
1240 asymbol *gsym = *gsymp;
1241 if ((gsym->flags & BSF_DEBUGGING) == 0 &&
1242 gsym->section == sym->section)
1243 lookup_system_map(&addrs, gsym->name,
1244 sym->value - gsym->value);
1248 *num_sym_addrs = addrs.size;
1249 if (addrs.size != 0) {
1250 struct supersect *array_ss = make_section(sbfd,
1251 ".ksplice_array");
1252 void *buf = sect_grow(array_ss, addrs.size,
1253 typeof(*addrs.data));
1254 memcpy(buf, addrs.data, addrs.size * sizeof(*addrs.data));
1255 write_reloc(ss, sym_addrs, &array_ss->symbol,
1256 addr_offset(array_ss, buf));
1257 } else {
1258 *sym_addrs = NULL;
1261 vec_free(&addrs);
1264 void write_ksplice_system_map(struct superbfd *sbfd, asymbol *sym,
1265 const char *addstr_sect)
1267 struct supersect *smap_ss = make_section(sbfd, ".ksplice_system_map");
1268 struct ksplice_system_map *smap;
1269 const char *label = label_lookup(sbfd, sym);
1271 bool *done = bool_hash_lookup(&system_map_written, label, TRUE);
1272 if (*done)
1273 return;
1274 *done = true;
1276 smap = sect_grow(smap_ss, 1, struct ksplice_system_map);
1278 write_system_map_array(sbfd, smap_ss, &smap->candidates,
1279 &smap->nr_candidates, sym);
1280 write_string(smap_ss, &smap->label, "%s%s", label, addstr_sect);
1283 void write_ksplice_symbol(struct supersect *ss,
1284 const struct ksplice_symbol *const *addr,
1285 asymbol *sym, struct span *span,
1286 const char *addstr_sect)
1288 struct supersect *ksymbol_ss = make_section(ss->parent,
1289 ".ksplice_symbols");
1290 struct ksplice_symbol *ksymbol;
1291 unsigned long *ksymbol_offp;
1292 const char *label;
1293 char *output;
1294 if (span != NULL && span->start != 0)
1295 label = span->label;
1296 else
1297 label = label_lookup(ss->parent, sym);
1298 assert(asprintf(&output, "%s%s", label, addstr_sect) >= 0);
1300 ksymbol_offp = ulong_hash_lookup(&ksplice_symbol_offset, output, FALSE);
1301 if (ksymbol_offp != NULL) {
1302 write_reloc(ss, addr, &ksymbol_ss->symbol, *ksymbol_offp);
1303 return;
1305 ksymbol = sect_grow(ksymbol_ss, 1, struct ksplice_symbol);
1306 ksymbol_offp = ulong_hash_lookup(&ksplice_symbol_offset, output, TRUE);
1307 *ksymbol_offp = addr_offset(ksymbol_ss, ksymbol);
1309 write_reloc(ss, addr, &ksymbol_ss->symbol, *ksymbol_offp);
1310 write_string(ksymbol_ss, &ksymbol->label, "%s", output);
1312 if (span != NULL && span->symbol == NULL) {
1313 ksymbol->name = NULL;
1314 return;
1317 write_ksplice_system_map(ksymbol_ss->parent, sym, addstr_sect);
1319 if (bfd_is_und_section(sym->section) || (sym->flags & BSF_GLOBAL) != 0) {
1320 write_string(ksymbol_ss, &ksymbol->name, "%s", sym->name);
1321 } else if (bfd_is_const_section(sym->section)) {
1322 ksymbol->name = NULL;
1323 } else {
1324 asymbol *gsym = canonical_symbol(ss->parent, sym);
1326 if (gsym == NULL || (gsym->flags & BSF_SECTION_SYM) != 0)
1327 ksymbol->name = NULL;
1328 else
1329 write_string(ksymbol_ss, &ksymbol->name, "%s",
1330 gsym->name);
1334 void write_ksplice_reloc(struct supersect *ss, arelent *orig_reloc)
1336 asymbol *sym_ptr = *orig_reloc->sym_ptr_ptr;
1337 reloc_howto_type *howto = orig_reloc->howto;
1338 bfd_vma addend = get_reloc_offset(ss, orig_reloc, false);
1340 if (mode("finalize") && starts_with(ss->name, ".ksplice_patches")) {
1341 unsigned long *repladdr =
1342 ss->contents.data + orig_reloc->address;
1343 *repladdr = 0;
1344 return;
1347 struct span *span = reloc_target_span(ss, orig_reloc);
1348 if (span == ss->spans.data && span->start != addend)
1349 span = NULL;
1350 blot_section(ss, orig_reloc->address, howto);
1352 struct supersect *kreloc_ss = make_section(ss->parent,
1353 mode("rmsyms") ?
1354 ".ksplice_init_relocs" :
1355 ".ksplice_relocs");
1356 struct ksplice_reloc *kreloc = sect_grow(kreloc_ss, 1,
1357 struct ksplice_reloc);
1359 write_reloc(kreloc_ss, &kreloc->blank_addr,
1360 &ss->symbol, orig_reloc->address);
1361 write_ksplice_symbol(kreloc_ss, &kreloc->symbol, sym_ptr, span, "");
1362 kreloc->pcrel = howto->pc_relative;
1363 if (span != NULL && span->start != 0)
1364 addend += sym_ptr->value - span->start;
1365 kreloc->addend = addend;
1366 kreloc->size = bfd_get_reloc_size(howto);
1367 kreloc->dst_mask = howto->dst_mask;
1368 kreloc->rightshift = howto->rightshift;
1369 kreloc->signed_addend =
1370 (howto->complain_on_overflow == complain_overflow_signed) ||
1371 (howto->complain_on_overflow == complain_overflow_bitfield);
1374 #define CANARY(x, canary) ((x & ~howto->dst_mask) | (canary & howto->dst_mask))
1376 void blot_section(struct supersect *ss, int offset, reloc_howto_type *howto)
1378 int bits = bfd_get_reloc_size(howto) * 8;
1379 void *address = ss->contents.data + offset;
1380 bfd_vma x = bfd_get(bits, ss->parent->abfd, address);
1381 x = (x & ~howto->dst_mask) |
1382 ((bfd_vma)KSPLICE_CANARY & howto->dst_mask);
1383 bfd_put(bits, ss->parent->abfd, x, address);
1386 void write_ksplice_section(struct superbfd *sbfd, asymbol **symp,
1387 struct span *span)
1389 asymbol *sym = span->symbol == NULL ? *symp : span->symbol;
1390 struct supersect *ksect_ss = make_section(sbfd, ".ksplice_sections");
1391 struct ksplice_section *ksect = sect_grow(ksect_ss, 1,
1392 struct ksplice_section);
1394 write_ksplice_symbol(ksect_ss, &ksect->symbol, sym, span,
1395 mode("keep-primary") ? "(post)" : "");
1396 ksect->size = span->size;
1397 ksect->flags = 0;
1398 struct supersect *sym_ss = fetch_supersect(sbfd, sym->section);
1399 if (sym_ss->type == SS_TYPE_RODATA || sym_ss->type == SS_TYPE_STRING)
1400 ksect->flags |= KSPLICE_SECTION_RODATA;
1401 if (sym_ss->type == SS_TYPE_DATA)
1402 ksect->flags |= KSPLICE_SECTION_DATA;
1403 if (sym_ss->type == SS_TYPE_TEXT)
1404 ksect->flags |= KSPLICE_SECTION_TEXT;
1405 assert(ksect->flags != 0);
1406 write_reloc(ksect_ss, &ksect->address, symp, span->start + span->shift);
1409 void write_ksplice_patch(struct superbfd *sbfd, const char *sectname)
1411 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
1412 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
1413 struct ksplice_patch);
1414 asection *sect = bfd_get_section_by_name(sbfd->abfd, sectname);
1415 assert(sect != NULL);
1417 write_string(kpatch_ss, &kpatch->label, "%s",
1418 label_lookup(sbfd, sect->symbol));
1419 write_reloc(kpatch_ss, &kpatch->repladdr, &sect->symbol, 0);
1422 void write_ksplice_deleted_patch(struct superbfd *sbfd, const char *name,
1423 const char *label)
1425 struct supersect *kpatch_ss = make_section(sbfd, ".ksplice_patches");
1426 struct ksplice_patch *kpatch = sect_grow(kpatch_ss, 1,
1427 struct ksplice_patch);
1429 write_string(kpatch_ss, &kpatch->label, "%s", label);
1430 asymbol **symp;
1431 for (symp = sbfd->syms.data; symp < sbfd->syms.data + sbfd->syms.size;
1432 symp++) {
1433 asymbol *sym = *symp;
1434 if (bfd_is_und_section(sym->section) &&
1435 strcmp(name, sym->name) == 0)
1436 break;
1438 if (symp >= sbfd->syms.data + sbfd->syms.size) {
1439 symp = malloc(sizeof(*symp));
1440 *symp = bfd_make_empty_symbol(sbfd->abfd);
1441 asymbol *sym = *symp;
1442 sym->name = strdup(name);
1443 sym->section = bfd_und_section_ptr;
1444 sym->flags = 0;
1445 sym->value = 0;
1446 *vec_grow(&sbfd->new_syms, 1) = symp;
1448 write_reloc(kpatch_ss, &kpatch->repladdr, symp, 0);
1451 void write_ksplice_export(struct superbfd *sbfd, const char *symname,
1452 const char *export_type, bool del)
1454 struct supersect *export_ss = make_section(sbfd, ".ksplice_exports");
1455 struct ksplice_export *exp = sect_grow(export_ss, 1,
1456 struct ksplice_export);
1458 if (del) {
1459 write_string(export_ss, &exp->name, "%s", symname);
1460 write_string(export_ss, &exp->new_name, "DISABLED_%s_%s",
1461 symname, kid);
1462 } else {
1463 write_string(export_ss, &exp->new_name, "%s", symname);
1464 write_string(export_ss, &exp->name, "DISABLED_%s_%s", symname,
1465 kid);
1469 struct fixup_entry {
1470 bfd_vma offset;
1471 bool used;
1473 DECLARE_VEC_TYPE(struct fixup_entry, fixup_entry_vec);
1475 int compare_fixups(const void *aptr, const void *bptr)
1477 const struct fixup_entry *a = aptr, *b = bptr;
1478 if (a->offset < b->offset)
1479 return -1;
1480 else if (a->offset > b->offset)
1481 return 1;
1482 else
1483 return (int)a->used - (int)b->used;
1486 void filter_table_sections(struct superbfd *isbfd)
1488 struct supersect *tables_ss =
1489 fetch_supersect(offsets_sbfd,
1490 bfd_get_section_by_name(offsets_sbfd->abfd,
1491 ".ksplice_table_sections"));
1492 const struct table_section *ts;
1493 for (ts = tables_ss->contents.data;
1494 (void *)ts < tables_ss->contents.data + tables_ss->contents.size;
1495 ts++) {
1496 struct table_section s = *ts;
1497 s.sect = read_string(tables_ss, &ts->sect);
1498 s.other_sect = read_string(tables_ss, &ts->other_sect);
1499 filter_table_section(isbfd, &s);
1503 void filter_table_section(struct superbfd *sbfd, const struct table_section *s)
1505 asection *isection = bfd_get_section_by_name(sbfd->abfd, s->sect);
1506 if (isection == NULL)
1507 return;
1508 asection *fixup_sect = NULL;
1509 if (s->other_sect != NULL)
1510 fixup_sect = bfd_get_section_by_name(sbfd->abfd, s->other_sect);
1512 struct supersect *ss = fetch_supersect(sbfd, isection);
1513 if (ss->alignment < ffs(s->entry_align) - 1)
1514 ss->alignment = ffs(s->entry_align) - 1;
1516 struct supersect *fixup_ss = NULL;
1517 if (fixup_sect != NULL)
1518 fixup_ss = fetch_supersect(sbfd, fixup_sect);
1520 struct fixup_entry_vec fixups;
1521 vec_init(&fixups);
1523 void *entry;
1524 for (entry = ss->contents.data;
1525 entry < ss->contents.data + ss->contents.size;
1526 entry += s->entry_size) {
1527 asymbol *sym, *fixup_sym;
1528 read_reloc(ss, entry + s->addr_offset, sizeof(void *), &sym);
1530 struct span *span = new_span(sbfd, isection,
1531 addr_offset(ss, entry),
1532 s->entry_size);
1533 struct supersect *sym_ss = fetch_supersect(sbfd, sym->section);
1534 span->keep = sym_ss->keep;
1536 struct fixup_entry *f;
1537 if (fixup_sect != NULL) {
1538 bfd_vma fixup_offset =
1539 read_reloc(ss, entry + s->other_offset,
1540 sizeof(void *), &fixup_sym);
1541 if (fixup_sym->section == fixup_sect) {
1542 assert(fixup_offset < fixup_ss->contents.size);
1543 f = vec_grow(&fixups, 1);
1544 f->offset = fixup_offset;
1545 f->used = span->keep;
1550 if (fixup_sect == NULL)
1551 return;
1553 qsort(fixups.data, fixups.size, sizeof(*fixups.data), compare_fixups);
1554 *vec_grow(&fixups, 1) = (struct fixup_entry)
1555 { .offset = fixup_ss->contents.size, .used = false };
1557 struct fixup_entry *f;
1558 for (f = fixups.data; f < fixups.data + fixups.size - 1; f++) {
1559 struct span *span = new_span(sbfd, fixup_sect, f->offset,
1560 (f + 1)->offset - f->offset);
1561 span->keep = f->used;
1565 void keep_referenced_sections(struct superbfd *sbfd)
1567 asection *sect;
1568 struct supersect *ss, *sym_ss;
1569 struct span *address_span, *target_span;
1570 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
1571 ss = fetch_supersect(sbfd, sect);
1572 arelent **relocp;
1573 if (ss->type == SS_TYPE_SPECIAL || ss->type == SS_TYPE_EXPORT)
1574 continue;
1575 for (relocp = ss->relocs.data;
1576 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1577 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1578 address_span = reloc_address_span(ss, *relocp);
1579 if (!address_span->keep)
1580 continue;
1581 target_span = reloc_target_span(ss, *relocp);
1582 if (target_span == NULL || target_span->keep)
1583 continue;
1584 sym_ss = fetch_supersect(sbfd, sym->section);
1585 if (sym_ss->type == SS_TYPE_IGNORED)
1586 continue;
1587 target_span->keep = true;
1588 sym_ss->keep = true;
1589 changed = true;
1594 void copy_symbols(struct asymbolp_vec *osyms, struct asymbolpp_vec *isyms)
1596 asymbol ***sympp;
1597 for (sympp = isyms->data; sympp < isyms->data + isyms->size; sympp++)
1598 *vec_grow(osyms, 1) = **sympp;
1601 /* Modified function from GNU Binutils objcopy.c */
1602 bfd_boolean copy_object(bfd *ibfd, bfd *obfd)
1604 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
1606 bfd_vma start = bfd_get_start_address(ibfd);
1608 flagword flags = bfd_get_file_flags(ibfd);
1609 flags &= bfd_applicable_file_flags(obfd);
1611 assert(bfd_set_start_address(obfd, start)
1612 && bfd_set_file_flags(obfd, flags));
1614 enum bfd_architecture iarch = bfd_get_arch(ibfd);
1615 unsigned int imach = bfd_get_mach(ibfd);
1616 assert(bfd_set_arch_mach(obfd, iarch, imach));
1617 assert(bfd_set_format(obfd, bfd_get_format(ibfd)));
1619 /* BFD mandates that all output sections be created and sizes set before
1620 any output is done. Thus, we traverse all sections multiple times. */
1621 bfd_map_over_sections(ibfd, setup_section, obfd);
1623 struct supersect *new_supersects = fetch_superbfd(ibfd)->new_supersects;
1624 struct supersect *ss;
1625 for (ss = new_supersects; ss != NULL; ss = ss->next)
1626 setup_new_section(obfd, ss);
1628 /* Mark symbols used in output relocations so that they
1629 are kept, even if they are local labels or static symbols.
1631 Note we iterate over the input sections examining their
1632 relocations since the relocations for the output sections
1633 haven't been set yet. mark_symbols_used_in_relocations will
1634 ignore input sections which have no corresponding output
1635 section. */
1637 bfd_map_over_sections(ibfd, mark_symbols_used_in_relocations, NULL);
1638 for (ss = new_supersects; ss != NULL; ss = ss->next)
1639 ss_mark_symbols_used_in_relocations(ss);
1640 struct asymbolp_vec osyms;
1641 vec_init(&osyms);
1642 filter_symbols(ibfd, obfd, &osyms, &fetch_superbfd(ibfd)->syms);
1643 copy_symbols(&osyms, &fetch_superbfd(ibfd)->new_syms);
1645 bfd_set_symtab(obfd, osyms.data, osyms.size);
1647 /* This has to happen after the symbol table has been set. */
1648 bfd_map_over_sections(obfd, write_section, NULL);
1650 /* Allow the BFD backend to copy any private data it understands
1651 from the input BFD to the output BFD. This is done last to
1652 permit the routine to look at the filtered symbol table, which is
1653 important for the ECOFF code at least. */
1654 assert(bfd_copy_private_bfd_data(ibfd, obfd));
1656 return TRUE;
1659 /* Modified function from GNU Binutils objcopy.c */
1660 void setup_section(bfd *ibfd, asection *isection, void *obfdarg)
1662 struct superbfd *isbfd = fetch_superbfd(ibfd);
1663 struct supersect *ss = fetch_supersect(isbfd, isection);
1664 bfd *obfd = obfdarg;
1665 bfd_vma vma;
1667 if (!ss->keep)
1668 return;
1670 asection *osection = bfd_make_section_anyway(obfd, isection->name);
1671 assert(osection != NULL);
1673 osection->userdata = ss;
1674 bfd_set_section_flags(obfd, osection, ss->flags);
1675 ss->symbol = osection->symbol;
1676 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
1678 vma = bfd_section_vma(ibfd, isection);
1679 assert(bfd_set_section_vma(obfd, osection, vma));
1681 osection->lma = isection->lma;
1682 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
1683 osection->entsize = isection->entsize;
1684 osection->output_section = osection;
1685 osection->output_offset = 0;
1686 isection->output_section = osection;
1687 isection->output_offset = 0;
1688 return;
1691 void setup_new_section(bfd *obfd, struct supersect *ss)
1693 asection *osection = bfd_make_section_anyway(obfd, ss->name);
1694 assert(osection != NULL);
1695 bfd_set_section_flags(obfd, osection, ss->flags);
1697 osection->userdata = ss;
1698 ss->symbol = osection->symbol;
1699 assert(bfd_set_section_size(obfd, osection, ss->contents.size));
1700 assert(bfd_set_section_vma(obfd, osection, 0));
1702 osection->lma = 0;
1703 assert(bfd_set_section_alignment(obfd, osection, ss->alignment));
1704 osection->entsize = 0;
1705 osection->output_section = osection;
1706 osection->output_offset = 0;
1709 void write_section(bfd *obfd, asection *osection, void *arg)
1711 struct supersect *ss = osection->userdata;
1713 if ((ss->flags & SEC_GROUP) != 0 || ss->contents.size == 0)
1714 return;
1716 arelent **relocp;
1717 char *error_message;
1718 for (relocp = ss->new_relocs.data;
1719 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
1720 bfd_vma val;
1721 if (bfd_get_arch(obfd) == bfd_arch_arm)
1722 val = osection->use_rela_p ? 0 : (*relocp)->addend;
1723 else
1724 val = 0;
1725 bfd_put(bfd_get_reloc_size((*relocp)->howto) * 8, obfd, val,
1726 ss->contents.data + (*relocp)->address);
1727 if (bfd_install_relocation(obfd, *relocp, ss->contents.data,
1728 0, osection, &error_message) !=
1729 bfd_reloc_ok) {
1730 err(ss->parent, "ksplice: error installing reloc: %s",
1731 error_message);
1732 DIE;
1735 memcpy(vec_grow(&ss->relocs, ss->new_relocs.size), ss->new_relocs.data,
1736 ss->new_relocs.size * sizeof(*ss->new_relocs.data));
1738 bfd_set_reloc(obfd, osection,
1739 ss->relocs.size == 0 ? NULL : ss->relocs.data,
1740 ss->relocs.size);
1742 if (ss->flags & SEC_HAS_CONTENTS)
1743 assert(bfd_set_section_contents
1744 (obfd, osection, ss->contents.data, 0,
1745 ss->contents.size));
1748 /* Modified function from GNU Binutils objcopy.c
1750 * Mark all the symbols which will be used in output relocations with
1751 * the BSF_KEEP flag so that those symbols will not be stripped.
1753 * Ignore relocations which will not appear in the output file.
1755 void mark_symbols_used_in_relocations(bfd *abfd, asection *isection,
1756 void *ignored)
1758 struct superbfd *sbfd = fetch_superbfd(abfd);
1759 if (isection->output_section == NULL)
1760 return;
1762 struct supersect *ss = fetch_supersect(sbfd, isection);
1763 ss_mark_symbols_used_in_relocations(ss);
1766 void ss_mark_symbols_used_in_relocations(struct supersect *ss)
1768 /* Examine each symbol used in a relocation. If it's not one of the
1769 special bfd section symbols, then mark it with BSF_KEEP. */
1770 arelent **relocp;
1771 for (relocp = ss->relocs.data;
1772 relocp < ss->relocs.data + ss->relocs.size; relocp++) {
1773 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1774 if (!(bfd_is_const_section(sym->section) &&
1775 sym == sym->section->symbol))
1776 sym->flags |= BSF_KEEP;
1778 for (relocp = ss->new_relocs.data;
1779 relocp < ss->new_relocs.data + ss->new_relocs.size; relocp++) {
1780 asymbol *sym = *(*relocp)->sym_ptr_ptr;
1781 if (!(bfd_is_const_section(sym->section) &&
1782 sym == sym->section->symbol))
1783 sym->flags |= BSF_KEEP;
1787 static bool deleted_table_section_symbol(bfd *abfd, asymbol *sym)
1789 struct superbfd *sbfd = fetch_superbfd(abfd);
1790 if (bfd_is_const_section(sym->section))
1791 return false;
1792 struct supersect *ss = fetch_supersect(sbfd, sym->section);
1794 asymbol **symp;
1795 for (symp = ss->syms.data; symp < ss->syms.data + ss->syms.size; symp++) {
1796 if (sym == *symp)
1797 break;
1799 return symp >= ss->syms.data + ss->syms.size;
1802 /* Modified function from GNU Binutils objcopy.c
1804 * Choose which symbol entries to copy.
1805 * We don't copy in place, because that confuses the relocs.
1806 * Return the number of symbols to print.
1808 void filter_symbols(bfd *ibfd, bfd *obfd, struct asymbolp_vec *osyms,
1809 struct asymbolp_vec *isyms)
1811 asymbol **symp;
1812 struct superbfd *sbfd = fetch_superbfd(ibfd);
1813 for (symp = isyms->data; symp < isyms->data + isyms->size; symp++) {
1814 asymbol *sym = *symp;
1815 struct supersect *sym_ss = NULL;
1816 if (!bfd_is_const_section(sym->section))
1817 sym_ss = fetch_supersect(sbfd, sym->section);
1819 bool keep = false;
1821 if (mode("keep") && (sym->flags & BSF_GLOBAL) != 0 &&
1822 !(mode("keep-primary") && sym_ss != NULL && sym_ss->new))
1823 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
1825 if (mode("finalize") && (sym->flags & BSF_GLOBAL) != 0)
1826 sym->flags = (sym->flags & ~BSF_GLOBAL) | BSF_LOCAL;
1828 if ((sym->flags & BSF_KEEP) != 0 /* Used in relocation. */
1829 || ((sym->flags & BSF_SECTION_SYM) != 0 && sym_ss != NULL &&
1830 sym_ss->keep))
1831 keep = true;
1832 else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 &&
1833 sym_ss != NULL && sym_ss->keep)
1834 keep = true;
1835 else if (mode("keep-primary") &&
1836 starts_with(sym->section->name, "__ksymtab"))
1837 keep = true;
1839 if (deleted_table_section_symbol(ibfd, sym))
1840 keep = false;
1842 if (bfd_is_com_section(sym->section))
1843 keep = false;
1845 if (mode("rmsyms"))
1846 keep = !str_in_set(sym->name, &rmsyms);
1848 if (keep) {
1849 if (sym_ss != NULL && !sym_ss->keep) {
1850 err(sbfd, "Kept symbol %s in unkept section "
1851 "%s\n", sym->name, sym->section->name);
1852 DIE;
1854 *vec_grow(osyms, 1) = sym;
1859 void read_str_set(struct str_vec *strs)
1861 char *buf = NULL;
1862 size_t n = 0;
1863 assert(getline(&buf, &n, stdin) >= 0);
1864 vec_init(strs);
1865 char *saveptr;
1866 while (1) {
1867 char *str = strtok_r(buf, " \n", &saveptr);
1868 buf = NULL;
1869 if (str == NULL)
1870 break;
1871 *vec_grow(strs, 1) = str;
1875 bool str_in_set(const char *str, const struct str_vec *strs)
1877 const char **strp;
1878 for (strp = strs->data; strp < strs->data + strs->size; strp++) {
1879 if (strcmp(str, *strp) == 0)
1880 return true;
1882 return false;
1885 bool is_table_section(const char *name, bool consider_other)
1887 struct supersect *tables_ss =
1888 fetch_supersect(offsets_sbfd,
1889 bfd_get_section_by_name(offsets_sbfd->abfd,
1890 ".ksplice_table_sections"));
1891 const struct table_section *ts;
1892 for (ts = tables_ss->contents.data;
1893 (void *)ts < tables_ss->contents.data + tables_ss->contents.size;
1894 ts++) {
1895 if (strcmp(name, read_string(tables_ss, &ts->sect)) == 0)
1896 return true;
1897 const char *osect_name = read_string(tables_ss,
1898 &ts->other_sect);
1899 if (consider_other && osect_name != NULL &&
1900 strcmp(name, osect_name) == 0)
1901 return true;
1903 return false;
1906 enum supersect_type supersect_type(struct supersect *ss)
1908 if (starts_with(ss->name, ".ksplice"))
1909 return SS_TYPE_KSPLICE;
1911 if (starts_with(ss->name, ".init"))
1912 return SS_TYPE_IGNORED;
1913 if (starts_with(ss->name, ".security_initcall.init"))
1914 return SS_TYPE_IGNORED;
1915 if (starts_with(ss->name, ".con_initcall.init"))
1916 return SS_TYPE_IGNORED;
1917 if (starts_with(ss->name, ".x86cpuvendor.init"))
1918 return SS_TYPE_IGNORED;
1919 if (starts_with(ss->name, ".early_param.init"))
1920 return SS_TYPE_IGNORED;
1921 if (starts_with(ss->name, ".taglist.init"))
1922 return SS_TYPE_IGNORED;
1923 if (starts_with(ss->name, ".arch.info.init"))
1924 return SS_TYPE_IGNORED;
1925 if (starts_with(ss->name, ".proc.info.init"))
1926 return SS_TYPE_IGNORED;
1927 /* .pci_fixup_* sections really should be treated as global rodata
1928 referenced only from quirks.c */
1929 if (starts_with(ss->name, ".pci_fixup_"))
1930 return SS_TYPE_IGNORED;
1931 /* .builtin_fw sections are similar to .pci_fixup */
1932 if (starts_with(ss->name, ".builtin_fw"))
1933 return SS_TYPE_IGNORED;
1934 /* same for .tracedata */
1935 if (starts_with(ss->name, ".tracedata"))
1936 return SS_TYPE_IGNORED;
1937 if (starts_with(ss->name, ".debug"))
1938 return SS_TYPE_IGNORED;
1939 /* .eh_frame should probably be discarded, not ignored */
1940 if (starts_with(ss->name, ".eh_frame"))
1941 return SS_TYPE_IGNORED;
1942 if (config->ignore_devinit && starts_with(ss->name, ".devinit"))
1943 return SS_TYPE_IGNORED;
1944 if (config->ignore_meminit && starts_with(ss->name, ".meminit"))
1945 return SS_TYPE_IGNORED;
1946 if (config->ignore_cpuinit && starts_with(ss->name, ".cpuinit"))
1947 return SS_TYPE_IGNORED;
1948 if (config->ignore_devinit && starts_with(ss->name, ".devexit"))
1949 return SS_TYPE_IGNORED;
1950 if (config->ignore_meminit && starts_with(ss->name, ".memexit"))
1951 return SS_TYPE_IGNORED;
1952 if (config->ignore_cpuinit && starts_with(ss->name, ".cpuexit"))
1953 return SS_TYPE_IGNORED;
1954 if (starts_with(ss->name, ".vgetcpu_mode") ||
1955 starts_with(ss->name, ".jiffies") ||
1956 starts_with(ss->name, ".wall_jiffies") ||
1957 starts_with(ss->name, ".vxtime") ||
1958 starts_with(ss->name, ".sys_tz") ||
1959 starts_with(ss->name, ".sysctl_vsyscall") ||
1960 starts_with(ss->name, ".xtime") ||
1961 starts_with(ss->name, ".xtime_lock") ||
1962 starts_with(ss->name, ".vsyscall"))
1963 return SS_TYPE_IGNORED;
1964 if (starts_with(ss->name, ".vdso"))
1965 return SS_TYPE_IGNORED;
1967 if (bfd_get_section_by_name(ss->parent->abfd, ".exitcall.exit") == NULL) {
1968 if (starts_with(ss->name, ".exit.text"))
1969 return SS_TYPE_TEXT;
1970 if (starts_with(ss->name, ".exit.data"))
1971 return SS_TYPE_DATA;
1972 } else if (starts_with(ss->name, ".exit.text") ||
1973 starts_with(ss->name, ".exit.data"))
1974 return SS_TYPE_IGNORED;
1976 if (starts_with(ss->name, ".text") ||
1977 starts_with(ss->name, ".kernel.text") ||
1978 starts_with(ss->name, ".devinit.text") ||
1979 starts_with(ss->name, ".meminit.text") ||
1980 starts_with(ss->name, ".cpuinit.text") ||
1981 starts_with(ss->name, ".devexit.text") ||
1982 starts_with(ss->name, ".memexit.text") ||
1983 starts_with(ss->name, ".cpuexit.text") ||
1984 starts_with(ss->name, ".ref.text") ||
1985 starts_with(ss->name, ".spinlock.text") ||
1986 starts_with(ss->name, ".kprobes.text") ||
1987 starts_with(ss->name, ".sched.text"))
1988 return SS_TYPE_TEXT;
1990 int n = -1;
1991 if (sscanf(ss->name, ".rodata.str%*u.%*u%n", &n) >= 0 &&
1992 n == strlen(ss->name))
1993 return SS_TYPE_STRING;
1995 if (starts_with(ss->name, ".rodata") ||
1996 starts_with(ss->name, ".kernel.rodata") ||
1997 starts_with(ss->name, ".devinit.rodata") ||
1998 starts_with(ss->name, ".meminit.rodata") ||
1999 starts_with(ss->name, ".cpuinit.rodata") ||
2000 starts_with(ss->name, ".devexit.rodata") ||
2001 starts_with(ss->name, ".memexit.rodata") ||
2002 starts_with(ss->name, ".cpuexit.rodata") ||
2003 starts_with(ss->name, ".ref.rodata") ||
2004 starts_with(ss->name, "__markers_strings"))
2005 return SS_TYPE_RODATA;
2007 if (starts_with(ss->name, ".bss"))
2008 return SS_TYPE_DATA;
2010 /* Ignore .data.percpu sections */
2011 if (starts_with(ss->name, ".data.percpu") ||
2012 starts_with(ss->name, ".kernel.data.percpu"))
2013 return SS_TYPE_IGNORED;
2014 if (starts_with(ss->name, ".data") ||
2015 starts_with(ss->name, ".kernel.data") ||
2016 starts_with(ss->name, ".devinit.data") ||
2017 starts_with(ss->name, ".cpuinit.data") ||
2018 starts_with(ss->name, ".meminit.data") ||
2019 starts_with(ss->name, ".devexit.data") ||
2020 starts_with(ss->name, ".memexit.data") ||
2021 starts_with(ss->name, ".cpuexit.data") ||
2022 starts_with(ss->name, ".ref.data") ||
2023 starts_with(ss->name, "__markers"))
2024 return SS_TYPE_DATA;
2026 if (starts_with(ss->name, "__ksymtab"))
2027 return SS_TYPE_EXPORT;
2028 if (starts_with(ss->name, "__kcrctab"))
2029 return SS_TYPE_EXPORT;
2031 if (is_table_section(ss->name, true))
2032 return SS_TYPE_SPECIAL;
2034 if (starts_with(ss->name, ".ARM."))
2035 return SS_TYPE_SPECIAL;
2037 if (starts_with(ss->name, ".note"))
2038 return SS_TYPE_IGNORED;
2039 if (starts_with(ss->name, ".comment"))
2040 return SS_TYPE_IGNORED;
2041 if (starts_with(ss->name, "__param"))
2042 return SS_TYPE_IGNORED;
2043 if (starts_with(ss->name, ".exitcall.exit"))
2044 return SS_TYPE_IGNORED;
2045 if (starts_with(ss->name, ".modinfo"))
2046 return SS_TYPE_IGNORED;
2048 return SS_TYPE_UNKNOWN;
2051 void initialize_supersect_types(struct superbfd *sbfd)
2053 asection *sect;
2054 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
2055 struct supersect *ss = fetch_supersect(sbfd, sect);
2056 ss->type = supersect_type(ss);
2057 if (ss->type == SS_TYPE_UNKNOWN) {
2058 err(sbfd, "Unknown section type: %s\n", ss->name);
2059 DIE;
2064 static void init_label_map(struct superbfd *sbfd)
2066 vec_init(&sbfd->maps);
2067 struct label_map *map, *map2;
2069 asymbol **symp;
2070 for (symp = sbfd->syms.data;
2071 symp < sbfd->syms.data + sbfd->syms.size; symp++) {
2072 asymbol *csym = canonical_symbol(sbfd, *symp);
2073 if (csym == NULL)
2074 continue;
2075 for (map = sbfd->maps.data;
2076 map < sbfd->maps.data + sbfd->maps.size; map++) {
2077 if (map->csym == csym)
2078 break;
2080 if (map < sbfd->maps.data + sbfd->maps.size)
2081 continue;
2082 map = vec_grow(&sbfd->maps, 1);
2083 map->csym = csym;
2084 map->count = 0;
2085 map->index = 0;
2086 map->label = symbol_label(sbfd, csym);
2088 for (map = sbfd->maps.data;
2089 map < sbfd->maps.data + sbfd->maps.size; map++) {
2090 for (map2 = sbfd->maps.data;
2091 map2 < sbfd->maps.data + sbfd->maps.size; map2++) {
2092 if (strcmp(map->label, map2->label) != 0)
2093 continue;
2094 map->count++;
2095 if (map2 < map)
2096 map->index++;
2100 for (map = sbfd->maps.data;
2101 map < sbfd->maps.data + sbfd->maps.size; map++) {
2102 if (map->count > 1) {
2103 char *buf;
2104 assert(asprintf(&buf, "%s~%d", map->label,
2105 map->index) >= 0);
2106 map->label = buf;
2108 map->orig_label = map->label;
2112 static const char *label_lookup(struct superbfd *sbfd, asymbol *sym)
2114 struct label_map *map;
2115 asymbol *csym = canonical_symbol(sbfd, sym);
2116 for (map = sbfd->maps.data;
2117 map < sbfd->maps.data + sbfd->maps.size; map++) {
2118 if (csym == map->csym)
2119 return map->label;
2121 return symbol_label(sbfd, sym);
2124 static void print_label_map(struct superbfd *sbfd)
2126 struct label_map *map;
2127 for (map = sbfd->maps.data;
2128 map < sbfd->maps.data + sbfd->maps.size; map++) {
2129 if (strcmp(map->orig_label, map->label) == 0)
2130 continue;
2131 debug1(sbfd, "Label change: %s -> %s\n",
2132 map->label, map->orig_label);
2136 static void label_map_set(struct superbfd *sbfd, const char *oldlabel,
2137 const char *label)
2139 struct label_map *map;
2140 for (map = sbfd->maps.data;
2141 map < sbfd->maps.data + sbfd->maps.size; map++) {
2142 if (strcmp(map->orig_label, oldlabel) == 0) {
2143 if (strcmp(map->orig_label, map->label) != 0 &&
2144 strcmp(map->label, label) != 0)
2145 DIE;
2146 map->label = label;
2147 return;
2150 DIE;
2153 static struct span *new_span(struct superbfd *sbfd, asection *sect,
2154 bfd_vma start, bfd_vma size)
2156 struct supersect *ss = fetch_supersect(sbfd, sect);
2157 struct span *span = vec_grow(&ss->spans, 1);
2158 span->size = size;
2159 span->start = start;
2160 span->ss = ss;
2161 span->keep = false;
2162 span->new = false;
2163 span->shift = 0;
2164 asymbol **symp = symbolp_scan(sbfd, sect, span->start);
2165 if (symp != NULL) {
2166 span->symbol = *symp;
2167 span->label = label_lookup(sbfd, span->symbol);
2168 } else {
2169 span->symbol = NULL;
2170 const char *label = label_lookup(sbfd, sect->symbol);
2171 if (span->start != 0) {
2172 char *buf;
2173 assert(asprintf(&buf, "%s<span:%lx>", label,
2174 (unsigned long)span->start) >= 0);
2175 span->label = buf;
2176 } else {
2177 span->label = label;
2180 return span;
2183 static void initialize_string_spans(struct superbfd *sbfd, asection *sect)
2185 struct supersect *ss = fetch_supersect(sbfd, sect);
2186 const char *str;
2187 for (str = ss->contents.data;
2188 (void *)str < ss->contents.data + ss->contents.size;) {
2189 bfd_vma start = (unsigned long)str -
2190 (unsigned long)ss->contents.data;
2191 bfd_vma size = strlen(str) + 1;
2192 while ((start + size) % (1 << ss->alignment) != 0 &&
2193 start + size < ss->contents.size) {
2194 if (str[size] != '\0')
2195 DIE;
2196 size++;
2198 new_span(sbfd, sect, start, size);
2199 str += size;
2203 static void initialize_spans(struct superbfd *sbfd)
2205 asection *sect;
2206 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
2207 struct supersect *ss = fetch_supersect(sbfd, sect);
2208 if (ss->type == SS_TYPE_STRING)
2209 initialize_string_spans(sbfd, sect);
2210 else if (ss->type != SS_TYPE_SPECIAL &&
2211 ss->type != SS_TYPE_EXPORT)
2212 new_span(sbfd, sect, 0, ss->contents.size);
2216 struct span *reloc_target_span(struct supersect *ss, arelent *reloc)
2218 asymbol *sym_ptr = *reloc->sym_ptr_ptr;
2219 if (bfd_is_const_section(sym_ptr->section))
2220 return NULL;
2222 bfd_vma addend = get_reloc_offset(ss, reloc, true) + sym_ptr->value;
2223 struct supersect *sym_ss =
2224 fetch_supersect(ss->parent, sym_ptr->section);
2225 struct span *span, *target_span = sym_ss->spans.data;
2226 for (span = sym_ss->spans.data;
2227 span < sym_ss->spans.data + sym_ss->spans.size; span++) {
2228 if (addend >= span->start && addend < span->start + span->size)
2229 target_span = span;
2231 return target_span;
2234 struct span *reloc_address_span(struct supersect *ss, arelent *reloc)
2236 struct span *span;
2237 for (span = ss->spans.data; span < ss->spans.data + ss->spans.size;
2238 span++) {
2239 if (reloc->address >= span->start &&
2240 reloc->address < span->start + span->size)
2241 return span;
2243 return NULL;
2246 void compute_span_shifts(struct superbfd *sbfd)
2248 asection *sect;
2249 struct span *span;
2250 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
2251 struct supersect *ss = fetch_supersect(sbfd, sect);
2252 if (!ss->keep || ss->type == SS_TYPE_EXPORT)
2253 continue;
2254 bfd_size_type offset = 0;
2255 for (span = ss->spans.data;
2256 span < ss->spans.data + ss->spans.size; span++) {
2257 if (!span->keep)
2258 continue;
2259 span->shift = offset - span->start;
2260 offset += span->size;
2265 void remove_unkept_spans(struct superbfd *sbfd)
2267 asection *sect;
2268 struct span *span;
2269 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
2270 struct supersect *ss = fetch_supersect(sbfd, sect);
2271 if (ss->type == SS_TYPE_EXPORT)
2272 continue;
2273 struct arelentp_vec orig_relocs;
2274 vec_move(&orig_relocs, &ss->relocs);
2275 arelent **relocp, *reloc;
2276 for (relocp = orig_relocs.data;
2277 relocp < orig_relocs.data + orig_relocs.size; relocp++) {
2278 reloc = *relocp;
2279 asymbol *sym = *reloc->sym_ptr_ptr;
2280 span = reloc_target_span(ss, reloc);
2281 if ((span != NULL && span->keep && span->shift == 0) ||
2282 bfd_is_const_section(sym->section)) {
2283 *vec_grow(&ss->relocs, 1) = reloc;
2284 continue;
2286 if (span != NULL && span->keep) {
2287 arelent *new_reloc = malloc(sizeof(*new_reloc));
2288 *new_reloc = *reloc;
2289 new_reloc->addend =
2290 get_reloc_offset(ss, reloc, false);
2291 new_reloc->addend += span->shift;
2292 *vec_grow(&ss->new_relocs, 1) = new_reloc;
2297 for (sect = sbfd->abfd->sections; sect != NULL; sect = sect->next) {
2298 struct supersect *ss = fetch_supersect(sbfd, sect), orig_ss;
2299 if (!ss->keep || ss->type == SS_TYPE_EXPORT)
2300 continue;
2301 supersect_move(&orig_ss, ss);
2302 vec_init(&ss->spans);
2303 for (span = orig_ss.spans.data;
2304 span < orig_ss.spans.data + orig_ss.spans.size; span++) {
2305 if (!span->keep)
2306 continue;
2307 struct span *new_span = vec_grow(&ss->spans, 1);
2308 *new_span = *span;
2309 new_span->start = span->start + span->shift;
2310 new_span->shift = 0;
2311 sect_copy(ss, sect_do_grow(ss, 1, span->size, 1),
2312 &orig_ss, orig_ss.contents.data + span->start,
2313 span->size);