ELFObjcopy.cpp revision 360784
1//===- ELFObjcopy.cpp -----------------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "ELFObjcopy.h" 10#include "Buffer.h" 11#include "CopyConfig.h" 12#include "Object.h" 13#include "llvm-objcopy.h" 14 15#include "llvm/ADT/BitmaskEnum.h" 16#include "llvm/ADT/DenseSet.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 48namespace llvm { 49namespace objcopy { 50namespace elf { 51 52using namespace object; 53using namespace ELF; 54using SectionPred = std::function<bool(const SectionBase &Sec)>; 55 56static bool isDebugSection(const SectionBase &Sec) { 57 return StringRef(Sec.Name).startswith(".debug") || 58 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index"; 59} 60 61static bool isDWOSection(const SectionBase &Sec) { 62 return StringRef(Sec.Name).endswith(".dwo"); 63} 64 65static 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 74uint64_t getNewShfFlags(SectionFlag AllFlags) { 75 uint64_t NewFlags = 0; 76 if (AllFlags & SectionFlag::SecAlloc) 77 NewFlags |= ELF::SHF_ALLOC; 78 if (!(AllFlags & SectionFlag::SecReadonly)) 79 NewFlags |= ELF::SHF_WRITE; 80 if (AllFlags & SectionFlag::SecCode) 81 NewFlags |= ELF::SHF_EXECINSTR; 82 if (AllFlags & SectionFlag::SecMerge) 83 NewFlags |= ELF::SHF_MERGE; 84 if (AllFlags & SectionFlag::SecStrings) 85 NewFlags |= ELF::SHF_STRINGS; 86 return NewFlags; 87} 88 89static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags, 90 uint64_t NewFlags) { 91 // Preserve some flags which should not be dropped when setting flags. 92 // Also, preserve anything OS/processor dependant. 93 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE | 94 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | 95 ELF::SHF_MASKOS | ELF::SHF_MASKPROC | 96 ELF::SHF_TLS | ELF::SHF_INFO_LINK; 97 return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask); 98} 99 100static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) { 101 Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags)); 102 103 // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule 104 // may promote more non-ALLOC sections than GNU objcopy, but it is fine as 105 // non-ALLOC SHT_NOBITS sections do not make much sense. 106 if (Sec.Type == SHT_NOBITS && 107 (!(Sec.Flags & ELF::SHF_ALLOC) || 108 Flags & (SectionFlag::SecContents | SectionFlag::SecLoad))) 109 Sec.Type = SHT_PROGBITS; 110} 111 112static ElfType getOutputElfType(const Binary &Bin) { 113 // Infer output ELF type from the input ELF object 114 if (isa<ELFObjectFile<ELF32LE>>(Bin)) 115 return ELFT_ELF32LE; 116 if (isa<ELFObjectFile<ELF64LE>>(Bin)) 117 return ELFT_ELF64LE; 118 if (isa<ELFObjectFile<ELF32BE>>(Bin)) 119 return ELFT_ELF32BE; 120 if (isa<ELFObjectFile<ELF64BE>>(Bin)) 121 return ELFT_ELF64BE; 122 llvm_unreachable("Invalid ELFType"); 123} 124 125static ElfType getOutputElfType(const MachineInfo &MI) { 126 // Infer output ELF type from the binary arch specified 127 if (MI.Is64Bit) 128 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE; 129 else 130 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; 131} 132 133static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config, 134 Object &Obj, Buffer &Buf, 135 ElfType OutputElfType) { 136 // Depending on the initial ELFT and OutputFormat we need a different Writer. 137 switch (OutputElfType) { 138 case ELFT_ELF32LE: 139 return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections, 140 Config.OnlyKeepDebug); 141 case ELFT_ELF64LE: 142 return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections, 143 Config.OnlyKeepDebug); 144 case ELFT_ELF32BE: 145 return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections, 146 Config.OnlyKeepDebug); 147 case ELFT_ELF64BE: 148 return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections, 149 Config.OnlyKeepDebug); 150 } 151 llvm_unreachable("Invalid output format"); 152} 153 154static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, 155 Object &Obj, Buffer &Buf, 156 ElfType OutputElfType) { 157 switch (Config.OutputFormat) { 158 case FileFormat::Binary: 159 return std::make_unique<BinaryWriter>(Obj, Buf); 160 case FileFormat::IHex: 161 return std::make_unique<IHexWriter>(Obj, Buf); 162 default: 163 return createELFWriter(Config, Obj, Buf, OutputElfType); 164 } 165} 166 167template <class ELFT> 168static Expected<ArrayRef<uint8_t>> 169findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) { 170 auto PhdrsOrErr = In.program_headers(); 171 if (auto Err = PhdrsOrErr.takeError()) 172 return createFileError(Config.InputFilename, std::move(Err)); 173 174 for (const auto &Phdr : *PhdrsOrErr) { 175 if (Phdr.p_type != PT_NOTE) 176 continue; 177 Error Err = Error::success(); 178 for (auto Note : In.notes(Phdr, Err)) 179 if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) 180 return Note.getDesc(); 181 if (Err) 182 return createFileError(Config.InputFilename, std::move(Err)); 183 } 184 185 return createFileError( 186 Config.InputFilename, 187 createStringError(llvm::errc::invalid_argument, 188 "could not find build ID")); 189} 190 191static Expected<ArrayRef<uint8_t>> 192findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) { 193 if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In)) 194 return findBuildID(Config, *O->getELFFile()); 195 else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In)) 196 return findBuildID(Config, *O->getELFFile()); 197 else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In)) 198 return findBuildID(Config, *O->getELFFile()); 199 else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In)) 200 return findBuildID(Config, *O->getELFFile()); 201 202 llvm_unreachable("Bad file format"); 203} 204 205template <class... Ts> 206static Error makeStringError(std::error_code EC, const Twine &Msg, Ts &&... Args) { 207 std::string FullMsg = (EC.message() + ": " + Msg).str(); 208 return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...); 209} 210 211#define MODEL_8 "%%%%%%%%" 212#define MODEL_16 MODEL_8 MODEL_8 213#define MODEL_32 (MODEL_16 MODEL_16) 214 215static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, 216 StringRef Suffix, 217 ArrayRef<uint8_t> BuildIdBytes) { 218 SmallString<128> Path = Config.BuildIdLinkDir; 219 sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true)); 220 if (auto EC = sys::fs::create_directories(Path)) 221 return createFileError( 222 Path.str(), 223 makeStringError(EC, "cannot create build ID link directory")); 224 225 sys::path::append(Path, 226 llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true)); 227 Path += Suffix; 228 SmallString<128> TmpPath; 229 // create_hard_link races so we need to link to a temporary path but 230 // we want to make sure that we choose a filename that does not exist. 231 // By using 32 model characters we get 128-bits of entropy. It is 232 // unlikely that this string has ever existed before much less exists 233 // on this disk or in the current working directory. 234 // Additionally we prepend the original Path for debugging but also 235 // because it ensures that we're linking within a directory on the same 236 // partition on the same device which is critical. It has the added 237 // win of yet further decreasing the odds of a conflict. 238 sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath, 239 /*MakeAbsolute*/ false); 240 if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) { 241 Path.push_back('\0'); 242 return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(), 243 Path.data()); 244 } 245 // We then atomically rename the link into place which will just move the 246 // link. If rename fails something is more seriously wrong so just return 247 // an error. 248 if (auto EC = sys::fs::rename(TmpPath, Path)) { 249 Path.push_back('\0'); 250 return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(), 251 Path.data()); 252 } 253 // If `Path` was already a hard-link to the same underlying file then the 254 // temp file will be left so we need to remove it. Remove will not cause 255 // an error by default if the file is already gone so just blindly remove 256 // it rather than checking. 257 if (auto EC = sys::fs::remove(TmpPath)) { 258 TmpPath.push_back('\0'); 259 return makeStringError(EC, "could not remove '%s'", TmpPath.data()); 260 } 261 return Error::success(); 262} 263 264static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, 265 StringRef File, ElfType OutputElfType) { 266 auto DWOFile = Reader.create(false); 267 auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { 268 return onlyKeepDWOPred(*DWOFile, Sec); 269 }; 270 if (Error E = DWOFile->removeSections(Config.AllowBrokenLinks, 271 OnlyKeepDWOPred)) 272 return E; 273 if (Config.OutputArch) { 274 DWOFile->Machine = Config.OutputArch.getValue().EMachine; 275 DWOFile->OSABI = Config.OutputArch.getValue().OSABI; 276 } 277 FileBuffer FB(File); 278 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); 279 if (Error E = Writer->finalize()) 280 return E; 281 return Writer->write(); 282} 283 284static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 285 Object &Obj) { 286 for (auto &Sec : Obj.sections()) { 287 if (Sec.Name == SecName) { 288 if (Sec.OriginalData.empty()) 289 return createStringError(object_error::parse_failed, 290 "cannot dump section '%s': it has no contents", 291 SecName.str().c_str()); 292 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 293 FileOutputBuffer::create(Filename, Sec.OriginalData.size()); 294 if (!BufferOrErr) 295 return BufferOrErr.takeError(); 296 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 297 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), 298 Buf->getBufferStart()); 299 if (Error E = Buf->commit()) 300 return E; 301 return Error::success(); 302 } 303 } 304 return createStringError(object_error::parse_failed, "section '%s' not found", 305 SecName.str().c_str()); 306} 307 308static bool isCompressable(const SectionBase &Sec) { 309 return !(Sec.Flags & ELF::SHF_COMPRESSED) && 310 StringRef(Sec.Name).startswith(".debug"); 311} 312 313static void replaceDebugSections( 314 Object &Obj, SectionPred &RemovePred, 315 function_ref<bool(const SectionBase &)> shouldReplace, 316 function_ref<SectionBase *(const SectionBase *)> addSection) { 317 // Build a list of the debug sections we are going to replace. 318 // We can't call `addSection` while iterating over sections, 319 // because it would mutate the sections array. 320 SmallVector<SectionBase *, 13> ToReplace; 321 for (auto &Sec : Obj.sections()) 322 if (shouldReplace(Sec)) 323 ToReplace.push_back(&Sec); 324 325 // Build a mapping from original section to a new one. 326 DenseMap<SectionBase *, SectionBase *> FromTo; 327 for (SectionBase *S : ToReplace) 328 FromTo[S] = addSection(S); 329 330 // Now we want to update the target sections of relocation 331 // sections. Also we will update the relocations themselves 332 // to update the symbol references. 333 for (auto &Sec : Obj.sections()) 334 Sec.replaceSectionReferences(FromTo); 335 336 RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) { 337 return shouldReplace(Sec) || RemovePred(Sec); 338 }; 339} 340 341static bool isUnneededSymbol(const Symbol &Sym) { 342 return !Sym.Referenced && 343 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && 344 Sym.Type != STT_SECTION; 345} 346 347static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { 348 // TODO: update or remove symbols only if there is an option that affects 349 // them. 350 if (!Obj.SymbolTable) 351 return Error::success(); 352 353 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 354 // Common and undefined symbols don't make sense as local symbols, and can 355 // even cause crashes if we localize those, so skip them. 356 if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF && 357 ((Config.LocalizeHidden && 358 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 359 Config.SymbolsToLocalize.matches(Sym.Name))) 360 Sym.Binding = STB_LOCAL; 361 362 // Note: these two globalize flags have very similar names but different 363 // meanings: 364 // 365 // --globalize-symbol: promote a symbol to global 366 // --keep-global-symbol: all symbols except for these should be made local 367 // 368 // If --globalize-symbol is specified for a given symbol, it will be 369 // global in the output file even if it is not included via 370 // --keep-global-symbol. Because of that, make sure to check 371 // --globalize-symbol second. 372 if (!Config.SymbolsToKeepGlobal.empty() && 373 !Config.SymbolsToKeepGlobal.matches(Sym.Name) && 374 Sym.getShndx() != SHN_UNDEF) 375 Sym.Binding = STB_LOCAL; 376 377 if (Config.SymbolsToGlobalize.matches(Sym.Name) && 378 Sym.getShndx() != SHN_UNDEF) 379 Sym.Binding = STB_GLOBAL; 380 381 if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL) 382 Sym.Binding = STB_WEAK; 383 384 if (Config.Weaken && Sym.Binding == STB_GLOBAL && 385 Sym.getShndx() != SHN_UNDEF) 386 Sym.Binding = STB_WEAK; 387 388 const auto I = Config.SymbolsToRename.find(Sym.Name); 389 if (I != Config.SymbolsToRename.end()) 390 Sym.Name = I->getValue(); 391 392 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) 393 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); 394 }); 395 396 // The purpose of this loop is to mark symbols referenced by sections 397 // (like GroupSection or RelocationSection). This way, we know which 398 // symbols are still 'needed' and which are not. 399 if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || 400 !Config.OnlySection.empty()) { 401 for (SectionBase &Sec : Obj.sections()) 402 Sec.markSymbols(); 403 } 404 405 auto RemoveSymbolsPred = [&](const Symbol &Sym) { 406 if (Config.SymbolsToKeep.matches(Sym.Name) || 407 (Config.KeepFileSymbols && Sym.Type == STT_FILE)) 408 return false; 409 410 if ((Config.DiscardMode == DiscardType::All || 411 (Config.DiscardMode == DiscardType::Locals && 412 StringRef(Sym.Name).startswith(".L"))) && 413 Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && 414 Sym.Type != STT_FILE && Sym.Type != STT_SECTION) 415 return true; 416 417 if (Config.StripAll || Config.StripAllGNU) 418 return true; 419 420 if (Config.SymbolsToRemove.matches(Sym.Name)) 421 return true; 422 423 if ((Config.StripUnneeded || 424 Config.UnneededSymbolsToRemove.matches(Sym.Name)) && 425 (!Obj.isRelocatable() || isUnneededSymbol(Sym))) 426 return true; 427 428 // We want to remove undefined symbols if all references have been stripped. 429 if (!Config.OnlySection.empty() && !Sym.Referenced && 430 Sym.getShndx() == SHN_UNDEF) 431 return true; 432 433 return false; 434 }; 435 436 return Obj.removeSymbols(RemoveSymbolsPred); 437} 438 439static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { 440 SectionPred RemovePred = [](const SectionBase &) { return false; }; 441 442 // Removes: 443 if (!Config.ToRemove.empty()) { 444 RemovePred = [&Config](const SectionBase &Sec) { 445 return Config.ToRemove.matches(Sec.Name); 446 }; 447 } 448 449 if (Config.StripDWO || !Config.SplitDWO.empty()) 450 RemovePred = [RemovePred](const SectionBase &Sec) { 451 return isDWOSection(Sec) || RemovePred(Sec); 452 }; 453 454 if (Config.ExtractDWO) 455 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 456 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 457 }; 458 459 if (Config.StripAllGNU) 460 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 461 if (RemovePred(Sec)) 462 return true; 463 if ((Sec.Flags & SHF_ALLOC) != 0) 464 return false; 465 if (&Sec == Obj.SectionNames) 466 return false; 467 switch (Sec.Type) { 468 case SHT_SYMTAB: 469 case SHT_REL: 470 case SHT_RELA: 471 case SHT_STRTAB: 472 return true; 473 } 474 return isDebugSection(Sec); 475 }; 476 477 if (Config.StripSections) { 478 RemovePred = [RemovePred](const SectionBase &Sec) { 479 return RemovePred(Sec) || Sec.ParentSegment == nullptr; 480 }; 481 } 482 483 if (Config.StripDebug || Config.StripUnneeded) { 484 RemovePred = [RemovePred](const SectionBase &Sec) { 485 return RemovePred(Sec) || isDebugSection(Sec); 486 }; 487 } 488 489 if (Config.StripNonAlloc) 490 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 491 if (RemovePred(Sec)) 492 return true; 493 if (&Sec == Obj.SectionNames) 494 return false; 495 return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr; 496 }; 497 498 if (Config.StripAll) 499 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 500 if (RemovePred(Sec)) 501 return true; 502 if (&Sec == Obj.SectionNames) 503 return false; 504 if (StringRef(Sec.Name).startswith(".gnu.warning")) 505 return false; 506 // We keep the .ARM.attribute section to maintain compatibility 507 // with Debian derived distributions. This is a bug in their 508 // patchset as documented here: 509 // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798 510 if (Sec.Type == SHT_ARM_ATTRIBUTES) 511 return false; 512 if (Sec.ParentSegment != nullptr) 513 return false; 514 return (Sec.Flags & SHF_ALLOC) == 0; 515 }; 516 517 if (Config.ExtractPartition || Config.ExtractMainPartition) { 518 RemovePred = [RemovePred](const SectionBase &Sec) { 519 if (RemovePred(Sec)) 520 return true; 521 if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR) 522 return true; 523 return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment; 524 }; 525 } 526 527 // Explicit copies: 528 if (!Config.OnlySection.empty()) { 529 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 530 // Explicitly keep these sections regardless of previous removes. 531 if (Config.OnlySection.matches(Sec.Name)) 532 return false; 533 534 // Allow all implicit removes. 535 if (RemovePred(Sec)) 536 return true; 537 538 // Keep special sections. 539 if (Obj.SectionNames == &Sec) 540 return false; 541 if (Obj.SymbolTable == &Sec || 542 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) 543 return false; 544 545 // Remove everything else. 546 return true; 547 }; 548 } 549 550 if (!Config.KeepSection.empty()) { 551 RemovePred = [&Config, RemovePred](const SectionBase &Sec) { 552 // Explicitly keep these sections regardless of previous removes. 553 if (Config.KeepSection.matches(Sec.Name)) 554 return false; 555 // Otherwise defer to RemovePred. 556 return RemovePred(Sec); 557 }; 558 } 559 560 // This has to be the last predicate assignment. 561 // If the option --keep-symbol has been specified 562 // and at least one of those symbols is present 563 // (equivalently, the updated symbol table is not empty) 564 // the symbol table and the string table should not be removed. 565 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && 566 Obj.SymbolTable && !Obj.SymbolTable->empty()) { 567 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { 568 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) 569 return false; 570 return RemovePred(Sec); 571 }; 572 } 573 574 if (Config.CompressionType != DebugCompressionType::None) 575 replaceDebugSections(Obj, RemovePred, isCompressable, 576 [&Config, &Obj](const SectionBase *S) { 577 return &Obj.addSection<CompressedSection>( 578 *S, Config.CompressionType); 579 }); 580 else if (Config.DecompressDebugSections) 581 replaceDebugSections( 582 Obj, RemovePred, 583 [](const SectionBase &S) { return isa<CompressedSection>(&S); }, 584 [&Obj](const SectionBase *S) { 585 auto CS = cast<CompressedSection>(S); 586 return &Obj.addSection<DecompressedSection>(*CS); 587 }); 588 589 return Obj.removeSections(Config.AllowBrokenLinks, RemovePred); 590} 591 592// This function handles the high level operations of GNU objcopy including 593// handling command line options. It's important to outline certain properties 594// we expect to hold of the command line operations. Any operation that "keeps" 595// should keep regardless of a remove. Additionally any removal should respect 596// any previous removals. Lastly whether or not something is removed shouldn't 597// depend a) on the order the options occur in or b) on some opaque priority 598// system. The only priority is that keeps/copies overrule removes. 599static Error handleArgs(const CopyConfig &Config, Object &Obj, 600 const Reader &Reader, ElfType OutputElfType) { 601 602 if (!Config.SplitDWO.empty()) 603 if (Error E = 604 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType)) 605 return E; 606 607 if (Config.OutputArch) { 608 Obj.Machine = Config.OutputArch.getValue().EMachine; 609 Obj.OSABI = Config.OutputArch.getValue().OSABI; 610 } 611 612 // It is important to remove the sections first. For example, we want to 613 // remove the relocation sections before removing the symbols. That allows 614 // us to avoid reporting the inappropriate errors about removing symbols 615 // named in relocations. 616 if (Error E = replaceAndRemoveSections(Config, Obj)) 617 return E; 618 619 if (Error E = updateAndRemoveSymbols(Config, Obj)) 620 return E; 621 622 if (!Config.SectionsToRename.empty()) { 623 for (SectionBase &Sec : Obj.sections()) { 624 const auto Iter = Config.SectionsToRename.find(Sec.Name); 625 if (Iter != Config.SectionsToRename.end()) { 626 const SectionRename &SR = Iter->second; 627 Sec.Name = SR.NewName; 628 if (SR.NewFlags.hasValue()) 629 setSectionFlagsAndType(Sec, SR.NewFlags.getValue()); 630 } 631 } 632 } 633 634 // Add a prefix to allocated sections and their relocation sections. This 635 // should be done after renaming the section by Config.SectionToRename to 636 // imitate the GNU objcopy behavior. 637 if (!Config.AllocSectionsPrefix.empty()) { 638 DenseSet<SectionBase *> PrefixedSections; 639 for (SectionBase &Sec : Obj.sections()) { 640 if (Sec.Flags & SHF_ALLOC) { 641 Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); 642 PrefixedSections.insert(&Sec); 643 } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) { 644 // Rename relocation sections associated to the allocated sections. 645 // For example, if we rename .text to .prefix.text, we also rename 646 // .rel.text to .rel.prefix.text. 647 // 648 // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled 649 // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not 650 // .rela.prefix.plt since GNU objcopy does so. 651 const SectionBase *TargetSec = RelocSec->getSection(); 652 if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) { 653 StringRef prefix; 654 switch (Sec.Type) { 655 case SHT_REL: 656 prefix = ".rel"; 657 break; 658 case SHT_RELA: 659 prefix = ".rela"; 660 break; 661 default: 662 llvm_unreachable("not a relocation section"); 663 } 664 665 // If the relocation section comes *after* the target section, we 666 // don't add Config.AllocSectionsPrefix because we've already added 667 // the prefix to TargetSec->Name. Otherwise, if the relocation 668 // section comes *before* the target section, we add the prefix. 669 if (PrefixedSections.count(TargetSec)) 670 Sec.Name = (prefix + TargetSec->Name).str(); 671 else 672 Sec.Name = 673 (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str(); 674 } 675 } 676 } 677 } 678 679 if (!Config.SetSectionAlignment.empty()) { 680 for (SectionBase &Sec : Obj.sections()) { 681 auto I = Config.SetSectionAlignment.find(Sec.Name); 682 if (I != Config.SetSectionAlignment.end()) 683 Sec.Align = I->second; 684 } 685 } 686 687 if (!Config.SetSectionFlags.empty()) { 688 for (auto &Sec : Obj.sections()) { 689 const auto Iter = Config.SetSectionFlags.find(Sec.Name); 690 if (Iter != Config.SetSectionFlags.end()) { 691 const SectionFlagsUpdate &SFU = Iter->second; 692 setSectionFlagsAndType(Sec, SFU.NewFlags); 693 } 694 } 695 } 696 697 if (Config.OnlyKeepDebug) 698 for (auto &Sec : Obj.sections()) 699 if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) 700 Sec.Type = SHT_NOBITS; 701 702 for (const auto &Flag : Config.AddSection) { 703 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 704 StringRef SecName = SecPair.first; 705 StringRef File = SecPair.second; 706 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 707 MemoryBuffer::getFile(File); 708 if (!BufOrErr) 709 return createFileError(File, errorCodeToError(BufOrErr.getError())); 710 std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr); 711 ArrayRef<uint8_t> Data( 712 reinterpret_cast<const uint8_t *>(Buf->getBufferStart()), 713 Buf->getBufferSize()); 714 OwnedDataSection &NewSection = 715 Obj.addSection<OwnedDataSection>(SecName, Data); 716 if (SecName.startswith(".note") && SecName != ".note.GNU-stack") 717 NewSection.Type = SHT_NOTE; 718 } 719 720 for (const auto &Flag : Config.DumpSection) { 721 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 722 StringRef SecName = SecPair.first; 723 StringRef File = SecPair.second; 724 if (Error E = dumpSectionToFile(SecName, File, Obj)) 725 return E; 726 } 727 728 if (!Config.AddGnuDebugLink.empty()) 729 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink, 730 Config.GnuDebugLinkCRC32); 731 732 for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { 733 SectionBase *Sec = Obj.findSection(SI.SectionName); 734 uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; 735 Obj.SymbolTable->addSymbol( 736 SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility, 737 Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); 738 } 739 740 if (Config.EntryExpr) 741 Obj.Entry = Config.EntryExpr(Obj.Entry); 742 return Error::success(); 743} 744 745static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out, 746 ElfType OutputElfType) { 747 std::unique_ptr<Writer> Writer = 748 createWriter(Config, Obj, Out, OutputElfType); 749 if (Error E = Writer->finalize()) 750 return E; 751 return Writer->write(); 752} 753 754Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, 755 Buffer &Out) { 756 IHexReader Reader(&In); 757 std::unique_ptr<Object> Obj = Reader.create(true); 758 const ElfType OutputElfType = 759 getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); 760 if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) 761 return E; 762 return writeOutput(Config, *Obj, Out, OutputElfType); 763} 764 765Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, 766 Buffer &Out) { 767 uint8_t NewSymbolVisibility = 768 Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); 769 BinaryReader Reader(&In, NewSymbolVisibility); 770 std::unique_ptr<Object> Obj = Reader.create(true); 771 772 // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch 773 // (-B<arch>). 774 const ElfType OutputElfType = 775 getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); 776 if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) 777 return E; 778 return writeOutput(Config, *Obj, Out, OutputElfType); 779} 780 781Error executeObjcopyOnBinary(const CopyConfig &Config, 782 object::ELFObjectFileBase &In, Buffer &Out) { 783 ELFReader Reader(&In, Config.ExtractPartition); 784 std::unique_ptr<Object> Obj = Reader.create(!Config.SymbolsToAdd.empty()); 785 // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input. 786 const ElfType OutputElfType = 787 Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) 788 : getOutputElfType(In); 789 ArrayRef<uint8_t> BuildIdBytes; 790 791 if (!Config.BuildIdLinkDir.empty()) { 792 auto BuildIdBytesOrErr = findBuildID(Config, In); 793 if (auto E = BuildIdBytesOrErr.takeError()) 794 return E; 795 BuildIdBytes = *BuildIdBytesOrErr; 796 797 if (BuildIdBytes.size() < 2) 798 return createFileError( 799 Config.InputFilename, 800 createStringError(object_error::parse_failed, 801 "build ID is smaller than two bytes")); 802 } 803 804 if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) 805 if (Error E = 806 linkToBuildIdDir(Config, Config.InputFilename, 807 Config.BuildIdLinkInput.getValue(), BuildIdBytes)) 808 return E; 809 810 if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) 811 return createFileError(Config.InputFilename, std::move(E)); 812 813 if (Error E = writeOutput(Config, *Obj, Out, OutputElfType)) 814 return createFileError(Config.InputFilename, std::move(E)); 815 if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) 816 if (Error E = 817 linkToBuildIdDir(Config, Config.OutputFilename, 818 Config.BuildIdLinkOutput.getValue(), BuildIdBytes)) 819 return createFileError(Config.OutputFilename, std::move(E)); 820 821 return Error::success(); 822} 823 824} // end namespace elf 825} // end namespace objcopy 826} // end namespace llvm 827