1 //===- ELFObjcopy.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 "ELFObjcopy.h" 11 #include "Buffer.h" 12 #include "CopyConfig.h" 13 #include "Object.h" 14 #include "llvm-objcopy.h" 15 16 #include "llvm/ADT/BitmaskEnum.h" 17 #include "llvm/ADT/Optional.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/ADT/Twine.h" 22 #include "llvm/BinaryFormat/ELF.h" 23 #include "llvm/MC/MCTargetOptions.h" 24 #include "llvm/Object/Binary.h" 25 #include "llvm/Object/ELFObjectFile.h" 26 #include "llvm/Object/ELFTypes.h" 27 #include "llvm/Object/Error.h" 28 #include "llvm/Option/Option.h" 29 #include "llvm/Support/Casting.h" 30 #include "llvm/Support/Compression.h" 31 #include "llvm/Support/Errc.h" 32 #include "llvm/Support/Error.h" 33 #include "llvm/Support/ErrorHandling.h" 34 #include "llvm/Support/ErrorOr.h" 35 #include "llvm/Support/Memory.h" 36 #include "llvm/Support/Path.h" 37 #include "llvm/Support/raw_ostream.h" 38 #include <algorithm> 39 #include <cassert> 40 #include <cstdlib> 41 #include <functional> 42 #include <iterator> 43 #include <memory> 44 #include <string> 45 #include <system_error> 46 #include <utility> 47 48 namespace llvm { 49 namespace objcopy { 50 namespace elf { 51 52 using namespace object; 53 using namespace ELF; 54 using SectionPred = std::function<bool(const SectionBase &Sec)>; 55 56 static bool isDebugSection(const SectionBase &Sec) { 57 return StringRef(Sec.Name).startswith(".debug") || 58 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index"; 59 } 60 61 static bool isDWOSection(const SectionBase &Sec) { 62 return StringRef(Sec.Name).endswith(".dwo"); 63 } 64 65 static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { 66 // We can't remove the section header string table. 67 if (&Sec == Obj.SectionNames) 68 return false; 69 // Short of keeping the string table we want to keep everything that is a DWO 70 // section and remove everything else. 71 return !isDWOSection(Sec); 72 } 73 74 static ElfType getOutputElfType(const Binary &Bin) { 75 // Infer output ELF type from the input ELF object 76 if (isa<ELFObjectFile<ELF32LE>>(Bin)) 77 return ELFT_ELF32LE; 78 if (isa<ELFObjectFile<ELF64LE>>(Bin)) 79 return ELFT_ELF64LE; 80 if (isa<ELFObjectFile<ELF32BE>>(Bin)) 81 return ELFT_ELF32BE; 82 if (isa<ELFObjectFile<ELF64BE>>(Bin)) 83 return ELFT_ELF64BE; 84 llvm_unreachable("Invalid ELFType"); 85 } 86 87 static ElfType getOutputElfType(const MachineInfo &MI) { 88 // Infer output ELF type from the binary arch specified 89 if (MI.Is64Bit) 90 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE; 91 else 92 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; 93 } 94 95 static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, 96 Object &Obj, Buffer &Buf, 97 ElfType OutputElfType) { 98 if (Config.OutputFormat == "binary") { 99 return llvm::make_unique<BinaryWriter>(Obj, Buf); 100 } 101 // Depending on the initial ELFT and OutputFormat we need a different Writer. 102 switch (OutputElfType) { 103 case ELFT_ELF32LE: 104 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, 105 !Config.StripSections); 106 case ELFT_ELF64LE: 107 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, 108 !Config.StripSections); 109 case ELFT_ELF32BE: 110 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, 111 !Config.StripSections); 112 case ELFT_ELF64BE: 113 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, 114 !Config.StripSections); 115 } 116 llvm_unreachable("Invalid output format"); 117 } 118 119 template <class ELFT> 120 static Expected<ArrayRef<uint8_t>> 121 findBuildID(const object::ELFFile<ELFT> &In) { 122 for (const auto &Phdr : unwrapOrError(In.program_headers())) { 123 if (Phdr.p_type != PT_NOTE) 124 continue; 125 Error Err = Error::success(); 126 for (const auto &Note : In.notes(Phdr, Err)) 127 if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) 128 return Note.getDesc(); 129 if (Err) 130 return std::move(Err); 131 } 132 return createStringError(llvm::errc::invalid_argument, 133 "Could not find build ID."); 134 } 135 136 static Expected<ArrayRef<uint8_t>> 137 findBuildID(const object::ELFObjectFileBase &In) { 138 if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In)) 139 return findBuildID(*O->getELFFile()); 140 else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In)) 141 return findBuildID(*O->getELFFile()); 142 else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In)) 143 return findBuildID(*O->getELFFile()); 144 else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In)) 145 return findBuildID(*O->getELFFile()); 146 147 llvm_unreachable("Bad file format"); 148 } 149 150 static void linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, 151 StringRef Suffix, ArrayRef<uint8_t> BuildIdBytes) { 152 SmallString<128> Path = Config.BuildIdLinkDir; 153 sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true)); 154 if (auto EC = sys::fs::create_directories(Path)) 155 error("cannot create build ID link directory " + Path + ": " + 156 EC.message()); 157 158 sys::path::append(Path, 159 llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true)); 160 Path += Suffix; 161 if (auto EC = sys::fs::create_hard_link(ToLink, Path)) { 162 // Hard linking failed, try to remove the file first if it exists. 163 if (sys::fs::exists(Path)) 164 sys::fs::remove(Path); 165 EC = sys::fs::create_hard_link(ToLink, Path); 166 if (EC) 167 error("cannot link " + ToLink + " to " + Path + ": " + EC.message()); 168 } 169 } 170 171 static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader, 172 StringRef File, ElfType OutputElfType) { 173 auto DWOFile = Reader.create(); 174 DWOFile->removeSections( 175 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); }); 176 if (Config.OutputArch) 177 DWOFile->Machine = Config.OutputArch.getValue().EMachine; 178 FileBuffer FB(File); 179 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); 180 Writer->finalize(); 181 Writer->write(); 182 } 183 184 static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 185 Object &Obj) { 186 for (auto &Sec : Obj.sections()) { 187 if (Sec.Name == SecName) { 188 if (Sec.OriginalData.empty()) 189 return make_error<StringError>("Can't dump section \"" + SecName + 190 "\": it has no contents", 191 object_error::parse_failed); 192 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 193 FileOutputBuffer::create(Filename, Sec.OriginalData.size()); 194 if (!BufferOrErr) 195 return BufferOrErr.takeError(); 196 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 197 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), 198 Buf->getBufferStart()); 199 if (Error E = Buf->commit()) 200 return E; 201 return Error::success(); 202 } 203 } 204 return make_error<StringError>("Section not found", 205 object_error::parse_failed); 206 } 207 208 static bool isCompressed(const SectionBase &Section) { 209 const char *Magic = "ZLIB"; 210 return StringRef(Section.Name).startswith(".zdebug") || 211 (Section.OriginalData.size() > strlen(Magic) && 212 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()), 213 Magic, strlen(Magic))) || 214 (Section.Flags & ELF::SHF_COMPRESSED); 215 } 216 217 static bool isCompressable(const SectionBase &Section) { 218 return !isCompressed(Section) && isDebugSection(Section) && 219 Section.Name != ".gdb_index"; 220 } 221 222 static void replaceDebugSections( 223 const CopyConfig &Config, Object &Obj, SectionPred &RemovePred, 224 function_ref<bool(const SectionBase &)> shouldReplace, 225 function_ref<SectionBase *(const SectionBase *)> addSection) { 226 SmallVector<SectionBase *, 13> ToReplace; 227 SmallVector<RelocationSection *, 13> RelocationSections; 228 for (auto &Sec : Obj.sections()) { 229 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) { 230 if (shouldReplace(*R->getSection())) 231 RelocationSections.push_back(R); 232 continue; 233 } 234 235 if (shouldReplace(Sec)) 236 ToReplace.push_back(&Sec); 237 } 238 239 for (SectionBase *S : ToReplace) { 240 SectionBase *NewSection = addSection(S); 241 242 for (RelocationSection *RS : RelocationSections) { 243 if (RS->getSection() == S) 244 RS->setSection(NewSection); 245 } 246 } 247 248 RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) { 249 return shouldReplace(Sec) || RemovePred(Sec); 250 }; 251 } 252 253 // This function handles the high level operations of GNU objcopy including 254 // handling command line options. It's important to outline certain properties 255 // we expect to hold of the command line operations. Any operation that "keeps" 256 // should keep regardless of a remove. Additionally any removal should respect 257 // any previous removals. Lastly whether or not something is removed shouldn't 258 // depend a) on the order the options occur in or b) on some opaque priority 259 // system. The only priority is that keeps/copies overrule removes. 260 static void handleArgs(const CopyConfig &Config, Object &Obj, 261 const Reader &Reader, ElfType OutputElfType) { 262 263 if (!Config.SplitDWO.empty()) { 264 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); 265 } 266 if (Config.OutputArch) 267 Obj.Machine = Config.OutputArch.getValue().EMachine; 268 269 // TODO: update or remove symbols only if there is an option that affects 270 // them. 271 if (Obj.SymbolTable) { 272 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 273 if (!Sym.isCommon() && 274 ((Config.LocalizeHidden && 275 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 276 is_contained(Config.SymbolsToLocalize, Sym.Name))) 277 Sym.Binding = STB_LOCAL; 278 279 // Note: these two globalize flags have very similar names but different 280 // meanings: 281 // 282 // --globalize-symbol: promote a symbol to global 283 // --keep-global-symbol: all symbols except for these should be made local 284 // 285 // If --globalize-symbol is specified for a given symbol, it will be 286 // global in the output file even if it is not included via 287 // --keep-global-symbol. Because of that, make sure to check 288 // --globalize-symbol second. 289 if (!Config.SymbolsToKeepGlobal.empty() && 290 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) && 291 Sym.getShndx() != SHN_UNDEF) 292 Sym.Binding = STB_LOCAL; 293 294 if (is_contained(Config.SymbolsToGlobalize, Sym.Name) && 295 Sym.getShndx() != SHN_UNDEF) 296 Sym.Binding = STB_GLOBAL; 297 298 if (is_contained(Config.SymbolsToWeaken, Sym.Name) && 299 Sym.Binding == STB_GLOBAL) 300 Sym.Binding = STB_WEAK; 301 302 if (Config.Weaken && Sym.Binding == STB_GLOBAL && 303 Sym.getShndx() != SHN_UNDEF) 304 Sym.Binding = STB_WEAK; 305 306 const auto I = Config.SymbolsToRename.find(Sym.Name); 307 if (I != Config.SymbolsToRename.end()) 308 Sym.Name = I->getValue(); 309 310 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) 311 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); 312 }); 313 314 // The purpose of this loop is to mark symbols referenced by sections 315 // (like GroupSection or RelocationSection). This way, we know which 316 // symbols are still 'needed' and which are not. 317 if (Config.StripUnneeded) { 318 for (auto &Section : Obj.sections()) 319 Section.markSymbols(); 320 } 321 322 Obj.removeSymbols([&](const Symbol &Sym) { 323 if (is_contained(Config.SymbolsToKeep, Sym.Name) || 324 (Config.KeepFileSymbols && Sym.Type == STT_FILE)) 325 return false; 326 327 if (Config.DiscardAll && Sym.Binding == STB_LOCAL && 328 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && 329 Sym.Type != STT_SECTION) 330 return true; 331 332 if (Config.StripAll || Config.StripAllGNU) 333 return true; 334 335 if (is_contained(Config.SymbolsToRemove, Sym.Name)) 336 return true; 337 338 if (Config.StripUnneeded && !Sym.Referenced && 339 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && 340 Sym.Type != STT_FILE && Sym.Type != STT_SECTION) 341 return true; 342 343 return false; 344 }); 345 } 346 347 SectionPred RemovePred = [](const SectionBase &) { return false; }; 348 349 // Removes: 350 if (!Config.ToRemove.empty()) { 351 RemovePred = [&Config](const SectionBase &Sec) { 352 return is_contained(Config.ToRemove, Sec.Name); 353 }; 354 } 355 356 if (Config.StripDWO || !Config.SplitDWO.empty()) 357 RemovePred = [RemovePred](const SectionBase &Sec) { 358 return isDWOSection(Sec) || RemovePred(Sec); 359 }; 360 361 if (Config.ExtractDWO) 362 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 363 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 364 }; 365 366 if (Config.StripAllGNU) 367 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 368 if (RemovePred(Sec)) 369 return true; 370 if ((Sec.Flags & SHF_ALLOC) != 0) 371 return false; 372 if (&Sec == Obj.SectionNames) 373 return false; 374 switch (Sec.Type) { 375 case SHT_SYMTAB: 376 case SHT_REL: 377 case SHT_RELA: 378 case SHT_STRTAB: 379 return true; 380 } 381 return isDebugSection(Sec); 382 }; 383 384 if (Config.StripSections) { 385 RemovePred = [RemovePred](const SectionBase &Sec) { 386 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 387 }; 388 } 389 390 if (Config.StripDebug) { 391 RemovePred = [RemovePred](const SectionBase &Sec) { 392 return RemovePred(Sec) || isDebugSection(Sec); 393 }; 394 } 395 396 if (Config.StripNonAlloc) 397 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 398 if (RemovePred(Sec)) 399 return true; 400 if (&Sec == Obj.SectionNames) 401 return false; 402 return (Sec.Flags & SHF_ALLOC) == 0; 403 }; 404 405 if (Config.StripAll) 406 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 407 if (RemovePred(Sec)) 408 return true; 409 if (&Sec == Obj.SectionNames) 410 return false; 411 if (StringRef(Sec.Name).startswith(".gnu.warning")) 412 return false; 413 return (Sec.Flags & SHF_ALLOC) == 0; 414 }; 415 416 // Explicit copies: 417 if (!Config.OnlySection.empty()) { 418 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 419 // Explicitly keep these sections regardless of previous removes. 420 if (is_contained(Config.OnlySection, Sec.Name)) 421 return false; 422 423 // Allow all implicit removes. 424 if (RemovePred(Sec)) 425 return true; 426 427 // Keep special sections. 428 if (Obj.SectionNames == &Sec) 429 return false; 430 if (Obj.SymbolTable == &Sec || 431 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) 432 return false; 433 434 // Remove everything else. 435 return true; 436 }; 437 } 438 439 if (!Config.KeepSection.empty()) { 440 RemovePred = [&Config, RemovePred](const SectionBase &Sec) { 441 // Explicitly keep these sections regardless of previous removes. 442 if (is_contained(Config.KeepSection, Sec.Name)) 443 return false; 444 // Otherwise defer to RemovePred. 445 return RemovePred(Sec); 446 }; 447 } 448 449 // This has to be the last predicate assignment. 450 // If the option --keep-symbol has been specified 451 // and at least one of those symbols is present 452 // (equivalently, the updated symbol table is not empty) 453 // the symbol table and the string table should not be removed. 454 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && 455 Obj.SymbolTable && !Obj.SymbolTable->empty()) { 456 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { 457 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) 458 return false; 459 return RemovePred(Sec); 460 }; 461 } 462 463 if (Config.CompressionType != DebugCompressionType::None) 464 replaceDebugSections(Config, Obj, RemovePred, isCompressable, 465 [&Config, &Obj](const SectionBase *S) { 466 return &Obj.addSection<CompressedSection>( 467 *S, Config.CompressionType); 468 }); 469 else if (Config.DecompressDebugSections) 470 replaceDebugSections( 471 Config, Obj, RemovePred, 472 [](const SectionBase &S) { return isa<CompressedSection>(&S); }, 473 [&Obj](const SectionBase *S) { 474 auto CS = cast<CompressedSection>(S); 475 return &Obj.addSection<DecompressedSection>(*CS); 476 }); 477 478 Obj.removeSections(RemovePred); 479 480 if (!Config.SectionsToRename.empty()) { 481 for (auto &Sec : Obj.sections()) { 482 const auto Iter = Config.SectionsToRename.find(Sec.Name); 483 if (Iter != Config.SectionsToRename.end()) { 484 const SectionRename &SR = Iter->second; 485 Sec.Name = SR.NewName; 486 if (SR.NewFlags.hasValue()) { 487 // Preserve some flags which should not be dropped when setting flags. 488 // Also, preserve anything OS/processor dependant. 489 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE | 490 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | 491 ELF::SHF_MASKOS | ELF::SHF_MASKPROC | 492 ELF::SHF_TLS | ELF::SHF_INFO_LINK; 493 Sec.Flags = (Sec.Flags & PreserveMask) | 494 (SR.NewFlags.getValue() & ~PreserveMask); 495 } 496 } 497 } 498 } 499 500 if (!Config.AddSection.empty()) { 501 for (const auto &Flag : Config.AddSection) { 502 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 503 StringRef SecName = SecPair.first; 504 StringRef File = SecPair.second; 505 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 506 MemoryBuffer::getFile(File); 507 if (!BufOrErr) 508 reportError(File, BufOrErr.getError()); 509 std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr); 510 ArrayRef<uint8_t> Data( 511 reinterpret_cast<const uint8_t *>(Buf->getBufferStart()), 512 Buf->getBufferSize()); 513 OwnedDataSection &NewSection = 514 Obj.addSection<OwnedDataSection>(SecName, Data); 515 if (SecName.startswith(".note") && SecName != ".note.GNU-stack") 516 NewSection.Type = SHT_NOTE; 517 } 518 } 519 520 if (!Config.DumpSection.empty()) { 521 for (const auto &Flag : Config.DumpSection) { 522 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 523 StringRef SecName = SecPair.first; 524 StringRef File = SecPair.second; 525 if (Error E = dumpSectionToFile(SecName, File, Obj)) 526 reportError(Config.InputFilename, std::move(E)); 527 } 528 } 529 530 if (!Config.AddGnuDebugLink.empty()) 531 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); 532 } 533 534 void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, 535 Buffer &Out) { 536 BinaryReader Reader(Config.BinaryArch, &In); 537 std::unique_ptr<Object> Obj = Reader.create(); 538 539 // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch 540 // (-B<arch>). 541 const ElfType OutputElfType = getOutputElfType( 542 Config.OutputArch ? Config.OutputArch.getValue() : Config.BinaryArch); 543 handleArgs(Config, *Obj, Reader, OutputElfType); 544 std::unique_ptr<Writer> Writer = 545 createWriter(Config, *Obj, Out, OutputElfType); 546 Writer->finalize(); 547 Writer->write(); 548 } 549 550 void executeObjcopyOnBinary(const CopyConfig &Config, 551 object::ELFObjectFileBase &In, Buffer &Out) { 552 ELFReader Reader(&In); 553 std::unique_ptr<Object> Obj = Reader.create(); 554 // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input. 555 const ElfType OutputElfType = 556 Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) 557 : getOutputElfType(In); 558 ArrayRef<uint8_t> BuildIdBytes; 559 560 if (!Config.BuildIdLinkDir.empty()) { 561 BuildIdBytes = unwrapOrError(findBuildID(In)); 562 if (BuildIdBytes.size() < 2) 563 error("build ID in file '" + Config.InputFilename + 564 "' is smaller than two bytes"); 565 } 566 567 if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) { 568 linkToBuildIdDir(Config, Config.InputFilename, 569 Config.BuildIdLinkInput.getValue(), BuildIdBytes); 570 } 571 handleArgs(Config, *Obj, Reader, OutputElfType); 572 std::unique_ptr<Writer> Writer = 573 createWriter(Config, *Obj, Out, OutputElfType); 574 Writer->finalize(); 575 Writer->write(); 576 if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) { 577 linkToBuildIdDir(Config, Config.OutputFilename, 578 Config.BuildIdLinkOutput.getValue(), BuildIdBytes); 579 } 580 } 581 582 } // end namespace elf 583 } // end namespace objcopy 584 } // end namespace llvm 585