1100 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ObjCopy/ELF/ELFObjcopy.h"10#include "ELFObject.h"11#include "llvm/ADT/BitmaskEnum.h"12#include "llvm/ADT/DenseSet.h"13#include "llvm/ADT/SmallVector.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/ADT/Twine.h"16#include "llvm/BinaryFormat/ELF.h"17#include "llvm/MC/MCTargetOptions.h"18#include "llvm/ObjCopy/CommonConfig.h"19#include "llvm/ObjCopy/ELF/ELFConfig.h"20#include "llvm/Object/Binary.h"21#include "llvm/Object/ELFObjectFile.h"22#include "llvm/Object/ELFTypes.h"23#include "llvm/Object/Error.h"24#include "llvm/Option/Option.h"25#include "llvm/Support/Casting.h"26#include "llvm/Support/Compression.h"27#include "llvm/Support/Errc.h"28#include "llvm/Support/Error.h"29#include "llvm/Support/ErrorHandling.h"30#include "llvm/Support/Memory.h"31#include "llvm/Support/raw_ostream.h"32#include <algorithm>33#include <cassert>34#include <cstdlib>35#include <functional>36#include <memory>37#include <string>38#include <system_error>39#include <utility>40 41using namespace llvm;42using namespace llvm::ELF;43using namespace llvm::objcopy;44using namespace llvm::objcopy::elf;45using namespace llvm::object;46 47using SectionPred = std::function<bool(const SectionBase &Sec)>;48 49static bool isDebugSection(const SectionBase &Sec) {50 return StringRef(Sec.Name).starts_with(".debug") || Sec.Name == ".gdb_index";51}52 53static bool isDWOSection(const SectionBase &Sec) {54 return StringRef(Sec.Name).ends_with(".dwo");55}56 57static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {58 // We can't remove the section header string table.59 if (&Sec == Obj.SectionNames)60 return false;61 // Short of keeping the string table we want to keep everything that is a DWO62 // section and remove everything else.63 return !isDWOSection(Sec);64}65 66static Expected<uint64_t> getNewShfFlags(SectionFlag AllFlags,67 uint16_t EMachine) {68 uint64_t NewFlags = 0;69 if (AllFlags & SectionFlag::SecAlloc)70 NewFlags |= ELF::SHF_ALLOC;71 if (!(AllFlags & SectionFlag::SecReadonly))72 NewFlags |= ELF::SHF_WRITE;73 if (AllFlags & SectionFlag::SecCode)74 NewFlags |= ELF::SHF_EXECINSTR;75 if (AllFlags & SectionFlag::SecMerge)76 NewFlags |= ELF::SHF_MERGE;77 if (AllFlags & SectionFlag::SecStrings)78 NewFlags |= ELF::SHF_STRINGS;79 if (AllFlags & SectionFlag::SecExclude)80 NewFlags |= ELF::SHF_EXCLUDE;81 if (AllFlags & SectionFlag::SecLarge) {82 if (EMachine != EM_X86_64)83 return createStringError(errc::invalid_argument,84 "section flag SHF_X86_64_LARGE can only be used "85 "with x86_64 architecture");86 NewFlags |= ELF::SHF_X86_64_LARGE;87 }88 return NewFlags;89}90 91static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,92 uint64_t NewFlags,93 uint16_t EMachine) {94 // Preserve some flags which should not be dropped when setting flags.95 // Also, preserve anything OS/processor dependant.96 const uint64_t PreserveMask =97 (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |98 ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |99 ELF::SHF_INFO_LINK) &100 ~ELF::SHF_EXCLUDE &101 ~(EMachine == EM_X86_64 ? (uint64_t)ELF::SHF_X86_64_LARGE : 0UL);102 return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);103}104 105static void setSectionType(SectionBase &Sec, uint64_t Type) {106 // If Sec's type is changed from SHT_NOBITS due to --set-section-flags,107 // Offset may not be aligned. Align it to max(Align, 1).108 if (Sec.Type == ELF::SHT_NOBITS && Type != ELF::SHT_NOBITS)109 Sec.Offset = alignTo(Sec.Offset, std::max(Sec.Align, uint64_t(1)));110 Sec.Type = Type;111}112 113static Error setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags,114 uint16_t EMachine) {115 Expected<uint64_t> NewFlags = getNewShfFlags(Flags, EMachine);116 if (!NewFlags)117 return NewFlags.takeError();118 Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, *NewFlags, EMachine);119 120 // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule121 // may promote more non-ALLOC sections than GNU objcopy, but it is fine as122 // non-ALLOC SHT_NOBITS sections do not make much sense.123 if (Sec.Type == SHT_NOBITS &&124 (!(Sec.Flags & ELF::SHF_ALLOC) ||125 Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))126 setSectionType(Sec, ELF::SHT_PROGBITS);127 128 return Error::success();129}130 131static ElfType getOutputElfType(const Binary &Bin) {132 // Infer output ELF type from the input ELF object133 if (isa<ELFObjectFile<ELF32LE>>(Bin))134 return ELFT_ELF32LE;135 if (isa<ELFObjectFile<ELF64LE>>(Bin))136 return ELFT_ELF64LE;137 if (isa<ELFObjectFile<ELF32BE>>(Bin))138 return ELFT_ELF32BE;139 if (isa<ELFObjectFile<ELF64BE>>(Bin))140 return ELFT_ELF64BE;141 llvm_unreachable("Invalid ELFType");142}143 144static ElfType getOutputElfType(const MachineInfo &MI) {145 // Infer output ELF type from the binary arch specified146 if (MI.Is64Bit)147 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;148 else149 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;150}151 152static std::unique_ptr<Writer> createELFWriter(const CommonConfig &Config,153 Object &Obj, raw_ostream &Out,154 ElfType OutputElfType) {155 // Depending on the initial ELFT and OutputFormat we need a different Writer.156 switch (OutputElfType) {157 case ELFT_ELF32LE:158 return std::make_unique<ELFWriter<ELF32LE>>(Obj, Out, !Config.StripSections,159 Config.OnlyKeepDebug);160 case ELFT_ELF64LE:161 return std::make_unique<ELFWriter<ELF64LE>>(Obj, Out, !Config.StripSections,162 Config.OnlyKeepDebug);163 case ELFT_ELF32BE:164 return std::make_unique<ELFWriter<ELF32BE>>(Obj, Out, !Config.StripSections,165 Config.OnlyKeepDebug);166 case ELFT_ELF64BE:167 return std::make_unique<ELFWriter<ELF64BE>>(Obj, Out, !Config.StripSections,168 Config.OnlyKeepDebug);169 }170 llvm_unreachable("Invalid output format");171}172 173static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,174 Object &Obj, raw_ostream &Out,175 ElfType OutputElfType) {176 switch (Config.OutputFormat) {177 case FileFormat::Binary:178 return std::make_unique<BinaryWriter>(Obj, Out, Config);179 case FileFormat::IHex:180 return std::make_unique<IHexWriter>(Obj, Out, Config.OutputFilename);181 case FileFormat::SREC:182 return std::make_unique<SRECWriter>(Obj, Out, Config.OutputFilename);183 default:184 return createELFWriter(Config, Obj, Out, OutputElfType);185 }186}187 188static Error dumpSectionToFile(StringRef SecName, StringRef Filename,189 StringRef InputFilename, Object &Obj) {190 for (auto &Sec : Obj.sections()) {191 if (Sec.Name == SecName) {192 if (Sec.Type == SHT_NOBITS)193 return createFileError(InputFilename, object_error::parse_failed,194 "cannot dump section '%s': it has no contents",195 SecName.str().c_str());196 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =197 FileOutputBuffer::create(Filename, Sec.OriginalData.size());198 if (!BufferOrErr)199 return createFileError(Filename, BufferOrErr.takeError());200 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);201 llvm::copy(Sec.OriginalData, Buf->getBufferStart());202 if (Error E = Buf->commit())203 return createFileError(Filename, std::move(E));204 return Error::success();205 }206 }207 208 return createFileError(InputFilename, object_error::parse_failed,209 "section '%s' not found", SecName.str().c_str());210}211 212Error Object::compressOrDecompressSections(const CommonConfig &Config) {213 // Build a list of sections we are going to replace.214 // We can't call `addSection` while iterating over sections,215 // because it would mutate the sections array.216 SmallVector<std::pair<SectionBase *, std::function<SectionBase *()>>, 0>217 ToReplace;218 for (SectionBase &Sec : sections()) {219 std::optional<DebugCompressionType> CType;220 for (auto &[Matcher, T] : Config.compressSections)221 if (Matcher.matches(Sec.Name))222 CType = T;223 // Handle --compress-debug-sections and --decompress-debug-sections, which224 // apply to non-ALLOC debug sections.225 if (!(Sec.Flags & SHF_ALLOC) && StringRef(Sec.Name).starts_with(".debug")) {226 if (Config.CompressionType != DebugCompressionType::None)227 CType = Config.CompressionType;228 else if (Config.DecompressDebugSections)229 CType = DebugCompressionType::None;230 }231 if (!CType)232 continue;233 234 if (Sec.ParentSegment)235 return createStringError(236 errc::invalid_argument,237 "section '" + Sec.Name +238 "' within a segment cannot be (de)compressed");239 240 if (auto *CS = dyn_cast<CompressedSection>(&Sec)) {241 if (*CType == DebugCompressionType::None)242 ToReplace.emplace_back(243 &Sec, [=] { return &addSection<DecompressedSection>(*CS); });244 } else if (*CType != DebugCompressionType::None) {245 ToReplace.emplace_back(&Sec, [=, S = &Sec] {246 return &addSection<CompressedSection>(247 CompressedSection(*S, *CType, Is64Bits));248 });249 }250 }251 252 DenseMap<SectionBase *, SectionBase *> FromTo;253 for (auto [S, Func] : ToReplace)254 FromTo[S] = Func();255 return replaceSections(FromTo);256}257 258static bool isAArch64MappingSymbol(const Symbol &Sym) {259 if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||260 Sym.getShndx() == SHN_UNDEF)261 return false;262 StringRef Name = Sym.Name;263 if (!Name.consume_front("$x") && !Name.consume_front("$d"))264 return false;265 return Name.empty() || Name.starts_with(".");266}267 268static bool isArmMappingSymbol(const Symbol &Sym) {269 if (Sym.Binding != STB_LOCAL || Sym.Type != STT_NOTYPE ||270 Sym.getShndx() == SHN_UNDEF)271 return false;272 StringRef Name = Sym.Name;273 if (!Name.consume_front("$a") && !Name.consume_front("$d") &&274 !Name.consume_front("$t"))275 return false;276 return Name.empty() || Name.starts_with(".");277}278 279// Check if the symbol should be preserved because it is required by ABI.280static bool isRequiredByABISymbol(const Object &Obj, const Symbol &Sym) {281 switch (Obj.Machine) {282 case EM_AARCH64:283 // Mapping symbols should be preserved for a relocatable object file.284 return Obj.isRelocatable() && isAArch64MappingSymbol(Sym);285 case EM_ARM:286 // Mapping symbols should be preserved for a relocatable object file.287 return Obj.isRelocatable() && isArmMappingSymbol(Sym);288 default:289 return false;290 }291}292 293static bool isUnneededSymbol(const Symbol &Sym) {294 return !Sym.Referenced &&295 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&296 Sym.Type != STT_SECTION;297}298 299static Error updateAndRemoveSymbols(const CommonConfig &Config,300 const ELFConfig &ELFConfig, Object &Obj) {301 // TODO: update or remove symbols only if there is an option that affects302 // them.303 if (!Obj.SymbolTable)304 return Error::success();305 306 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {307 if (Config.SymbolsToSkip.matches(Sym.Name))308 return;309 310 // Common and undefined symbols don't make sense as local symbols, and can311 // even cause crashes if we localize those, so skip them.312 if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&313 ((ELFConfig.LocalizeHidden &&314 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||315 Config.SymbolsToLocalize.matches(Sym.Name)))316 Sym.Binding = STB_LOCAL;317 318 for (auto &[Matcher, Visibility] : ELFConfig.SymbolsToSetVisibility)319 if (Matcher.matches(Sym.Name))320 Sym.Visibility = Visibility;321 322 // Note: these two globalize flags have very similar names but different323 // meanings:324 //325 // --globalize-symbol: promote a symbol to global326 // --keep-global-symbol: all symbols except for these should be made local327 //328 // If --globalize-symbol is specified for a given symbol, it will be329 // global in the output file even if it is not included via330 // --keep-global-symbol. Because of that, make sure to check331 // --globalize-symbol second.332 if (!Config.SymbolsToKeepGlobal.empty() &&333 !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&334 Sym.getShndx() != SHN_UNDEF)335 Sym.Binding = STB_LOCAL;336 337 if (Config.SymbolsToGlobalize.matches(Sym.Name) &&338 Sym.getShndx() != SHN_UNDEF)339 Sym.Binding = STB_GLOBAL;340 341 // SymbolsToWeaken applies to both STB_GLOBAL and STB_GNU_UNIQUE.342 if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding != STB_LOCAL)343 Sym.Binding = STB_WEAK;344 345 if (Config.Weaken && Sym.Binding != STB_LOCAL &&346 Sym.getShndx() != SHN_UNDEF)347 Sym.Binding = STB_WEAK;348 349 const auto I = Config.SymbolsToRename.find(Sym.Name);350 if (I != Config.SymbolsToRename.end())351 Sym.Name = std::string(I->getValue());352 353 if (!Config.SymbolsPrefixRemove.empty() && Sym.Type != STT_SECTION)354 if (StringRef(Sym.Name).starts_with(Config.SymbolsPrefixRemove))355 Sym.Name = Sym.Name.substr(Config.SymbolsPrefixRemove.size());356 357 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)358 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();359 });360 361 // The purpose of this loop is to mark symbols referenced by sections362 // (like GroupSection or RelocationSection). This way, we know which363 // symbols are still 'needed' and which are not.364 if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||365 !Config.OnlySection.empty() || Config.DiscardMode != DiscardType::None) {366 for (SectionBase &Sec : Obj.sections())367 Sec.markSymbols();368 }369 370 auto RemoveSymbolsPred = [&](const Symbol &Sym) {371 if (Config.SymbolsToKeep.matches(Sym.Name) ||372 (ELFConfig.KeepFileSymbols && Sym.Type == STT_FILE))373 return false;374 375 if (Config.SymbolsToRemove.matches(Sym.Name))376 return true;377 378 if (Config.StripAll || Config.StripAllGNU)379 return true;380 381 if (isRequiredByABISymbol(Obj, Sym))382 return false;383 384 if (Config.StripDebug && Sym.Type == STT_FILE)385 return true;386 387 if ((Config.StripUnneeded ||388 Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&389 (!Obj.isRelocatable() || isUnneededSymbol(Sym)))390 return true;391 392 if (!Sym.Referenced) {393 if ((Config.DiscardMode == DiscardType::All ||394 (Config.DiscardMode == DiscardType::Locals &&395 StringRef(Sym.Name).starts_with(".L"))) &&396 Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&397 Sym.Type != STT_FILE && Sym.Type != STT_SECTION)398 return true;399 // We want to remove undefined symbols if all references have been400 // stripped.401 if (!Config.OnlySection.empty() && Sym.getShndx() == SHN_UNDEF)402 return true;403 }404 405 return false;406 };407 408 return Obj.removeSymbols(RemoveSymbolsPred);409}410 411static Error replaceAndRemoveSections(const CommonConfig &Config,412 const ELFConfig &ELFConfig, Object &Obj) {413 SectionPred RemovePred = [](const SectionBase &) { return false; };414 415 // Removes:416 if (!Config.ToRemove.empty()) {417 RemovePred = [&Config](const SectionBase &Sec) {418 return Config.ToRemove.matches(Sec.Name);419 };420 }421 422 if (Config.StripDWO)423 RemovePred = [RemovePred](const SectionBase &Sec) {424 return isDWOSection(Sec) || RemovePred(Sec);425 };426 427 if (Config.ExtractDWO)428 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {429 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);430 };431 432 if (Config.StripAllGNU)433 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {434 if (RemovePred(Sec))435 return true;436 if ((Sec.Flags & SHF_ALLOC) != 0)437 return false;438 if (&Sec == Obj.SectionNames)439 return false;440 switch (Sec.Type) {441 case SHT_SYMTAB:442 case SHT_REL:443 case SHT_RELA:444 case SHT_STRTAB:445 return true;446 }447 return isDebugSection(Sec);448 };449 450 if (Config.StripSections) {451 RemovePred = [RemovePred](const SectionBase &Sec) {452 return RemovePred(Sec) || Sec.ParentSegment == nullptr;453 };454 }455 456 if (Config.StripDebug || Config.StripUnneeded) {457 RemovePred = [RemovePred](const SectionBase &Sec) {458 return RemovePred(Sec) || isDebugSection(Sec);459 };460 }461 462 if (Config.StripNonAlloc)463 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {464 if (RemovePred(Sec))465 return true;466 if (&Sec == Obj.SectionNames)467 return false;468 return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;469 };470 471 if (Config.StripAll)472 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {473 if (RemovePred(Sec))474 return true;475 if (&Sec == Obj.SectionNames)476 return false;477 if (StringRef(Sec.Name).starts_with(".gnu.warning"))478 return false;479 if (StringRef(Sec.Name).starts_with(".gnu_debuglink"))480 return false;481 // We keep the .ARM.attribute section to maintain compatibility482 // with Debian derived distributions. This is a bug in their483 // patchset as documented here:484 // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798485 if (Sec.Type == SHT_ARM_ATTRIBUTES)486 return false;487 if (Sec.ParentSegment != nullptr)488 return false;489 return (Sec.Flags & SHF_ALLOC) == 0;490 };491 492 if (Config.ExtractPartition || Config.ExtractMainPartition) {493 RemovePred = [RemovePred](const SectionBase &Sec) {494 if (RemovePred(Sec))495 return true;496 if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)497 return true;498 return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;499 };500 }501 502 // Explicit copies:503 if (!Config.OnlySection.empty()) {504 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {505 // Explicitly keep these sections regardless of previous removes.506 if (Config.OnlySection.matches(Sec.Name))507 return false;508 509 // Allow all implicit removes.510 if (RemovePred(Sec))511 return true;512 513 // Keep special sections.514 if (Obj.SectionNames == &Sec)515 return false;516 if (Obj.SymbolTable == &Sec ||517 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))518 return false;519 520 // Remove everything else.521 return true;522 };523 }524 525 if (!Config.KeepSection.empty()) {526 RemovePred = [&Config, RemovePred](const SectionBase &Sec) {527 // Explicitly keep these sections regardless of previous removes.528 if (Config.KeepSection.matches(Sec.Name))529 return false;530 // Otherwise defer to RemovePred.531 return RemovePred(Sec);532 };533 }534 535 // This has to be the last predicate assignment.536 // If the option --keep-symbol has been specified537 // and at least one of those symbols is present538 // (equivalently, the updated symbol table is not empty)539 // the symbol table and the string table should not be removed.540 if ((!Config.SymbolsToKeep.empty() || ELFConfig.KeepFileSymbols) &&541 Obj.SymbolTable && !Obj.SymbolTable->empty()) {542 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {543 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())544 return false;545 return RemovePred(Sec);546 };547 }548 549 if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred))550 return E;551 552 if (Error E = Obj.compressOrDecompressSections(Config))553 return E;554 555 return Error::success();556}557 558// Add symbol to the Object symbol table with the specified properties.559static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,560 uint8_t DefaultVisibility) {561 SectionBase *Sec = Obj.findSection(SymInfo.SectionName);562 uint64_t Value = Sec ? Sec->Addr + SymInfo.Value : SymInfo.Value;563 564 uint8_t Bind = ELF::STB_GLOBAL;565 uint8_t Type = ELF::STT_NOTYPE;566 uint8_t Visibility = DefaultVisibility;567 568 for (SymbolFlag FlagValue : SymInfo.Flags)569 switch (FlagValue) {570 case SymbolFlag::Global:571 Bind = ELF::STB_GLOBAL;572 break;573 case SymbolFlag::Local:574 Bind = ELF::STB_LOCAL;575 break;576 case SymbolFlag::Weak:577 Bind = ELF::STB_WEAK;578 break;579 case SymbolFlag::Default:580 Visibility = ELF::STV_DEFAULT;581 break;582 case SymbolFlag::Hidden:583 Visibility = ELF::STV_HIDDEN;584 break;585 case SymbolFlag::Protected:586 Visibility = ELF::STV_PROTECTED;587 break;588 case SymbolFlag::File:589 Type = ELF::STT_FILE;590 break;591 case SymbolFlag::Section:592 Type = ELF::STT_SECTION;593 break;594 case SymbolFlag::Object:595 Type = ELF::STT_OBJECT;596 break;597 case SymbolFlag::Function:598 Type = ELF::STT_FUNC;599 break;600 case SymbolFlag::IndirectFunction:601 Type = ELF::STT_GNU_IFUNC;602 break;603 default: /* Other flag values are ignored for ELF. */604 break;605 };606 607 Obj.SymbolTable->addSymbol(608 SymInfo.SymbolName, Bind, Type, Sec, Value, Visibility,609 Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);610}611 612namespace {613struct RemoveNoteDetail {614 struct DeletedRange {615 uint64_t OldFrom;616 uint64_t OldTo;617 };618 619 template <class ELFT>620 static std::vector<DeletedRange>621 findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,622 ArrayRef<RemoveNoteInfo> NotesToRemove);623 static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,624 ArrayRef<DeletedRange> ToRemove);625};626} // namespace627 628template <class ELFT>629std::vector<RemoveNoteDetail::DeletedRange>630RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,631 ArrayRef<RemoveNoteInfo> NotesToRemove) {632 using Elf_Nhdr = typename ELFT::Nhdr;633 using Elf_Note = typename ELFT::Note;634 std::vector<DeletedRange> ToRemove;635 uint64_t CurPos = 0;636 while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) {637 auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos);638 size_t FullSize = Nhdr->getSize(Align);639 if (CurPos + FullSize > Data.size())640 break;641 Elf_Note Note(*Nhdr);642 bool ShouldRemove =643 llvm::any_of(NotesToRemove, [&Note](const RemoveNoteInfo &NoteInfo) {644 return NoteInfo.TypeId == Note.getType() &&645 (NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());646 });647 if (ShouldRemove)648 ToRemove.push_back({CurPos, CurPos + FullSize});649 CurPos += FullSize;650 }651 return ToRemove;652}653 654std::vector<uint8_t>655RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,656 ArrayRef<DeletedRange> ToRemove) {657 std::vector<uint8_t> NewData;658 NewData.reserve(OldData.size());659 uint64_t CurPos = 0;660 for (const DeletedRange &RemRange : ToRemove) {661 if (CurPos < RemRange.OldFrom) {662 auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);663 llvm::append_range(NewData, Slice);664 }665 CurPos = RemRange.OldTo;666 }667 if (CurPos < OldData.size()) {668 auto Slice = OldData.slice(CurPos);669 llvm::append_range(NewData, Slice);670 }671 return NewData;672}673 674static Error removeNotes(Object &Obj, endianness Endianness,675 ArrayRef<RemoveNoteInfo> NotesToRemove,676 function_ref<Error(Error)> ErrorCallback) {677 // TODO: Support note segments.678 if (ErrorCallback) {679 for (Segment &Seg : Obj.segments()) {680 if (Seg.Type == PT_NOTE) {681 if (Error E = ErrorCallback(createStringError(682 errc::not_supported, "note segments are not supported")))683 return E;684 break;685 }686 }687 }688 for (auto &Sec : Obj.sections()) {689 if (Sec.Type != SHT_NOTE || !Sec.hasContents())690 continue;691 // TODO: Support note sections in segments.692 if (Sec.ParentSegment) {693 if (ErrorCallback)694 if (Error E = ErrorCallback(createStringError(695 errc::not_supported,696 "cannot remove note(s) from " + Sec.Name +697 ": sections in segments are not supported")))698 return E;699 continue;700 }701 ArrayRef<uint8_t> OldData = Sec.getContents();702 size_t Align = std::max<size_t>(4, Sec.Align);703 // Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the704 // header, so the parsers are the same.705 auto ToRemove = (Endianness == endianness::little)706 ? RemoveNoteDetail::findNotesToRemove<ELF64LE>(707 OldData, Align, NotesToRemove)708 : RemoveNoteDetail::findNotesToRemove<ELF64BE>(709 OldData, Align, NotesToRemove);710 if (!ToRemove.empty()) {711 if (Error E = Obj.updateSectionData(712 Sec, RemoveNoteDetail::updateData(OldData, ToRemove)))713 return E;714 }715 }716 return Error::success();717}718 719static Error720handleUserSection(const NewSectionInfo &NewSection,721 function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {722 ArrayRef<uint8_t> Data(reinterpret_cast<const uint8_t *>(723 NewSection.SectionData->getBufferStart()),724 NewSection.SectionData->getBufferSize());725 return F(NewSection.SectionName, Data);726}727 728static Error verifyNoteSection(StringRef Name, endianness Endianness,729 ArrayRef<uint8_t> Data) {730 // An ELF note has the following structure:731 // Name Size: 4 bytes (integer)732 // Desc Size: 4 bytes (integer)733 // Type : 4 bytes734 // Name : variable size, padded to a 4 byte boundary735 // Desc : variable size, padded to a 4 byte boundary736 737 if (Data.empty())738 return Error::success();739 740 if (Data.size() < 12) {741 std::string msg;742 raw_string_ostream(msg)743 << Name << " data must be either empty or at least 12 bytes long";744 return createStringError(errc::invalid_argument, msg);745 }746 if (Data.size() % 4 != 0) {747 std::string msg;748 raw_string_ostream(msg)749 << Name << " data size must be a multiple of 4 bytes";750 return createStringError(errc::invalid_argument, msg);751 }752 ArrayRef<uint8_t> NameSize = Data.slice(0, 4);753 ArrayRef<uint8_t> DescSize = Data.slice(4, 4);754 755 uint32_t NameSizeValue = support::endian::read32(NameSize.data(), Endianness);756 uint32_t DescSizeValue = support::endian::read32(DescSize.data(), Endianness);757 758 uint64_t ExpectedDataSize =759 /*NameSize=*/4 + /*DescSize=*/4 + /*Type=*/4 +760 /*Name=*/alignTo(NameSizeValue, 4) +761 /*Desc=*/alignTo(DescSizeValue, 4);762 uint64_t ActualDataSize = Data.size();763 if (ActualDataSize != ExpectedDataSize) {764 std::string msg;765 raw_string_ostream(msg)766 << Name767 << " data size is incompatible with the content of "768 "the name and description size fields:"769 << " expecting " << ExpectedDataSize << ", found " << ActualDataSize;770 return createStringError(errc::invalid_argument, msg);771 }772 773 return Error::success();774}775 776// This function handles the high level operations of GNU objcopy including777// handling command line options. It's important to outline certain properties778// we expect to hold of the command line operations. Any operation that "keeps"779// should keep regardless of a remove. Additionally any removal should respect780// any previous removals. Lastly whether or not something is removed shouldn't781// depend a) on the order the options occur in or b) on some opaque priority782// system. The only priority is that keeps/copies overrule removes.783static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,784 ElfType OutputElfType, Object &Obj) {785 if (Config.OutputArch) {786 Obj.Machine = Config.OutputArch->EMachine;787 Obj.OSABI = Config.OutputArch->OSABI;788 }789 790 if (!Config.SplitDWO.empty() && Config.ExtractDWO) {791 return Obj.removeSections(792 ELFConfig.AllowBrokenLinks,793 [&Obj](const SectionBase &Sec) { return onlyKeepDWOPred(Obj, Sec); });794 }795 796 // Dump sections before add/remove for compatibility with GNU objcopy.797 for (StringRef Flag : Config.DumpSection) {798 StringRef SectionName;799 StringRef FileName;800 std::tie(SectionName, FileName) = Flag.split('=');801 if (Error E =802 dumpSectionToFile(SectionName, FileName, Config.InputFilename, Obj))803 return E;804 }805 806 // It is important to remove the sections first. For example, we want to807 // remove the relocation sections before removing the symbols. That allows808 // us to avoid reporting the inappropriate errors about removing symbols809 // named in relocations.810 if (Error E = replaceAndRemoveSections(Config, ELFConfig, Obj))811 return createFileError(Config.InputFilename, std::move(E));812 813 if (Error E = updateAndRemoveSymbols(Config, ELFConfig, Obj))814 return createFileError(Config.InputFilename, std::move(E));815 816 if (!Config.SetSectionAlignment.empty()) {817 for (SectionBase &Sec : Obj.sections()) {818 auto I = Config.SetSectionAlignment.find(Sec.Name);819 if (I != Config.SetSectionAlignment.end())820 Sec.Align = I->second;821 }822 }823 824 if (Config.ChangeSectionLMAValAll != 0) {825 for (Segment &Seg : Obj.segments()) {826 if (Seg.MemSize > 0) {827 if (Config.ChangeSectionLMAValAll > 0 &&828 Seg.PAddr > std::numeric_limits<uint64_t>::max() -829 Config.ChangeSectionLMAValAll) {830 return createFileError(831 Config.InputFilename, errc::invalid_argument,832 "address 0x" + Twine::utohexstr(Seg.PAddr) +833 " cannot be increased by 0x" +834 Twine::utohexstr(Config.ChangeSectionLMAValAll) +835 ". The result would overflow");836 } else if (Config.ChangeSectionLMAValAll < 0 &&837 Seg.PAddr < std::numeric_limits<uint64_t>::min() -838 Config.ChangeSectionLMAValAll) {839 return createFileError(840 Config.InputFilename, errc::invalid_argument,841 "address 0x" + Twine::utohexstr(Seg.PAddr) +842 " cannot be decreased by 0x" +843 Twine::utohexstr(std::abs(Config.ChangeSectionLMAValAll)) +844 ". The result would underflow");845 }846 Seg.PAddr += Config.ChangeSectionLMAValAll;847 }848 }849 }850 851 if (!Config.ChangeSectionAddress.empty()) {852 if (Obj.Type != ELF::ET_REL)853 return createFileError(854 Config.InputFilename, object_error::invalid_file_type,855 "cannot change section address in a non-relocatable file");856 StringMap<AddressUpdate> SectionsToUpdateAddress;857 for (const SectionPatternAddressUpdate &PatternUpdate :858 reverse(Config.ChangeSectionAddress)) {859 for (SectionBase &Sec : Obj.sections()) {860 if (PatternUpdate.SectionPattern.matches(Sec.Name) &&861 SectionsToUpdateAddress.try_emplace(Sec.Name, PatternUpdate.Update)862 .second) {863 if (PatternUpdate.Update.Kind == AdjustKind::Subtract &&864 Sec.Addr < PatternUpdate.Update.Value) {865 return createFileError(866 Config.InputFilename, errc::invalid_argument,867 "address 0x" + Twine::utohexstr(Sec.Addr) +868 " cannot be decreased by 0x" +869 Twine::utohexstr(PatternUpdate.Update.Value) +870 ". The result would underflow");871 }872 if (PatternUpdate.Update.Kind == AdjustKind::Add &&873 Sec.Addr > std::numeric_limits<uint64_t>::max() -874 PatternUpdate.Update.Value) {875 return createFileError(876 Config.InputFilename, errc::invalid_argument,877 "address 0x" + Twine::utohexstr(Sec.Addr) +878 " cannot be increased by 0x" +879 Twine::utohexstr(PatternUpdate.Update.Value) +880 ". The result would overflow");881 }882 883 switch (PatternUpdate.Update.Kind) {884 case (AdjustKind::Set):885 Sec.Addr = PatternUpdate.Update.Value;886 break;887 case (AdjustKind::Subtract):888 Sec.Addr -= PatternUpdate.Update.Value;889 break;890 case (AdjustKind::Add):891 Sec.Addr += PatternUpdate.Update.Value;892 break;893 }894 }895 }896 }897 }898 899 if (Config.OnlyKeepDebug)900 for (auto &Sec : Obj.sections())901 if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)902 Sec.Type = SHT_NOBITS;903 904 endianness E = OutputElfType == ELFT_ELF32LE || OutputElfType == ELFT_ELF64LE905 ? endianness::little906 : endianness::big;907 908 if (!ELFConfig.NotesToRemove.empty()) {909 if (Error Err =910 removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback))911 return createFileError(Config.InputFilename, std::move(Err));912 }913 914 for (const NewSectionInfo &AddedSection : Config.AddSection) {915 auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error {916 OwnedDataSection &NewSection =917 Obj.addSection<OwnedDataSection>(Name, Data);918 if (Name.starts_with(".note") && Name != ".note.GNU-stack") {919 NewSection.Type = SHT_NOTE;920 if (ELFConfig.VerifyNoteSections)921 return verifyNoteSection(Name, E, Data);922 }923 return Error::success();924 };925 if (Error E = handleUserSection(AddedSection, AddSection))926 return createFileError(Config.InputFilename, std::move(E));927 }928 929 for (const NewSectionInfo &NewSection : Config.UpdateSection) {930 auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {931 return Obj.updateSection(Name, Data);932 };933 if (Error E = handleUserSection(NewSection, UpdateSection))934 return createFileError(Config.InputFilename, std::move(E));935 }936 937 if (!Config.AddGnuDebugLink.empty())938 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,939 Config.GnuDebugLinkCRC32);940 941 // If the symbol table was previously removed, we need to create a new one942 // before adding new symbols.943 if (!Obj.SymbolTable && !Config.SymbolsToAdd.empty())944 if (Error E = Obj.addNewSymbolTable())945 return createFileError(Config.InputFilename, std::move(E));946 947 for (const NewSymbolInfo &SI : Config.SymbolsToAdd)948 addSymbol(Obj, SI, ELFConfig.NewSymbolVisibility);949 950 // --set-section-{flags,type} work with sections added by --add-section.951 if (!Config.SetSectionFlags.empty() || !Config.SetSectionType.empty()) {952 for (auto &Sec : Obj.sections()) {953 const auto Iter = Config.SetSectionFlags.find(Sec.Name);954 if (Iter != Config.SetSectionFlags.end()) {955 const SectionFlagsUpdate &SFU = Iter->second;956 if (Error E = setSectionFlagsAndType(Sec, SFU.NewFlags, Obj.Machine))957 return createFileError(Config.InputFilename, std::move(E));958 }959 auto It2 = Config.SetSectionType.find(Sec.Name);960 if (It2 != Config.SetSectionType.end())961 setSectionType(Sec, It2->second);962 }963 }964 965 if (!Config.SectionsToRename.empty()) {966 std::vector<RelocationSectionBase *> RelocSections;967 DenseSet<SectionBase *> RenamedSections;968 for (SectionBase &Sec : Obj.sections()) {969 auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec);970 const auto Iter = Config.SectionsToRename.find(Sec.Name);971 if (Iter != Config.SectionsToRename.end()) {972 const SectionRename &SR = Iter->second;973 Sec.Name = std::string(SR.NewName);974 if (SR.NewFlags) {975 if (Error E = setSectionFlagsAndType(Sec, *SR.NewFlags, Obj.Machine))976 return createFileError(Config.InputFilename, std::move(E));977 }978 RenamedSections.insert(&Sec);979 } else if (RelocSec && !(Sec.Flags & SHF_ALLOC))980 // Postpone processing relocation sections which are not specified in981 // their explicit '--rename-section' commands until after their target982 // sections are renamed.983 // Dynamic relocation sections (i.e. ones with SHF_ALLOC) should be984 // renamed only explicitly. Otherwise, renaming, for example, '.got.plt'985 // would affect '.rela.plt', which is not desirable.986 RelocSections.push_back(RelocSec);987 }988 989 // Rename relocation sections according to their target sections.990 for (RelocationSectionBase *RelocSec : RelocSections) {991 auto Iter = RenamedSections.find(RelocSec->getSection());992 if (Iter != RenamedSections.end())993 RelocSec->Name = (RelocSec->getNamePrefix() + (*Iter)->Name).str();994 }995 }996 997 // Add a prefix to allocated sections and their relocation sections. This998 // should be done after renaming the section by Config.SectionToRename to999 // imitate the GNU objcopy behavior.1000 if (!Config.AllocSectionsPrefix.empty()) {1001 DenseSet<SectionBase *> PrefixedSections;1002 for (SectionBase &Sec : Obj.sections()) {1003 if (Sec.Flags & SHF_ALLOC) {1004 Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();1005 PrefixedSections.insert(&Sec);1006 } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {1007 // Rename relocation sections associated to the allocated sections.1008 // For example, if we rename .text to .prefix.text, we also rename1009 // .rel.text to .rel.prefix.text.1010 //1011 // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled1012 // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not1013 // .rela.prefix.plt since GNU objcopy does so.1014 const SectionBase *TargetSec = RelocSec->getSection();1015 if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {1016 // If the relocation section comes *after* the target section, we1017 // don't add Config.AllocSectionsPrefix because we've already added1018 // the prefix to TargetSec->Name. Otherwise, if the relocation1019 // section comes *before* the target section, we add the prefix.1020 if (PrefixedSections.count(TargetSec))1021 Sec.Name = (RelocSec->getNamePrefix() + TargetSec->Name).str();1022 else1023 Sec.Name = (RelocSec->getNamePrefix() + Config.AllocSectionsPrefix +1024 TargetSec->Name)1025 .str();1026 }1027 }1028 }1029 }1030 1031 if (ELFConfig.EntryExpr)1032 Obj.Entry = ELFConfig.EntryExpr(Obj.Entry);1033 return Error::success();1034}1035 1036static Error writeOutput(const CommonConfig &Config, Object &Obj,1037 raw_ostream &Out, ElfType OutputElfType) {1038 std::unique_ptr<Writer> Writer =1039 createWriter(Config, Obj, Out, OutputElfType);1040 if (Error E = Writer->finalize())1041 return E;1042 return Writer->write();1043}1044 1045Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,1046 const ELFConfig &ELFConfig,1047 MemoryBuffer &In, raw_ostream &Out) {1048 IHexReader Reader(&In);1049 Expected<std::unique_ptr<Object>> Obj = Reader.create(true);1050 if (!Obj)1051 return Obj.takeError();1052 1053 const ElfType OutputElfType =1054 getOutputElfType(Config.OutputArch.value_or(MachineInfo()));1055 if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))1056 return E;1057 return writeOutput(Config, **Obj, Out, OutputElfType);1058}1059 1060Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,1061 const ELFConfig &ELFConfig,1062 MemoryBuffer &In,1063 raw_ostream &Out) {1064 BinaryReader Reader(&In, ELFConfig.NewSymbolVisibility);1065 Expected<std::unique_ptr<Object>> Obj = Reader.create(true);1066 if (!Obj)1067 return Obj.takeError();1068 1069 // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch1070 // (-B<arch>).1071 const ElfType OutputElfType =1072 getOutputElfType(Config.OutputArch.value_or(MachineInfo()));1073 if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))1074 return E;1075 return writeOutput(Config, **Obj, Out, OutputElfType);1076}1077 1078Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,1079 const ELFConfig &ELFConfig,1080 object::ELFObjectFileBase &In,1081 raw_ostream &Out) {1082 ELFReader Reader(&In, Config.ExtractPartition);1083 Expected<std::unique_ptr<Object>> Obj =1084 Reader.create(!Config.SymbolsToAdd.empty());1085 if (!Obj)1086 return Obj.takeError();1087 // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.1088 const ElfType OutputElfType = Config.OutputArch1089 ? getOutputElfType(*Config.OutputArch)1090 : getOutputElfType(In);1091 1092 if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))1093 return E;1094 1095 if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))1096 return createFileError(Config.InputFilename, std::move(E));1097 1098 return Error::success();1099}1100