objcopy.c (27649B)
1 #include <kit/archive.h> 2 #include <kit/core.h> 3 #include <kit/image.h> 4 #include <kit/object.h> 5 #include <stdint.h> 6 #include <string.h> 7 8 #include "driver.h" 9 #include "objedit.h" 10 11 /* `kit objcopy` — copy + transform an object file. v1 scope is the 12 * high-traffic build-system subset called out in CTOOLCHAIN.md: 13 * 14 * --remove-section=NAME drop the named section 15 * --only-section=NAME drop every section except NAME (may repeat) 16 * --rename-section=OLD=NEW rename a section 17 * --redefine-sym=OLD=NEW rename a symbol 18 * --globalize-symbol=NAME promote a symbol to SB_GLOBAL 19 * --localize-symbol=NAME demote a symbol to SB_LOCAL 20 * --weaken-symbol=NAME flip a symbol to SB_WEAK 21 * --strip-debug drop KIT_SEC_DEBUG sections 22 * --strip-all drop debug + every non-essential symbol 23 * --strip-unneeded drop debug + symbols not needed by relocs 24 * --add-section=NAME=FILE append a new section with FILE's bytes 25 * --update-section=NAME=FILE replace NAME's bytes with FILE's bytes 26 * -O <bfdname> emit in a different object format 27 * 28 * Linked ELF (ET_EXEC / ET_DYN) input is out of scope for v1. 29 * 30 * Usage: kit objcopy [OPTIONS] INPUT [OUTPUT] 31 * If OUTPUT is omitted, INPUT is rewritten in place. */ 32 33 #define OBJCOPY_TOOL "objcopy" 34 35 void driver_help_objcopy(void) { 36 driver_printf( 37 "%.*s", 38 KIT_SLICE_ARG(KIT_SLICE_LIT( 39 "kit objcopy — copy and transform an object file\n" 40 "\n" 41 "USAGE\n" 42 " kit objcopy [OPTIONS] INPUT [OUTPUT]\n" 43 "\n" 44 "DESCRIPTION\n" 45 " Copies an object while transforming its sections, symbols, strip\n" 46 " policy, or output format. If OUTPUT is omitted, INPUT is replaced\n" 47 " in place.\n" 48 "\n" 49 "OPTIONS\n" 50 " -h, --help Show this help and exit\n" 51 "\n" 52 "OUTPUT\n" 53 " With OUTPUT, write a separate file. If OUTPUT is omitted, INPUT\n" 54 " is rewritten in place; name an OUTPUT while evaluating a\n" 55 " transform so the original remains available for comparison.\n" 56 "\n" 57 "SECTION OPS\n" 58 " --remove-section=NAME drop section NAME (may repeat)\n" 59 " --only-section=NAME keep only section NAME (may repeat)\n" 60 " --rename-section=OLD=NEW rename section OLD to NEW\n" 61 " --add-section=NAME=FILE append a new section with FILE's " 62 "bytes\n" 63 " --update-section=NAME=FILE replace NAME's bytes with FILE's " 64 "bytes\n" 65 "\n" 66 "SYMBOL OPS\n" 67 " --redefine-sym=OLD=NEW rename a symbol (may repeat)\n" 68 " --globalize-symbol=NAME set NAME's binding to global\n" 69 " --localize-symbol=NAME set NAME's binding to local\n" 70 " --weaken-symbol=NAME set NAME's binding to weak\n" 71 "\n" 72 "STRIP OPS\n" 73 " --strip-debug, --strip-unneeded, --strip-all\n" 74 " same semantics as `kit strip`\n" 75 "\n" 76 "FORMAT\n" 77 " -O BFDNAME emit as a different format. " 78 "Recognized\n" 79 " names: elf*, mach-o / macho*, coff*, " 80 "wasm*, binary, ihex, srec\n" 81 "\n" 82 " Binary, IHEX, and SREC use load segments from linked images and\n" 83 " allocated section contents from relocatable objects. Unapplied\n" 84 " relocations in selected sections are rejected. --only-section\n" 85 " and --remove-section select the ranges to emit.\n" 86 "\n" 87 "EXAMPLES\n" 88 " kit objcopy --strip-debug input.o output.o\n" 89 " kit objcopy --add-section=.kitnote=note.txt input.o noted.o\n" 90 " kit objdump -h -s -j .kitnote noted.o\n" 91 " kit objcopy --redefine-sym=old_name=new_name input.o renamed.o\n" 92 " kit nm renamed.o\n" 93 " kit image --format bin linked.elf -o linked.bin\n" 94 "\n" 95 "EXIT CODES\n" 96 " 0 success 1 I/O or transform error 2 bad " 97 "usage\n"))); 98 } 99 100 typedef enum CopyOp { 101 COPY_OP_NONE, 102 COPY_OP_STRIP_DEBUG, 103 COPY_OP_STRIP_UNNEEDED, 104 COPY_OP_STRIP_ALL, 105 } CopyOp; 106 107 typedef struct NamePair { 108 const char* old_name; 109 const char* new_name; 110 } NamePair; 111 112 typedef struct CopyOpts { 113 CopyOp op; 114 /* Section ops */ 115 const char** remove_sections; 116 uint32_t nremove; 117 uint32_t cap_remove; 118 const char** only_sections; 119 uint32_t nonly; 120 uint32_t cap_only; 121 NamePair* rename_sections; 122 uint32_t nrename_sec; 123 uint32_t cap_rename_sec; 124 NamePair* add_sections; 125 uint32_t nadd; 126 uint32_t cap_add; 127 NamePair* update_sections; 128 uint32_t nupdate; 129 uint32_t cap_update; 130 /* Symbol ops */ 131 NamePair* redefine_syms; 132 uint32_t nredef; 133 uint32_t cap_redef; 134 const char** globalize; 135 uint32_t nglob; 136 uint32_t cap_glob; 137 const char** localize; 138 uint32_t nloc; 139 uint32_t cap_loc; 140 const char** weaken; 141 uint32_t nweak; 142 uint32_t cap_weak; 143 /* Format conversion */ 144 int have_output_fmt; 145 KitObjFmt output_fmt; 146 int output_image; 147 KitImageFormat output_image_format; 148 /* I/O */ 149 const char* input; 150 const char* output; 151 } CopyOpts; 152 153 static int push_str(DriverEnv* env, const char*** arr, uint32_t* n, 154 uint32_t* cap, const char* s) { 155 if (*n >= *cap) { 156 uint32_t newcap = *cap ? *cap * 2u : 4u; 157 const char** nb = 158 (const char**)driver_alloc_zeroed(env, (size_t)newcap * sizeof(*nb)); 159 if (!nb) return -1; 160 if (*arr) { 161 memcpy(nb, *arr, (size_t)(*n) * sizeof(*nb)); 162 driver_free(env, (void*)*arr, (size_t)(*cap) * sizeof(*nb)); 163 } 164 *arr = nb; 165 *cap = newcap; 166 } 167 (*arr)[(*n)++] = s; 168 return 0; 169 } 170 171 static int push_pair(DriverEnv* env, NamePair** arr, uint32_t* n, uint32_t* cap, 172 const char* old_name, const char* new_name) { 173 if (*n >= *cap) { 174 uint32_t newcap = *cap ? *cap * 2u : 4u; 175 NamePair* nb = 176 (NamePair*)driver_alloc_zeroed(env, (size_t)newcap * sizeof(*nb)); 177 if (!nb) return -1; 178 if (*arr) { 179 memcpy(nb, *arr, (size_t)(*n) * sizeof(*nb)); 180 driver_free(env, *arr, (size_t)(*cap) * sizeof(*nb)); 181 } 182 *arr = nb; 183 *cap = newcap; 184 } 185 (*arr)[*n].old_name = old_name; 186 (*arr)[*n].new_name = new_name; 187 (*n)++; 188 return 0; 189 } 190 191 /* Parse VAL of `--flag=VAL` or take the next argv. */ 192 static int take_value(int* i, int argc, char** argv, const char* flag, 193 const char** out) { 194 const char* a = argv[*i]; 195 size_t flen = kit_slice_cstr(flag).len; 196 if (driver_strneq(a, flag, flen) && a[flen] == '=') { 197 *out = a + flen + 1; 198 return 1; 199 } 200 if (driver_streq(a, flag)) { 201 if (*i + 1 >= argc) return -1; 202 *out = argv[++(*i)]; 203 return 1; 204 } 205 return 0; 206 } 207 208 /* Split "old=new" / "name=file" at the first '='. */ 209 static int split_pair(DriverEnv* env, const char* spec, const char** out_left, 210 const char** out_right) { 211 const char* eq = driver_strchr(spec, '='); 212 size_t llen; 213 char* left; 214 if (!eq || eq == spec || !eq[1]) return -1; 215 llen = (size_t)(eq - spec); 216 left = (char*)driver_alloc_zeroed(env, llen + 1u); 217 if (!left) return -1; 218 memcpy(left, spec, llen); 219 left[llen] = '\0'; 220 *out_left = left; 221 *out_right = eq + 1; 222 return 0; 223 } 224 225 static int parse_fmt_name(const char* name, KitObjFmt* out) { 226 if (!name) return -1; 227 /* Canonical bare names (elf/coff/pe/macho/wasm) come from the obj layer's 228 * single source of truth. */ 229 if (kit_obj_fmt_from_name(name, out) == KIT_OK) return 0; 230 /* binutils-name compatibility (not a second source of truth): accept the 231 * BFD-style decorated spellings objcopy users pass, e.g. "elf64-x86-64", 232 * "mach-o-arm64", "coff-x86-64", "pe-i386". */ 233 if (driver_strneq(name, "elf", sizeof("elf") - 1)) { 234 *out = KIT_OBJ_ELF; 235 return 0; 236 } 237 if (driver_strneq(name, "mach", sizeof("mach") - 1)) { 238 *out = KIT_OBJ_MACHO; 239 return 0; 240 } 241 if (driver_strneq(name, "coff", sizeof("coff") - 1) || 242 driver_strneq(name, "pe-", sizeof("pe-") - 1)) { 243 *out = KIT_OBJ_COFF; 244 return 0; 245 } 246 if (driver_strneq(name, "wasm", sizeof("wasm") - 1)) { 247 *out = KIT_OBJ_WASM; 248 return 0; 249 } 250 return -1; 251 } 252 253 static int is_binary_fmt_name(const char* name) { 254 return driver_streq(name, "binary") || driver_streq(name, "bin") || 255 driver_streq(name, "raw"); 256 } 257 258 static int is_ihex_fmt_name(const char* name) { 259 return driver_streq(name, "ihex") || driver_streq(name, "ihex8"); 260 } 261 262 static int is_srec_fmt_name(const char* name) { 263 return driver_streq(name, "srec") || driver_streq(name, "s19"); 264 } 265 266 static int has_non_image_transforms(const CopyOpts* opts) { 267 return opts->op != COPY_OP_NONE || opts->nrename_sec || opts->nadd || 268 opts->nupdate || opts->nredef || opts->nglob || opts->nloc || 269 opts->nweak; 270 } 271 272 /* Lookup a symbol by name; KIT_OBJ_SYMBOL_NONE if not found. */ 273 static KitObjSymbol find_sym_id(KitObjFile* of, const char* name) { 274 KitObjSymInfo si; 275 if (kit_obj_symbol_by_name(of, kit_slice_cstr(name), &si) != KIT_OK) { 276 return KIT_OBJ_SYMBOL_NONE; 277 } 278 return si.id; 279 } 280 281 /* Lookup a section by name; KIT_SECTION_NONE if not found. */ 282 static KitObjSection find_sec_id(KitObjFile* of, const char* name) { 283 KitObjSection s = KIT_SECTION_NONE; 284 if (kit_obj_section_by_name(of, kit_slice_cstr(name), &s) != KIT_OK) { 285 return KIT_SECTION_NONE; 286 } 287 return s; 288 } 289 290 static int apply_strip_pass(DriverEnv* env, KitObjFile* of, KitObjBuilder* b, 291 const CopyOpts* opts) { 292 int level; 293 (void)env; 294 (void)of; 295 296 if (opts->op == COPY_OP_NONE) return 0; 297 298 level = opts->op == COPY_OP_STRIP_DEBUG ? KIT_STRIP_DEBUG 299 : opts->op == COPY_OP_STRIP_UNNEEDED ? KIT_STRIP_UNNEEDED 300 : KIT_STRIP_ALL; 301 if (kit_obj_builder_strip(b, level, NULL, 0) != KIT_OK) { 302 driver_errf(OBJCOPY_TOOL, "strip failed"); 303 return 1; 304 } 305 return 0; 306 } 307 308 /* Apply --only-section: every section whose name isn't on the list is 309 * dropped. Sections of KIT_SEC_TEXT/RODATA/DATA/BSS are user-visible; 310 * symbol-table / strtab / etc. are also affected. */ 311 static void apply_only_sections(KitObjFile* of, KitObjBuilder* b, 312 const CopyOpts* opts) { 313 uint32_t i, n; 314 if (!opts->nonly) return; 315 n = kit_obj_nsections(of); 316 for (i = 0; i < n; ++i) { 317 KitObjSecInfo si; 318 if (kit_obj_section(of, i, &si) != KIT_OK) continue; 319 if (!driver_name_in_list(si.name, opts->only_sections, opts->nonly)) { 320 kit_obj_builder_remove_section(b, i); 321 } 322 } 323 } 324 325 static int run_transforms(DriverEnv* env, const KitContext* ctx, KitObjFile* of, 326 KitObjBuilder* b, const CopyOpts* opts) { 327 uint32_t i; 328 329 /* --strip-* */ 330 if (apply_strip_pass(env, of, b, opts) != 0) return 1; 331 332 /* --only-section overrides --remove-section because they're an inverse 333 * pair; if both are passed, --only-section's keep-set is authoritative. */ 334 if (opts->nonly) { 335 apply_only_sections(of, b, opts); 336 } else if (opts->nremove) { 337 for (i = 0; i < opts->nremove; ++i) { 338 KitObjSection sid = find_sec_id(of, opts->remove_sections[i]); 339 if (sid != KIT_SECTION_NONE) kit_obj_builder_remove_section(b, sid); 340 } 341 } 342 343 /* --rename-section */ 344 for (i = 0; i < opts->nrename_sec; ++i) { 345 KitObjSection sid = find_sec_id(of, opts->rename_sections[i].old_name); 346 if (sid == KIT_SECTION_NONE) { 347 driver_errf( 348 OBJCOPY_TOOL, "rename-section: '%.*s' not found", 349 KIT_SLICE_ARG(kit_slice_cstr(opts->rename_sections[i].old_name))); 350 return 1; 351 } 352 KitSym ns = 353 kit_sym_intern(kit_obj_builder_compiler(b), 354 kit_slice_cstr(opts->rename_sections[i].new_name)); 355 kit_obj_builder_rename_section(b, sid, ns); 356 } 357 358 /* --update-section */ 359 for (i = 0; i < opts->nupdate; ++i) { 360 KitObjSection sid = find_sec_id(of, opts->update_sections[i].old_name); 361 KitFileData fd = {0}; 362 if (sid == KIT_SECTION_NONE) { 363 driver_errf( 364 OBJCOPY_TOOL, "update-section: '%.*s' not found", 365 KIT_SLICE_ARG(kit_slice_cstr(opts->update_sections[i].old_name))); 366 return 1; 367 } 368 if (ctx->file_io->read_all(ctx->file_io->user, 369 opts->update_sections[i].new_name, 370 &fd) != KIT_OK) { 371 driver_errf( 372 OBJCOPY_TOOL, "update-section: cannot read %.*s", 373 KIT_SLICE_ARG(kit_slice_cstr(opts->update_sections[i].new_name))); 374 return 1; 375 } 376 kit_obj_builder_section_replace_bytes(b, sid, fd.data, fd.size); 377 ctx->file_io->release(ctx->file_io->user, &fd); 378 } 379 380 /* --add-section: create a new SEC_OTHER PROGBITS section and write its 381 * contents from the on-disk file. */ 382 for (i = 0; i < opts->nadd; ++i) { 383 KitObjSectionDesc desc; 384 KitObjSection nsid; 385 KitFileData fd = {0}; 386 if (ctx->file_io->read_all(ctx->file_io->user, 387 opts->add_sections[i].new_name, &fd) != KIT_OK) { 388 driver_errf( 389 OBJCOPY_TOOL, "add-section: cannot read %.*s", 390 KIT_SLICE_ARG(kit_slice_cstr(opts->add_sections[i].new_name))); 391 return 1; 392 } 393 memset(&desc, 0, sizeof desc); 394 desc.name = kit_sym_intern(kit_obj_builder_compiler(b), 395 kit_slice_cstr(opts->add_sections[i].old_name)); 396 desc.kind = KIT_SEC_OTHER; 397 desc.flags = 0; 398 desc.align = 1; 399 desc.entsize = 0; 400 if (kit_obj_builder_section(b, &desc, &nsid) != KIT_OK) { 401 driver_errf( 402 OBJCOPY_TOOL, "add-section: failed to create '%.*s'", 403 KIT_SLICE_ARG(kit_slice_cstr(opts->add_sections[i].old_name))); 404 ctx->file_io->release(ctx->file_io->user, &fd); 405 return 1; 406 } 407 kit_obj_builder_write(b, nsid, fd.data, fd.size); 408 ctx->file_io->release(ctx->file_io->user, &fd); 409 } 410 411 /* --redefine-sym */ 412 for (i = 0; i < opts->nredef; ++i) { 413 KitObjSymbol sid = find_sym_id(of, opts->redefine_syms[i].old_name); 414 if (sid == KIT_OBJ_SYMBOL_NONE) continue; /* tolerate missing */ 415 kit_obj_builder_rename_symbol( 416 b, sid, 417 kit_sym_intern(kit_obj_builder_compiler(b), 418 kit_slice_cstr(opts->redefine_syms[i].new_name))); 419 } 420 421 /* --globalize-symbol / --localize-symbol / --weaken-symbol */ 422 for (i = 0; i < opts->nglob; ++i) { 423 KitObjSymbol sid = find_sym_id(of, opts->globalize[i]); 424 if (sid != KIT_OBJ_SYMBOL_NONE) 425 kit_obj_builder_symbol_set_bind(b, sid, KIT_SB_GLOBAL); 426 } 427 for (i = 0; i < opts->nloc; ++i) { 428 KitObjSymbol sid = find_sym_id(of, opts->localize[i]); 429 if (sid != KIT_OBJ_SYMBOL_NONE) 430 kit_obj_builder_symbol_set_bind(b, sid, KIT_SB_LOCAL); 431 } 432 for (i = 0; i < opts->nweak; ++i) { 433 KitObjSymbol sid = find_sym_id(of, opts->weaken[i]); 434 if (sid != KIT_OBJ_SYMBOL_NONE) 435 kit_obj_builder_symbol_set_bind(b, sid, KIT_SB_WEAK); 436 } 437 438 return 0; 439 } 440 441 static int copy_one_object(DriverEnv* env, const KitContext* ctx, 442 const char* input_name, const KitSlice* input, 443 const CopyOpts* opts, const char* output_path) { 444 KitObjFile* of = NULL; 445 KitObjBuilder* b; 446 KitWriter* w = NULL; 447 KitStatus st; 448 int rc = 1; 449 450 if (kit_obj_open(ctx, kit_slice_cstr(input_name), input, &of) != KIT_OK) { 451 driver_errf(OBJCOPY_TOOL, "%.*s: not a recognized object", 452 KIT_SLICE_ARG(kit_slice_cstr(input_name))); 453 return 1; 454 } 455 b = kit_obj_file_builder(of); 456 if (!b) { 457 driver_errf(OBJCOPY_TOOL, "%.*s: no builder", 458 KIT_SLICE_ARG(kit_slice_cstr(input_name))); 459 kit_obj_free(of); 460 return 1; 461 } 462 if (run_transforms(env, ctx, of, b, opts) != 0) { 463 kit_obj_free(of); 464 return 1; 465 } 466 if (ctx->file_io->open_writer(ctx->file_io->user, output_path, &w) != 467 KIT_OK) { 468 driver_errf(OBJCOPY_TOOL, "cannot open %.*s", 469 KIT_SLICE_ARG(kit_slice_cstr(output_path))); 470 kit_obj_free(of); 471 return 1; 472 } 473 if (opts->have_output_fmt) { 474 st = kit_obj_builder_emit_as(b, opts->output_fmt, w); 475 } else { 476 st = kit_obj_builder_emit(b, w); 477 } 478 if (st != KIT_OK) { 479 driver_errf(OBJCOPY_TOOL, "emit failed"); 480 kit_writer_close(w); 481 kit_obj_free(of); 482 return 1; 483 } 484 kit_writer_close(w); 485 kit_obj_free(of); 486 rc = 0; 487 return rc; 488 } 489 490 static KitSlice* copy_image_names(const KitContext* ctx, 491 const char* const* names, uint32_t n) { 492 KitSlice* slices; 493 uint32_t i; 494 size_t bytes; 495 if (n == 0) return NULL; 496 if ((size_t)n > SIZE_MAX / sizeof(*slices)) return NULL; 497 bytes = (size_t)n * sizeof(*slices); 498 slices = (KitSlice*)ctx->heap->alloc(ctx->heap, bytes, _Alignof(KitSlice)); 499 if (!slices) return NULL; 500 for (i = 0; i < n; ++i) slices[i] = kit_slice_cstr(names[i]); 501 return slices; 502 } 503 504 static void free_image_names(const KitContext* ctx, KitSlice* names, 505 uint32_t n) { 506 if (names) 507 ctx->heap->free(ctx->heap, names, (size_t)n * sizeof(*names)); 508 } 509 510 static int copy_one_image(const KitContext* ctx, const CopyOpts* opts, 511 const char* input_name, const KitSlice* input, 512 const char* output_path) { 513 KitImageOptions iopts; 514 KitSlice* only_sections = NULL; 515 KitSlice* remove_sections = NULL; 516 KitWriter* w = NULL; 517 KitStatus st; 518 int rc = 1; 519 520 memset(&iopts, 0, sizeof iopts); 521 iopts.format = opts->output_image_format; 522 iopts.from = KIT_IMAGE_FROM_SEGMENTS; 523 iopts.addr = KIT_IMAGE_ADDR_VADDR; 524 iopts.fill = 0; 525 only_sections = copy_image_names(ctx, opts->only_sections, opts->nonly); 526 remove_sections = 527 copy_image_names(ctx, opts->remove_sections, opts->nremove); 528 if ((opts->nonly && !only_sections) || (opts->nremove && !remove_sections)) { 529 driver_errf(OBJCOPY_TOOL, "out of memory preparing section selection"); 530 goto done; 531 } 532 iopts.only_sections = only_sections; 533 iopts.nonly_sections = opts->nonly; 534 iopts.remove_sections = remove_sections; 535 iopts.nremove_sections = opts->nremove; 536 537 if (ctx->file_io->open_writer(ctx->file_io->user, output_path, &w) != 538 KIT_OK) { 539 driver_errf(OBJCOPY_TOOL, "cannot open %.*s", 540 KIT_SLICE_ARG(kit_slice_cstr(output_path))); 541 goto done; 542 } 543 st = kit_image_emit_bytes(ctx, kit_slice_cstr(input_name), input, &iopts, w, 544 NULL); 545 if (st != KIT_OK || kit_writer_status(w) != KIT_OK) { 546 driver_writer_abort(w); 547 kit_writer_close(w); 548 w = NULL; 549 goto done; 550 } 551 kit_writer_close(w); 552 w = NULL; 553 rc = 0; 554 555 done: 556 if (w) kit_writer_close(w); 557 free_image_names(ctx, only_sections, opts->nonly); 558 free_image_names(ctx, remove_sections, opts->nremove); 559 return rc; 560 } 561 562 int driver_objcopy(int argc, char** argv) { 563 DriverEnv env; 564 KitContext ctx; 565 CopyOpts opts; 566 KitFileData in_fd = {0}; 567 KitSlice input; 568 int have_in = 0; 569 int rc = 1; 570 int i, options = 1; 571 const char* out_path; 572 573 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 574 driver_help_objcopy(); 575 return 0; 576 } 577 578 memset(&opts, 0, sizeof opts); 579 opts.op = COPY_OP_NONE; 580 driver_env_init(&env); 581 ctx = driver_env_to_context(&env); 582 583 for (i = 1; i < argc; ++i) { 584 const char* a = argv[i]; 585 const char* val = NULL; 586 int matched; 587 if (options && driver_streq(a, "--")) { 588 options = 0; 589 continue; 590 } 591 if (!options) { 592 if (!opts.input) 593 opts.input = a; 594 else if (!opts.output) 595 opts.output = a; 596 else { 597 driver_errf(OBJCOPY_TOOL, "unexpected argument: %s", a); 598 rc = 2; 599 goto done; 600 } 601 continue; 602 } 603 if (driver_streq(a, "--strip-debug")) { 604 opts.op = COPY_OP_STRIP_DEBUG; 605 continue; 606 } 607 if (driver_streq(a, "--strip-unneeded")) { 608 opts.op = COPY_OP_STRIP_UNNEEDED; 609 continue; 610 } 611 if (driver_streq(a, "--strip-all") || driver_streq(a, "-S")) { 612 opts.op = COPY_OP_STRIP_ALL; 613 continue; 614 } 615 if (driver_streq(a, "-O")) { 616 if (i + 1 >= argc) { 617 driver_errf(OBJCOPY_TOOL, "-O requires a format name"); 618 rc = 2; 619 goto done; 620 } 621 ++i; 622 if (is_binary_fmt_name(argv[i])) { 623 opts.output_image = 1; 624 opts.output_image_format = KIT_IMAGE_FORMAT_BIN; 625 opts.have_output_fmt = 0; 626 continue; 627 } 628 if (is_ihex_fmt_name(argv[i])) { 629 opts.output_image = 1; 630 opts.output_image_format = KIT_IMAGE_FORMAT_IHEX; 631 opts.have_output_fmt = 0; 632 continue; 633 } 634 if (is_srec_fmt_name(argv[i])) { 635 opts.output_image = 1; 636 opts.output_image_format = KIT_IMAGE_FORMAT_SREC; 637 opts.have_output_fmt = 0; 638 continue; 639 } 640 if (parse_fmt_name(argv[i], &opts.output_fmt) != 0) { 641 driver_errf(OBJCOPY_TOOL, "unknown output format: %.*s", 642 KIT_SLICE_ARG(kit_slice_cstr(argv[i]))); 643 rc = 2; 644 goto done; 645 } 646 opts.have_output_fmt = 1; 647 opts.output_image = 0; 648 continue; 649 } 650 matched = take_value(&i, argc, argv, "--remove-section", &val); 651 if (matched < 0) goto missing_value; 652 if (matched) { 653 if (push_str(&env, &opts.remove_sections, &opts.nremove, &opts.cap_remove, 654 val) != 0) 655 goto oom; 656 continue; 657 } 658 matched = take_value(&i, argc, argv, "--only-section", &val); 659 if (matched < 0) goto missing_value; 660 if (matched) { 661 if (push_str(&env, &opts.only_sections, &opts.nonly, &opts.cap_only, 662 val) != 0) 663 goto oom; 664 continue; 665 } 666 matched = take_value(&i, argc, argv, "--rename-section", &val); 667 if (matched < 0) goto missing_value; 668 if (matched) { 669 const char *left, *right; 670 if (split_pair(&env, val, &left, &right) != 0) { 671 driver_errf(OBJCOPY_TOOL, "rename-section: expected OLD=NEW (got %.*s)", 672 KIT_SLICE_ARG(kit_slice_cstr(val))); 673 rc = 2; 674 goto done; 675 } 676 if (push_pair(&env, &opts.rename_sections, &opts.nrename_sec, 677 &opts.cap_rename_sec, left, right) != 0) 678 goto oom; 679 continue; 680 } 681 matched = take_value(&i, argc, argv, "--add-section", &val); 682 if (matched < 0) goto missing_value; 683 if (matched) { 684 const char *left, *right; 685 if (split_pair(&env, val, &left, &right) != 0) { 686 driver_errf(OBJCOPY_TOOL, "add-section: expected NAME=FILE (got %.*s)", 687 KIT_SLICE_ARG(kit_slice_cstr(val))); 688 rc = 2; 689 goto done; 690 } 691 if (push_pair(&env, &opts.add_sections, &opts.nadd, &opts.cap_add, left, 692 right) != 0) 693 goto oom; 694 continue; 695 } 696 matched = take_value(&i, argc, argv, "--update-section", &val); 697 if (matched < 0) goto missing_value; 698 if (matched) { 699 const char *left, *right; 700 if (split_pair(&env, val, &left, &right) != 0) { 701 driver_errf(OBJCOPY_TOOL, 702 "update-section: expected NAME=FILE (got %.*s)", 703 KIT_SLICE_ARG(kit_slice_cstr(val))); 704 rc = 2; 705 goto done; 706 } 707 if (push_pair(&env, &opts.update_sections, &opts.nupdate, 708 &opts.cap_update, left, right) != 0) 709 goto oom; 710 continue; 711 } 712 matched = take_value(&i, argc, argv, "--redefine-sym", &val); 713 if (matched < 0) goto missing_value; 714 if (matched) { 715 const char *left, *right; 716 if (split_pair(&env, val, &left, &right) != 0) { 717 driver_errf(OBJCOPY_TOOL, "redefine-sym: expected OLD=NEW (got %.*s)", 718 KIT_SLICE_ARG(kit_slice_cstr(val))); 719 rc = 2; 720 goto done; 721 } 722 if (push_pair(&env, &opts.redefine_syms, &opts.nredef, &opts.cap_redef, 723 left, right) != 0) 724 goto oom; 725 continue; 726 } 727 matched = take_value(&i, argc, argv, "--globalize-symbol", &val); 728 if (matched < 0) goto missing_value; 729 if (matched) { 730 if (push_str(&env, &opts.globalize, &opts.nglob, &opts.cap_glob, val) != 731 0) 732 goto oom; 733 continue; 734 } 735 matched = take_value(&i, argc, argv, "--localize-symbol", &val); 736 if (matched < 0) goto missing_value; 737 if (matched) { 738 if (push_str(&env, &opts.localize, &opts.nloc, &opts.cap_loc, val) != 0) 739 goto oom; 740 continue; 741 } 742 matched = take_value(&i, argc, argv, "--weaken-symbol", &val); 743 if (matched < 0) goto missing_value; 744 if (matched) { 745 if (push_str(&env, &opts.weaken, &opts.nweak, &opts.cap_weak, val) != 0) 746 goto oom; 747 continue; 748 } 749 if (a[0] == '-' && a[1] != '\0') { 750 driver_errf(OBJCOPY_TOOL, "unknown option: %.*s", 751 KIT_SLICE_ARG(kit_slice_cstr(a))); 752 rc = 2; 753 goto done; 754 } 755 if (!opts.input) { 756 opts.input = a; 757 } else if (!opts.output) { 758 opts.output = a; 759 } else { 760 driver_errf(OBJCOPY_TOOL, "unexpected argument: %.*s", 761 KIT_SLICE_ARG(kit_slice_cstr(a))); 762 rc = 2; 763 goto done; 764 } 765 } 766 767 if (!opts.input) { 768 driver_errf(OBJCOPY_TOOL, "missing input file"); 769 rc = 2; 770 goto done; 771 } 772 out_path = opts.output ? opts.output : opts.input; 773 774 if (opts.output_image && has_non_image_transforms(&opts)) { 775 driver_errf(OBJCOPY_TOOL, 776 "image output format cannot be combined with object transform " 777 "options"); 778 rc = 2; 779 goto done; 780 } 781 782 if (ctx.file_io->read_all(ctx.file_io->user, opts.input, &in_fd) != KIT_OK) { 783 driver_errf(OBJCOPY_TOOL, "cannot read %.*s", 784 KIT_SLICE_ARG(kit_slice_cstr(opts.input))); 785 goto done; 786 } 787 have_in = 1; 788 input.data = in_fd.data; 789 input.len = in_fd.size; 790 791 if (opts.output_image) { 792 rc = copy_one_image(&ctx, &opts, opts.input, &input, out_path); 793 } else { 794 rc = copy_one_object(&env, &ctx, opts.input, &input, &opts, out_path); 795 } 796 797 done: 798 if (have_in) ctx.file_io->release(ctx.file_io->user, &in_fd); 799 if (opts.remove_sections) 800 driver_free(&env, (void*)opts.remove_sections, 801 (size_t)opts.cap_remove * sizeof(*opts.remove_sections)); 802 if (opts.only_sections) 803 driver_free(&env, (void*)opts.only_sections, 804 (size_t)opts.cap_only * sizeof(*opts.only_sections)); 805 if (opts.rename_sections) 806 driver_free(&env, opts.rename_sections, 807 (size_t)opts.cap_rename_sec * sizeof(*opts.rename_sections)); 808 if (opts.add_sections) 809 driver_free(&env, opts.add_sections, 810 (size_t)opts.cap_add * sizeof(*opts.add_sections)); 811 if (opts.update_sections) 812 driver_free(&env, opts.update_sections, 813 (size_t)opts.cap_update * sizeof(*opts.update_sections)); 814 if (opts.redefine_syms) 815 driver_free(&env, opts.redefine_syms, 816 (size_t)opts.cap_redef * sizeof(*opts.redefine_syms)); 817 if (opts.globalize) 818 driver_free(&env, (void*)opts.globalize, 819 (size_t)opts.cap_glob * sizeof(*opts.globalize)); 820 if (opts.localize) 821 driver_free(&env, (void*)opts.localize, 822 (size_t)opts.cap_loc * sizeof(*opts.localize)); 823 if (opts.weaken) 824 driver_free(&env, (void*)opts.weaken, 825 (size_t)opts.cap_weak * sizeof(*opts.weaken)); 826 driver_env_fini(&env); 827 return rc; 828 829 missing_value: 830 driver_errf(OBJCOPY_TOOL, "%.*s requires a value", 831 KIT_SLICE_ARG(kit_slice_cstr(argv[i]))); 832 rc = 2; 833 goto done; 834 oom: 835 driver_errf(OBJCOPY_TOOL, "out of memory"); 836 rc = 1; 837 goto done; 838 }