bfd_boolean plugin_should_reload (bfd *abfd) { return ((abfd->flags & DYNAMIC) != 0 && bfd_get_flavour (abfd) == bfd_target_elf_flavour && bfd_get_format (abfd) == bfd_object && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0); }
main (int argc, char **argv) { bfd *ibfd, *obfd; asection *p; static asymbol **osympp, **delsympp; long symsize, symcount, delsymcount; int i; int c; int idx; struct add_reloc_struct *new_reloc; struct change_reloc_struct *new_change; struct delete_reloc_struct *new_delete; struct modify_byte_struct *new_modify; struct globalize_sym_struct *new_globalize; while ((c = getopt (argc, argv, "a:d:c:m:G:")) != -1) { switch (c) { case 'a': /* check to see if we have two args: name and loc */ if ((index(optarg, ',') == NULL) || (index(optarg, ',') != rindex(optarg, ','))) { fprintf(stderr, "usage: -a argument should be <symbolname>,<location>, not \"%s\"\n", optarg); exit(1); } /* record the add reloc command in the global array */ new_reloc = (add_reloc_struct *)malloc(sizeof(add_reloc_struct)); new_reloc->symbol_name = strndup(optarg, (index(optarg, ',') - optarg)); new_reloc->loc = strtol(index(optarg, ',') + 1, NULL, 0); if (errno == EINVAL) { fprintf(stderr, "the value %s is not a valid location for the add command\n", index(optarg, ',') + 1); exit(1); } new_reloc->next = additional_relocs; additional_relocs = new_reloc; break; case 'c': /* check to see if we have two args */ if ((index(optarg, ',') == NULL) || (index(optarg, ',') != rindex(optarg, ','))) { fprintf(stderr, "usage: -c argument should be <symbolname>,<symbolname>, not \"%s\"\n", optarg); exit(1); } new_change = (change_reloc_struct *)malloc(sizeof(change_reloc_struct)); new_change->old_symbol_name = strndup(optarg, strlen(optarg) - strlen(index(optarg, ','))); new_change->new_symbol_name = strdup(index(optarg, ',') + 1); new_change->next = change_relocs; change_relocs = new_change; break; case 'd': new_delete = (delete_reloc_struct *)malloc(sizeof(delete_reloc_struct)); new_delete->symbol_name = strdup(optarg); new_delete->next = delete_relocs; delete_relocs = new_delete; break; case 'm': if ((index(optarg, '=') == NULL) || (index(optarg, '=') != rindex(optarg, '='))) { fprintf(stderr, "usage: -m argument should be <location>=<value>, not \"%s\"\n", optarg); exit(1); } new_modify = (modify_byte_struct *)malloc(sizeof(modify_byte_struct)); new_modify->location = strtol(optarg, NULL, 0); new_modify->value = strtol(index(optarg, '=') + 1, NULL, 0); if (new_modify->value > 0xff) { fprintf(stderr, "requested modify value %lx for location %lx exceeds 0xff\n", new_modify->value, new_modify->location); exit(1); } new_modify->next = modify_bytes; modify_bytes = new_modify; break; case 'G': new_globalize = (globalize_sym_struct *)malloc(sizeof(globalize_sym_struct)); new_globalize->symbol_name = strdup(optarg); new_globalize->next = globalize_syms; globalize_syms = new_globalize; break; default: fprintf(stderr, "unrecognized argument character |%c|\n", c); } } if ((argc - optind) != 2) { fprintf(stderr, "usage: fixup_relocs [-a newsymbol,location] [-c oldsymbol,newsymbol] [-d symbol] infile.o outfile.o\n"); exit(1); } ibfd = bfd_openr(argv[optind], NULL); if (ibfd == NULL) { bfd_perror("while opening input object file"); exit(1); } /* if I don't do "check_format", there's no data in the bfd object. wtf? */ if (!bfd_check_format(ibfd, bfd_object)) { fprintf(stderr, "input file %s seems to NOT be an object file! exiting.\n", argv[optind]); exit(1); } obfd = bfd_openw(argv[optind+1], bfd_get_target(ibfd)); if (obfd == NULL) { bfd_perror("while opening output object file"); exit(1); } if (!bfd_set_format(obfd, bfd_get_format(ibfd))) { bfd_perror("while setting output object file format"); } /* copy a bunch of necessary global stuff */ bfd_set_start_address(obfd, bfd_get_start_address(ibfd)); bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd)); bfd_set_arch_mach(obfd, bfd_get_arch(ibfd), bfd_get_mach(ibfd)); /* BOZO objcopy sets format again at this point. why? */ bfd_map_over_sections (ibfd, setup_section, obfd); setup_bfd_headers (ibfd, obfd); /* Symbol filtering must happen after the output sections have been created, but before their contents are set. */ symsize = bfd_get_symtab_upper_bound (ibfd); if (symsize < 0) { fprintf(stderr, "problem processing %s\n", bfd_get_filename (ibfd)); return FALSE; } /* count the added relocations so we can put extra space in the output symbol table for them */ int reloc_add_cnt, reloc_delete_cnt; reloc_add_cnt = 0; reloc_delete_cnt = 0; for (new_reloc = additional_relocs; new_reloc != NULL; new_reloc = new_reloc->next) { reloc_add_cnt++; } /* the "change" symbols might also not be in the symbol table yet */ for (new_change = change_relocs; new_change != NULL; new_change = new_change->next) { reloc_add_cnt++; /* the old symbol may be deleted, also */ reloc_delete_cnt++; } for (new_delete = delete_relocs; new_delete != NULL; new_delete = new_delete->next) { reloc_delete_cnt++; } /* filter symbol table in two steps: */ /* 1) move symbols bound for deletion to the end of the output symbol table array */ /* 2) truncate the table at the first of those */ /* this makes it possible to do the reloc processing with the symbol table intact, */ /* and remove the deleted symbols afterwards, without corrupting the reloc data structures */ isympp = malloc (symsize); osympp = malloc (symsize + reloc_add_cnt * sizeof(asymbol *)); delsympp = malloc (reloc_delete_cnt * sizeof(asymbol *)); symcount = bfd_canonicalize_symtab (ibfd, isympp); if (symcount < 0) { fprintf(stderr, "problem processing %s\n", bfd_get_filename (ibfd)); return FALSE; } /* remove any undefined symbols whose relocation entries were deleted or changed */ int osym_idx, delsym_idx; osym_idx = delsym_idx = 0; delsymcount = 0; for (i = 0; i < symcount; i++) { if ((is_delete_reloc(bfd_asymbol_name(isympp[i]), delete_relocs) || (find_change_reloc(bfd_asymbol_name(isympp[i]), change_relocs) != NULL)) && (isympp[i]->section != NULL) && (strcmp(isympp[i]->section->name, BFD_UND_SECTION_NAME) == 0)) { delsympp[delsym_idx++] = isympp[i]; } else { if (is_globalize_sym(bfd_asymbol_name(isympp[i]), globalize_syms)) { isympp[i]->flags = BSF_GLOBAL; } osympp[osym_idx++] = isympp[i]; } } symcount = osym_idx; delsymcount = delsym_idx; osympp[symcount] = NULL; /* add the symbols for additional relocs to the table */ int added_symbol_cnt = 0; for (new_reloc = additional_relocs; new_reloc != NULL; new_reloc = new_reloc->next) { if (find_symbol(osympp, new_reloc->symbol_name) < 0) { /* not yet present, so add it */ asymbol *new_sym; new_sym = bfd_make_empty_symbol(obfd); new_sym->name = strdup(new_reloc->symbol_name); new_sym->section = bfd_get_section_by_name (obfd, ".text"); new_sym->value = new_reloc->loc; new_sym->flags = BSF_GLOBAL; osympp[symcount + added_symbol_cnt++] = new_sym; osympp[symcount + added_symbol_cnt] = NULL; } } /* do the same for changed relocs */ for (new_change = change_relocs; new_change != NULL; new_change = new_change->next) { if (find_symbol(osympp, new_change->new_symbol_name) < 0) { /* not yet present, so add it */ /* since this is a name change, we will reuse the existing address (value field of reloc) */ int old_symbol_idx; if ((old_symbol_idx = find_symbol(isympp, new_change->old_symbol_name)) < 0) { fprintf(stderr, "change command old symbol name %s not found in symbol table! Exiting.\n", new_change->old_symbol_name); exit(1); } asymbol *new_sym; new_sym = bfd_make_empty_symbol(obfd); new_sym->name = strdup(new_change->new_symbol_name); new_sym->section = bfd_und_section_ptr; new_sym->value = isympp[old_symbol_idx]->value; new_sym->flags = BSF_GLOBAL; fprintf(stderr, "adding new symbol %s for change reloc command\n", new_sym->name); osympp[symcount + added_symbol_cnt++] = new_sym; osympp[symcount + added_symbol_cnt] = NULL; } } /* append the soon-to-be deleted symbols to the end of the output symbol table */ for (i = 0; i < delsymcount; i++) { osympp[symcount + added_symbol_cnt + i] = delsympp[i]; } osympp[symcount + added_symbol_cnt + delsymcount] = NULL; bfd_set_symtab (obfd, osympp, symcount + added_symbol_cnt + delsymcount); /* This has to happen after the symbol table has been set. */ bfd_map_over_sections (ibfd, copy_section_relocs_edit, obfd); /* now truncate the symbol table to eliminate the deleted symbols */ osympp[symcount + added_symbol_cnt] = NULL; bfd_set_symtab (obfd, osympp, symcount + added_symbol_cnt); /* now that we've set the relocs and cleaned the symtab, can call this */ bfd_map_over_sections (ibfd, copy_section_data, obfd); bfd_close(obfd); bfd_close(ibfd); return 0; }
void replace_hello(const char *input_path, const char *output_path) { bfd_init(); bfd *ibfd = bfd_openr(input_path, NULL); if (ibfd == NULL) errx(1, bfd_errmsg(bfd_get_error())); if (!bfd_check_format(ibfd, bfd_object)) { bfd_close_all_done(ibfd); errx(1, "Input file is not a valid object file."); } bfd *obfd = bfd_openw(output_path, bfd_get_target(ibfd)); if (obfd == NULL) { bfd_close_all_done(ibfd); errx(1, bfd_errmsg(bfd_get_error())); } if (!bfd_set_format(obfd, bfd_get_format(ibfd))) { bfd_close_all_done(ibfd); bfd_close_all_done(obfd); errx(1, "Setting obfd format failed: %s\n", bfd_errmsg(bfd_get_error())); } bfd_set_arch_info(obfd, bfd_get_arch_info(ibfd)); // Create sections for .data asection *section = bfd_get_section_by_name(ibfd, ".data"); while (section != NULL) { if (section->flags & SEC_HAS_CONTENTS) { char *section_contents = (char *)malloc(section->size); bfd_get_section_contents(ibfd, section, section_contents, 0, section->size); char *hello_pos = (char *)memmem(section_contents, section->size, "hello", 5); if (hello_pos != NULL) { if (bfd_make_section_anyway_with_flags(obfd, ".data", section->flags) == NULL) { free(section_contents); bfd_close_all_done(ibfd); bfd_close_all_done(obfd); errx(1, bfd_errmsg(bfd_get_error())); } } free(section_contents); } section = bfd_get_next_section_by_name(ibfd, section); } asection *comment_section = bfd_make_section_anyway_with_flags(obfd, ".comment.my_objcopy", SEC_HAS_CONTENTS); if (comment_section == NULL) { bfd_close_all_done(ibfd); bfd_close_all_done(obfd); errx(1, bfd_errmsg(bfd_get_error())); } if (!bfd_set_section_size(obfd, comment_section, 3)) { bfd_close_all_done(ibfd); bfd_close_all_done(obfd); errx(1, bfd_errmsg(bfd_get_error())); } if (!bfd_set_section_contents(obfd, comment_section, "moo", 0, 3)) { bfd_close_all_done(ibfd); bfd_close_all_done(obfd); errx(1, bfd_errmsg(bfd_get_error())); } // section = bfd_get_section_by_name(ibfd, ".data"); // asection *osection = bfd_get_section_by_name(obfd, ".data"); // if (osection == NULL) { // bfd_close_all_done(ibfd); // bfd_close_all_done(obfd); // errx(1, bfd_errmsg(bfd_get_error())); // } // while (section != NULL) { // if (section->flags & SEC_HAS_CONTENTS) { // char *section_contents = (char *)malloc(section->size); // bfd_get_section_contents(ibfd, section, section_contents, 0, section->size); // // char *hello_pos = (char *)memmem(section_contents, section->size, "hello", 5); // if (hello_pos != NULL) { // hello_pos[1] = 'o'; // hello_pos[4] = 'a'; // if (bfd_set_section_contents(obfd, osection, section_contents, 0, section->size)) { // free(section_contents); // bfd_close_all_done(ibfd); // bfd_close_all_done(obfd); // errx(1, bfd_errmsg(bfd_get_error())); // } // } // // free(section_contents); // osection = bfd_get_next_section_by_name(obfd, osection); // } // // section = bfd_get_next_section_by_name(ibfd, section); // } if (!bfd_close(obfd)) errx(1, "Closing obfd failed: %s\n", bfd_errmsg(bfd_get_error())); if (!bfd_close(ibfd)) errx(1, "Closing ibfd failed: %s\n", bfd_errmsg(bfd_get_error())); }
int main(int argc, char * argv[]) { bfd * bfd_in; bfd * bfd_out; char * filename_in; char * filename_out; log_init(PROGRAM_NAME, LOG_MESSAGE); atexit(log_fini); filename_in = NULL; filename_out = NULL; int c; // int digit_optind = 0; while (1) { // int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { { "input", 1, 0, 'i' }, { "output", 1, 0, 'o' }, { "debug", 0, 0, 'd' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; c = getopt_long(argc, argv, "i:o:dvVh", long_options, &option_index); if (c == -1) { break; } debug("Handling option character '%c'\n", c); switch (c) { case 'i': filename_in = optarg; break; case 'o': filename_out = optarg; break; case 'd': log_level(LOG_DEBUG); break; case 'v': log_level(LOG_VERBOSE); break; case 'V': version(PROGRAM_NAME); return 0; case 'h': help(); return 0; case '?': hint(PROGRAM_NAME, "Unrecognized option"); return 1; default: BUG(); return 1; } } if (!filename_in) { fatal("Missing input filename\n"); exit(EXIT_FAILURE); } if (!filename_out) { fatal("Missing output filename\n"); exit(EXIT_FAILURE); } /* XXX FIXME: Use stat instead of strcmp */ if (!strcmp(filename_in, filename_out)) { fatal("Input and output are the same file\n"); exit(EXIT_FAILURE); } bfd_init(); debug("Reading input file %s\n", filename_in); bfd_in = bfd_openr(filename_in, NULL); if (!bfd_in) { fatal("Cannot open input file %s (%s)\n", filename_in, BFD_strerror()); exit(EXIT_FAILURE); } if (!bfd_check_format(bfd_in, bfd_object)) { fatal("Wrong input file format (not an object)\n"); exit(EXIT_FAILURE); } bfd_out = bfd_openw(filename_out, NULL); if (!bfd_out) { fatal("Cannot open output file %s (%s)\n", filename_out, BFD_strerror()); exit(EXIT_FAILURE); } debug("Generating output file %s\n", filename_out); bfd_set_format(bfd_out, bfd_get_format(bfd_in)); if (bfd_copy_private_bfd_data(bfd_in, bfd_out) == FALSE) { fatal("Cannot copy private bfd data (%s)\n", BFD_strerror()); exit(EXIT_FAILURE); } if (bfd_copy_private_header_data(bfd_in, bfd_out) == FALSE) { fatal("Cannot copy private header data (%s)\n", BFD_strerror()); exit(EXIT_FAILURE); } bfd_close(bfd_in); bfd_close(bfd_out); exit(EXIT_SUCCESS); }