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