1 //===- llvm-objcopy.cpp ---------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm-objcopy.h" 11 12 #include "Object.h" 13 #include "llvm/ADT/BitmaskEnum.h" 14 #include "llvm/ADT/Optional.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/SmallVector.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ADT/Twine.h" 19 #include "llvm/BinaryFormat/ELF.h" 20 #include "llvm/MC/MCTargetOptions.h" 21 #include "llvm/Object/Archive.h" 22 #include "llvm/Object/ArchiveWriter.h" 23 #include "llvm/Object/Binary.h" 24 #include "llvm/Object/ELFObjectFile.h" 25 #include "llvm/Object/ELFTypes.h" 26 #include "llvm/Object/Error.h" 27 #include "llvm/Option/Arg.h" 28 #include "llvm/Option/ArgList.h" 29 #include "llvm/Option/Option.h" 30 #include "llvm/Support/Casting.h" 31 #include "llvm/Support/CommandLine.h" 32 #include "llvm/Support/Compiler.h" 33 #include "llvm/Support/Compression.h" 34 #include "llvm/Support/Error.h" 35 #include "llvm/Support/ErrorHandling.h" 36 #include "llvm/Support/ErrorOr.h" 37 #include "llvm/Support/FileOutputBuffer.h" 38 #include "llvm/Support/InitLLVM.h" 39 #include "llvm/Support/Memory.h" 40 #include "llvm/Support/Path.h" 41 #include "llvm/Support/Process.h" 42 #include "llvm/Support/WithColor.h" 43 #include "llvm/Support/raw_ostream.h" 44 #include <algorithm> 45 #include <cassert> 46 #include <cstdlib> 47 #include <functional> 48 #include <iterator> 49 #include <memory> 50 #include <string> 51 #include <system_error> 52 #include <utility> 53 54 using namespace llvm; 55 using namespace llvm::objcopy; 56 using namespace object; 57 using namespace ELF; 58 59 namespace { 60 61 enum ObjcopyID { 62 OBJCOPY_INVALID = 0, // This is not an option ID. 63 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 64 HELPTEXT, METAVAR, VALUES) \ 65 OBJCOPY_##ID, 66 #include "ObjcopyOpts.inc" 67 #undef OPTION 68 }; 69 70 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE; 71 #include "ObjcopyOpts.inc" 72 #undef PREFIX 73 74 static const opt::OptTable::Info ObjcopyInfoTable[] = { 75 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 76 HELPTEXT, METAVAR, VALUES) \ 77 {OBJCOPY_##PREFIX, \ 78 NAME, \ 79 HELPTEXT, \ 80 METAVAR, \ 81 OBJCOPY_##ID, \ 82 opt::Option::KIND##Class, \ 83 PARAM, \ 84 FLAGS, \ 85 OBJCOPY_##GROUP, \ 86 OBJCOPY_##ALIAS, \ 87 ALIASARGS, \ 88 VALUES}, 89 #include "ObjcopyOpts.inc" 90 #undef OPTION 91 }; 92 93 class ObjcopyOptTable : public opt::OptTable { 94 public: 95 ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {} 96 }; 97 98 enum StripID { 99 STRIP_INVALID = 0, // This is not an option ID. 100 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 101 HELPTEXT, METAVAR, VALUES) \ 102 STRIP_##ID, 103 #include "StripOpts.inc" 104 #undef OPTION 105 }; 106 107 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE; 108 #include "StripOpts.inc" 109 #undef PREFIX 110 111 static const opt::OptTable::Info StripInfoTable[] = { 112 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 113 HELPTEXT, METAVAR, VALUES) \ 114 {STRIP_##PREFIX, NAME, HELPTEXT, \ 115 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \ 116 PARAM, FLAGS, STRIP_##GROUP, \ 117 STRIP_##ALIAS, ALIASARGS, VALUES}, 118 #include "StripOpts.inc" 119 #undef OPTION 120 }; 121 122 class StripOptTable : public opt::OptTable { 123 public: 124 StripOptTable() : OptTable(StripInfoTable, true) {} 125 }; 126 127 struct SectionRename { 128 StringRef OriginalName; 129 StringRef NewName; 130 Optional<uint64_t> NewFlags; 131 }; 132 133 // Configuration for copying/stripping a single file. 134 struct CopyConfig { 135 // Main input/output options 136 StringRef InputFilename; 137 StringRef InputFormat; 138 StringRef OutputFilename; 139 StringRef OutputFormat; 140 141 // Only applicable for --input-format=Binary 142 MachineInfo BinaryArch; 143 144 // Advanced options 145 StringRef AddGnuDebugLink; 146 StringRef SplitDWO; 147 StringRef SymbolsPrefix; 148 149 // Repeated options 150 std::vector<StringRef> AddSection; 151 std::vector<StringRef> DumpSection; 152 std::vector<StringRef> Keep; 153 std::vector<StringRef> OnlyKeep; 154 std::vector<StringRef> SymbolsToGlobalize; 155 std::vector<StringRef> SymbolsToKeep; 156 std::vector<StringRef> SymbolsToLocalize; 157 std::vector<StringRef> SymbolsToRemove; 158 std::vector<StringRef> SymbolsToWeaken; 159 std::vector<StringRef> ToRemove; 160 std::vector<std::string> SymbolsToKeepGlobal; 161 162 // Map options 163 StringMap<SectionRename> SectionsToRename; 164 StringMap<StringRef> SymbolsToRename; 165 166 // Boolean options 167 bool DiscardAll = false; 168 bool ExtractDWO = false; 169 bool KeepFileSymbols = false; 170 bool LocalizeHidden = false; 171 bool OnlyKeepDebug = false; 172 bool PreserveDates = false; 173 bool StripAll = false; 174 bool StripAllGNU = false; 175 bool StripDWO = false; 176 bool StripDebug = false; 177 bool StripNonAlloc = false; 178 bool StripSections = false; 179 bool StripUnneeded = false; 180 bool Weaken = false; 181 bool DecompressDebugSections = false; 182 DebugCompressionType CompressionType = DebugCompressionType::None; 183 }; 184 185 // Configuration for the overall invocation of this tool. When invoked as 186 // objcopy, will always contain exactly one CopyConfig. When invoked as strip, 187 // will contain one or more CopyConfigs. 188 struct DriverConfig { 189 SmallVector<CopyConfig, 1> CopyConfigs; 190 }; 191 192 using SectionPred = std::function<bool(const SectionBase &Sec)>; 193 194 enum SectionFlag { 195 SecNone = 0, 196 SecAlloc = 1 << 0, 197 SecLoad = 1 << 1, 198 SecNoload = 1 << 2, 199 SecReadonly = 1 << 3, 200 SecDebug = 1 << 4, 201 SecCode = 1 << 5, 202 SecData = 1 << 6, 203 SecRom = 1 << 7, 204 SecMerge = 1 << 8, 205 SecStrings = 1 << 9, 206 SecContents = 1 << 10, 207 SecShare = 1 << 11, 208 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare) 209 }; 210 211 } // namespace 212 213 namespace llvm { 214 namespace objcopy { 215 216 // The name this program was invoked as. 217 StringRef ToolName; 218 219 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 220 WithColor::error(errs(), ToolName) << Message << ".\n"; 221 errs().flush(); 222 exit(1); 223 } 224 225 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 226 assert(EC); 227 WithColor::error(errs(), ToolName) 228 << "'" << File << "': " << EC.message() << ".\n"; 229 exit(1); 230 } 231 232 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 233 assert(E); 234 std::string Buf; 235 raw_string_ostream OS(Buf); 236 logAllUnhandledErrors(std::move(E), OS, ""); 237 OS.flush(); 238 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; 239 exit(1); 240 } 241 242 } // end namespace objcopy 243 } // end namespace llvm 244 245 static SectionFlag parseSectionRenameFlag(StringRef SectionName) { 246 return llvm::StringSwitch<SectionFlag>(SectionName) 247 .Case("alloc", SectionFlag::SecAlloc) 248 .Case("load", SectionFlag::SecLoad) 249 .Case("noload", SectionFlag::SecNoload) 250 .Case("readonly", SectionFlag::SecReadonly) 251 .Case("debug", SectionFlag::SecDebug) 252 .Case("code", SectionFlag::SecCode) 253 .Case("data", SectionFlag::SecData) 254 .Case("rom", SectionFlag::SecRom) 255 .Case("merge", SectionFlag::SecMerge) 256 .Case("strings", SectionFlag::SecStrings) 257 .Case("contents", SectionFlag::SecContents) 258 .Case("share", SectionFlag::SecShare) 259 .Default(SectionFlag::SecNone); 260 } 261 262 static SectionRename parseRenameSectionValue(StringRef FlagValue) { 263 if (!FlagValue.contains('=')) 264 error("Bad format for --rename-section: missing '='"); 265 266 // Initial split: ".foo" = ".bar,f1,f2,..." 267 auto Old2New = FlagValue.split('='); 268 SectionRename SR; 269 SR.OriginalName = Old2New.first; 270 271 // Flags split: ".bar" "f1" "f2" ... 272 SmallVector<StringRef, 6> NameAndFlags; 273 Old2New.second.split(NameAndFlags, ','); 274 SR.NewName = NameAndFlags[0]; 275 276 if (NameAndFlags.size() > 1) { 277 SectionFlag Flags = SectionFlag::SecNone; 278 for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) { 279 SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]); 280 if (Flag == SectionFlag::SecNone) 281 error("Unrecognized section flag '" + NameAndFlags[I] + 282 "'. Flags supported for GNU compatibility: alloc, load, noload, " 283 "readonly, debug, code, data, rom, share, contents, merge, " 284 "strings."); 285 Flags |= Flag; 286 } 287 288 SR.NewFlags = 0; 289 if (Flags & SectionFlag::SecAlloc) 290 *SR.NewFlags |= ELF::SHF_ALLOC; 291 if (!(Flags & SectionFlag::SecReadonly)) 292 *SR.NewFlags |= ELF::SHF_WRITE; 293 if (Flags & SectionFlag::SecCode) 294 *SR.NewFlags |= ELF::SHF_EXECINSTR; 295 if (Flags & SectionFlag::SecMerge) 296 *SR.NewFlags |= ELF::SHF_MERGE; 297 if (Flags & SectionFlag::SecStrings) 298 *SR.NewFlags |= ELF::SHF_STRINGS; 299 } 300 301 return SR; 302 } 303 304 static bool isDebugSection(const SectionBase &Sec) { 305 return StringRef(Sec.Name).startswith(".debug") || 306 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index"; 307 } 308 309 static bool isDWOSection(const SectionBase &Sec) { 310 return StringRef(Sec.Name).endswith(".dwo"); 311 } 312 313 static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { 314 // We can't remove the section header string table. 315 if (&Sec == Obj.SectionNames) 316 return false; 317 // Short of keeping the string table we want to keep everything that is a DWO 318 // section and remove everything else. 319 return !isDWOSection(Sec); 320 } 321 322 static const StringMap<MachineInfo> ArchMap{ 323 // Name, {EMachine, 64bit, LittleEndian} 324 {"aarch64", {EM_AARCH64, true, true}}, 325 {"arm", {EM_ARM, false, true}}, 326 {"i386", {EM_386, false, true}}, 327 {"i386:x86-64", {EM_X86_64, true, true}}, 328 {"powerpc:common64", {EM_PPC64, true, true}}, 329 {"sparc", {EM_SPARC, false, true}}, 330 {"x86-64", {EM_X86_64, true, true}}, 331 }; 332 333 static const MachineInfo &getMachineInfo(StringRef Arch) { 334 auto Iter = ArchMap.find(Arch); 335 if (Iter == std::end(ArchMap)) 336 error("Invalid architecture: '" + Arch + "'"); 337 return Iter->getValue(); 338 } 339 340 static ElfType getOutputElfType(const Binary &Bin) { 341 // Infer output ELF type from the input ELF object 342 if (isa<ELFObjectFile<ELF32LE>>(Bin)) 343 return ELFT_ELF32LE; 344 if (isa<ELFObjectFile<ELF64LE>>(Bin)) 345 return ELFT_ELF64LE; 346 if (isa<ELFObjectFile<ELF32BE>>(Bin)) 347 return ELFT_ELF32BE; 348 if (isa<ELFObjectFile<ELF64BE>>(Bin)) 349 return ELFT_ELF64BE; 350 llvm_unreachable("Invalid ELFType"); 351 } 352 353 static ElfType getOutputElfType(const MachineInfo &MI) { 354 // Infer output ELF type from the binary arch specified 355 if (MI.Is64Bit) 356 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE; 357 else 358 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; 359 } 360 361 static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, 362 Object &Obj, Buffer &Buf, 363 ElfType OutputElfType) { 364 if (Config.OutputFormat == "binary") { 365 return llvm::make_unique<BinaryWriter>(Obj, Buf); 366 } 367 // Depending on the initial ELFT and OutputFormat we need a different Writer. 368 switch (OutputElfType) { 369 case ELFT_ELF32LE: 370 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, 371 !Config.StripSections); 372 case ELFT_ELF64LE: 373 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, 374 !Config.StripSections); 375 case ELFT_ELF32BE: 376 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, 377 !Config.StripSections); 378 case ELFT_ELF64BE: 379 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, 380 !Config.StripSections); 381 } 382 llvm_unreachable("Invalid output format"); 383 } 384 385 static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader, 386 StringRef File, ElfType OutputElfType) { 387 auto DWOFile = Reader.create(); 388 DWOFile->removeSections( 389 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); }); 390 FileBuffer FB(File); 391 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); 392 Writer->finalize(); 393 Writer->write(); 394 } 395 396 static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 397 Object &Obj) { 398 for (auto &Sec : Obj.sections()) { 399 if (Sec.Name == SecName) { 400 if (Sec.OriginalData.size() == 0) 401 return make_error<StringError>("Can't dump section \"" + SecName + 402 "\": it has no contents", 403 object_error::parse_failed); 404 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 405 FileOutputBuffer::create(Filename, Sec.OriginalData.size()); 406 if (!BufferOrErr) 407 return BufferOrErr.takeError(); 408 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 409 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), 410 Buf->getBufferStart()); 411 if (Error E = Buf->commit()) 412 return E; 413 return Error::success(); 414 } 415 } 416 return make_error<StringError>("Section not found", 417 object_error::parse_failed); 418 } 419 420 static bool isCompressed(const SectionBase &Section) { 421 const char *Magic = "ZLIB"; 422 return StringRef(Section.Name).startswith(".zdebug") || 423 (Section.OriginalData.size() > strlen(Magic) && 424 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()), 425 Magic, strlen(Magic))) || 426 (Section.Flags & ELF::SHF_COMPRESSED); 427 } 428 429 static bool isCompressable(const SectionBase &Section) { 430 return !isCompressed(Section) && isDebugSection(Section) && 431 Section.Name != ".gdb_index"; 432 } 433 434 static void replaceDebugSections( 435 const CopyConfig &Config, Object &Obj, SectionPred &RemovePred, 436 function_ref<bool(const SectionBase &)> shouldReplace, 437 function_ref<SectionBase *(const SectionBase *)> addSection) { 438 SmallVector<SectionBase *, 13> ToReplace; 439 SmallVector<RelocationSection *, 13> RelocationSections; 440 for (auto &Sec : Obj.sections()) { 441 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) { 442 if (shouldReplace(*R->getSection())) 443 RelocationSections.push_back(R); 444 continue; 445 } 446 447 if (shouldReplace(Sec)) 448 ToReplace.push_back(&Sec); 449 } 450 451 for (SectionBase *S : ToReplace) { 452 SectionBase *NewSection = addSection(S); 453 454 for (RelocationSection *RS : RelocationSections) { 455 if (RS->getSection() == S) 456 RS->setSection(NewSection); 457 } 458 } 459 460 RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) { 461 return shouldReplace(Sec) || RemovePred(Sec); 462 }; 463 } 464 465 // This function handles the high level operations of GNU objcopy including 466 // handling command line options. It's important to outline certain properties 467 // we expect to hold of the command line operations. Any operation that "keeps" 468 // should keep regardless of a remove. Additionally any removal should respect 469 // any previous removals. Lastly whether or not something is removed shouldn't 470 // depend a) on the order the options occur in or b) on some opaque priority 471 // system. The only priority is that keeps/copies overrule removes. 472 static void handleArgs(const CopyConfig &Config, Object &Obj, 473 const Reader &Reader, ElfType OutputElfType) { 474 475 if (!Config.SplitDWO.empty()) { 476 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); 477 } 478 479 // TODO: update or remove symbols only if there is an option that affects 480 // them. 481 if (Obj.SymbolTable) { 482 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 483 if ((Config.LocalizeHidden && 484 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 485 (!Config.SymbolsToLocalize.empty() && 486 is_contained(Config.SymbolsToLocalize, Sym.Name))) 487 Sym.Binding = STB_LOCAL; 488 489 // Note: these two globalize flags have very similar names but different 490 // meanings: 491 // 492 // --globalize-symbol: promote a symbol to global 493 // --keep-global-symbol: all symbols except for these should be made local 494 // 495 // If --globalize-symbol is specified for a given symbol, it will be 496 // global in the output file even if it is not included via 497 // --keep-global-symbol. Because of that, make sure to check 498 // --globalize-symbol second. 499 if (!Config.SymbolsToKeepGlobal.empty() && 500 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name)) 501 Sym.Binding = STB_LOCAL; 502 503 if (!Config.SymbolsToGlobalize.empty() && 504 is_contained(Config.SymbolsToGlobalize, Sym.Name)) 505 Sym.Binding = STB_GLOBAL; 506 507 if (!Config.SymbolsToWeaken.empty() && 508 is_contained(Config.SymbolsToWeaken, Sym.Name) && 509 Sym.Binding == STB_GLOBAL) 510 Sym.Binding = STB_WEAK; 511 512 if (Config.Weaken && Sym.Binding == STB_GLOBAL && 513 Sym.getShndx() != SHN_UNDEF) 514 Sym.Binding = STB_WEAK; 515 516 const auto I = Config.SymbolsToRename.find(Sym.Name); 517 if (I != Config.SymbolsToRename.end()) 518 Sym.Name = I->getValue(); 519 520 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) 521 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); 522 }); 523 524 // The purpose of this loop is to mark symbols referenced by sections 525 // (like GroupSection or RelocationSection). This way, we know which 526 // symbols are still 'needed' and which are not. 527 if (Config.StripUnneeded) { 528 for (auto &Section : Obj.sections()) 529 Section.markSymbols(); 530 } 531 532 Obj.removeSymbols([&](const Symbol &Sym) { 533 if ((!Config.SymbolsToKeep.empty() && 534 is_contained(Config.SymbolsToKeep, Sym.Name)) || 535 (Config.KeepFileSymbols && Sym.Type == STT_FILE)) 536 return false; 537 538 if (Config.DiscardAll && Sym.Binding == STB_LOCAL && 539 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && 540 Sym.Type != STT_SECTION) 541 return true; 542 543 if (Config.StripAll || Config.StripAllGNU) 544 return true; 545 546 if (!Config.SymbolsToRemove.empty() && 547 is_contained(Config.SymbolsToRemove, Sym.Name)) { 548 return true; 549 } 550 551 if (Config.StripUnneeded && !Sym.Referenced && 552 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && 553 Sym.Type != STT_FILE && Sym.Type != STT_SECTION) 554 return true; 555 556 return false; 557 }); 558 } 559 560 SectionPred RemovePred = [](const SectionBase &) { return false; }; 561 562 // Removes: 563 if (!Config.ToRemove.empty()) { 564 RemovePred = [&Config](const SectionBase &Sec) { 565 return is_contained(Config.ToRemove, Sec.Name); 566 }; 567 } 568 569 if (Config.StripDWO || !Config.SplitDWO.empty()) 570 RemovePred = [RemovePred](const SectionBase &Sec) { 571 return isDWOSection(Sec) || RemovePred(Sec); 572 }; 573 574 if (Config.ExtractDWO) 575 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 576 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 577 }; 578 579 if (Config.StripAllGNU) 580 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 581 if (RemovePred(Sec)) 582 return true; 583 if ((Sec.Flags & SHF_ALLOC) != 0) 584 return false; 585 if (&Sec == Obj.SectionNames) 586 return false; 587 switch (Sec.Type) { 588 case SHT_SYMTAB: 589 case SHT_REL: 590 case SHT_RELA: 591 case SHT_STRTAB: 592 return true; 593 } 594 return isDebugSection(Sec); 595 }; 596 597 if (Config.StripSections) { 598 RemovePred = [RemovePred](const SectionBase &Sec) { 599 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 600 }; 601 } 602 603 if (Config.StripDebug) { 604 RemovePred = [RemovePred](const SectionBase &Sec) { 605 return RemovePred(Sec) || isDebugSection(Sec); 606 }; 607 } 608 609 if (Config.StripNonAlloc) 610 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 611 if (RemovePred(Sec)) 612 return true; 613 if (&Sec == Obj.SectionNames) 614 return false; 615 return (Sec.Flags & SHF_ALLOC) == 0; 616 }; 617 618 if (Config.StripAll) 619 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 620 if (RemovePred(Sec)) 621 return true; 622 if (&Sec == Obj.SectionNames) 623 return false; 624 if (StringRef(Sec.Name).startswith(".gnu.warning")) 625 return false; 626 return (Sec.Flags & SHF_ALLOC) == 0; 627 }; 628 629 // Explicit copies: 630 if (!Config.OnlyKeep.empty()) { 631 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 632 // Explicitly keep these sections regardless of previous removes. 633 if (is_contained(Config.OnlyKeep, Sec.Name)) 634 return false; 635 636 // Allow all implicit removes. 637 if (RemovePred(Sec)) 638 return true; 639 640 // Keep special sections. 641 if (Obj.SectionNames == &Sec) 642 return false; 643 if (Obj.SymbolTable == &Sec || 644 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) 645 return false; 646 647 // Remove everything else. 648 return true; 649 }; 650 } 651 652 if (!Config.Keep.empty()) { 653 RemovePred = [Config, RemovePred](const SectionBase &Sec) { 654 // Explicitly keep these sections regardless of previous removes. 655 if (is_contained(Config.Keep, Sec.Name)) 656 return false; 657 // Otherwise defer to RemovePred. 658 return RemovePred(Sec); 659 }; 660 } 661 662 // This has to be the last predicate assignment. 663 // If the option --keep-symbol has been specified 664 // and at least one of those symbols is present 665 // (equivalently, the updated symbol table is not empty) 666 // the symbol table and the string table should not be removed. 667 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && 668 Obj.SymbolTable && !Obj.SymbolTable->empty()) { 669 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { 670 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) 671 return false; 672 return RemovePred(Sec); 673 }; 674 } 675 676 if (Config.CompressionType != DebugCompressionType::None) 677 replaceDebugSections(Config, Obj, RemovePred, isCompressable, 678 [&Config, &Obj](const SectionBase *S) { 679 return &Obj.addSection<CompressedSection>( 680 *S, Config.CompressionType); 681 }); 682 else if (Config.DecompressDebugSections) 683 replaceDebugSections( 684 Config, Obj, RemovePred, 685 [](const SectionBase &S) { return isa<CompressedSection>(&S); }, 686 [&Obj](const SectionBase *S) { 687 auto CS = cast<CompressedSection>(S); 688 return &Obj.addSection<DecompressedSection>(*CS); 689 }); 690 691 Obj.removeSections(RemovePred); 692 693 if (!Config.SectionsToRename.empty()) { 694 for (auto &Sec : Obj.sections()) { 695 const auto Iter = Config.SectionsToRename.find(Sec.Name); 696 if (Iter != Config.SectionsToRename.end()) { 697 const SectionRename &SR = Iter->second; 698 Sec.Name = SR.NewName; 699 if (SR.NewFlags.hasValue()) { 700 // Preserve some flags which should not be dropped when setting flags. 701 // Also, preserve anything OS/processor dependant. 702 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE | 703 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | 704 ELF::SHF_MASKOS | ELF::SHF_MASKPROC | 705 ELF::SHF_TLS | ELF::SHF_INFO_LINK; 706 Sec.Flags = (Sec.Flags & PreserveMask) | 707 (SR.NewFlags.getValue() & ~PreserveMask); 708 } 709 } 710 } 711 } 712 713 if (!Config.AddSection.empty()) { 714 for (const auto &Flag : Config.AddSection) { 715 auto SecPair = Flag.split("="); 716 auto SecName = SecPair.first; 717 auto File = SecPair.second; 718 auto BufOrErr = MemoryBuffer::getFile(File); 719 if (!BufOrErr) 720 reportError(File, BufOrErr.getError()); 721 auto Buf = std::move(*BufOrErr); 722 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 723 auto BufSize = Buf->getBufferSize(); 724 Obj.addSection<OwnedDataSection>(SecName, 725 ArrayRef<uint8_t>(BufPtr, BufSize)); 726 } 727 } 728 729 if (!Config.DumpSection.empty()) { 730 for (const auto &Flag : Config.DumpSection) { 731 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 732 StringRef SecName = SecPair.first; 733 StringRef File = SecPair.second; 734 if (Error E = dumpSectionToFile(SecName, File, Obj)) 735 reportError(Config.InputFilename, std::move(E)); 736 } 737 } 738 739 if (!Config.AddGnuDebugLink.empty()) 740 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); 741 } 742 743 static void executeElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader, 744 Buffer &Out, ElfType OutputElfType) { 745 std::unique_ptr<Object> Obj = Reader.create(); 746 747 handleArgs(Config, *Obj, Reader, OutputElfType); 748 749 std::unique_ptr<Writer> Writer = 750 createWriter(Config, *Obj, Out, OutputElfType); 751 Writer->finalize(); 752 Writer->write(); 753 } 754 755 // For regular archives this function simply calls llvm::writeArchive, 756 // For thin archives it writes the archive file itself as well as its members. 757 static Error deepWriteArchive(StringRef ArcName, 758 ArrayRef<NewArchiveMember> NewMembers, 759 bool WriteSymtab, object::Archive::Kind Kind, 760 bool Deterministic, bool Thin) { 761 Error E = 762 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin); 763 if (!Thin || E) 764 return E; 765 for (const NewArchiveMember &Member : NewMembers) { 766 // Internally, FileBuffer will use the buffer created by 767 // FileOutputBuffer::create, for regular files (that is the case for 768 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer. 769 // OnDiskBuffer uses a temporary file and then renames it. So in reality 770 // there is no inefficiency / duplicated in-memory buffers in this case. For 771 // now in-memory buffers can not be completely avoided since 772 // NewArchiveMember still requires them even though writeArchive does not 773 // write them on disk. 774 FileBuffer FB(Member.MemberName); 775 FB.allocate(Member.Buf->getBufferSize()); 776 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 777 FB.getBufferStart()); 778 if (auto E = FB.commit()) 779 return E; 780 } 781 return Error::success(); 782 } 783 784 static void executeElfObjcopyOnArchive(const CopyConfig &Config, 785 const Archive &Ar) { 786 std::vector<NewArchiveMember> NewArchiveMembers; 787 Error Err = Error::success(); 788 for (const Archive::Child &Child : Ar.children(Err)) { 789 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 790 if (!ChildOrErr) 791 reportError(Ar.getFileName(), ChildOrErr.takeError()); 792 Binary *Bin = ChildOrErr->get(); 793 794 Expected<StringRef> ChildNameOrErr = Child.getName(); 795 if (!ChildNameOrErr) 796 reportError(Ar.getFileName(), ChildNameOrErr.takeError()); 797 798 MemBuffer MB(ChildNameOrErr.get()); 799 ELFReader Reader(Bin); 800 executeElfObjcopyOnBinary(Config, Reader, MB, getOutputElfType(*Bin)); 801 802 Expected<NewArchiveMember> Member = 803 NewArchiveMember::getOldMember(Child, true); 804 if (!Member) 805 reportError(Ar.getFileName(), Member.takeError()); 806 Member->Buf = MB.releaseMemoryBuffer(); 807 Member->MemberName = Member->Buf->getBufferIdentifier(); 808 NewArchiveMembers.push_back(std::move(*Member)); 809 } 810 811 if (Err) 812 reportError(Config.InputFilename, std::move(Err)); 813 if (Error E = 814 deepWriteArchive(Config.OutputFilename, NewArchiveMembers, 815 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin())) 816 reportError(Config.OutputFilename, std::move(E)); 817 } 818 819 static void restoreDateOnFile(StringRef Filename, 820 const sys::fs::file_status &Stat) { 821 int FD; 822 823 if (auto EC = 824 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) 825 reportError(Filename, EC); 826 827 if (auto EC = sys::fs::setLastAccessAndModificationTime( 828 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) 829 reportError(Filename, EC); 830 831 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) 832 reportError(Filename, EC); 833 } 834 835 static void executeElfObjcopy(const CopyConfig &Config) { 836 sys::fs::file_status Stat; 837 if (Config.PreserveDates) 838 if (auto EC = sys::fs::status(Config.InputFilename, Stat)) 839 reportError(Config.InputFilename, EC); 840 841 if (Config.InputFormat == "binary") { 842 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); 843 if (!BufOrErr) 844 reportError(Config.InputFilename, BufOrErr.getError()); 845 846 FileBuffer FB(Config.OutputFilename); 847 BinaryReader Reader(Config.BinaryArch, BufOrErr->get()); 848 executeElfObjcopyOnBinary(Config, Reader, FB, 849 getOutputElfType(Config.BinaryArch)); 850 } else { 851 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 852 createBinary(Config.InputFilename); 853 if (!BinaryOrErr) 854 reportError(Config.InputFilename, BinaryOrErr.takeError()); 855 856 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) { 857 executeElfObjcopyOnArchive(Config, *Ar); 858 } else { 859 FileBuffer FB(Config.OutputFilename); 860 Binary *Bin = BinaryOrErr.get().getBinary(); 861 ELFReader Reader(Bin); 862 executeElfObjcopyOnBinary(Config, Reader, FB, getOutputElfType(*Bin)); 863 } 864 } 865 866 if (Config.PreserveDates) { 867 restoreDateOnFile(Config.OutputFilename, Stat); 868 if (!Config.SplitDWO.empty()) 869 restoreDateOnFile(Config.SplitDWO, Stat); 870 } 871 } 872 873 static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols, 874 StringRef Filename) { 875 SmallVector<StringRef, 16> Lines; 876 auto BufOrErr = MemoryBuffer::getFile(Filename); 877 if (!BufOrErr) 878 reportError(Filename, BufOrErr.getError()); 879 880 BufOrErr.get()->getBuffer().split(Lines, '\n'); 881 for (StringRef Line : Lines) { 882 // Ignore everything after '#', trim whitespace, and only add the symbol if 883 // it's not empty. 884 auto TrimmedLine = Line.split('#').first.trim(); 885 if (!TrimmedLine.empty()) 886 Symbols.push_back(TrimmedLine.str()); 887 } 888 } 889 890 // ParseObjcopyOptions returns the config and sets the input arguments. If a 891 // help flag is set then ParseObjcopyOptions will print the help messege and 892 // exit. 893 static DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) { 894 ObjcopyOptTable T; 895 unsigned MissingArgumentIndex, MissingArgumentCount; 896 llvm::opt::InputArgList InputArgs = 897 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 898 899 if (InputArgs.size() == 0) { 900 T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool"); 901 exit(1); 902 } 903 904 if (InputArgs.hasArg(OBJCOPY_help)) { 905 T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool"); 906 exit(0); 907 } 908 909 if (InputArgs.hasArg(OBJCOPY_version)) { 910 cl::PrintVersionMessage(); 911 exit(0); 912 } 913 914 SmallVector<const char *, 2> Positional; 915 916 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 917 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 918 919 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) 920 Positional.push_back(Arg->getValue()); 921 922 if (Positional.empty()) 923 error("No input file specified"); 924 925 if (Positional.size() > 2) 926 error("Too many positional arguments"); 927 928 CopyConfig Config; 929 Config.InputFilename = Positional[0]; 930 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; 931 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 932 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 933 if (Config.InputFormat == "binary") { 934 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); 935 if (BinaryArch.empty()) 936 error("Specified binary input without specifiying an architecture"); 937 Config.BinaryArch = getMachineInfo(BinaryArch); 938 } 939 940 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, 941 OBJCOPY_compress_debug_sections_eq)) { 942 Config.CompressionType = DebugCompressionType::Z; 943 944 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) { 945 Config.CompressionType = 946 StringSwitch<DebugCompressionType>( 947 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)) 948 .Case("zlib-gnu", DebugCompressionType::GNU) 949 .Case("zlib", DebugCompressionType::Z) 950 .Default(DebugCompressionType::None); 951 if (Config.CompressionType == DebugCompressionType::None) 952 error("Invalid or unsupported --compress-debug-sections format: " + 953 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)); 954 if (!zlib::isAvailable()) 955 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress."); 956 } 957 } 958 959 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); 960 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); 961 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); 962 963 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { 964 if (!StringRef(Arg->getValue()).contains('=')) 965 error("Bad format for --redefine-sym"); 966 auto Old2New = StringRef(Arg->getValue()).split('='); 967 if (!Config.SymbolsToRename.insert(Old2New).second) 968 error("Multiple redefinition of symbol " + Old2New.first); 969 } 970 971 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { 972 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue())); 973 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second) 974 error("Multiple renames of section " + SR.OriginalName); 975 } 976 977 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) 978 Config.ToRemove.push_back(Arg->getValue()); 979 for (auto Arg : InputArgs.filtered(OBJCOPY_keep)) 980 Config.Keep.push_back(Arg->getValue()); 981 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep)) 982 Config.OnlyKeep.push_back(Arg->getValue()); 983 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) 984 Config.AddSection.push_back(Arg->getValue()); 985 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section)) 986 Config.DumpSection.push_back(Arg->getValue()); 987 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); 988 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); 989 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); 990 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); 991 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); 992 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); 993 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); 994 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); 995 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); 996 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); 997 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all); 998 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); 999 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); 1000 Config.DecompressDebugSections = 1001 InputArgs.hasArg(OBJCOPY_decompress_debug_sections); 1002 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) 1003 Config.SymbolsToLocalize.push_back(Arg->getValue()); 1004 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) 1005 Config.SymbolsToKeepGlobal.push_back(Arg->getValue()); 1006 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) 1007 addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue()); 1008 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) 1009 Config.SymbolsToGlobalize.push_back(Arg->getValue()); 1010 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) 1011 Config.SymbolsToWeaken.push_back(Arg->getValue()); 1012 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) 1013 Config.SymbolsToRemove.push_back(Arg->getValue()); 1014 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) 1015 Config.SymbolsToKeep.push_back(Arg->getValue()); 1016 1017 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); 1018 1019 DriverConfig DC; 1020 DC.CopyConfigs.push_back(std::move(Config)); 1021 if (Config.DecompressDebugSections && 1022 Config.CompressionType != DebugCompressionType::None) { 1023 error("Cannot specify --compress-debug-sections at the same time as " 1024 "--decompress-debug-sections at the same time"); 1025 } 1026 1027 if (Config.DecompressDebugSections && !zlib::isAvailable()) 1028 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress."); 1029 1030 return DC; 1031 } 1032 1033 // ParseStripOptions returns the config and sets the input arguments. If a 1034 // help flag is set then ParseStripOptions will print the help messege and 1035 // exit. 1036 static DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) { 1037 StripOptTable T; 1038 unsigned MissingArgumentIndex, MissingArgumentCount; 1039 llvm::opt::InputArgList InputArgs = 1040 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 1041 1042 static const char Usage[] = "llvm-strip [options] file..."; 1043 if (InputArgs.size() == 0) { 1044 T.PrintHelp(errs(), Usage, "strip tool"); 1045 exit(1); 1046 } 1047 1048 if (InputArgs.hasArg(STRIP_help)) { 1049 T.PrintHelp(outs(), Usage, "strip tool"); 1050 exit(0); 1051 } 1052 1053 if (InputArgs.hasArg(STRIP_version)) { 1054 cl::PrintVersionMessage(); 1055 exit(0); 1056 } 1057 1058 SmallVector<const char *, 2> Positional; 1059 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) 1060 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 1061 for (auto Arg : InputArgs.filtered(STRIP_INPUT)) 1062 Positional.push_back(Arg->getValue()); 1063 1064 if (Positional.empty()) 1065 error("No input file specified"); 1066 1067 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) 1068 error("Multiple input files cannot be used in combination with -o"); 1069 1070 CopyConfig Config; 1071 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); 1072 1073 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all); 1074 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); 1075 Config.StripAll = InputArgs.hasArg(STRIP_strip_all); 1076 1077 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll) 1078 Config.StripAll = true; 1079 1080 for (auto Arg : InputArgs.filtered(STRIP_remove_section)) 1081 Config.ToRemove.push_back(Arg->getValue()); 1082 1083 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) 1084 Config.SymbolsToKeep.push_back(Arg->getValue()); 1085 1086 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); 1087 1088 DriverConfig DC; 1089 if (Positional.size() == 1) { 1090 Config.InputFilename = Positional[0]; 1091 Config.OutputFilename = 1092 InputArgs.getLastArgValue(STRIP_output, Positional[0]); 1093 DC.CopyConfigs.push_back(std::move(Config)); 1094 } else { 1095 for (const char *Filename : Positional) { 1096 Config.InputFilename = Filename; 1097 Config.OutputFilename = Filename; 1098 DC.CopyConfigs.push_back(Config); 1099 } 1100 } 1101 1102 return DC; 1103 } 1104 1105 int main(int argc, char **argv) { 1106 InitLLVM X(argc, argv); 1107 ToolName = argv[0]; 1108 DriverConfig DriverConfig; 1109 if (sys::path::stem(ToolName).endswith_lower("strip")) 1110 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc)); 1111 else 1112 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); 1113 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs) 1114 executeElfObjcopy(CopyConfig); 1115 } 1116