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