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 const char *Magic = "ZLIB"; 421 return StringRef(Section.Name).startswith(".zdebug") || 422 (Section.OriginalData.size() > strlen(Magic) && 423 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()), 424 Magic, strlen(Magic))) || 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 463 // This function handles the high level operations of GNU objcopy including 464 // handling command line options. It's important to outline certain properties 465 // we expect to hold of the command line operations. Any operation that "keeps" 466 // should keep regardless of a remove. Additionally any removal should respect 467 // any previous removals. Lastly whether or not something is removed shouldn't 468 // depend a) on the order the options occur in or b) on some opaque priority 469 // system. The only priority is that keeps/copies overrule removes. 470 static void handleArgs(const CopyConfig &Config, Object &Obj, 471 const Reader &Reader, ElfType OutputElfType) { 472 473 if (!Config.SplitDWO.empty()) { 474 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); 475 } 476 477 // TODO: update or remove symbols only if there is an option that affects 478 // them. 479 if (Obj.SymbolTable) { 480 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 481 if ((Config.LocalizeHidden && 482 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 483 (!Config.SymbolsToLocalize.empty() && 484 is_contained(Config.SymbolsToLocalize, Sym.Name))) 485 Sym.Binding = STB_LOCAL; 486 487 // Note: these two globalize flags have very similar names but different 488 // meanings: 489 // 490 // --globalize-symbol: promote a symbol to global 491 // --keep-global-symbol: all symbols except for these should be made local 492 // 493 // If --globalize-symbol is specified for a given symbol, it will be 494 // global in the output file even if it is not included via 495 // --keep-global-symbol. Because of that, make sure to check 496 // --globalize-symbol second. 497 if (!Config.SymbolsToKeepGlobal.empty() && 498 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name)) 499 Sym.Binding = STB_LOCAL; 500 501 if (!Config.SymbolsToGlobalize.empty() && 502 is_contained(Config.SymbolsToGlobalize, Sym.Name)) 503 Sym.Binding = STB_GLOBAL; 504 505 if (!Config.SymbolsToWeaken.empty() && 506 is_contained(Config.SymbolsToWeaken, Sym.Name) && 507 Sym.Binding == STB_GLOBAL) 508 Sym.Binding = STB_WEAK; 509 510 if (Config.Weaken && Sym.Binding == STB_GLOBAL && 511 Sym.getShndx() != SHN_UNDEF) 512 Sym.Binding = STB_WEAK; 513 514 const auto I = Config.SymbolsToRename.find(Sym.Name); 515 if (I != Config.SymbolsToRename.end()) 516 Sym.Name = I->getValue(); 517 518 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) 519 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); 520 }); 521 522 // The purpose of this loop is to mark symbols referenced by sections 523 // (like GroupSection or RelocationSection). This way, we know which 524 // symbols are still 'needed' and wich are not. 525 if (Config.StripUnneeded) { 526 for (auto &Section : Obj.sections()) 527 Section.markSymbols(); 528 } 529 530 Obj.removeSymbols([&](const Symbol &Sym) { 531 if ((!Config.SymbolsToKeep.empty() && 532 is_contained(Config.SymbolsToKeep, Sym.Name)) || 533 (Config.KeepFileSymbols && Sym.Type == STT_FILE)) 534 return false; 535 536 if (Config.DiscardAll && Sym.Binding == STB_LOCAL && 537 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && 538 Sym.Type != STT_SECTION) 539 return true; 540 541 if (Config.StripAll || Config.StripAllGNU) 542 return true; 543 544 if (!Config.SymbolsToRemove.empty() && 545 is_contained(Config.SymbolsToRemove, Sym.Name)) { 546 return true; 547 } 548 549 if (Config.StripUnneeded && !Sym.Referenced && 550 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && 551 Sym.Type != STT_FILE && Sym.Type != STT_SECTION) 552 return true; 553 554 return false; 555 }); 556 } 557 558 SectionPred RemovePred = [](const SectionBase &) { return false; }; 559 560 // Removes: 561 if (!Config.ToRemove.empty()) { 562 RemovePred = [&Config](const SectionBase &Sec) { 563 return is_contained(Config.ToRemove, Sec.Name); 564 }; 565 } 566 567 if (Config.StripDWO || !Config.SplitDWO.empty()) 568 RemovePred = [RemovePred](const SectionBase &Sec) { 569 return isDWOSection(Sec) || RemovePred(Sec); 570 }; 571 572 if (Config.ExtractDWO) 573 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 574 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 575 }; 576 577 if (Config.StripAllGNU) 578 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 579 if (RemovePred(Sec)) 580 return true; 581 if ((Sec.Flags & SHF_ALLOC) != 0) 582 return false; 583 if (&Sec == Obj.SectionNames) 584 return false; 585 switch (Sec.Type) { 586 case SHT_SYMTAB: 587 case SHT_REL: 588 case SHT_RELA: 589 case SHT_STRTAB: 590 return true; 591 } 592 return isDebugSection(Sec); 593 }; 594 595 if (Config.StripSections) { 596 RemovePred = [RemovePred](const SectionBase &Sec) { 597 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 598 }; 599 } 600 601 if (Config.StripDebug) { 602 RemovePred = [RemovePred](const SectionBase &Sec) { 603 return RemovePred(Sec) || isDebugSection(Sec); 604 }; 605 } 606 607 if (Config.StripNonAlloc) 608 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 609 if (RemovePred(Sec)) 610 return true; 611 if (&Sec == Obj.SectionNames) 612 return false; 613 return (Sec.Flags & SHF_ALLOC) == 0; 614 }; 615 616 if (Config.StripAll) 617 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 618 if (RemovePred(Sec)) 619 return true; 620 if (&Sec == Obj.SectionNames) 621 return false; 622 if (StringRef(Sec.Name).startswith(".gnu.warning")) 623 return false; 624 return (Sec.Flags & SHF_ALLOC) == 0; 625 }; 626 627 // Explicit copies: 628 if (!Config.OnlyKeep.empty()) { 629 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 630 // Explicitly keep these sections regardless of previous removes. 631 if (is_contained(Config.OnlyKeep, Sec.Name)) 632 return false; 633 634 // Allow all implicit removes. 635 if (RemovePred(Sec)) 636 return true; 637 638 // Keep special sections. 639 if (Obj.SectionNames == &Sec) 640 return false; 641 if (Obj.SymbolTable == &Sec || 642 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) 643 return false; 644 645 // Remove everything else. 646 return true; 647 }; 648 } 649 650 if (!Config.Keep.empty()) { 651 RemovePred = [Config, RemovePred](const SectionBase &Sec) { 652 // Explicitly keep these sections regardless of previous removes. 653 if (is_contained(Config.Keep, Sec.Name)) 654 return false; 655 // Otherwise defer to RemovePred. 656 return RemovePred(Sec); 657 }; 658 } 659 660 // This has to be the last predicate assignment. 661 // If the option --keep-symbol has been specified 662 // and at least one of those symbols is present 663 // (equivalently, the updated symbol table is not empty) 664 // the symbol table and the string table should not be removed. 665 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && 666 Obj.SymbolTable && !Obj.SymbolTable->empty()) { 667 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { 668 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) 669 return false; 670 return RemovePred(Sec); 671 }; 672 } 673 674 if (Config.CompressionType != DebugCompressionType::None) 675 compressSections(Config, Obj, RemovePred); 676 677 Obj.removeSections(RemovePred); 678 679 if (!Config.SectionsToRename.empty()) { 680 for (auto &Sec : Obj.sections()) { 681 const auto Iter = Config.SectionsToRename.find(Sec.Name); 682 if (Iter != Config.SectionsToRename.end()) { 683 const SectionRename &SR = Iter->second; 684 Sec.Name = SR.NewName; 685 if (SR.NewFlags.hasValue()) { 686 // Preserve some flags which should not be dropped when setting flags. 687 // Also, preserve anything OS/processor dependant. 688 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE | 689 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | 690 ELF::SHF_MASKOS | ELF::SHF_MASKPROC | 691 ELF::SHF_TLS | ELF::SHF_INFO_LINK; 692 Sec.Flags = (Sec.Flags & PreserveMask) | 693 (SR.NewFlags.getValue() & ~PreserveMask); 694 } 695 } 696 } 697 } 698 699 if (!Config.AddSection.empty()) { 700 for (const auto &Flag : Config.AddSection) { 701 auto SecPair = Flag.split("="); 702 auto SecName = SecPair.first; 703 auto File = SecPair.second; 704 auto BufOrErr = MemoryBuffer::getFile(File); 705 if (!BufOrErr) 706 reportError(File, BufOrErr.getError()); 707 auto Buf = std::move(*BufOrErr); 708 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 709 auto BufSize = Buf->getBufferSize(); 710 Obj.addSection<OwnedDataSection>(SecName, 711 ArrayRef<uint8_t>(BufPtr, BufSize)); 712 } 713 } 714 715 if (!Config.DumpSection.empty()) { 716 for (const auto &Flag : Config.DumpSection) { 717 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 718 StringRef SecName = SecPair.first; 719 StringRef File = SecPair.second; 720 if (Error E = dumpSectionToFile(SecName, File, Obj)) 721 reportError(Config.InputFilename, std::move(E)); 722 } 723 } 724 725 if (!Config.AddGnuDebugLink.empty()) 726 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); 727 } 728 729 static void executeElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader, 730 Buffer &Out, ElfType OutputElfType) { 731 std::unique_ptr<Object> Obj = Reader.create(); 732 733 handleArgs(Config, *Obj, Reader, OutputElfType); 734 735 std::unique_ptr<Writer> Writer = 736 createWriter(Config, *Obj, Out, OutputElfType); 737 Writer->finalize(); 738 Writer->write(); 739 } 740 741 // For regular archives this function simply calls llvm::writeArchive, 742 // For thin archives it writes the archive file itself as well as its members. 743 static Error deepWriteArchive(StringRef ArcName, 744 ArrayRef<NewArchiveMember> NewMembers, 745 bool WriteSymtab, object::Archive::Kind Kind, 746 bool Deterministic, bool Thin) { 747 Error E = 748 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin); 749 if (!Thin || E) 750 return E; 751 for (const NewArchiveMember &Member : NewMembers) { 752 // Internally, FileBuffer will use the buffer created by 753 // FileOutputBuffer::create, for regular files (that is the case for 754 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer. 755 // OnDiskBuffer uses a temporary file and then renames it. So in reality 756 // there is no inefficiency / duplicated in-memory buffers in this case. For 757 // now in-memory buffers can not be completely avoided since 758 // NewArchiveMember still requires them even though writeArchive does not 759 // write them on disk. 760 FileBuffer FB(Member.MemberName); 761 FB.allocate(Member.Buf->getBufferSize()); 762 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 763 FB.getBufferStart()); 764 if (auto E = FB.commit()) 765 return E; 766 } 767 return Error::success(); 768 } 769 770 static void executeElfObjcopyOnArchive(const CopyConfig &Config, 771 const Archive &Ar) { 772 std::vector<NewArchiveMember> NewArchiveMembers; 773 Error Err = Error::success(); 774 for (const Archive::Child &Child : Ar.children(Err)) { 775 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 776 if (!ChildOrErr) 777 reportError(Ar.getFileName(), ChildOrErr.takeError()); 778 Binary *Bin = ChildOrErr->get(); 779 780 Expected<StringRef> ChildNameOrErr = Child.getName(); 781 if (!ChildNameOrErr) 782 reportError(Ar.getFileName(), ChildNameOrErr.takeError()); 783 784 MemBuffer MB(ChildNameOrErr.get()); 785 ELFReader Reader(Bin); 786 executeElfObjcopyOnBinary(Config, Reader, MB, getOutputElfType(*Bin)); 787 788 Expected<NewArchiveMember> Member = 789 NewArchiveMember::getOldMember(Child, true); 790 if (!Member) 791 reportError(Ar.getFileName(), Member.takeError()); 792 Member->Buf = MB.releaseMemoryBuffer(); 793 Member->MemberName = Member->Buf->getBufferIdentifier(); 794 NewArchiveMembers.push_back(std::move(*Member)); 795 } 796 797 if (Err) 798 reportError(Config.InputFilename, std::move(Err)); 799 if (Error E = 800 deepWriteArchive(Config.OutputFilename, NewArchiveMembers, 801 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin())) 802 reportError(Config.OutputFilename, std::move(E)); 803 } 804 805 static void restoreDateOnFile(StringRef Filename, 806 const sys::fs::file_status &Stat) { 807 int FD; 808 809 if (auto EC = 810 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) 811 reportError(Filename, EC); 812 813 if (auto EC = sys::fs::setLastAccessAndModificationTime( 814 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) 815 reportError(Filename, EC); 816 817 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) 818 reportError(Filename, EC); 819 } 820 821 static void executeElfObjcopy(const CopyConfig &Config) { 822 sys::fs::file_status Stat; 823 if (Config.PreserveDates) 824 if (auto EC = sys::fs::status(Config.InputFilename, Stat)) 825 reportError(Config.InputFilename, EC); 826 827 if (Config.InputFormat == "binary") { 828 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); 829 if (!BufOrErr) 830 reportError(Config.InputFilename, BufOrErr.getError()); 831 832 FileBuffer FB(Config.OutputFilename); 833 BinaryReader Reader(Config.BinaryArch, BufOrErr->get()); 834 executeElfObjcopyOnBinary(Config, Reader, FB, 835 getOutputElfType(Config.BinaryArch)); 836 } else { 837 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 838 createBinary(Config.InputFilename); 839 if (!BinaryOrErr) 840 reportError(Config.InputFilename, BinaryOrErr.takeError()); 841 842 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) { 843 executeElfObjcopyOnArchive(Config, *Ar); 844 } else { 845 FileBuffer FB(Config.OutputFilename); 846 Binary *Bin = BinaryOrErr.get().getBinary(); 847 ELFReader Reader(Bin); 848 executeElfObjcopyOnBinary(Config, Reader, FB, getOutputElfType(*Bin)); 849 } 850 } 851 852 if (Config.PreserveDates) { 853 restoreDateOnFile(Config.OutputFilename, Stat); 854 if (!Config.SplitDWO.empty()) 855 restoreDateOnFile(Config.SplitDWO, Stat); 856 } 857 } 858 859 static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols, 860 StringRef Filename) { 861 SmallVector<StringRef, 16> Lines; 862 auto BufOrErr = MemoryBuffer::getFile(Filename); 863 if (!BufOrErr) 864 reportError(Filename, BufOrErr.getError()); 865 866 BufOrErr.get()->getBuffer().split(Lines, '\n'); 867 for (StringRef Line : Lines) { 868 // Ignore everything after '#', trim whitespace, and only add the symbol if 869 // it's not empty. 870 auto TrimmedLine = Line.split('#').first.trim(); 871 if (!TrimmedLine.empty()) 872 Symbols.push_back(TrimmedLine.str()); 873 } 874 } 875 876 // ParseObjcopyOptions returns the config and sets the input arguments. If a 877 // help flag is set then ParseObjcopyOptions will print the help messege and 878 // exit. 879 static DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) { 880 ObjcopyOptTable T; 881 unsigned MissingArgumentIndex, MissingArgumentCount; 882 llvm::opt::InputArgList InputArgs = 883 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 884 885 if (InputArgs.size() == 0) { 886 T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); 887 exit(1); 888 } 889 890 if (InputArgs.hasArg(OBJCOPY_help)) { 891 T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); 892 exit(0); 893 } 894 895 SmallVector<const char *, 2> Positional; 896 897 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 898 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 899 900 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) 901 Positional.push_back(Arg->getValue()); 902 903 if (Positional.empty()) 904 error("No input file specified"); 905 906 if (Positional.size() > 2) 907 error("Too many positional arguments"); 908 909 CopyConfig Config; 910 Config.InputFilename = Positional[0]; 911 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; 912 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 913 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 914 if (Config.InputFormat == "binary") { 915 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); 916 if (BinaryArch.empty()) 917 error("Specified binary input without specifiying an architecture"); 918 Config.BinaryArch = getMachineInfo(BinaryArch); 919 } 920 921 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, 922 OBJCOPY_compress_debug_sections_eq)) { 923 Config.CompressionType = DebugCompressionType::Z; 924 925 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) { 926 Config.CompressionType = 927 StringSwitch<DebugCompressionType>( 928 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)) 929 .Case("zlib-gnu", DebugCompressionType::GNU) 930 .Case("zlib", DebugCompressionType::Z) 931 .Default(DebugCompressionType::None); 932 if (Config.CompressionType == DebugCompressionType::None) 933 error("Invalid or unsupported --compress-debug-sections format: " + 934 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)); 935 if (!zlib::isAvailable()) 936 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress."); 937 } 938 } 939 940 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); 941 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); 942 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); 943 944 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { 945 if (!StringRef(Arg->getValue()).contains('=')) 946 error("Bad format for --redefine-sym"); 947 auto Old2New = StringRef(Arg->getValue()).split('='); 948 if (!Config.SymbolsToRename.insert(Old2New).second) 949 error("Multiple redefinition of symbol " + Old2New.first); 950 } 951 952 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { 953 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue())); 954 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second) 955 error("Multiple renames of section " + SR.OriginalName); 956 } 957 958 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) 959 Config.ToRemove.push_back(Arg->getValue()); 960 for (auto Arg : InputArgs.filtered(OBJCOPY_keep)) 961 Config.Keep.push_back(Arg->getValue()); 962 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep)) 963 Config.OnlyKeep.push_back(Arg->getValue()); 964 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) 965 Config.AddSection.push_back(Arg->getValue()); 966 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section)) 967 Config.DumpSection.push_back(Arg->getValue()); 968 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); 969 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); 970 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); 971 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); 972 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); 973 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); 974 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); 975 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); 976 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); 977 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); 978 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all); 979 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); 980 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); 981 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) 982 Config.SymbolsToLocalize.push_back(Arg->getValue()); 983 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) 984 Config.SymbolsToKeepGlobal.push_back(Arg->getValue()); 985 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) 986 addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue()); 987 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) 988 Config.SymbolsToGlobalize.push_back(Arg->getValue()); 989 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) 990 Config.SymbolsToWeaken.push_back(Arg->getValue()); 991 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) 992 Config.SymbolsToRemove.push_back(Arg->getValue()); 993 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) 994 Config.SymbolsToKeep.push_back(Arg->getValue()); 995 996 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); 997 998 DriverConfig DC; 999 DC.CopyConfigs.push_back(std::move(Config)); 1000 return DC; 1001 } 1002 1003 // ParseStripOptions returns the config and sets the input arguments. If a 1004 // help flag is set then ParseStripOptions will print the help messege and 1005 // exit. 1006 static DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) { 1007 StripOptTable T; 1008 unsigned MissingArgumentIndex, MissingArgumentCount; 1009 llvm::opt::InputArgList InputArgs = 1010 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 1011 1012 if (InputArgs.size() == 0) { 1013 T.PrintHelp(errs(), "llvm-strip", "strip tool"); 1014 exit(1); 1015 } 1016 1017 if (InputArgs.hasArg(STRIP_help)) { 1018 T.PrintHelp(outs(), "llvm-strip", "strip tool"); 1019 exit(0); 1020 } 1021 1022 SmallVector<const char *, 2> Positional; 1023 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) 1024 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 1025 for (auto Arg : InputArgs.filtered(STRIP_INPUT)) 1026 Positional.push_back(Arg->getValue()); 1027 1028 if (Positional.empty()) 1029 error("No input file specified"); 1030 1031 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) 1032 error("Multiple input files cannot be used in combination with -o"); 1033 1034 CopyConfig Config; 1035 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); 1036 1037 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all); 1038 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); 1039 Config.StripAll = InputArgs.hasArg(STRIP_strip_all); 1040 1041 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll) 1042 Config.StripAll = true; 1043 1044 for (auto Arg : InputArgs.filtered(STRIP_remove_section)) 1045 Config.ToRemove.push_back(Arg->getValue()); 1046 1047 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) 1048 Config.SymbolsToKeep.push_back(Arg->getValue()); 1049 1050 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); 1051 1052 DriverConfig DC; 1053 if (Positional.size() == 1) { 1054 Config.InputFilename = Positional[0]; 1055 Config.OutputFilename = 1056 InputArgs.getLastArgValue(STRIP_output, Positional[0]); 1057 DC.CopyConfigs.push_back(std::move(Config)); 1058 } else { 1059 for (const char *Filename : Positional) { 1060 Config.InputFilename = Filename; 1061 Config.OutputFilename = Filename; 1062 DC.CopyConfigs.push_back(Config); 1063 } 1064 } 1065 1066 return DC; 1067 } 1068 1069 int main(int argc, char **argv) { 1070 InitLLVM X(argc, argv); 1071 ToolName = argv[0]; 1072 DriverConfig DriverConfig; 1073 if (sys::path::stem(ToolName).endswith_lower("strip")) 1074 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc)); 1075 else 1076 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); 1077 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs) 1078 executeElfObjcopy(CopyConfig); 1079 } 1080