diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:51:42 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:51:42 +0000 |
commit | 1d5ae1026e831016fc29fd927877c86af904481f (patch) | |
tree | 2cdfd12620fcfa5d9e4a0389f85368e8e36f63f9 /tools/llvm-objcopy/ELF | |
parent | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (diff) |
Notes
Diffstat (limited to 'tools/llvm-objcopy/ELF')
-rw-r--r-- | tools/llvm-objcopy/ELF/ELFConfig.cpp | 133 | ||||
-rw-r--r-- | tools/llvm-objcopy/ELF/ELFConfig.h | 44 | ||||
-rw-r--r-- | tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 169 | ||||
-rw-r--r-- | tools/llvm-objcopy/ELF/Object.cpp | 252 | ||||
-rw-r--r-- | tools/llvm-objcopy/ELF/Object.h | 56 |
5 files changed, 429 insertions, 225 deletions
diff --git a/tools/llvm-objcopy/ELF/ELFConfig.cpp b/tools/llvm-objcopy/ELF/ELFConfig.cpp new file mode 100644 index 000000000000..40993760add7 --- /dev/null +++ b/tools/llvm-objcopy/ELF/ELFConfig.cpp @@ -0,0 +1,133 @@ +//===- ELFConfig.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CopyConfig.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace objcopy { +namespace elf { + +static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue, + uint8_t DefaultVisibility) { + // Parse value given with --add-symbol option and create the + // new symbol if possible. The value format for --add-symbol is: + // + // <name>=[<section>:]<value>[,<flags>] + // + // where: + // <name> - symbol name, can be empty string + // <section> - optional section name. If not given ABS symbol is created + // <value> - symbol value, can be decimal or hexadecimal number prefixed + // with 0x. + // <flags> - optional flags affecting symbol type, binding or visibility: + // The following are currently supported: + // + // global, local, weak, default, hidden, file, section, object, + // indirect-function. + // + // The following flags are ignored and provided for GNU + // compatibility only: + // + // warning, debug, constructor, indirect, synthetic, + // unique-object, before=<symbol>. + NewSymbolInfo SI; + StringRef Value; + std::tie(SI.SymbolName, Value) = FlagValue.split('='); + if (Value.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --add-symbol, missing '=' after '%s'", + SI.SymbolName.str().c_str()); + + if (Value.contains(':')) { + std::tie(SI.SectionName, Value) = Value.split(':'); + if (SI.SectionName.empty() || Value.empty()) + return createStringError( + errc::invalid_argument, + "bad format for --add-symbol, missing section name or symbol value"); + } + + SmallVector<StringRef, 6> Flags; + Value.split(Flags, ','); + if (Flags[0].getAsInteger(0, SI.Value)) + return createStringError(errc::invalid_argument, "bad symbol value: '%s'", + Flags[0].str().c_str()); + + SI.Visibility = DefaultVisibility; + + using Functor = std::function<void(void)>; + SmallVector<StringRef, 6> UnsupportedFlags; + for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) + static_cast<Functor>( + StringSwitch<Functor>(Flags[I]) + .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; }) + .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; }) + .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; }) + .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; }) + .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; }) + .CaseLower("protected", + [&SI] { SI.Visibility = ELF::STV_PROTECTED; }) + .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; }) + .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; }) + .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; }) + .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; }) + .CaseLower("indirect-function", + [&SI] { SI.Type = ELF::STT_GNU_IFUNC; }) + .CaseLower("debug", [] {}) + .CaseLower("constructor", [] {}) + .CaseLower("warning", [] {}) + .CaseLower("indirect", [] {}) + .CaseLower("synthetic", [] {}) + .CaseLower("unique-object", [] {}) + .StartsWithLower("before", [] {}) + .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); + if (!UnsupportedFlags.empty()) + return createStringError(errc::invalid_argument, + "unsupported flag%s for --add-symbol: '%s'", + UnsupportedFlags.size() > 1 ? "s" : "", + join(UnsupportedFlags, "', '").c_str()); + return SI; +} + +Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) { + ELFCopyConfig ELFConfig; + if (Config.NewSymbolVisibility) { + const uint8_t Invalid = 0xff; + ELFConfig.NewSymbolVisibility = + StringSwitch<uint8_t>(*Config.NewSymbolVisibility) + .Case("default", ELF::STV_DEFAULT) + .Case("hidden", ELF::STV_HIDDEN) + .Case("internal", ELF::STV_INTERNAL) + .Case("protected", ELF::STV_PROTECTED) + .Default(Invalid); + + if (ELFConfig.NewSymbolVisibility == Invalid) + return createStringError(errc::invalid_argument, + "'%s' is not a valid symbol visibility", + Config.NewSymbolVisibility->str().c_str()); + } + + for (StringRef Arg : Config.SymbolsToAdd) { + Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo( + Arg, + ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT)); + if (!NSI) + return NSI.takeError(); + ELFConfig.SymbolsToAdd.push_back(*NSI); + } + + return ELFConfig; +} + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm diff --git a/tools/llvm-objcopy/ELF/ELFConfig.h b/tools/llvm-objcopy/ELF/ELFConfig.h new file mode 100644 index 000000000000..977efbc4166f --- /dev/null +++ b/tools/llvm-objcopy/ELF/ELFConfig.h @@ -0,0 +1,44 @@ +//===- ELFConfig.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_ELFCONFIG_H +#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/Error.h" +#include <vector> + +namespace llvm { +namespace objcopy { +struct CopyConfig; + +namespace elf { + +struct NewSymbolInfo { + StringRef SymbolName; + StringRef SectionName; + uint64_t Value = 0; + uint8_t Type = ELF::STT_NOTYPE; + uint8_t Bind = ELF::STB_GLOBAL; + uint8_t Visibility = ELF::STV_DEFAULT; +}; + +struct ELFCopyConfig { + Optional<uint8_t> NewSymbolVisibility; + std::vector<NewSymbolInfo> SymbolsToAdd; +}; + +Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config); + +} // namespace elf +} // namespace objcopy +} // namespace llvm + +#endif diff --git a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index b366c6e55987..8bf7e0f88010 100644 --- a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -136,16 +136,16 @@ static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config, // Depending on the initial ELFT and OutputFormat we need a different Writer. switch (OutputElfType) { case ELFT_ELF32LE: - return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, + return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections); case ELFT_ELF64LE: - return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, + return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections); case ELFT_ELF32BE: - return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, + return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections); case ELFT_ELF64BE: - return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, + return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections); } llvm_unreachable("Invalid output format"); @@ -156,9 +156,9 @@ static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, ElfType OutputElfType) { switch (Config.OutputFormat) { case FileFormat::Binary: - return llvm::make_unique<BinaryWriter>(Obj, Buf); + return std::make_unique<BinaryWriter>(Obj, Buf); case FileFormat::IHex: - return llvm::make_unique<IHexWriter>(Obj, Buf); + return std::make_unique<IHexWriter>(Obj, Buf); default: return createELFWriter(Config, Obj, Buf, OutputElfType); } @@ -263,7 +263,7 @@ static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, StringRef File, ElfType OutputElfType) { - auto DWOFile = Reader.create(); + auto DWOFile = Reader.create(false); auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); }; @@ -305,9 +305,9 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename, SecName.str().c_str()); } -static bool isCompressable(const SectionBase &Section) { - return !(Section.Flags & ELF::SHF_COMPRESSED) && - StringRef(Section.Name).startswith(".debug"); +static bool isCompressable(const SectionBase &Sec) { + return !(Sec.Flags & ELF::SHF_COMPRESSED) && + StringRef(Sec.Name).startswith(".debug"); } static void replaceDebugSections( @@ -356,7 +356,7 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF && ((Config.LocalizeHidden && (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || - is_contained(Config.SymbolsToLocalize, Sym.Name))) + Config.SymbolsToLocalize.matches(Sym.Name))) Sym.Binding = STB_LOCAL; // Note: these two globalize flags have very similar names but different @@ -370,16 +370,15 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { // --keep-global-symbol. Because of that, make sure to check // --globalize-symbol second. if (!Config.SymbolsToKeepGlobal.empty() && - !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) && + !Config.SymbolsToKeepGlobal.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_LOCAL; - if (is_contained(Config.SymbolsToGlobalize, Sym.Name) && + if (Config.SymbolsToGlobalize.matches(Sym.Name) && Sym.getShndx() != SHN_UNDEF) Sym.Binding = STB_GLOBAL; - if (is_contained(Config.SymbolsToWeaken, Sym.Name) && - Sym.Binding == STB_GLOBAL) + if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL) Sym.Binding = STB_WEAK; if (Config.Weaken && Sym.Binding == STB_GLOBAL && @@ -399,12 +398,12 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { // symbols are still 'needed' and which are not. if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || !Config.OnlySection.empty()) { - for (auto &Section : Obj.sections()) - Section.markSymbols(); + for (SectionBase &Sec : Obj.sections()) + Sec.markSymbols(); } auto RemoveSymbolsPred = [&](const Symbol &Sym) { - if (is_contained(Config.SymbolsToKeep, Sym.Name) || + if (Config.SymbolsToKeep.matches(Sym.Name) || (Config.KeepFileSymbols && Sym.Type == STT_FILE)) return false; @@ -418,12 +417,12 @@ static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { if (Config.StripAll || Config.StripAllGNU) return true; - if (is_contained(Config.SymbolsToRemove, Sym.Name)) + if (Config.SymbolsToRemove.matches(Sym.Name)) return true; if ((Config.StripUnneeded || - is_contained(Config.UnneededSymbolsToRemove, Sym.Name)) && - isUnneededSymbol(Sym)) + Config.UnneededSymbolsToRemove.matches(Sym.Name)) && + (!Obj.isRelocatable() || isUnneededSymbol(Sym))) return true; // We want to remove undefined symbols if all references have been stripped. @@ -443,7 +442,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { // Removes: if (!Config.ToRemove.empty()) { RemovePred = [&Config](const SectionBase &Sec) { - return is_contained(Config.ToRemove, Sec.Name); + return Config.ToRemove.matches(Sec.Name); }; } @@ -481,7 +480,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { }; } - if (Config.StripDebug) { + if (Config.StripDebug || Config.StripUnneeded) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || isDebugSection(Sec); }; @@ -523,7 +522,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { if (!Config.OnlySection.empty()) { RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes. - if (is_contained(Config.OnlySection, Sec.Name)) + if (Config.OnlySection.matches(Sec.Name)) return false; // Allow all implicit removes. @@ -545,7 +544,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { if (!Config.KeepSection.empty()) { RemovePred = [&Config, RemovePred](const SectionBase &Sec) { // Explicitly keep these sections regardless of previous removes. - if (is_contained(Config.KeepSection, Sec.Name)) + if (Config.KeepSection.matches(Sec.Name)) return false; // Otherwise defer to RemovePred. return RemovePred(Sec); @@ -614,9 +613,8 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, if (Error E = updateAndRemoveSymbols(Config, Obj)) return E; - if (!Config.SectionsToRename.empty() || !Config.AllocSectionsPrefix.empty()) { - DenseSet<SectionBase *> PrefixedSections; - for (auto &Sec : Obj.sections()) { + if (!Config.SectionsToRename.empty()) { + for (SectionBase &Sec : Obj.sections()) { const auto Iter = Config.SectionsToRename.find(Sec.Name); if (Iter != Config.SectionsToRename.end()) { const SectionRename &SR = Iter->second; @@ -624,63 +622,62 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, if (SR.NewFlags.hasValue()) setSectionFlagsAndType(Sec, SR.NewFlags.getValue()); } + } + } - // Add a prefix to allocated sections and their relocation sections. This - // should be done after renaming the section by Config.SectionToRename to - // imitate the GNU objcopy behavior. - if (!Config.AllocSectionsPrefix.empty()) { - if (Sec.Flags & SHF_ALLOC) { - Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); - PrefixedSections.insert(&Sec); - - // Rename relocation sections associated to the allocated sections. - // For example, if we rename .text to .prefix.text, we also rename - // .rel.text to .rel.prefix.text. - // - // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled - // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not - // .rela.prefix.plt since GNU objcopy does so. - } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) { - auto *TargetSec = RelocSec->getSection(); - if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) { - StringRef prefix; - switch (Sec.Type) { - case SHT_REL: - prefix = ".rel"; - break; - case SHT_RELA: - prefix = ".rela"; - break; - default: - continue; - } - - // If the relocation section comes *after* the target section, we - // don't add Config.AllocSectionsPrefix because we've already added - // the prefix to TargetSec->Name. Otherwise, if the relocation - // section comes *before* the target section, we add the prefix. - if (PrefixedSections.count(TargetSec)) { - Sec.Name = (prefix + TargetSec->Name).str(); - } else { - const auto Iter = Config.SectionsToRename.find(TargetSec->Name); - if (Iter != Config.SectionsToRename.end()) { - // Both `--rename-section` and `--prefix-alloc-sections` are - // given but the target section is not yet renamed. - Sec.Name = - (prefix + Config.AllocSectionsPrefix + Iter->second.NewName) - .str(); - } else { - Sec.Name = - (prefix + Config.AllocSectionsPrefix + TargetSec->Name) - .str(); - } - } + // Add a prefix to allocated sections and their relocation sections. This + // should be done after renaming the section by Config.SectionToRename to + // imitate the GNU objcopy behavior. + if (!Config.AllocSectionsPrefix.empty()) { + DenseSet<SectionBase *> PrefixedSections; + for (SectionBase &Sec : Obj.sections()) { + if (Sec.Flags & SHF_ALLOC) { + Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str(); + PrefixedSections.insert(&Sec); + } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) { + // Rename relocation sections associated to the allocated sections. + // For example, if we rename .text to .prefix.text, we also rename + // .rel.text to .rel.prefix.text. + // + // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled + // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not + // .rela.prefix.plt since GNU objcopy does so. + const SectionBase *TargetSec = RelocSec->getSection(); + if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) { + StringRef prefix; + switch (Sec.Type) { + case SHT_REL: + prefix = ".rel"; + break; + case SHT_RELA: + prefix = ".rela"; + break; + default: + llvm_unreachable("not a relocation section"); } + + // If the relocation section comes *after* the target section, we + // don't add Config.AllocSectionsPrefix because we've already added + // the prefix to TargetSec->Name. Otherwise, if the relocation + // section comes *before* the target section, we add the prefix. + if (PrefixedSections.count(TargetSec)) + Sec.Name = (prefix + TargetSec->Name).str(); + else + Sec.Name = + (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str(); } } } } + if (!Config.SetSectionAlignment.empty()) { + for (SectionBase &Sec : Obj.sections()) { + auto I = Config.SetSectionAlignment.find(Sec.Name); + if (I != Config.SetSectionAlignment.end()) + Sec.Align = I->second; + } + } + if (!Config.SetSectionFlags.empty()) { for (auto &Sec : Obj.sections()) { const auto Iter = Config.SetSectionFlags.find(Sec.Name); @@ -721,7 +718,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink, Config.GnuDebugLinkCRC32); - for (const NewSymbolInfo &SI : Config.SymbolsToAdd) { + for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) { SectionBase *Sec = Obj.findSection(SI.SectionName); uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value; Obj.SymbolTable->addSymbol( @@ -746,9 +743,9 @@ static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out, Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, Buffer &Out) { IHexReader Reader(&In); - std::unique_ptr<Object> Obj = Reader.create(); + std::unique_ptr<Object> Obj = Reader.create(true); const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); + getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) return E; return writeOutput(Config, *Obj, Out, OutputElfType); @@ -756,13 +753,15 @@ Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, Buffer &Out) { - BinaryReader Reader(Config.BinaryArch, &In); - std::unique_ptr<Object> Obj = Reader.create(); + uint8_t NewSymbolVisibility = + Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + BinaryReader Reader(&In, NewSymbolVisibility); + std::unique_ptr<Object> Obj = Reader.create(true); // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch // (-B<arch>). const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch)); + getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType)) return E; return writeOutput(Config, *Obj, Out, OutputElfType); @@ -771,7 +770,7 @@ Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, Error executeObjcopyOnBinary(const CopyConfig &Config, object::ELFObjectFileBase &In, Buffer &Out) { ELFReader Reader(&In, Config.ExtractPartition); - std::unique_ptr<Object> Obj = Reader.create(); + std::unique_ptr<Object> Obj = Reader.create(!Config.SymbolsToAdd.empty()); // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input. const ElfType OutputElfType = Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) diff --git a/tools/llvm-objcopy/ELF/Object.cpp b/tools/llvm-objcopy/ELF/Object.cpp index fa696380e17c..74145dad6e6b 100644 --- a/tools/llvm-objcopy/ELF/Object.cpp +++ b/tools/llvm-objcopy/ELF/Object.cpp @@ -397,7 +397,7 @@ void SectionWriter::visit(const OwnedDataSection &Sec) { llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset); } -static const std::vector<uint8_t> ZlibGnuMagic = {'Z', 'L', 'I', 'B'}; +static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}}; static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) { return Data.size() > ZlibGnuMagic.size() && @@ -665,7 +665,7 @@ void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, Sym.Visibility = Visibility; Sym.Size = SymbolSize; Sym.Index = Symbols.size(); - Symbols.emplace_back(llvm::make_unique<Symbol>(Sym)); + Symbols.emplace_back(std::make_unique<Symbol>(Sym)); Size += this->EntrySize; } @@ -1055,29 +1055,28 @@ void GroupSection::accept(MutableSectionVisitor &Visitor) { } // Returns true IFF a section is wholly inside the range of a segment -static bool sectionWithinSegment(const SectionBase &Section, - const Segment &Segment) { +static bool sectionWithinSegment(const SectionBase &Sec, const Segment &Seg) { // If a section is empty it should be treated like it has a size of 1. This is // to clarify the case when an empty section lies on a boundary between two // segments and ensures that the section "belongs" to the second segment and // not the first. - uint64_t SecSize = Section.Size ? Section.Size : 1; + uint64_t SecSize = Sec.Size ? Sec.Size : 1; - if (Section.Type == SHT_NOBITS) { - if (!(Section.Flags & SHF_ALLOC)) + if (Sec.Type == SHT_NOBITS) { + if (!(Sec.Flags & SHF_ALLOC)) return false; - bool SectionIsTLS = Section.Flags & SHF_TLS; - bool SegmentIsTLS = Segment.Type == PT_TLS; + bool SectionIsTLS = Sec.Flags & SHF_TLS; + bool SegmentIsTLS = Seg.Type == PT_TLS; if (SectionIsTLS != SegmentIsTLS) return false; - return Segment.VAddr <= Section.Addr && - Segment.VAddr + Segment.MemSize >= Section.Addr + SecSize; + return Seg.VAddr <= Sec.Addr && + Seg.VAddr + Seg.MemSize >= Sec.Addr + SecSize; } - return Segment.Offset <= Section.OriginalOffset && - Segment.Offset + Segment.FileSize >= Section.OriginalOffset + SecSize; + return Seg.Offset <= Sec.OriginalOffset && + Seg.Offset + Seg.FileSize >= Sec.OriginalOffset + SecSize; } // Returns true IFF a segment's original offset is inside of another segment's @@ -1113,7 +1112,7 @@ void BasicELFBuilder::initFileHeader() { Obj->OSABI = ELFOSABI_NONE; Obj->ABIVersion = 0; Obj->Entry = 0x0; - Obj->Machine = EMachine; + Obj->Machine = EM_NONE; Obj->Version = 1; } @@ -1141,8 +1140,8 @@ SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) { } void BasicELFBuilder::initSections() { - for (auto &Section : Obj->sections()) - Section.initialize(Obj->sections()); + for (SectionBase &Sec : Obj->sections()) + Sec.initialize(Obj->sections()); } void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { @@ -1161,11 +1160,12 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { Twine Prefix = Twine("_binary_") + SanitizedFilename; SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection, - /*Value=*/0, STV_DEFAULT, 0, 0); + /*Value=*/0, NewSymbolVisibility, 0, 0); SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection, - /*Value=*/DataSection.Size, STV_DEFAULT, 0, 0); + /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0); SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr, - /*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0); + /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS, + 0); } std::unique_ptr<Object> BinaryELFBuilder::build() { @@ -1255,10 +1255,9 @@ template <class ELFT> void ELFBuilder<ELFT>::findEhdrOffset() { if (!ExtractPartition) return; - for (const SectionBase &Section : Obj.sections()) { - if (Section.Type == SHT_LLVM_PART_EHDR && - Section.Name == *ExtractPartition) { - EhdrOffset = Section.Offset; + for (const SectionBase &Sec : Obj.sections()) { + if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) { + EhdrOffset = Sec.Offset; return; } } @@ -1287,15 +1286,12 @@ void ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) { Seg.MemSize = Phdr.p_memsz; Seg.Align = Phdr.p_align; Seg.Index = Index++; - for (SectionBase &Section : Obj.sections()) { - if (sectionWithinSegment(Section, Seg)) { - Seg.addSection(&Section); - if (!Section.ParentSegment || - Section.ParentSegment->Offset > Seg.Offset) { - Section.ParentSegment = &Seg; - } + for (SectionBase &Sec : Obj.sections()) + if (sectionWithinSegment(Sec, Seg)) { + Seg.addSection(&Sec); + if (!Sec.ParentSegment || Sec.ParentSegment->Offset > Seg.Offset) + Sec.ParentSegment = &Seg; } - } } auto &ElfHdr = Obj.ElfHdrSegment; @@ -1531,7 +1527,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { } } -template <class ELFT> void ELFBuilder<ELFT>::readSections() { +template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { // If a section index table exists we'll need to initialize it before we // initialize the symbol table because the symbol table might need to // reference it. @@ -1544,16 +1540,37 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections() { if (Obj.SymbolTable) { Obj.SymbolTable->initialize(Obj.sections()); initSymbolTable(Obj.SymbolTable); + } else if (EnsureSymtab) { + // Reuse the existing SHT_STRTAB section if exists. + StringTableSection *StrTab = nullptr; + for (auto &Sec : Obj.sections()) { + if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { + StrTab = static_cast<StringTableSection *>(&Sec); + + // Prefer .strtab to .shstrtab. + if (Obj.SectionNames != &Sec) + break; + } + } + if (!StrTab) + StrTab = &Obj.addSection<StringTableSection>(); + + SymbolTableSection &SymTab = Obj.addSection<SymbolTableSection>(); + SymTab.Name = ".symtab"; + SymTab.Link = StrTab->Index; + SymTab.initialize(Obj.sections()); + SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); + Obj.SymbolTable = &SymTab; } // Now that all sections and symbols have been added we can add // relocations that reference symbols and set the link and info fields for // relocation sections. - for (auto &Section : Obj.sections()) { - if (&Section == Obj.SymbolTable) + for (auto &Sec : Obj.sections()) { + if (&Sec == Obj.SymbolTable) continue; - Section.initialize(Obj.sections()); - if (auto RelSec = dyn_cast<RelocationSection>(&Section)) { + Sec.initialize(Obj.sections()); + if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) { auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index; if (RelSec->Type == SHT_REL) initRelocations(RelSec, Obj.SymbolTable, @@ -1561,7 +1578,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections() { else initRelocations(RelSec, Obj.SymbolTable, unwrapOrError(ElfFile.relas(Shdr))); - } else if (auto GroupSec = dyn_cast<GroupSection>(&Section)) { + } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) { initGroupSection(GroupSec); } } @@ -1582,7 +1599,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readSections() { " is not a string table"); } -template <class ELFT> void ELFBuilder<ELFT>::build() { +template <class ELFT> void ELFBuilder<ELFT>::build(bool EnsureSymtab) { readSectionHeaders(); findEhdrOffset(); @@ -1601,7 +1618,7 @@ template <class ELFT> void ELFBuilder<ELFT>::build() { Obj.Entry = Ehdr.e_entry; Obj.Flags = Ehdr.e_flags; - readSections(); + readSections(EnsureSymtab); readProgramHeaders(HeadersFile); } @@ -1609,8 +1626,8 @@ Writer::~Writer() {} Reader::~Reader() {} -std::unique_ptr<Object> BinaryReader::create() const { - return BinaryELFBuilder(MInfo.EMachine, MemBuf).build(); +std::unique_ptr<Object> BinaryReader::create(bool /*EnsureSymtab*/) const { + return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build(); } Expected<std::vector<IHexRecord>> IHexReader::parse() const { @@ -1639,28 +1656,28 @@ Expected<std::vector<IHexRecord>> IHexReader::parse() const { return std::move(Records); } -std::unique_ptr<Object> IHexReader::create() const { +std::unique_ptr<Object> IHexReader::create(bool /*EnsureSymtab*/) const { std::vector<IHexRecord> Records = unwrapOrError(parse()); return IHexELFBuilder(Records).build(); } -std::unique_ptr<Object> ELFReader::create() const { - auto Obj = llvm::make_unique<Object>(); +std::unique_ptr<Object> ELFReader::create(bool EnsureSymtab) const { + auto Obj = std::make_unique<Object>(); if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) { ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition); - Builder.build(); + Builder.build(EnsureSymtab); return Obj; } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) { ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition); - Builder.build(); + Builder.build(EnsureSymtab); return Obj; } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) { ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition); - Builder.build(); + Builder.build(EnsureSymtab); return Obj; } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) { ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition); - Builder.build(); + Builder.build(EnsureSymtab); return Obj; } error("invalid file type"); @@ -1693,7 +1710,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() { Ehdr.e_ehsize = sizeof(Elf_Ehdr); if (WriteSectionHeaders && Obj.sections().size() != 0) { Ehdr.e_shentsize = sizeof(Elf_Shdr); - Ehdr.e_shoff = Obj.SHOffset; + Ehdr.e_shoff = Obj.SHOff; // """ // If the number of sections is greater than or equal to // SHN_LORESERVE (0xff00), this member has the value zero and the actual @@ -1732,7 +1749,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdrs() { // This reference serves to write the dummy section header at the begining // of the file. It is not used for anything else Elf_Shdr &Shdr = - *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOffset); + *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOff); Shdr.sh_name = 0; Shdr.sh_type = SHT_NULL; Shdr.sh_flags = 0; @@ -1862,26 +1879,13 @@ void Object::sortSections() { }); } -static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { - // Calculate Diff such that (Offset + Diff) & -Align == Addr & -Align. - if (Align == 0) - Align = 1; - auto Diff = - static_cast<int64_t>(Addr % Align) - static_cast<int64_t>(Offset % Align); - // We only want to add to Offset, however, so if Diff < 0 we can add Align and - // (Offset + Diff) & -Align == Addr & -Align will still hold. - if (Diff < 0) - Diff += Align; - return Offset + Diff; -} - // Orders segments such that if x = y->ParentSegment then y comes before x. static void orderSegments(std::vector<Segment *> &Segments) { llvm::stable_sort(Segments, compareSegmentsByOffset); } // This function finds a consistent layout for a list of segments starting from -// an Offset. It assumes that Segments have been sorted by OrderSegments and +// an Offset. It assumes that Segments have been sorted by orderSegments and // returns an Offset one past the end of the last segment. static uint64_t layoutSegments(std::vector<Segment *> &Segments, uint64_t Offset) { @@ -1902,8 +1906,8 @@ static uint64_t layoutSegments(std::vector<Segment *> &Segments, Seg->Offset = Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset; } else { - Offset = alignToAddr(Offset, Seg->VAddr, Seg->Align); - Seg->Offset = Offset; + Seg->Offset = + alignTo(Offset, std::max<uint64_t>(Seg->Align, 1), Seg->VAddr); } Offset = std::max(Offset, Seg->Offset + Seg->FileSize); } @@ -1925,17 +1929,17 @@ static uint64_t layoutSections(Range Sections, uint64_t Offset) { // of the segment we can assign a new offset to the section. For sections not // covered by segments we can just bump Offset to the next valid location. uint32_t Index = 1; - for (auto &Section : Sections) { - Section.Index = Index++; - if (Section.ParentSegment != nullptr) { - auto Segment = *Section.ParentSegment; - Section.Offset = - Segment.Offset + (Section.OriginalOffset - Segment.OriginalOffset); + for (auto &Sec : Sections) { + Sec.Index = Index++; + if (Sec.ParentSegment != nullptr) { + auto Segment = *Sec.ParentSegment; + Sec.Offset = + Segment.Offset + (Sec.OriginalOffset - Segment.OriginalOffset); } else { - Offset = alignTo(Offset, Section.Align == 0 ? 1 : Section.Align); - Section.Offset = Offset; - if (Section.Type != SHT_NOBITS) - Offset += Section.Size; + Offset = alignTo(Offset, Sec.Align == 0 ? 1 : Sec.Align); + Sec.Offset = Offset; + if (Sec.Type != SHT_NOBITS) + Offset += Sec.Size; } } return Offset; @@ -1971,16 +1975,16 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { // Offset so that SHOffset is valid. if (WriteSectionHeaders) Offset = alignTo(Offset, sizeof(Elf_Addr)); - Obj.SHOffset = Offset; + Obj.SHOff = Offset; } template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const { // We already have the section header offset so we can calculate the total // size by just adding up the size of each section header. if (!WriteSectionHeaders) - return Obj.SHOffset; + return Obj.SHOff; size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr. - return Obj.SHOffset + ShdrCount * sizeof(Elf_Shdr); + return Obj.SHOff + ShdrCount * sizeof(Elf_Shdr); } template <class ELFT> Error ELFWriter<ELFT>::write() { @@ -1995,6 +1999,25 @@ template <class ELFT> Error ELFWriter<ELFT>::write() { return Buf.commit(); } +static Error removeUnneededSections(Object &Obj) { + // We can remove an empty symbol table from non-relocatable objects. + // Relocatable objects typically have relocation sections whose + // sh_link field points to .symtab, so we can't remove .symtab + // even if it is empty. + if (Obj.isRelocatable() || Obj.SymbolTable == nullptr || + !Obj.SymbolTable->empty()) + return Error::success(); + + // .strtab can be used for section names. In such a case we shouldn't + // remove it. + auto *StrTab = Obj.SymbolTable->getStrTab() == Obj.SectionNames + ? nullptr + : Obj.SymbolTable->getStrTab(); + return Obj.removeSections(false, [&](const SectionBase &Sec) { + return &Sec == Obj.SymbolTable || &Sec == StrTab; + }); +} + template <class ELFT> Error ELFWriter<ELFT>::finalize() { // It could happen that SectionNames has been removed and yet the user wants // a section header table output. We need to throw an error if a user tries @@ -2004,6 +2027,8 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() { "cannot write section header table because " "section header string table was removed"); + if (Error E = removeUnneededSections(Obj)) + return E; Obj.sortSections(); // We need to assign indexes before we perform layout because we need to know @@ -2045,9 +2070,8 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() { // Make sure we add the names of all the sections. Importantly this must be // done after we decide to add or remove SectionIndexes. if (Obj.SectionNames != nullptr) - for (const auto &Section : Obj.sections()) { - Obj.SectionNames->addString(Section.Name); - } + for (const SectionBase &Sec : Obj.sections()) + Obj.SectionNames->addString(Sec.Name); initEhdrSegment(); @@ -2055,8 +2079,8 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() { // Also, the output arch may not be the same as the input arch, so fix up // size-related fields before doing layout calculations. uint64_t Index = 0; - auto SecSizer = llvm::make_unique<ELFSectionSizer<ELFT>>(); - for (auto &Sec : Obj.sections()) { + auto SecSizer = std::make_unique<ELFSectionSizer<ELFT>>(); + for (SectionBase &Sec : Obj.sections()) { Sec.Index = Index++; Sec.accept(*SecSizer); } @@ -2082,40 +2106,36 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() { // Finally now that all offsets and indexes have been set we can finalize any // remaining issues. - uint64_t Offset = Obj.SHOffset + sizeof(Elf_Shdr); - for (SectionBase &Section : Obj.sections()) { - Section.HeaderOffset = Offset; + uint64_t Offset = Obj.SHOff + sizeof(Elf_Shdr); + for (SectionBase &Sec : Obj.sections()) { + Sec.HeaderOffset = Offset; Offset += sizeof(Elf_Shdr); if (WriteSectionHeaders) - Section.NameIndex = Obj.SectionNames->findIndex(Section.Name); - Section.finalize(); + Sec.NameIndex = Obj.SectionNames->findIndex(Sec.Name); + Sec.finalize(); } if (Error E = Buf.allocate(totalSize())) return E; - SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf); + SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf); return Error::success(); } Error BinaryWriter::write() { - for (auto &Section : Obj.sections()) - if (Section.Flags & SHF_ALLOC) - Section.accept(*SecWriter); + for (const SectionBase &Sec : Obj.allocSections()) + Sec.accept(*SecWriter); return Buf.commit(); } Error BinaryWriter::finalize() { - // TODO: Create a filter range to construct OrderedSegments from so that this - // code can be deduped with assignOffsets above. This should also solve the - // todo below for LayoutSections. // We need a temporary list of segments that has a special order to it // so that we know that anytime ->ParentSegment is set that segment has // already had it's offset properly set. We only want to consider the segments // that will affect layout of allocated sections so we only add those. std::vector<Segment *> OrderedSegments; - for (SectionBase &Section : Obj.sections()) - if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr) - OrderedSegments.push_back(Section.ParentSegment); + for (const SectionBase &Sec : Obj.allocSections()) + if (Sec.ParentSegment != nullptr) + OrderedSegments.push_back(Sec.ParentSegment); // For binary output, we're going to use physical addresses instead of // virtual addresses, since a binary output is used for cases like ROM @@ -2130,7 +2150,7 @@ Error BinaryWriter::finalize() { llvm::stable_sort(OrderedSegments, compareSegmentsByPAddr); // Because we add a ParentSegment for each section we might have duplicate - // segments in OrderedSegments. If there were duplicates then LayoutSegments + // segments in OrderedSegments. If there were duplicates then layoutSegments // would do very strange things. auto End = std::unique(std::begin(OrderedSegments), std::end(OrderedSegments)); @@ -2158,28 +2178,20 @@ Error BinaryWriter::finalize() { } } - // TODO: generalize LayoutSections to take a range. Pass a special range - // constructed from an iterator that skips values for which a predicate does - // not hold. Then pass such a range to LayoutSections instead of constructing - // AllocatedSections here. - std::vector<SectionBase *> AllocatedSections; - for (SectionBase &Section : Obj.sections()) - if (Section.Flags & SHF_ALLOC) - AllocatedSections.push_back(&Section); - layoutSections(make_pointee_range(AllocatedSections), Offset); + layoutSections(Obj.allocSections(), Offset); // Now that every section has been laid out we just need to compute the total // file size. This might not be the same as the offset returned by - // LayoutSections, because we want to truncate the last segment to the end of + // layoutSections, because we want to truncate the last segment to the end of // its last section, to match GNU objcopy's behaviour. TotalSize = 0; - for (SectionBase *Section : AllocatedSections) - if (Section->Type != SHT_NOBITS) - TotalSize = std::max(TotalSize, Section->Offset + Section->Size); + for (const SectionBase &Sec : Obj.allocSections()) + if (Sec.Type != SHT_NOBITS) + TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); if (Error E = Buf.allocate(TotalSize)) return E; - SecWriter = llvm::make_unique<BinarySectionWriter>(Buf); + SecWriter = std::make_unique<BinarySectionWriter>(Buf); return Error::success(); } @@ -2259,17 +2271,17 @@ Error IHexWriter::finalize() { // If any section we're to write has segment then we // switch to using physical addresses. Otherwise we // use section virtual address. - for (auto &Section : Obj.sections()) - if (ShouldWrite(Section) && IsInPtLoad(Section)) { + for (const SectionBase &Sec : Obj.sections()) + if (ShouldWrite(Sec) && IsInPtLoad(Sec)) { UseSegments = true; break; } - for (auto &Section : Obj.sections()) - if (ShouldWrite(Section) && (!UseSegments || IsInPtLoad(Section))) { - if (Error E = checkSection(Section)) + for (const SectionBase &Sec : Obj.sections()) + if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) { + if (Error E = checkSection(Sec)) return E; - Sections.insert(&Section); + Sections.insert(&Sec); } IHexSectionWriterBase LengthCalc(Buf); diff --git a/tools/llvm-objcopy/ELF/Object.h b/tools/llvm-objcopy/ELF/Object.h index f3df93b9662f..eeacb014e4dc 100644 --- a/tools/llvm-objcopy/ELF/Object.h +++ b/tools/llvm-objcopy/ELF/Object.h @@ -57,8 +57,8 @@ public: : Sections(Secs) {} SectionTableRef(const SectionTableRef &) = default; - iterator begin() { return iterator(Sections.data()); } - iterator end() { return iterator(Sections.data() + Sections.size()); } + iterator begin() const { return iterator(Sections.data()); } + iterator end() const { return iterator(Sections.data() + Sections.size()); } size_t size() const { return Sections.size(); } SectionBase *getSection(uint32_t Index, Twine ErrMsg); @@ -863,7 +863,7 @@ public: class Reader { public: virtual ~Reader(); - virtual std::unique_ptr<Object> create() const = 0; + virtual std::unique_ptr<Object> create(bool EnsureSymtab) const = 0; }; using object::Binary; @@ -873,7 +873,6 @@ using object::OwningBinary; class BasicELFBuilder { protected: - uint16_t EMachine; std::unique_ptr<Object> Obj; void initFileHeader(); @@ -883,17 +882,18 @@ protected: void initSections(); public: - BasicELFBuilder(uint16_t EM) - : EMachine(EM), Obj(llvm::make_unique<Object>()) {} + BasicELFBuilder() : Obj(std::make_unique<Object>()) {} }; class BinaryELFBuilder : public BasicELFBuilder { MemoryBuffer *MemBuf; + uint8_t NewSymbolVisibility; void addData(SymbolTableSection *SymTab); public: - BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB) - : BasicELFBuilder(EM), MemBuf(MB) {} + BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility) + : BasicELFBuilder(), MemBuf(MB), + NewSymbolVisibility(NewSymbolVisibility) {} std::unique_ptr<Object> build(); }; @@ -905,7 +905,7 @@ class IHexELFBuilder : public BasicELFBuilder { public: IHexELFBuilder(const std::vector<IHexRecord> &Records) - : BasicELFBuilder(ELF::EM_386), Records(Records) {} + : BasicELFBuilder(), Records(Records) {} std::unique_ptr<Object> build(); }; @@ -926,7 +926,7 @@ private: void initGroupSection(GroupSection *GroupSec); void initSymbolTable(SymbolTableSection *SymTab); void readSectionHeaders(); - void readSections(); + void readSections(bool EnsureSymtab); void findEhdrOffset(); SectionBase &makeSection(const Elf_Shdr &Shdr); @@ -936,17 +936,17 @@ public: : ElfFile(*ElfObj.getELFFile()), Obj(Obj), ExtractPartition(ExtractPartition) {} - void build(); + void build(bool EnsureSymtab); }; class BinaryReader : public Reader { - const MachineInfo &MInfo; MemoryBuffer *MemBuf; + uint8_t NewSymbolVisibility; public: - BinaryReader(const MachineInfo &MI, MemoryBuffer *MB) - : MInfo(MI), MemBuf(MB) {} - std::unique_ptr<Object> create() const override; + BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility) + : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {} + std::unique_ptr<Object> create(bool EnsureSymtab) const override; }; class IHexReader : public Reader { @@ -968,7 +968,7 @@ class IHexReader : public Reader { public: IHexReader(MemoryBuffer *MB) : MemBuf(MB) {} - std::unique_ptr<Object> create() const override; + std::unique_ptr<Object> create(bool EnsureSymtab) const override; }; class ELFReader : public Reader { @@ -976,7 +976,7 @@ class ELFReader : public Reader { Optional<StringRef> ExtractPartition; public: - std::unique_ptr<Object> create() const override; + std::unique_ptr<Object> create(bool EnsureSymtab) const override; explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition) : Bin(B), ExtractPartition(ExtractPartition) {} }; @@ -990,6 +990,10 @@ private: std::vector<SegPtr> Segments; std::vector<SecPtr> RemovedSections; + static bool sectionIsAlloc(const SectionBase &Sec) { + return Sec.Flags & ELF::SHF_ALLOC; + }; + public: template <class T> using Range = iterator_range< @@ -1011,13 +1015,14 @@ public: uint8_t OSABI; uint8_t ABIVersion; uint64_t Entry; - uint64_t SHOffset; + uint64_t SHOff; uint32_t Type; uint32_t Machine; uint32_t Version; uint32_t Flags; bool HadShdrs = true; + bool MustBeRelocatable = false; StringTableSection *SectionNames = nullptr; SymbolTableSection *SymbolTable = nullptr; SectionIndexSection *SectionIndexTable = nullptr; @@ -1027,6 +1032,13 @@ public: ConstRange<SectionBase> sections() const { return make_pointee_range(Sections); } + iterator_range< + filter_iterator<pointee_iterator<std::vector<SecPtr>::const_iterator>, + decltype(§ionIsAlloc)>> + allocSections() const { + return make_filter_range(make_pointee_range(Sections), sectionIsAlloc); + } + SectionBase *findSection(StringRef Name) { auto SecIt = find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; }); @@ -1041,16 +1053,20 @@ public: std::function<bool(const SectionBase &)> ToRemove); Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); template <class T, class... Ts> T &addSection(Ts &&... Args) { - auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...); + auto Sec = std::make_unique<T>(std::forward<Ts>(Args)...); auto Ptr = Sec.get(); + MustBeRelocatable |= isa<RelocationSection>(*Ptr); Sections.emplace_back(std::move(Sec)); Ptr->Index = Sections.size(); return *Ptr; } Segment &addSegment(ArrayRef<uint8_t> Data) { - Segments.emplace_back(llvm::make_unique<Segment>(Data)); + Segments.emplace_back(std::make_unique<Segment>(Data)); return *Segments.back(); } + bool isRelocatable() const { + return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable; + } }; } // end namespace elf |