diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/llvm12/tools/llvm-objcopy/ELF | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/tools/llvm-objcopy/ELF')
-rw-r--r-- | contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp | 266 | ||||
-rw-r--r-- | contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h | 88 | ||||
-rw-r--r-- | contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 1556 | ||||
-rw-r--r-- | contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h | 72 | ||||
-rw-r--r-- | contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp | 4204 | ||||
-rw-r--r-- | contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h | 1926 |
6 files changed, 4056 insertions, 4056 deletions
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp index 40993760ad..fcedf8ee11 100644 --- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp +++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp @@ -1,133 +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 +//===- 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/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h index 977efbc416..a51ac07546 100644 --- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h +++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h @@ -1,44 +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 +//===- 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/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index c53a34bc46..6067ed6d26 100644 --- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -1,592 +1,592 @@ -//===- ELFObjcopy.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 "ELFObjcopy.h" -#include "Buffer.h" -#include "CopyConfig.h" -#include "Object.h" -#include "llvm/ADT/BitmaskEnum.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/MC/MCTargetOptions.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/ELFTypes.h" -#include "llvm/Object/Error.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Memory.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <cstdlib> -#include <functional> -#include <iterator> -#include <memory> -#include <string> -#include <system_error> -#include <utility> - -namespace llvm { -namespace objcopy { -namespace elf { - -using namespace object; -using namespace ELF; -using SectionPred = std::function<bool(const SectionBase &Sec)>; - -static bool isDebugSection(const SectionBase &Sec) { - return StringRef(Sec.Name).startswith(".debug") || - StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index"; -} - -static bool isDWOSection(const SectionBase &Sec) { - return StringRef(Sec.Name).endswith(".dwo"); -} - -static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { - // We can't remove the section header string table. - if (&Sec == Obj.SectionNames) - return false; - // Short of keeping the string table we want to keep everything that is a DWO - // section and remove everything else. - return !isDWOSection(Sec); -} - -uint64_t getNewShfFlags(SectionFlag AllFlags) { - uint64_t NewFlags = 0; - if (AllFlags & SectionFlag::SecAlloc) - NewFlags |= ELF::SHF_ALLOC; - if (!(AllFlags & SectionFlag::SecReadonly)) - NewFlags |= ELF::SHF_WRITE; - if (AllFlags & SectionFlag::SecCode) - NewFlags |= ELF::SHF_EXECINSTR; - if (AllFlags & SectionFlag::SecMerge) - NewFlags |= ELF::SHF_MERGE; - if (AllFlags & SectionFlag::SecStrings) - NewFlags |= ELF::SHF_STRINGS; - if (AllFlags & SectionFlag::SecExclude) - NewFlags |= ELF::SHF_EXCLUDE; - return NewFlags; -} - -static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags, - uint64_t NewFlags) { - // Preserve some flags which should not be dropped when setting flags. - // Also, preserve anything OS/processor dependant. - const uint64_t PreserveMask = - (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | - ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS | - ELF::SHF_INFO_LINK) & - ~ELF::SHF_EXCLUDE; - return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask); -} - -static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) { - Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags)); - - // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule - // may promote more non-ALLOC sections than GNU objcopy, but it is fine as - // non-ALLOC SHT_NOBITS sections do not make much sense. - if (Sec.Type == SHT_NOBITS && - (!(Sec.Flags & ELF::SHF_ALLOC) || - Flags & (SectionFlag::SecContents | SectionFlag::SecLoad))) - Sec.Type = SHT_PROGBITS; -} - -static ElfType getOutputElfType(const Binary &Bin) { - // Infer output ELF type from the input ELF object - if (isa<ELFObjectFile<ELF32LE>>(Bin)) - return ELFT_ELF32LE; - if (isa<ELFObjectFile<ELF64LE>>(Bin)) - return ELFT_ELF64LE; - if (isa<ELFObjectFile<ELF32BE>>(Bin)) - return ELFT_ELF32BE; - if (isa<ELFObjectFile<ELF64BE>>(Bin)) - return ELFT_ELF64BE; - llvm_unreachable("Invalid ELFType"); -} - -static ElfType getOutputElfType(const MachineInfo &MI) { - // Infer output ELF type from the binary arch specified - if (MI.Is64Bit) - return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE; - else - return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; -} - -static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config, - Object &Obj, Buffer &Buf, - ElfType OutputElfType) { - // Depending on the initial ELFT and OutputFormat we need a different Writer. - switch (OutputElfType) { - case ELFT_ELF32LE: - return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); - case ELFT_ELF64LE: - return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); - case ELFT_ELF32BE: - return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); - case ELFT_ELF64BE: - return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); - } - llvm_unreachable("Invalid output format"); -} - -static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, - Object &Obj, Buffer &Buf, - ElfType OutputElfType) { - switch (Config.OutputFormat) { - case FileFormat::Binary: - return std::make_unique<BinaryWriter>(Obj, Buf); - case FileFormat::IHex: - return std::make_unique<IHexWriter>(Obj, Buf); - default: - return createELFWriter(Config, Obj, Buf, OutputElfType); - } -} - -template <class ELFT> -static Expected<ArrayRef<uint8_t>> -findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) { - auto PhdrsOrErr = In.program_headers(); - if (auto Err = PhdrsOrErr.takeError()) - return createFileError(Config.InputFilename, std::move(Err)); - - for (const auto &Phdr : *PhdrsOrErr) { - if (Phdr.p_type != PT_NOTE) - continue; - Error Err = Error::success(); - for (auto Note : In.notes(Phdr, Err)) - if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) - return Note.getDesc(); - if (Err) - return createFileError(Config.InputFilename, std::move(Err)); - } - +//===- ELFObjcopy.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 "ELFObjcopy.h" +#include "Buffer.h" +#include "CopyConfig.h" +#include "Object.h" +#include "llvm/ADT/BitmaskEnum.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdlib> +#include <functional> +#include <iterator> +#include <memory> +#include <string> +#include <system_error> +#include <utility> + +namespace llvm { +namespace objcopy { +namespace elf { + +using namespace object; +using namespace ELF; +using SectionPred = std::function<bool(const SectionBase &Sec)>; + +static bool isDebugSection(const SectionBase &Sec) { + return StringRef(Sec.Name).startswith(".debug") || + StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index"; +} + +static bool isDWOSection(const SectionBase &Sec) { + return StringRef(Sec.Name).endswith(".dwo"); +} + +static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { + // We can't remove the section header string table. + if (&Sec == Obj.SectionNames) + return false; + // Short of keeping the string table we want to keep everything that is a DWO + // section and remove everything else. + return !isDWOSection(Sec); +} + +uint64_t getNewShfFlags(SectionFlag AllFlags) { + uint64_t NewFlags = 0; + if (AllFlags & SectionFlag::SecAlloc) + NewFlags |= ELF::SHF_ALLOC; + if (!(AllFlags & SectionFlag::SecReadonly)) + NewFlags |= ELF::SHF_WRITE; + if (AllFlags & SectionFlag::SecCode) + NewFlags |= ELF::SHF_EXECINSTR; + if (AllFlags & SectionFlag::SecMerge) + NewFlags |= ELF::SHF_MERGE; + if (AllFlags & SectionFlag::SecStrings) + NewFlags |= ELF::SHF_STRINGS; + if (AllFlags & SectionFlag::SecExclude) + NewFlags |= ELF::SHF_EXCLUDE; + return NewFlags; +} + +static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags, + uint64_t NewFlags) { + // Preserve some flags which should not be dropped when setting flags. + // Also, preserve anything OS/processor dependant. + const uint64_t PreserveMask = + (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | + ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS | + ELF::SHF_INFO_LINK) & + ~ELF::SHF_EXCLUDE; + return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask); +} + +static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) { + Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags)); + + // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule + // may promote more non-ALLOC sections than GNU objcopy, but it is fine as + // non-ALLOC SHT_NOBITS sections do not make much sense. + if (Sec.Type == SHT_NOBITS && + (!(Sec.Flags & ELF::SHF_ALLOC) || + Flags & (SectionFlag::SecContents | SectionFlag::SecLoad))) + Sec.Type = SHT_PROGBITS; +} + +static ElfType getOutputElfType(const Binary &Bin) { + // Infer output ELF type from the input ELF object + if (isa<ELFObjectFile<ELF32LE>>(Bin)) + return ELFT_ELF32LE; + if (isa<ELFObjectFile<ELF64LE>>(Bin)) + return ELFT_ELF64LE; + if (isa<ELFObjectFile<ELF32BE>>(Bin)) + return ELFT_ELF32BE; + if (isa<ELFObjectFile<ELF64BE>>(Bin)) + return ELFT_ELF64BE; + llvm_unreachable("Invalid ELFType"); +} + +static ElfType getOutputElfType(const MachineInfo &MI) { + // Infer output ELF type from the binary arch specified + if (MI.Is64Bit) + return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE; + else + return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; +} + +static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config, + Object &Obj, Buffer &Buf, + ElfType OutputElfType) { + // Depending on the initial ELFT and OutputFormat we need a different Writer. + switch (OutputElfType) { + case ELFT_ELF32LE: + return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); + case ELFT_ELF64LE: + return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); + case ELFT_ELF32BE: + return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); + case ELFT_ELF64BE: + return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections, + Config.OnlyKeepDebug); + } + llvm_unreachable("Invalid output format"); +} + +static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, + Object &Obj, Buffer &Buf, + ElfType OutputElfType) { + switch (Config.OutputFormat) { + case FileFormat::Binary: + return std::make_unique<BinaryWriter>(Obj, Buf); + case FileFormat::IHex: + return std::make_unique<IHexWriter>(Obj, Buf); + default: + return createELFWriter(Config, Obj, Buf, OutputElfType); + } +} + +template <class ELFT> +static Expected<ArrayRef<uint8_t>> +findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) { + auto PhdrsOrErr = In.program_headers(); + if (auto Err = PhdrsOrErr.takeError()) + return createFileError(Config.InputFilename, std::move(Err)); + + for (const auto &Phdr : *PhdrsOrErr) { + if (Phdr.p_type != PT_NOTE) + continue; + Error Err = Error::success(); + for (auto Note : In.notes(Phdr, Err)) + if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) + return Note.getDesc(); + if (Err) + return createFileError(Config.InputFilename, std::move(Err)); + } + return createFileError(Config.InputFilename, createStringError(llvm::errc::invalid_argument, "could not find build ID")); -} - -static Expected<ArrayRef<uint8_t>> -findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) { - if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In)) +} + +static Expected<ArrayRef<uint8_t>> +findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) { + if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In)) return findBuildID(Config, O->getELFFile()); - else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In)) + else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In)) return findBuildID(Config, O->getELFFile()); - else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In)) + else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In)) return findBuildID(Config, O->getELFFile()); - else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In)) + else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In)) return findBuildID(Config, O->getELFFile()); - - llvm_unreachable("Bad file format"); -} - -template <class... Ts> + + llvm_unreachable("Bad file format"); +} + +template <class... Ts> static Error makeStringError(std::error_code EC, const Twine &Msg, Ts &&... Args) { - std::string FullMsg = (EC.message() + ": " + Msg).str(); - return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...); -} - -#define MODEL_8 "%%%%%%%%" -#define MODEL_16 MODEL_8 MODEL_8 -#define MODEL_32 (MODEL_16 MODEL_16) - -static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, - StringRef Suffix, - ArrayRef<uint8_t> BuildIdBytes) { - SmallString<128> Path = Config.BuildIdLinkDir; - sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true)); - if (auto EC = sys::fs::create_directories(Path)) - return createFileError( - Path.str(), - makeStringError(EC, "cannot create build ID link directory")); - - sys::path::append(Path, - llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true)); - Path += Suffix; - SmallString<128> TmpPath; - // create_hard_link races so we need to link to a temporary path but - // we want to make sure that we choose a filename that does not exist. - // By using 32 model characters we get 128-bits of entropy. It is - // unlikely that this string has ever existed before much less exists - // on this disk or in the current working directory. - // Additionally we prepend the original Path for debugging but also - // because it ensures that we're linking within a directory on the same - // partition on the same device which is critical. It has the added - // win of yet further decreasing the odds of a conflict. - sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath, - /*MakeAbsolute*/ false); - if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) { - Path.push_back('\0'); - return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(), - Path.data()); - } - // We then atomically rename the link into place which will just move the - // link. If rename fails something is more seriously wrong so just return - // an error. - if (auto EC = sys::fs::rename(TmpPath, Path)) { - Path.push_back('\0'); - return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(), - Path.data()); - } - // If `Path` was already a hard-link to the same underlying file then the - // temp file will be left so we need to remove it. Remove will not cause - // an error by default if the file is already gone so just blindly remove - // it rather than checking. - if (auto EC = sys::fs::remove(TmpPath)) { - TmpPath.push_back('\0'); - return makeStringError(EC, "could not remove '%s'", TmpPath.data()); - } - return Error::success(); -} - -static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, - StringRef File, ElfType OutputElfType) { + std::string FullMsg = (EC.message() + ": " + Msg).str(); + return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...); +} + +#define MODEL_8 "%%%%%%%%" +#define MODEL_16 MODEL_8 MODEL_8 +#define MODEL_32 (MODEL_16 MODEL_16) + +static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink, + StringRef Suffix, + ArrayRef<uint8_t> BuildIdBytes) { + SmallString<128> Path = Config.BuildIdLinkDir; + sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true)); + if (auto EC = sys::fs::create_directories(Path)) + return createFileError( + Path.str(), + makeStringError(EC, "cannot create build ID link directory")); + + sys::path::append(Path, + llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true)); + Path += Suffix; + SmallString<128> TmpPath; + // create_hard_link races so we need to link to a temporary path but + // we want to make sure that we choose a filename that does not exist. + // By using 32 model characters we get 128-bits of entropy. It is + // unlikely that this string has ever existed before much less exists + // on this disk or in the current working directory. + // Additionally we prepend the original Path for debugging but also + // because it ensures that we're linking within a directory on the same + // partition on the same device which is critical. It has the added + // win of yet further decreasing the odds of a conflict. + sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath, + /*MakeAbsolute*/ false); + if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) { + Path.push_back('\0'); + return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(), + Path.data()); + } + // We then atomically rename the link into place which will just move the + // link. If rename fails something is more seriously wrong so just return + // an error. + if (auto EC = sys::fs::rename(TmpPath, Path)) { + Path.push_back('\0'); + return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(), + Path.data()); + } + // If `Path` was already a hard-link to the same underlying file then the + // temp file will be left so we need to remove it. Remove will not cause + // an error by default if the file is already gone so just blindly remove + // it rather than checking. + if (auto EC = sys::fs::remove(TmpPath)) { + TmpPath.push_back('\0'); + return makeStringError(EC, "could not remove '%s'", TmpPath.data()); + } + return Error::success(); +} + +static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader, + StringRef File, ElfType OutputElfType) { Expected<std::unique_ptr<Object>> DWOFile = Reader.create(false); if (!DWOFile) return DWOFile.takeError(); - auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { + auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) { return onlyKeepDWOPred(**DWOFile, Sec); - }; + }; if (Error E = (*DWOFile)->removeSections(Config.AllowBrokenLinks, OnlyKeepDWOPred)) - return E; - if (Config.OutputArch) { + return E; + if (Config.OutputArch) { (*DWOFile)->Machine = Config.OutputArch.getValue().EMachine; (*DWOFile)->OSABI = Config.OutputArch.getValue().OSABI; - } - FileBuffer FB(File); + } + FileBuffer FB(File); std::unique_ptr<Writer> Writer = createWriter(Config, **DWOFile, FB, OutputElfType); - if (Error E = Writer->finalize()) - return E; - return Writer->write(); -} - -static Error dumpSectionToFile(StringRef SecName, StringRef Filename, - Object &Obj) { - for (auto &Sec : Obj.sections()) { - if (Sec.Name == SecName) { - if (Sec.Type == SHT_NOBITS) - return createStringError(object_error::parse_failed, - "cannot dump section '%s': it has no contents", - SecName.str().c_str()); - Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = - FileOutputBuffer::create(Filename, Sec.OriginalData.size()); - if (!BufferOrErr) - return BufferOrErr.takeError(); - std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); - std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), - Buf->getBufferStart()); - if (Error E = Buf->commit()) - return E; - return Error::success(); - } - } - return createStringError(object_error::parse_failed, "section '%s' not found", - SecName.str().c_str()); -} - -static bool isCompressable(const SectionBase &Sec) { - return !(Sec.Flags & ELF::SHF_COMPRESSED) && - StringRef(Sec.Name).startswith(".debug"); -} - + if (Error E = Writer->finalize()) + return E; + return Writer->write(); +} + +static Error dumpSectionToFile(StringRef SecName, StringRef Filename, + Object &Obj) { + for (auto &Sec : Obj.sections()) { + if (Sec.Name == SecName) { + if (Sec.Type == SHT_NOBITS) + return createStringError(object_error::parse_failed, + "cannot dump section '%s': it has no contents", + SecName.str().c_str()); + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + FileOutputBuffer::create(Filename, Sec.OriginalData.size()); + if (!BufferOrErr) + return BufferOrErr.takeError(); + std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); + std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), + Buf->getBufferStart()); + if (Error E = Buf->commit()) + return E; + return Error::success(); + } + } + return createStringError(object_error::parse_failed, "section '%s' not found", + SecName.str().c_str()); +} + +static bool isCompressable(const SectionBase &Sec) { + return !(Sec.Flags & ELF::SHF_COMPRESSED) && + StringRef(Sec.Name).startswith(".debug"); +} + static Error replaceDebugSections( - Object &Obj, SectionPred &RemovePred, + Object &Obj, SectionPred &RemovePred, function_ref<bool(const SectionBase &)> ShouldReplace, function_ref<Expected<SectionBase *>(const SectionBase *)> AddSection) { - // Build a list of the debug sections we are going to replace. + // Build a list of the debug sections we are going to replace. // We can't call `AddSection` while iterating over sections, - // because it would mutate the sections array. - SmallVector<SectionBase *, 13> ToReplace; - for (auto &Sec : Obj.sections()) + // because it would mutate the sections array. + SmallVector<SectionBase *, 13> ToReplace; + for (auto &Sec : Obj.sections()) if (ShouldReplace(Sec)) - ToReplace.push_back(&Sec); - - // Build a mapping from original section to a new one. - DenseMap<SectionBase *, SectionBase *> FromTo; + ToReplace.push_back(&Sec); + + // Build a mapping from original section to a new one. + DenseMap<SectionBase *, SectionBase *> FromTo; for (SectionBase *S : ToReplace) { Expected<SectionBase *> NewSection = AddSection(S); if (!NewSection) return NewSection.takeError(); - + FromTo[S] = *NewSection; } - // Now we want to update the target sections of relocation - // sections. Also we will update the relocations themselves - // to update the symbol references. - for (auto &Sec : Obj.sections()) - Sec.replaceSectionReferences(FromTo); - + // Now we want to update the target sections of relocation + // sections. Also we will update the relocations themselves + // to update the symbol references. + for (auto &Sec : Obj.sections()) + Sec.replaceSectionReferences(FromTo); + RemovePred = [ShouldReplace, RemovePred](const SectionBase &Sec) { return ShouldReplace(Sec) || RemovePred(Sec); - }; + }; return Error::success(); -} - -static bool isUnneededSymbol(const Symbol &Sym) { - return !Sym.Referenced && - (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && - Sym.Type != STT_SECTION; -} - -static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { - // TODO: update or remove symbols only if there is an option that affects - // them. - if (!Obj.SymbolTable) - return Error::success(); - - Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { - // Common and undefined symbols don't make sense as local symbols, and can - // even cause crashes if we localize those, so skip them. - if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF && - ((Config.LocalizeHidden && - (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || - Config.SymbolsToLocalize.matches(Sym.Name))) - Sym.Binding = STB_LOCAL; - - // Note: these two globalize flags have very similar names but different - // meanings: - // - // --globalize-symbol: promote a symbol to global - // --keep-global-symbol: all symbols except for these should be made local - // - // If --globalize-symbol is specified for a given symbol, it will be - // global in the output file even if it is not included via - // --keep-global-symbol. Because of that, make sure to check - // --globalize-symbol second. - if (!Config.SymbolsToKeepGlobal.empty() && - !Config.SymbolsToKeepGlobal.matches(Sym.Name) && - Sym.getShndx() != SHN_UNDEF) - Sym.Binding = STB_LOCAL; - - if (Config.SymbolsToGlobalize.matches(Sym.Name) && - Sym.getShndx() != SHN_UNDEF) - 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 && - Sym.getShndx() != SHN_UNDEF) - Sym.Binding = STB_WEAK; - - const auto I = Config.SymbolsToRename.find(Sym.Name); - if (I != Config.SymbolsToRename.end()) - Sym.Name = std::string(I->getValue()); - - if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) - Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); - }); - - // The purpose of this loop is to mark symbols referenced by sections - // (like GroupSection or RelocationSection). This way, we know which - // symbols are still 'needed' and which are not. - if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || - !Config.OnlySection.empty()) { - for (SectionBase &Sec : Obj.sections()) - Sec.markSymbols(); - } - - auto RemoveSymbolsPred = [&](const Symbol &Sym) { - if (Config.SymbolsToKeep.matches(Sym.Name) || - (Config.KeepFileSymbols && Sym.Type == STT_FILE)) - return false; - - if ((Config.DiscardMode == DiscardType::All || - (Config.DiscardMode == DiscardType::Locals && - StringRef(Sym.Name).startswith(".L"))) && - Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && - Sym.Type != STT_FILE && Sym.Type != STT_SECTION) - return true; - - if (Config.StripAll || Config.StripAllGNU) - return true; - - if (Config.StripDebug && Sym.Type == STT_FILE) - return true; - - if (Config.SymbolsToRemove.matches(Sym.Name)) - return true; - - if ((Config.StripUnneeded || - Config.UnneededSymbolsToRemove.matches(Sym.Name)) && - (!Obj.isRelocatable() || isUnneededSymbol(Sym))) - return true; - - // We want to remove undefined symbols if all references have been stripped. - if (!Config.OnlySection.empty() && !Sym.Referenced && - Sym.getShndx() == SHN_UNDEF) - return true; - - return false; - }; - - return Obj.removeSymbols(RemoveSymbolsPred); -} - -static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { - SectionPred RemovePred = [](const SectionBase &) { return false; }; - - // Removes: - if (!Config.ToRemove.empty()) { - RemovePred = [&Config](const SectionBase &Sec) { - return Config.ToRemove.matches(Sec.Name); - }; - } - - if (Config.StripDWO || !Config.SplitDWO.empty()) - RemovePred = [RemovePred](const SectionBase &Sec) { - return isDWOSection(Sec) || RemovePred(Sec); - }; - - if (Config.ExtractDWO) - RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { - return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); - }; - - if (Config.StripAllGNU) - RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { - if (RemovePred(Sec)) - return true; - if ((Sec.Flags & SHF_ALLOC) != 0) - return false; - if (&Sec == Obj.SectionNames) - return false; - switch (Sec.Type) { - case SHT_SYMTAB: - case SHT_REL: - case SHT_RELA: - case SHT_STRTAB: - return true; - } - return isDebugSection(Sec); - }; - - if (Config.StripSections) { - RemovePred = [RemovePred](const SectionBase &Sec) { - return RemovePred(Sec) || Sec.ParentSegment == nullptr; - }; - } - - if (Config.StripDebug || Config.StripUnneeded) { - RemovePred = [RemovePred](const SectionBase &Sec) { - return RemovePred(Sec) || isDebugSection(Sec); - }; - } - - if (Config.StripNonAlloc) - RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { - if (RemovePred(Sec)) - return true; - if (&Sec == Obj.SectionNames) - return false; - return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr; - }; - - if (Config.StripAll) - RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { - if (RemovePred(Sec)) - return true; - if (&Sec == Obj.SectionNames) - return false; - if (StringRef(Sec.Name).startswith(".gnu.warning")) - return false; - // We keep the .ARM.attribute section to maintain compatibility - // with Debian derived distributions. This is a bug in their - // patchset as documented here: - // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798 - if (Sec.Type == SHT_ARM_ATTRIBUTES) - return false; - if (Sec.ParentSegment != nullptr) - return false; - return (Sec.Flags & SHF_ALLOC) == 0; - }; - - if (Config.ExtractPartition || Config.ExtractMainPartition) { - RemovePred = [RemovePred](const SectionBase &Sec) { - if (RemovePred(Sec)) - return true; - if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR) - return true; - return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment; - }; - } - - // Explicit copies: - if (!Config.OnlySection.empty()) { - RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { - // Explicitly keep these sections regardless of previous removes. - if (Config.OnlySection.matches(Sec.Name)) - return false; - - // Allow all implicit removes. - if (RemovePred(Sec)) - return true; - - // Keep special sections. - if (Obj.SectionNames == &Sec) - return false; - if (Obj.SymbolTable == &Sec || - (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) - return false; - - // Remove everything else. - return true; - }; - } - - if (!Config.KeepSection.empty()) { - RemovePred = [&Config, RemovePred](const SectionBase &Sec) { - // Explicitly keep these sections regardless of previous removes. - if (Config.KeepSection.matches(Sec.Name)) - return false; - // Otherwise defer to RemovePred. - return RemovePred(Sec); - }; - } - - // This has to be the last predicate assignment. - // If the option --keep-symbol has been specified - // and at least one of those symbols is present - // (equivalently, the updated symbol table is not empty) - // the symbol table and the string table should not be removed. - if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && - Obj.SymbolTable && !Obj.SymbolTable->empty()) { - RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { - if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) - return false; - return RemovePred(Sec); - }; - } - +} + +static bool isUnneededSymbol(const Symbol &Sym) { + return !Sym.Referenced && + (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && + Sym.Type != STT_SECTION; +} + +static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) { + // TODO: update or remove symbols only if there is an option that affects + // them. + if (!Obj.SymbolTable) + return Error::success(); + + Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { + // Common and undefined symbols don't make sense as local symbols, and can + // even cause crashes if we localize those, so skip them. + if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF && + ((Config.LocalizeHidden && + (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || + Config.SymbolsToLocalize.matches(Sym.Name))) + Sym.Binding = STB_LOCAL; + + // Note: these two globalize flags have very similar names but different + // meanings: + // + // --globalize-symbol: promote a symbol to global + // --keep-global-symbol: all symbols except for these should be made local + // + // If --globalize-symbol is specified for a given symbol, it will be + // global in the output file even if it is not included via + // --keep-global-symbol. Because of that, make sure to check + // --globalize-symbol second. + if (!Config.SymbolsToKeepGlobal.empty() && + !Config.SymbolsToKeepGlobal.matches(Sym.Name) && + Sym.getShndx() != SHN_UNDEF) + Sym.Binding = STB_LOCAL; + + if (Config.SymbolsToGlobalize.matches(Sym.Name) && + Sym.getShndx() != SHN_UNDEF) + 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 && + Sym.getShndx() != SHN_UNDEF) + Sym.Binding = STB_WEAK; + + const auto I = Config.SymbolsToRename.find(Sym.Name); + if (I != Config.SymbolsToRename.end()) + Sym.Name = std::string(I->getValue()); + + if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) + Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); + }); + + // The purpose of this loop is to mark symbols referenced by sections + // (like GroupSection or RelocationSection). This way, we know which + // symbols are still 'needed' and which are not. + if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || + !Config.OnlySection.empty()) { + for (SectionBase &Sec : Obj.sections()) + Sec.markSymbols(); + } + + auto RemoveSymbolsPred = [&](const Symbol &Sym) { + if (Config.SymbolsToKeep.matches(Sym.Name) || + (Config.KeepFileSymbols && Sym.Type == STT_FILE)) + return false; + + if ((Config.DiscardMode == DiscardType::All || + (Config.DiscardMode == DiscardType::Locals && + StringRef(Sym.Name).startswith(".L"))) && + Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && + Sym.Type != STT_FILE && Sym.Type != STT_SECTION) + return true; + + if (Config.StripAll || Config.StripAllGNU) + return true; + + if (Config.StripDebug && Sym.Type == STT_FILE) + return true; + + if (Config.SymbolsToRemove.matches(Sym.Name)) + return true; + + if ((Config.StripUnneeded || + Config.UnneededSymbolsToRemove.matches(Sym.Name)) && + (!Obj.isRelocatable() || isUnneededSymbol(Sym))) + return true; + + // We want to remove undefined symbols if all references have been stripped. + if (!Config.OnlySection.empty() && !Sym.Referenced && + Sym.getShndx() == SHN_UNDEF) + return true; + + return false; + }; + + return Obj.removeSymbols(RemoveSymbolsPred); +} + +static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { + SectionPred RemovePred = [](const SectionBase &) { return false; }; + + // Removes: + if (!Config.ToRemove.empty()) { + RemovePred = [&Config](const SectionBase &Sec) { + return Config.ToRemove.matches(Sec.Name); + }; + } + + if (Config.StripDWO || !Config.SplitDWO.empty()) + RemovePred = [RemovePred](const SectionBase &Sec) { + return isDWOSection(Sec) || RemovePred(Sec); + }; + + if (Config.ExtractDWO) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); + }; + + if (Config.StripAllGNU) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if ((Sec.Flags & SHF_ALLOC) != 0) + return false; + if (&Sec == Obj.SectionNames) + return false; + switch (Sec.Type) { + case SHT_SYMTAB: + case SHT_REL: + case SHT_RELA: + case SHT_STRTAB: + return true; + } + return isDebugSection(Sec); + }; + + if (Config.StripSections) { + RemovePred = [RemovePred](const SectionBase &Sec) { + return RemovePred(Sec) || Sec.ParentSegment == nullptr; + }; + } + + if (Config.StripDebug || Config.StripUnneeded) { + RemovePred = [RemovePred](const SectionBase &Sec) { + return RemovePred(Sec) || isDebugSection(Sec); + }; + } + + if (Config.StripNonAlloc) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if (&Sec == Obj.SectionNames) + return false; + return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr; + }; + + if (Config.StripAll) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if (&Sec == Obj.SectionNames) + return false; + if (StringRef(Sec.Name).startswith(".gnu.warning")) + return false; + // We keep the .ARM.attribute section to maintain compatibility + // with Debian derived distributions. This is a bug in their + // patchset as documented here: + // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798 + if (Sec.Type == SHT_ARM_ATTRIBUTES) + return false; + if (Sec.ParentSegment != nullptr) + return false; + return (Sec.Flags & SHF_ALLOC) == 0; + }; + + if (Config.ExtractPartition || Config.ExtractMainPartition) { + RemovePred = [RemovePred](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR) + return true; + return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment; + }; + } + + // Explicit copies: + if (!Config.OnlySection.empty()) { + RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (Config.OnlySection.matches(Sec.Name)) + return false; + + // Allow all implicit removes. + if (RemovePred(Sec)) + return true; + + // Keep special sections. + if (Obj.SectionNames == &Sec) + return false; + if (Obj.SymbolTable == &Sec || + (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) + return false; + + // Remove everything else. + return true; + }; + } + + if (!Config.KeepSection.empty()) { + RemovePred = [&Config, RemovePred](const SectionBase &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (Config.KeepSection.matches(Sec.Name)) + return false; + // Otherwise defer to RemovePred. + return RemovePred(Sec); + }; + } + + // This has to be the last predicate assignment. + // If the option --keep-symbol has been specified + // and at least one of those symbols is present + // (equivalently, the updated symbol table is not empty) + // the symbol table and the string table should not be removed. + if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && + Obj.SymbolTable && !Obj.SymbolTable->empty()) { + RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { + if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) + return false; + return RemovePred(Sec); + }; + } + if (Config.CompressionType != DebugCompressionType::None) { if (Error Err = replaceDebugSections( Obj, RemovePred, isCompressable, @@ -595,7 +595,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { CompressedSection::create(*S, Config.CompressionType); if (!NewSection) return NewSection.takeError(); - + return &Obj.addSection<CompressedSection>(std::move(*NewSection)); })) return Err; @@ -610,156 +610,156 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) { return Err; } - return Obj.removeSections(Config.AllowBrokenLinks, RemovePred); -} - -// This function handles the high level operations of GNU objcopy including -// handling command line options. It's important to outline certain properties -// we expect to hold of the command line operations. Any operation that "keeps" -// should keep regardless of a remove. Additionally any removal should respect -// any previous removals. Lastly whether or not something is removed shouldn't -// depend a) on the order the options occur in or b) on some opaque priority -// system. The only priority is that keeps/copies overrule removes. -static Error handleArgs(const CopyConfig &Config, Object &Obj, - const Reader &Reader, ElfType OutputElfType) { - if (Config.StripSwiftSymbols) - return createStringError(llvm::errc::invalid_argument, - "option not supported by llvm-objcopy for ELF"); - if (!Config.SplitDWO.empty()) - if (Error E = - splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType)) - return E; - - if (Config.OutputArch) { - Obj.Machine = Config.OutputArch.getValue().EMachine; - Obj.OSABI = Config.OutputArch.getValue().OSABI; - } - - // Dump sections before add/remove for compatibility with GNU objcopy. - for (StringRef Flag : Config.DumpSection) { - StringRef SectionName; - StringRef FileName; - std::tie(SectionName, FileName) = Flag.split('='); - if (Error E = dumpSectionToFile(SectionName, FileName, Obj)) - return E; - } - - // It is important to remove the sections first. For example, we want to - // remove the relocation sections before removing the symbols. That allows - // us to avoid reporting the inappropriate errors about removing symbols - // named in relocations. - if (Error E = replaceAndRemoveSections(Config, Obj)) - return E; - - if (Error E = updateAndRemoveSymbols(Config, Obj)) - return E; - - 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; - Sec.Name = std::string(SR.NewName); - 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()) { - 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.OnlyKeepDebug) - for (auto &Sec : Obj.sections()) - if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) - Sec.Type = SHT_NOBITS; - - for (const auto &Flag : Config.AddSection) { - std::pair<StringRef, StringRef> SecPair = Flag.split("="); - StringRef SecName = SecPair.first; - StringRef File = SecPair.second; - ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = - MemoryBuffer::getFile(File); - if (!BufOrErr) - return createFileError(File, errorCodeToError(BufOrErr.getError())); - std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr); - ArrayRef<uint8_t> Data( - reinterpret_cast<const uint8_t *>(Buf->getBufferStart()), - Buf->getBufferSize()); - OwnedDataSection &NewSection = - Obj.addSection<OwnedDataSection>(SecName, Data); - if (SecName.startswith(".note") && SecName != ".note.GNU-stack") - NewSection.Type = SHT_NOTE; - } - - if (!Config.AddGnuDebugLink.empty()) - Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink, - Config.GnuDebugLinkCRC32); - - // If the symbol table was previously removed, we need to create a new one - // before adding new symbols. + return Obj.removeSections(Config.AllowBrokenLinks, RemovePred); +} + +// This function handles the high level operations of GNU objcopy including +// handling command line options. It's important to outline certain properties +// we expect to hold of the command line operations. Any operation that "keeps" +// should keep regardless of a remove. Additionally any removal should respect +// any previous removals. Lastly whether or not something is removed shouldn't +// depend a) on the order the options occur in or b) on some opaque priority +// system. The only priority is that keeps/copies overrule removes. +static Error handleArgs(const CopyConfig &Config, Object &Obj, + const Reader &Reader, ElfType OutputElfType) { + if (Config.StripSwiftSymbols) + return createStringError(llvm::errc::invalid_argument, + "option not supported by llvm-objcopy for ELF"); + if (!Config.SplitDWO.empty()) + if (Error E = + splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType)) + return E; + + if (Config.OutputArch) { + Obj.Machine = Config.OutputArch.getValue().EMachine; + Obj.OSABI = Config.OutputArch.getValue().OSABI; + } + + // Dump sections before add/remove for compatibility with GNU objcopy. + for (StringRef Flag : Config.DumpSection) { + StringRef SectionName; + StringRef FileName; + std::tie(SectionName, FileName) = Flag.split('='); + if (Error E = dumpSectionToFile(SectionName, FileName, Obj)) + return E; + } + + // It is important to remove the sections first. For example, we want to + // remove the relocation sections before removing the symbols. That allows + // us to avoid reporting the inappropriate errors about removing symbols + // named in relocations. + if (Error E = replaceAndRemoveSections(Config, Obj)) + return E; + + if (Error E = updateAndRemoveSymbols(Config, Obj)) + return E; + + 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; + Sec.Name = std::string(SR.NewName); + 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()) { + 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.OnlyKeepDebug) + for (auto &Sec : Obj.sections()) + if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) + Sec.Type = SHT_NOBITS; + + for (const auto &Flag : Config.AddSection) { + std::pair<StringRef, StringRef> SecPair = Flag.split("="); + StringRef SecName = SecPair.first; + StringRef File = SecPair.second; + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = + MemoryBuffer::getFile(File); + if (!BufOrErr) + return createFileError(File, errorCodeToError(BufOrErr.getError())); + std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr); + ArrayRef<uint8_t> Data( + reinterpret_cast<const uint8_t *>(Buf->getBufferStart()), + Buf->getBufferSize()); + OwnedDataSection &NewSection = + Obj.addSection<OwnedDataSection>(SecName, Data); + if (SecName.startswith(".note") && SecName != ".note.GNU-stack") + NewSection.Type = SHT_NOTE; + } + + if (!Config.AddGnuDebugLink.empty()) + Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink, + Config.GnuDebugLinkCRC32); + + // If the symbol table was previously removed, we need to create a new one + // before adding new symbols. if (!Obj.SymbolTable && !Config.ELF->SymbolsToAdd.empty()) if (Error E = Obj.addNewSymbolTable()) return E; - - 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( - SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility, - Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); - } - + + 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( + SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility, + Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0); + } + // --set-section-flags works with sections added by --add-section. if (!Config.SetSectionFlags.empty()) { for (auto &Sec : Obj.sections()) { @@ -771,98 +771,98 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj, } } - if (Config.EntryExpr) - Obj.Entry = Config.EntryExpr(Obj.Entry); - return Error::success(); -} - -static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out, - ElfType OutputElfType) { - std::unique_ptr<Writer> Writer = - createWriter(Config, Obj, Out, OutputElfType); - if (Error E = Writer->finalize()) - return E; - return Writer->write(); -} - -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out) { - IHexReader Reader(&In); + if (Config.EntryExpr) + Obj.Entry = Config.EntryExpr(Obj.Entry); + return Error::success(); +} + +static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out, + ElfType OutputElfType) { + std::unique_ptr<Writer> Writer = + createWriter(Config, Obj, Out, OutputElfType); + if (Error E = Writer->finalize()) + return E; + return Writer->write(); +} + +Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, + Buffer &Out) { + IHexReader Reader(&In); Expected<std::unique_ptr<Object>> Obj = Reader.create(true); if (!Obj) return Obj.takeError(); - const ElfType OutputElfType = + const ElfType OutputElfType = getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType)) - return E; + return E; return writeOutput(Config, **Obj, Out, OutputElfType); -} - -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out) { - uint8_t NewSymbolVisibility = - Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); - BinaryReader Reader(&In, NewSymbolVisibility); +} + +Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, + Buffer &Out) { + uint8_t NewSymbolVisibility = + Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT); + BinaryReader Reader(&In, NewSymbolVisibility); Expected<std::unique_ptr<Object>> Obj = Reader.create(true); if (!Obj) return Obj.takeError(); - - // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch - // (-B<arch>). - const ElfType OutputElfType = - getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); + + // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch + // (-B<arch>). + const ElfType OutputElfType = + getOutputElfType(Config.OutputArch.getValueOr(MachineInfo())); if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType)) - return E; + return E; return writeOutput(Config, **Obj, Out, OutputElfType); -} - -Error executeObjcopyOnBinary(const CopyConfig &Config, - object::ELFObjectFileBase &In, Buffer &Out) { - ELFReader Reader(&In, Config.ExtractPartition); +} + +Error executeObjcopyOnBinary(const CopyConfig &Config, + object::ELFObjectFileBase &In, Buffer &Out) { + ELFReader Reader(&In, Config.ExtractPartition); Expected<std::unique_ptr<Object>> Obj = Reader.create(!Config.SymbolsToAdd.empty()); if (!Obj) return Obj.takeError(); - // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input. - const ElfType OutputElfType = - Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) - : getOutputElfType(In); - ArrayRef<uint8_t> BuildIdBytes; - - if (!Config.BuildIdLinkDir.empty()) { - auto BuildIdBytesOrErr = findBuildID(Config, In); - if (auto E = BuildIdBytesOrErr.takeError()) - return E; - BuildIdBytes = *BuildIdBytesOrErr; - - if (BuildIdBytes.size() < 2) - return createFileError( - Config.InputFilename, - createStringError(object_error::parse_failed, - "build ID is smaller than two bytes")); - } - - if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) - if (Error E = - linkToBuildIdDir(Config, Config.InputFilename, - Config.BuildIdLinkInput.getValue(), BuildIdBytes)) - return E; - + // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input. + const ElfType OutputElfType = + Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue()) + : getOutputElfType(In); + ArrayRef<uint8_t> BuildIdBytes; + + if (!Config.BuildIdLinkDir.empty()) { + auto BuildIdBytesOrErr = findBuildID(Config, In); + if (auto E = BuildIdBytesOrErr.takeError()) + return E; + BuildIdBytes = *BuildIdBytesOrErr; + + if (BuildIdBytes.size() < 2) + return createFileError( + Config.InputFilename, + createStringError(object_error::parse_failed, + "build ID is smaller than two bytes")); + } + + if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) + if (Error E = + linkToBuildIdDir(Config, Config.InputFilename, + Config.BuildIdLinkInput.getValue(), BuildIdBytes)) + return E; + if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType)) - return createFileError(Config.InputFilename, std::move(E)); - + return createFileError(Config.InputFilename, std::move(E)); + if (Error E = writeOutput(Config, **Obj, Out, OutputElfType)) - return createFileError(Config.InputFilename, std::move(E)); - if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) - if (Error E = - linkToBuildIdDir(Config, Config.OutputFilename, - Config.BuildIdLinkOutput.getValue(), BuildIdBytes)) - return createFileError(Config.OutputFilename, std::move(E)); - - return Error::success(); -} - -} // end namespace elf -} // end namespace objcopy -} // end namespace llvm + return createFileError(Config.InputFilename, std::move(E)); + if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) + if (Error E = + linkToBuildIdDir(Config, Config.OutputFilename, + Config.BuildIdLinkOutput.getValue(), BuildIdBytes)) + return createFileError(Config.OutputFilename, std::move(E)); + + return Error::success(); +} + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h index e13e237e29..619a0bd908 100644 --- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h +++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h @@ -1,36 +1,36 @@ -//===- ELFObjcopy.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_ELFOBJCOPY_H -#define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H - -namespace llvm { -class Error; -class MemoryBuffer; - -namespace object { -class ELFObjectFileBase; -} // end namespace object - -namespace objcopy { -struct CopyConfig; -class Buffer; - -namespace elf { -Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out); -Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out); -Error executeObjcopyOnBinary(const CopyConfig &Config, - object::ELFObjectFileBase &In, Buffer &Out); - -} // end namespace elf -} // end namespace objcopy -} // end namespace llvm - -#endif // LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H +//===- ELFObjcopy.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_ELFOBJCOPY_H +#define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H + +namespace llvm { +class Error; +class MemoryBuffer; + +namespace object { +class ELFObjectFileBase; +} // end namespace object + +namespace objcopy { +struct CopyConfig; +class Buffer; + +namespace elf { +Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, + Buffer &Out); +Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, + Buffer &Out); +Error executeObjcopyOnBinary(const CopyConfig &Config, + object::ELFObjectFileBase &In, Buffer &Out); + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp index 0ff82f951b..d3094d351b 100644 --- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp +++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp @@ -1,551 +1,551 @@ -//===- Object.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 "Object.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/MC/MCTargetOptions.h" +//===- Object.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 "Object.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Object/ELF.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/Path.h" -#include <algorithm> -#include <cstddef> -#include <cstdint> -#include <iterator> -#include <unordered_set> -#include <utility> -#include <vector> - -namespace llvm { -namespace objcopy { -namespace elf { - -using namespace object; -using namespace ELF; - -template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) { - uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset + - Seg.Index * sizeof(Elf_Phdr); - Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B); - Phdr.p_type = Seg.Type; - Phdr.p_flags = Seg.Flags; - Phdr.p_offset = Seg.Offset; - Phdr.p_vaddr = Seg.VAddr; - Phdr.p_paddr = Seg.PAddr; - Phdr.p_filesz = Seg.FileSize; - Phdr.p_memsz = Seg.MemSize; - Phdr.p_align = Seg.Align; -} - -Error SectionBase::removeSectionReferences( +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/Path.h" +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <iterator> +#include <unordered_set> +#include <utility> +#include <vector> + +namespace llvm { +namespace objcopy { +namespace elf { + +using namespace object; +using namespace ELF; + +template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) { + uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset + + Seg.Index * sizeof(Elf_Phdr); + Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B); + Phdr.p_type = Seg.Type; + Phdr.p_flags = Seg.Flags; + Phdr.p_offset = Seg.Offset; + Phdr.p_vaddr = Seg.VAddr; + Phdr.p_paddr = Seg.PAddr; + Phdr.p_filesz = Seg.FileSize; + Phdr.p_memsz = Seg.MemSize; + Phdr.p_align = Seg.Align; +} + +Error SectionBase::removeSectionReferences( bool, function_ref<bool(const SectionBase *)>) { - return Error::success(); -} - + return Error::success(); +} + Error SectionBase::removeSymbols(function_ref<bool(const Symbol &)>) { - return Error::success(); -} - + return Error::success(); +} + Error SectionBase::initialize(SectionTableRef) { return Error::success(); } -void SectionBase::finalize() {} -void SectionBase::markSymbols() {} -void SectionBase::replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &) {} -void SectionBase::onRemove() {} - -template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) { - uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset; - Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B); - Shdr.sh_name = Sec.NameIndex; - Shdr.sh_type = Sec.Type; - Shdr.sh_flags = Sec.Flags; - Shdr.sh_addr = Sec.Addr; - Shdr.sh_offset = Sec.Offset; - Shdr.sh_size = Sec.Size; - Shdr.sh_link = Sec.Link; - Shdr.sh_info = Sec.Info; - Shdr.sh_addralign = Sec.Align; - Shdr.sh_entsize = Sec.EntrySize; -} - +void SectionBase::finalize() {} +void SectionBase::markSymbols() {} +void SectionBase::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &) {} +void SectionBase::onRemove() {} + +template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) { + uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset; + Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B); + Shdr.sh_name = Sec.NameIndex; + Shdr.sh_type = Sec.Type; + Shdr.sh_flags = Sec.Flags; + Shdr.sh_addr = Sec.Addr; + Shdr.sh_offset = Sec.Offset; + Shdr.sh_size = Sec.Size; + Shdr.sh_link = Sec.Link; + Shdr.sh_info = Sec.Info; + Shdr.sh_addralign = Sec.Align; + Shdr.sh_entsize = Sec.EntrySize; +} + template <class ELFT> Error ELFSectionSizer<ELFT>::visit(Section &) { return Error::success(); } - + template <class ELFT> Error ELFSectionSizer<ELFT>::visit(OwnedDataSection &) { return Error::success(); } - + template <class ELFT> Error ELFSectionSizer<ELFT>::visit(StringTableSection &) { return Error::success(); } - -template <class ELFT> + +template <class ELFT> Error ELFSectionSizer<ELFT>::visit(DynamicRelocationSection &) { return Error::success(); } - -template <class ELFT> + +template <class ELFT> Error ELFSectionSizer<ELFT>::visit(SymbolTableSection &Sec) { - Sec.EntrySize = sizeof(Elf_Sym); - Sec.Size = Sec.Symbols.size() * Sec.EntrySize; - // Align to the largest field in Elf_Sym. - Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word); + Sec.EntrySize = sizeof(Elf_Sym); + Sec.Size = Sec.Symbols.size() * Sec.EntrySize; + // Align to the largest field in Elf_Sym. + Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word); return Error::success(); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) { - Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela); - Sec.Size = Sec.Relocations.size() * Sec.EntrySize; - // Align to the largest field in Elf_Rel(a). - Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word); + Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela); + Sec.Size = Sec.Relocations.size() * Sec.EntrySize; + // Align to the largest field in Elf_Rel(a). + Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word); return Error::success(); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionSizer<ELFT>::visit(GnuDebugLinkSection &) { return Error::success(); } - + template <class ELFT> Error ELFSectionSizer<ELFT>::visit(GroupSection &Sec) { - Sec.Size = sizeof(Elf_Word) + Sec.GroupMembers.size() * sizeof(Elf_Word); + Sec.Size = sizeof(Elf_Word) + Sec.GroupMembers.size() * sizeof(Elf_Word); return Error::success(); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionSizer<ELFT>::visit(SectionIndexSection &) { return Error::success(); } - + template <class ELFT> Error ELFSectionSizer<ELFT>::visit(CompressedSection &) { return Error::success(); } - -template <class ELFT> + +template <class ELFT> Error ELFSectionSizer<ELFT>::visit(DecompressedSection &) { return Error::success(); } - + Error BinarySectionWriter::visit(const SectionIndexSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write symbol section index table '" + Sec.Name + "' "); -} - +} + Error BinarySectionWriter::visit(const SymbolTableSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write symbol table '" + Sec.Name + "' out to binary"); -} - +} + Error BinarySectionWriter::visit(const RelocationSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write relocation section '" + Sec.Name + "' out to binary"); -} - +} + Error BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write '" + Sec.Name + "' out to binary"); -} - +} + Error BinarySectionWriter::visit(const GroupSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write '" + Sec.Name + "' out to binary"); -} - +} + Error SectionWriter::visit(const Section &Sec) { - if (Sec.Type != SHT_NOBITS) - llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); + if (Sec.Type != SHT_NOBITS) + llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); return Error::success(); -} - -static bool addressOverflows32bit(uint64_t Addr) { - // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok - return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX; -} - -template <class T> static T checkedGetHex(StringRef S) { - T Value; - bool Fail = S.getAsInteger(16, Value); - assert(!Fail); - (void)Fail; - return Value; -} - -// Fills exactly Len bytes of buffer with hexadecimal characters -// representing value 'X' -template <class T, class Iterator> -static Iterator utohexstr(T X, Iterator It, size_t Len) { - // Fill range with '0' - std::fill(It, It + Len, '0'); - - for (long I = Len - 1; I >= 0; --I) { - unsigned char Mod = static_cast<unsigned char>(X) & 15; - *(It + I) = hexdigit(Mod, false); - X >>= 4; - } - assert(X == 0); - return It + Len; -} - -uint8_t IHexRecord::getChecksum(StringRef S) { - assert((S.size() & 1) == 0); - uint8_t Checksum = 0; - while (!S.empty()) { - Checksum += checkedGetHex<uint8_t>(S.take_front(2)); - S = S.drop_front(2); - } - return -Checksum; -} - -IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr, - ArrayRef<uint8_t> Data) { - IHexLineData Line(getLineLength(Data.size())); - assert(Line.size()); - auto Iter = Line.begin(); - *Iter++ = ':'; - Iter = utohexstr(Data.size(), Iter, 2); - Iter = utohexstr(Addr, Iter, 4); - Iter = utohexstr(Type, Iter, 2); - for (uint8_t X : Data) - Iter = utohexstr(X, Iter, 2); - StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter)); - Iter = utohexstr(getChecksum(S), Iter, 2); - *Iter++ = '\r'; - *Iter++ = '\n'; - assert(Iter == Line.end()); - return Line; -} - -static Error checkRecord(const IHexRecord &R) { - switch (R.Type) { - case IHexRecord::Data: - if (R.HexData.size() == 0) - return createStringError( - errc::invalid_argument, - "zero data length is not allowed for data records"); - break; - case IHexRecord::EndOfFile: - break; - case IHexRecord::SegmentAddr: - // 20-bit segment address. Data length must be 2 bytes - // (4 bytes in hex) - if (R.HexData.size() != 4) - return createStringError( - errc::invalid_argument, - "segment address data should be 2 bytes in size"); - break; - case IHexRecord::StartAddr80x86: - case IHexRecord::StartAddr: - if (R.HexData.size() != 8) - return createStringError(errc::invalid_argument, - "start address data should be 4 bytes in size"); - // According to Intel HEX specification '03' record - // only specifies the code address within the 20-bit - // segmented address space of the 8086/80186. This - // means 12 high order bits should be zeroes. - if (R.Type == IHexRecord::StartAddr80x86 && - R.HexData.take_front(3) != "000") - return createStringError(errc::invalid_argument, - "start address exceeds 20 bit for 80x86"); - break; - case IHexRecord::ExtendedAddr: - // 16-31 bits of linear base address - if (R.HexData.size() != 4) - return createStringError( - errc::invalid_argument, - "extended address data should be 2 bytes in size"); - break; - default: - // Unknown record type - return createStringError(errc::invalid_argument, "unknown record type: %u", - static_cast<unsigned>(R.Type)); - } - return Error::success(); -} - -// Checks that IHEX line contains valid characters. -// This allows converting hexadecimal data to integers -// without extra verification. -static Error checkChars(StringRef Line) { - assert(!Line.empty()); - if (Line[0] != ':') - return createStringError(errc::invalid_argument, - "missing ':' in the beginning of line."); - - for (size_t Pos = 1; Pos < Line.size(); ++Pos) - if (hexDigitValue(Line[Pos]) == -1U) - return createStringError(errc::invalid_argument, - "invalid character at position %zu.", Pos + 1); - return Error::success(); -} - -Expected<IHexRecord> IHexRecord::parse(StringRef Line) { - assert(!Line.empty()); - - // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC' - if (Line.size() < 11) - return createStringError(errc::invalid_argument, - "line is too short: %zu chars.", Line.size()); - - if (Error E = checkChars(Line)) - return std::move(E); - - IHexRecord Rec; - size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2)); - if (Line.size() != getLength(DataLen)) - return createStringError(errc::invalid_argument, - "invalid line length %zu (should be %zu)", - Line.size(), getLength(DataLen)); - - Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4)); - Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2)); - Rec.HexData = Line.substr(9, DataLen * 2); - - if (getChecksum(Line.drop_front(1)) != 0) - return createStringError(errc::invalid_argument, "incorrect checksum."); - if (Error E = checkRecord(Rec)) - return std::move(E); - return Rec; -} - -static uint64_t sectionPhysicalAddr(const SectionBase *Sec) { - Segment *Seg = Sec->ParentSegment; - if (Seg && Seg->Type != ELF::PT_LOAD) - Seg = nullptr; - return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset - : Sec->Addr; -} - -void IHexSectionWriterBase::writeSection(const SectionBase *Sec, - ArrayRef<uint8_t> Data) { - assert(Data.size() == Sec->Size); - const uint32_t ChunkSize = 16; - uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU; - while (!Data.empty()) { - uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize); - if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) { - if (Addr > 0xFFFFFU) { - // Write extended address record, zeroing segment address - // if needed. - if (SegmentAddr != 0) - SegmentAddr = writeSegmentAddr(0U); - BaseAddr = writeBaseAddr(Addr); - } else { - // We can still remain 16-bit - SegmentAddr = writeSegmentAddr(Addr); - } - } - uint64_t SegOffset = Addr - BaseAddr - SegmentAddr; - assert(SegOffset <= 0xFFFFU); - DataSize = std::min(DataSize, 0x10000U - SegOffset); - writeData(0, SegOffset, Data.take_front(DataSize)); - Addr += DataSize; - Data = Data.drop_front(DataSize); - } -} - -uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) { - assert(Addr <= 0xFFFFFU); - uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0}; - writeData(2, 0, Data); - return Addr & 0xF0000U; -} - -uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) { - assert(Addr <= 0xFFFFFFFFU); - uint64_t Base = Addr & 0xFFFF0000U; - uint8_t Data[] = {static_cast<uint8_t>(Base >> 24), - static_cast<uint8_t>((Base >> 16) & 0xFF)}; - writeData(4, 0, Data); - return Base; -} - +} + +static bool addressOverflows32bit(uint64_t Addr) { + // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok + return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX; +} + +template <class T> static T checkedGetHex(StringRef S) { + T Value; + bool Fail = S.getAsInteger(16, Value); + assert(!Fail); + (void)Fail; + return Value; +} + +// Fills exactly Len bytes of buffer with hexadecimal characters +// representing value 'X' +template <class T, class Iterator> +static Iterator utohexstr(T X, Iterator It, size_t Len) { + // Fill range with '0' + std::fill(It, It + Len, '0'); + + for (long I = Len - 1; I >= 0; --I) { + unsigned char Mod = static_cast<unsigned char>(X) & 15; + *(It + I) = hexdigit(Mod, false); + X >>= 4; + } + assert(X == 0); + return It + Len; +} + +uint8_t IHexRecord::getChecksum(StringRef S) { + assert((S.size() & 1) == 0); + uint8_t Checksum = 0; + while (!S.empty()) { + Checksum += checkedGetHex<uint8_t>(S.take_front(2)); + S = S.drop_front(2); + } + return -Checksum; +} + +IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data) { + IHexLineData Line(getLineLength(Data.size())); + assert(Line.size()); + auto Iter = Line.begin(); + *Iter++ = ':'; + Iter = utohexstr(Data.size(), Iter, 2); + Iter = utohexstr(Addr, Iter, 4); + Iter = utohexstr(Type, Iter, 2); + for (uint8_t X : Data) + Iter = utohexstr(X, Iter, 2); + StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter)); + Iter = utohexstr(getChecksum(S), Iter, 2); + *Iter++ = '\r'; + *Iter++ = '\n'; + assert(Iter == Line.end()); + return Line; +} + +static Error checkRecord(const IHexRecord &R) { + switch (R.Type) { + case IHexRecord::Data: + if (R.HexData.size() == 0) + return createStringError( + errc::invalid_argument, + "zero data length is not allowed for data records"); + break; + case IHexRecord::EndOfFile: + break; + case IHexRecord::SegmentAddr: + // 20-bit segment address. Data length must be 2 bytes + // (4 bytes in hex) + if (R.HexData.size() != 4) + return createStringError( + errc::invalid_argument, + "segment address data should be 2 bytes in size"); + break; + case IHexRecord::StartAddr80x86: + case IHexRecord::StartAddr: + if (R.HexData.size() != 8) + return createStringError(errc::invalid_argument, + "start address data should be 4 bytes in size"); + // According to Intel HEX specification '03' record + // only specifies the code address within the 20-bit + // segmented address space of the 8086/80186. This + // means 12 high order bits should be zeroes. + if (R.Type == IHexRecord::StartAddr80x86 && + R.HexData.take_front(3) != "000") + return createStringError(errc::invalid_argument, + "start address exceeds 20 bit for 80x86"); + break; + case IHexRecord::ExtendedAddr: + // 16-31 bits of linear base address + if (R.HexData.size() != 4) + return createStringError( + errc::invalid_argument, + "extended address data should be 2 bytes in size"); + break; + default: + // Unknown record type + return createStringError(errc::invalid_argument, "unknown record type: %u", + static_cast<unsigned>(R.Type)); + } + return Error::success(); +} + +// Checks that IHEX line contains valid characters. +// This allows converting hexadecimal data to integers +// without extra verification. +static Error checkChars(StringRef Line) { + assert(!Line.empty()); + if (Line[0] != ':') + return createStringError(errc::invalid_argument, + "missing ':' in the beginning of line."); + + for (size_t Pos = 1; Pos < Line.size(); ++Pos) + if (hexDigitValue(Line[Pos]) == -1U) + return createStringError(errc::invalid_argument, + "invalid character at position %zu.", Pos + 1); + return Error::success(); +} + +Expected<IHexRecord> IHexRecord::parse(StringRef Line) { + assert(!Line.empty()); + + // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC' + if (Line.size() < 11) + return createStringError(errc::invalid_argument, + "line is too short: %zu chars.", Line.size()); + + if (Error E = checkChars(Line)) + return std::move(E); + + IHexRecord Rec; + size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2)); + if (Line.size() != getLength(DataLen)) + return createStringError(errc::invalid_argument, + "invalid line length %zu (should be %zu)", + Line.size(), getLength(DataLen)); + + Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4)); + Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2)); + Rec.HexData = Line.substr(9, DataLen * 2); + + if (getChecksum(Line.drop_front(1)) != 0) + return createStringError(errc::invalid_argument, "incorrect checksum."); + if (Error E = checkRecord(Rec)) + return std::move(E); + return Rec; +} + +static uint64_t sectionPhysicalAddr(const SectionBase *Sec) { + Segment *Seg = Sec->ParentSegment; + if (Seg && Seg->Type != ELF::PT_LOAD) + Seg = nullptr; + return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset + : Sec->Addr; +} + +void IHexSectionWriterBase::writeSection(const SectionBase *Sec, + ArrayRef<uint8_t> Data) { + assert(Data.size() == Sec->Size); + const uint32_t ChunkSize = 16; + uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU; + while (!Data.empty()) { + uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize); + if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) { + if (Addr > 0xFFFFFU) { + // Write extended address record, zeroing segment address + // if needed. + if (SegmentAddr != 0) + SegmentAddr = writeSegmentAddr(0U); + BaseAddr = writeBaseAddr(Addr); + } else { + // We can still remain 16-bit + SegmentAddr = writeSegmentAddr(Addr); + } + } + uint64_t SegOffset = Addr - BaseAddr - SegmentAddr; + assert(SegOffset <= 0xFFFFU); + DataSize = std::min(DataSize, 0x10000U - SegOffset); + writeData(0, SegOffset, Data.take_front(DataSize)); + Addr += DataSize; + Data = Data.drop_front(DataSize); + } +} + +uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) { + assert(Addr <= 0xFFFFFU); + uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0}; + writeData(2, 0, Data); + return Addr & 0xF0000U; +} + +uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) { + assert(Addr <= 0xFFFFFFFFU); + uint64_t Base = Addr & 0xFFFF0000U; + uint8_t Data[] = {static_cast<uint8_t>(Base >> 24), + static_cast<uint8_t>((Base >> 16) & 0xFF)}; + writeData(4, 0, Data); + return Base; +} + void IHexSectionWriterBase::writeData(uint8_t, uint16_t, - ArrayRef<uint8_t> Data) { - Offset += IHexRecord::getLineLength(Data.size()); -} - + ArrayRef<uint8_t> Data) { + Offset += IHexRecord::getLineLength(Data.size()); +} + Error IHexSectionWriterBase::visit(const Section &Sec) { - writeSection(&Sec, Sec.Contents); + writeSection(&Sec, Sec.Contents); return Error::success(); -} - +} + Error IHexSectionWriterBase::visit(const OwnedDataSection &Sec) { - writeSection(&Sec, Sec.Data); + writeSection(&Sec, Sec.Data); return Error::success(); -} - +} + Error IHexSectionWriterBase::visit(const StringTableSection &Sec) { - // Check that sizer has already done its work - assert(Sec.Size == Sec.StrTabBuilder.getSize()); - // We are free to pass an invalid pointer to writeSection as long - // as we don't actually write any data. The real writer class has - // to override this method . - writeSection(&Sec, {nullptr, static_cast<size_t>(Sec.Size)}); + // Check that sizer has already done its work + assert(Sec.Size == Sec.StrTabBuilder.getSize()); + // We are free to pass an invalid pointer to writeSection as long + // as we don't actually write any data. The real writer class has + // to override this method . + writeSection(&Sec, {nullptr, static_cast<size_t>(Sec.Size)}); return Error::success(); -} - +} + Error IHexSectionWriterBase::visit(const DynamicRelocationSection &Sec) { - writeSection(&Sec, Sec.Contents); + writeSection(&Sec, Sec.Contents); return Error::success(); -} - -void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr, - ArrayRef<uint8_t> Data) { - IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data); - memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size()); - Offset += HexData.size(); -} - +} + +void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data) { + IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data); + memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size()); + Offset += HexData.size(); +} + Error IHexSectionWriter::visit(const StringTableSection &Sec) { - assert(Sec.Size == Sec.StrTabBuilder.getSize()); - std::vector<uint8_t> Data(Sec.Size); - Sec.StrTabBuilder.write(Data.data()); - writeSection(&Sec, Data); + assert(Sec.Size == Sec.StrTabBuilder.getSize()); + std::vector<uint8_t> Data(Sec.Size); + Sec.StrTabBuilder.write(Data.data()); + writeSection(&Sec, Data); return Error::success(); -} - +} + Error Section::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); } - + Error Section::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); } - + Error SectionWriter::visit(const OwnedDataSection &Sec) { - llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset); + llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset); return Error::success(); -} - -static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}}; - -static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) { - return Data.size() > ZlibGnuMagic.size() && - std::equal(ZlibGnuMagic.begin(), ZlibGnuMagic.end(), Data.data()); -} - -template <class ELFT> -static std::tuple<uint64_t, uint64_t> -getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) { - const bool IsGnuDebug = isDataGnuCompressed(Data); - const uint64_t DecompressedSize = - IsGnuDebug - ? support::endian::read64be(Data.data() + ZlibGnuMagic.size()) - : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size; - const uint64_t DecompressedAlign = - IsGnuDebug ? 1 - : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data()) - ->ch_addralign; - - return std::make_tuple(DecompressedSize, DecompressedAlign); -} - -template <class ELFT> +} + +static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}}; + +static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) { + return Data.size() > ZlibGnuMagic.size() && + std::equal(ZlibGnuMagic.begin(), ZlibGnuMagic.end(), Data.data()); +} + +template <class ELFT> +static std::tuple<uint64_t, uint64_t> +getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) { + const bool IsGnuDebug = isDataGnuCompressed(Data); + const uint64_t DecompressedSize = + IsGnuDebug + ? support::endian::read64be(Data.data() + ZlibGnuMagic.size()) + : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size; + const uint64_t DecompressedAlign = + IsGnuDebug ? 1 + : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data()) + ->ch_addralign; + + return std::make_tuple(DecompressedSize, DecompressedAlign); +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) { - const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData) - ? (ZlibGnuMagic.size() + sizeof(Sec.Size)) - : sizeof(Elf_Chdr_Impl<ELFT>); - - StringRef CompressedContent( - reinterpret_cast<const char *>(Sec.OriginalData.data()) + DataOffset, - Sec.OriginalData.size() - DataOffset); - - SmallVector<char, 128> DecompressedContent; + const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData) + ? (ZlibGnuMagic.size() + sizeof(Sec.Size)) + : sizeof(Elf_Chdr_Impl<ELFT>); + + StringRef CompressedContent( + reinterpret_cast<const char *>(Sec.OriginalData.data()) + DataOffset, + Sec.OriginalData.size() - DataOffset); + + SmallVector<char, 128> DecompressedContent; if (Error Err = zlib::uncompress(CompressedContent, DecompressedContent, static_cast<size_t>(Sec.Size))) return createStringError(errc::invalid_argument, "'" + Sec.Name + "': " + toString(std::move(Err))); - - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf); + + uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf); return Error::success(); -} - +} + Error BinarySectionWriter::visit(const DecompressedSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write compressed section '" + Sec.Name + "' "); -} - +} + Error DecompressedSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error DecompressedSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - +} + Error OwnedDataSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error OwnedDataSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -void OwnedDataSection::appendHexData(StringRef HexData) { - assert((HexData.size() & 1) == 0); - while (!HexData.empty()) { - Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2))); - HexData = HexData.drop_front(2); - } - Size = Data.size(); -} - +} + +void OwnedDataSection::appendHexData(StringRef HexData) { + assert((HexData.size() & 1) == 0); + while (!HexData.empty()) { + Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2))); + HexData = HexData.drop_front(2); + } + Size = Data.size(); +} + Error BinarySectionWriter::visit(const CompressedSection &Sec) { return createStringError(errc::operation_not_permitted, "cannot write compressed section '" + Sec.Name + "' "); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - if (Sec.CompressionType == DebugCompressionType::None) { - std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf); + uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + if (Sec.CompressionType == DebugCompressionType::None) { + std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf); return Error::success(); - } - - if (Sec.CompressionType == DebugCompressionType::GNU) { - const char *Magic = "ZLIB"; - memcpy(Buf, Magic, strlen(Magic)); - Buf += strlen(Magic); - const uint64_t DecompressedSize = - support::endian::read64be(&Sec.DecompressedSize); - memcpy(Buf, &DecompressedSize, sizeof(DecompressedSize)); - Buf += sizeof(DecompressedSize); - } else { - Elf_Chdr_Impl<ELFT> Chdr; - Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB; - Chdr.ch_size = Sec.DecompressedSize; - Chdr.ch_addralign = Sec.DecompressedAlign; - memcpy(Buf, &Chdr, sizeof(Chdr)); - Buf += sizeof(Chdr); - } - - std::copy(Sec.CompressedData.begin(), Sec.CompressedData.end(), Buf); + } + + if (Sec.CompressionType == DebugCompressionType::GNU) { + const char *Magic = "ZLIB"; + memcpy(Buf, Magic, strlen(Magic)); + Buf += strlen(Magic); + const uint64_t DecompressedSize = + support::endian::read64be(&Sec.DecompressedSize); + memcpy(Buf, &DecompressedSize, sizeof(DecompressedSize)); + Buf += sizeof(DecompressedSize); + } else { + Elf_Chdr_Impl<ELFT> Chdr; + Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB; + Chdr.ch_size = Sec.DecompressedSize; + Chdr.ch_addralign = Sec.DecompressedAlign; + memcpy(Buf, &Chdr, sizeof(Chdr)); + Buf += sizeof(Chdr); + } + + std::copy(Sec.CompressedData.begin(), Sec.CompressedData.end(), Buf); return Error::success(); -} - +} + Expected<CompressedSection> CompressedSection::create(const SectionBase &Sec, DebugCompressionType CompressionType) { @@ -564,87 +564,87 @@ CompressedSection::create(ArrayRef<uint8_t> CompressedData, return CompressedSection(CompressedData, DecompressedSize, DecompressedAlign); } -CompressedSection::CompressedSection(const SectionBase &Sec, +CompressedSection::CompressedSection(const SectionBase &Sec, DebugCompressionType CompressionType, Error &OutErr) - : SectionBase(Sec), CompressionType(CompressionType), - DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { + : SectionBase(Sec), CompressionType(CompressionType), + DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) { ErrorAsOutParameter EAO(&OutErr); if (Error Err = zlib::compress( - StringRef(reinterpret_cast<const char *>(OriginalData.data()), - OriginalData.size()), + StringRef(reinterpret_cast<const char *>(OriginalData.data()), + OriginalData.size()), CompressedData)) { OutErr = createStringError(llvm::errc::invalid_argument, "'" + Name + "': " + toString(std::move(Err))); return; } - - size_t ChdrSize; - if (CompressionType == DebugCompressionType::GNU) { - Name = ".z" + Sec.Name.substr(1); - ChdrSize = sizeof("ZLIB") - 1 + sizeof(uint64_t); - } else { - Flags |= ELF::SHF_COMPRESSED; - ChdrSize = - std::max(std::max(sizeof(object::Elf_Chdr_Impl<object::ELF64LE>), - sizeof(object::Elf_Chdr_Impl<object::ELF64BE>)), - std::max(sizeof(object::Elf_Chdr_Impl<object::ELF32LE>), - sizeof(object::Elf_Chdr_Impl<object::ELF32BE>))); - } - Size = ChdrSize + CompressedData.size(); - Align = 8; -} - -CompressedSection::CompressedSection(ArrayRef<uint8_t> CompressedData, - uint64_t DecompressedSize, - uint64_t DecompressedAlign) - : CompressionType(DebugCompressionType::None), - DecompressedSize(DecompressedSize), DecompressedAlign(DecompressedAlign) { - OriginalData = CompressedData; -} - + + size_t ChdrSize; + if (CompressionType == DebugCompressionType::GNU) { + Name = ".z" + Sec.Name.substr(1); + ChdrSize = sizeof("ZLIB") - 1 + sizeof(uint64_t); + } else { + Flags |= ELF::SHF_COMPRESSED; + ChdrSize = + std::max(std::max(sizeof(object::Elf_Chdr_Impl<object::ELF64LE>), + sizeof(object::Elf_Chdr_Impl<object::ELF64BE>)), + std::max(sizeof(object::Elf_Chdr_Impl<object::ELF32LE>), + sizeof(object::Elf_Chdr_Impl<object::ELF32BE>))); + } + Size = ChdrSize + CompressedData.size(); + Align = 8; +} + +CompressedSection::CompressedSection(ArrayRef<uint8_t> CompressedData, + uint64_t DecompressedSize, + uint64_t DecompressedAlign) + : CompressionType(DebugCompressionType::None), + DecompressedSize(DecompressedSize), DecompressedAlign(DecompressedAlign) { + OriginalData = CompressedData; +} + Error CompressedSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error CompressedSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); } - -uint32_t StringTableSection::findIndex(StringRef Name) const { - return StrTabBuilder.getOffset(Name); -} - -void StringTableSection::prepareForLayout() { - StrTabBuilder.finalize(); - Size = StrTabBuilder.getSize(); -} - +} + +void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); } + +uint32_t StringTableSection::findIndex(StringRef Name) const { + return StrTabBuilder.getOffset(Name); +} + +void StringTableSection::prepareForLayout() { + StrTabBuilder.finalize(); + Size = StrTabBuilder.getSize(); +} + Error SectionWriter::visit(const StringTableSection &Sec) { - Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset); + Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset); return Error::success(); -} - +} + Error StringTableSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error StringTableSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf)); + uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf)); return Error::success(); -} - +} + Error SectionIndexSection::initialize(SectionTableRef SecTable) { - Size = 0; + Size = 0; Expected<SymbolTableSection *> Sec = SecTable.getSectionOfType<SymbolTableSection>( Link, @@ -656,145 +656,145 @@ Error SectionIndexSection::initialize(SectionTableRef SecTable) { return Sec.takeError(); setSymTab(*Sec); - Symbols->setShndxTable(this); + Symbols->setShndxTable(this); return Error::success(); -} - -void SectionIndexSection::finalize() { Link = Symbols->Index; } - +} + +void SectionIndexSection::finalize() { Link = Symbols->Index; } + Error SectionIndexSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error SectionIndexSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) { - switch (Index) { - case SHN_ABS: - case SHN_COMMON: - return true; - } - - if (Machine == EM_AMDGPU) { - return Index == SHN_AMDGPU_LDS; - } - - if (Machine == EM_HEXAGON) { - switch (Index) { - case SHN_HEXAGON_SCOMMON: - case SHN_HEXAGON_SCOMMON_1: - case SHN_HEXAGON_SCOMMON_2: - case SHN_HEXAGON_SCOMMON_4: - case SHN_HEXAGON_SCOMMON_8: - return true; - } - } - return false; -} - -// Large indexes force us to clarify exactly what this function should do. This -// function should return the value that will appear in st_shndx when written -// out. -uint16_t Symbol::getShndx() const { - if (DefinedIn != nullptr) { - if (DefinedIn->Index >= SHN_LORESERVE) - return SHN_XINDEX; - return DefinedIn->Index; - } - - if (ShndxType == SYMBOL_SIMPLE_INDEX) { - // This means that we don't have a defined section but we do need to - // output a legitimate section index. - return SHN_UNDEF; - } - - assert(ShndxType == SYMBOL_ABS || ShndxType == SYMBOL_COMMON || - (ShndxType >= SYMBOL_LOPROC && ShndxType <= SYMBOL_HIPROC) || - (ShndxType >= SYMBOL_LOOS && ShndxType <= SYMBOL_HIOS)); - return static_cast<uint16_t>(ShndxType); -} - -bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; } - -void SymbolTableSection::assignIndices() { - uint32_t Index = 0; - for (auto &Sym : Symbols) - Sym->Index = Index++; -} - -void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, - SectionBase *DefinedIn, uint64_t Value, - uint8_t Visibility, uint16_t Shndx, - uint64_t SymbolSize) { - Symbol Sym; - Sym.Name = Name.str(); - Sym.Binding = Bind; - Sym.Type = Type; - Sym.DefinedIn = DefinedIn; - if (DefinedIn != nullptr) - DefinedIn->HasSymbol = true; - if (DefinedIn == nullptr) { - if (Shndx >= SHN_LORESERVE) - Sym.ShndxType = static_cast<SymbolShndxType>(Shndx); - else - Sym.ShndxType = SYMBOL_SIMPLE_INDEX; - } - Sym.Value = Value; - Sym.Visibility = Visibility; - Sym.Size = SymbolSize; - Sym.Index = Symbols.size(); - Symbols.emplace_back(std::make_unique<Symbol>(Sym)); - Size += this->EntrySize; -} - -Error SymbolTableSection::removeSectionReferences( +} + +static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) { + switch (Index) { + case SHN_ABS: + case SHN_COMMON: + return true; + } + + if (Machine == EM_AMDGPU) { + return Index == SHN_AMDGPU_LDS; + } + + if (Machine == EM_HEXAGON) { + switch (Index) { + case SHN_HEXAGON_SCOMMON: + case SHN_HEXAGON_SCOMMON_1: + case SHN_HEXAGON_SCOMMON_2: + case SHN_HEXAGON_SCOMMON_4: + case SHN_HEXAGON_SCOMMON_8: + return true; + } + } + return false; +} + +// Large indexes force us to clarify exactly what this function should do. This +// function should return the value that will appear in st_shndx when written +// out. +uint16_t Symbol::getShndx() const { + if (DefinedIn != nullptr) { + if (DefinedIn->Index >= SHN_LORESERVE) + return SHN_XINDEX; + return DefinedIn->Index; + } + + if (ShndxType == SYMBOL_SIMPLE_INDEX) { + // This means that we don't have a defined section but we do need to + // output a legitimate section index. + return SHN_UNDEF; + } + + assert(ShndxType == SYMBOL_ABS || ShndxType == SYMBOL_COMMON || + (ShndxType >= SYMBOL_LOPROC && ShndxType <= SYMBOL_HIPROC) || + (ShndxType >= SYMBOL_LOOS && ShndxType <= SYMBOL_HIOS)); + return static_cast<uint16_t>(ShndxType); +} + +bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; } + +void SymbolTableSection::assignIndices() { + uint32_t Index = 0; + for (auto &Sym : Symbols) + Sym->Index = Index++; +} + +void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type, + SectionBase *DefinedIn, uint64_t Value, + uint8_t Visibility, uint16_t Shndx, + uint64_t SymbolSize) { + Symbol Sym; + Sym.Name = Name.str(); + Sym.Binding = Bind; + Sym.Type = Type; + Sym.DefinedIn = DefinedIn; + if (DefinedIn != nullptr) + DefinedIn->HasSymbol = true; + if (DefinedIn == nullptr) { + if (Shndx >= SHN_LORESERVE) + Sym.ShndxType = static_cast<SymbolShndxType>(Shndx); + else + Sym.ShndxType = SYMBOL_SIMPLE_INDEX; + } + Sym.Value = Value; + Sym.Visibility = Visibility; + Sym.Size = SymbolSize; + Sym.Index = Symbols.size(); + Symbols.emplace_back(std::make_unique<Symbol>(Sym)); + Size += this->EntrySize; +} + +Error SymbolTableSection::removeSectionReferences( bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { - if (ToRemove(SectionIndexTable)) - SectionIndexTable = nullptr; - if (ToRemove(SymbolNames)) { - if (!AllowBrokenLinks) - return createStringError( - llvm::errc::invalid_argument, - "string table '%s' cannot be removed because it is " - "referenced by the symbol table '%s'", - SymbolNames->Name.data(), this->Name.data()); - SymbolNames = nullptr; - } - return removeSymbols( - [ToRemove](const Symbol &Sym) { return ToRemove(Sym.DefinedIn); }); -} - -void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) { - std::for_each(std::begin(Symbols) + 1, std::end(Symbols), - [Callable](SymPtr &Sym) { Callable(*Sym); }); - std::stable_partition( - std::begin(Symbols), std::end(Symbols), - [](const SymPtr &Sym) { return Sym->Binding == STB_LOCAL; }); - assignIndices(); -} - -Error SymbolTableSection::removeSymbols( - function_ref<bool(const Symbol &)> ToRemove) { - Symbols.erase( - std::remove_if(std::begin(Symbols) + 1, std::end(Symbols), - [ToRemove](const SymPtr &Sym) { return ToRemove(*Sym); }), - std::end(Symbols)); - Size = Symbols.size() * EntrySize; - assignIndices(); - return Error::success(); -} - -void SymbolTableSection::replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &FromTo) { - for (std::unique_ptr<Symbol> &Sym : Symbols) - if (SectionBase *To = FromTo.lookup(Sym->DefinedIn)) - Sym->DefinedIn = To; -} - + if (ToRemove(SectionIndexTable)) + SectionIndexTable = nullptr; + if (ToRemove(SymbolNames)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "string table '%s' cannot be removed because it is " + "referenced by the symbol table '%s'", + SymbolNames->Name.data(), this->Name.data()); + SymbolNames = nullptr; + } + return removeSymbols( + [ToRemove](const Symbol &Sym) { return ToRemove(Sym.DefinedIn); }); +} + +void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) { + std::for_each(std::begin(Symbols) + 1, std::end(Symbols), + [Callable](SymPtr &Sym) { Callable(*Sym); }); + std::stable_partition( + std::begin(Symbols), std::end(Symbols), + [](const SymPtr &Sym) { return Sym->Binding == STB_LOCAL; }); + assignIndices(); +} + +Error SymbolTableSection::removeSymbols( + function_ref<bool(const Symbol &)> ToRemove) { + Symbols.erase( + std::remove_if(std::begin(Symbols) + 1, std::end(Symbols), + [ToRemove](const SymPtr &Sym) { return ToRemove(*Sym); }), + std::end(Symbols)); + Size = Symbols.size() * EntrySize; + assignIndices(); + return Error::success(); +} + +void SymbolTableSection::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) { + for (std::unique_ptr<Symbol> &Sym : Symbols) + if (SectionBase *To = FromTo.lookup(Sym->DefinedIn)) + Sym->DefinedIn = To; +} + Error SymbolTableSection::initialize(SectionTableRef SecTable) { - Size = 0; + Size = 0; Expected<StringTableSection *> Sec = SecTable.getSectionOfType<StringTableSection>( Link, @@ -807,58 +807,58 @@ Error SymbolTableSection::initialize(SectionTableRef SecTable) { setStrTab(*Sec); return Error::success(); -} - -void SymbolTableSection::finalize() { - uint32_t MaxLocalIndex = 0; - for (std::unique_ptr<Symbol> &Sym : Symbols) { - Sym->NameIndex = - SymbolNames == nullptr ? 0 : SymbolNames->findIndex(Sym->Name); - if (Sym->Binding == STB_LOCAL) - MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index); - } - // Now we need to set the Link and Info fields. - Link = SymbolNames == nullptr ? 0 : SymbolNames->Index; - Info = MaxLocalIndex + 1; -} - -void SymbolTableSection::prepareForLayout() { - // Reserve proper amount of space in section index table, so we can - // layout sections correctly. We will fill the table with correct - // indexes later in fillShdnxTable. - if (SectionIndexTable) - SectionIndexTable->reserve(Symbols.size()); - - // Add all of our strings to SymbolNames so that SymbolNames has the right - // size before layout is decided. - // If the symbol names section has been removed, don't try to add strings to - // the table. - if (SymbolNames != nullptr) - for (std::unique_ptr<Symbol> &Sym : Symbols) - SymbolNames->addString(Sym->Name); -} - -void SymbolTableSection::fillShndxTable() { - if (SectionIndexTable == nullptr) - return; - // Fill section index table with real section indexes. This function must - // be called after assignOffsets. - for (const std::unique_ptr<Symbol> &Sym : Symbols) { - if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE) - SectionIndexTable->addIndex(Sym->DefinedIn->Index); - else - SectionIndexTable->addIndex(SHN_UNDEF); - } -} - +} + +void SymbolTableSection::finalize() { + uint32_t MaxLocalIndex = 0; + for (std::unique_ptr<Symbol> &Sym : Symbols) { + Sym->NameIndex = + SymbolNames == nullptr ? 0 : SymbolNames->findIndex(Sym->Name); + if (Sym->Binding == STB_LOCAL) + MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index); + } + // Now we need to set the Link and Info fields. + Link = SymbolNames == nullptr ? 0 : SymbolNames->Index; + Info = MaxLocalIndex + 1; +} + +void SymbolTableSection::prepareForLayout() { + // Reserve proper amount of space in section index table, so we can + // layout sections correctly. We will fill the table with correct + // indexes later in fillShdnxTable. + if (SectionIndexTable) + SectionIndexTable->reserve(Symbols.size()); + + // Add all of our strings to SymbolNames so that SymbolNames has the right + // size before layout is decided. + // If the symbol names section has been removed, don't try to add strings to + // the table. + if (SymbolNames != nullptr) + for (std::unique_ptr<Symbol> &Sym : Symbols) + SymbolNames->addString(Sym->Name); +} + +void SymbolTableSection::fillShndxTable() { + if (SectionIndexTable == nullptr) + return; + // Fill section index table with real section indexes. This function must + // be called after assignOffsets. + for (const std::unique_ptr<Symbol> &Sym : Symbols) { + if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE) + SectionIndexTable->addIndex(Sym->DefinedIn->Index); + else + SectionIndexTable->addIndex(SHN_UNDEF); + } +} + Expected<const Symbol *> SymbolTableSection::getSymbolByIndex(uint32_t Index) const { - if (Symbols.size() <= Index) + if (Symbols.size() <= Index) return createStringError(errc::invalid_argument, "invalid symbol index: " + Twine(Index)); - return Symbols[Index].get(); -} - + return Symbols[Index].get(); +} + Expected<Symbol *> SymbolTableSection::getSymbolByIndex(uint32_t Index) { Expected<const Symbol *> Sym = static_cast<const SymbolTableSection *>(this)->getSymbolByIndex(Index); @@ -866,73 +866,73 @@ Expected<Symbol *> SymbolTableSection::getSymbolByIndex(uint32_t Index) { return Sym.takeError(); return const_cast<Symbol *>(*Sym); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const SymbolTableSection &Sec) { - Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out.getBufferStart() + Sec.Offset); - // Loop though symbols setting each entry of the symbol table. - for (const std::unique_ptr<Symbol> &Symbol : Sec.Symbols) { - Sym->st_name = Symbol->NameIndex; - Sym->st_value = Symbol->Value; - Sym->st_size = Symbol->Size; - Sym->st_other = Symbol->Visibility; - Sym->setBinding(Symbol->Binding); - Sym->setType(Symbol->Type); - Sym->st_shndx = Symbol->getShndx(); - ++Sym; - } + Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out.getBufferStart() + Sec.Offset); + // Loop though symbols setting each entry of the symbol table. + for (const std::unique_ptr<Symbol> &Symbol : Sec.Symbols) { + Sym->st_name = Symbol->NameIndex; + Sym->st_value = Symbol->Value; + Sym->st_size = Symbol->Size; + Sym->st_other = Symbol->Visibility; + Sym->setBinding(Symbol->Binding); + Sym->setType(Symbol->Type); + Sym->st_shndx = Symbol->getShndx(); + ++Sym; + } return Error::success(); -} - +} + Error SymbolTableSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error SymbolTableSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -Error RelocationSection::removeSectionReferences( +} + +Error RelocationSection::removeSectionReferences( bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { - if (ToRemove(Symbols)) { - if (!AllowBrokenLinks) - return createStringError( - llvm::errc::invalid_argument, - "symbol table '%s' cannot be removed because it is " - "referenced by the relocation section '%s'", - Symbols->Name.data(), this->Name.data()); - Symbols = nullptr; - } - - for (const Relocation &R : Relocations) { - if (!R.RelocSymbol || !R.RelocSymbol->DefinedIn || - !ToRemove(R.RelocSymbol->DefinedIn)) - continue; - return createStringError(llvm::errc::invalid_argument, - "section '%s' cannot be removed: (%s+0x%" PRIx64 - ") has relocation against symbol '%s'", - R.RelocSymbol->DefinedIn->Name.data(), - SecToApplyRel->Name.data(), R.Offset, - R.RelocSymbol->Name.c_str()); - } - - return Error::success(); -} - -template <class SymTabType> + if (ToRemove(Symbols)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "symbol table '%s' cannot be removed because it is " + "referenced by the relocation section '%s'", + Symbols->Name.data(), this->Name.data()); + Symbols = nullptr; + } + + for (const Relocation &R : Relocations) { + if (!R.RelocSymbol || !R.RelocSymbol->DefinedIn || + !ToRemove(R.RelocSymbol->DefinedIn)) + continue; + return createStringError(llvm::errc::invalid_argument, + "section '%s' cannot be removed: (%s+0x%" PRIx64 + ") has relocation against symbol '%s'", + R.RelocSymbol->DefinedIn->Name.data(), + SecToApplyRel->Name.data(), R.Offset, + R.RelocSymbol->Name.c_str()); + } + + return Error::success(); +} + +template <class SymTabType> Error RelocSectionWithSymtabBase<SymTabType>::initialize( - SectionTableRef SecTable) { + SectionTableRef SecTable) { if (Link != SHN_UNDEF) { Expected<SymTabType *> Sec = SecTable.getSectionOfType<SymTabType>( - Link, - "Link field value " + Twine(Link) + " in section " + Name + - " is invalid", - "Link field value " + Twine(Link) + " in section " + Name + + Link, + "Link field value " + Twine(Link) + " in section " + Name + + " is invalid", + "Link field value " + Twine(Link) + " in section " + Name + " is not a symbol table"); if (!Sec) return Sec.takeError(); - + setSymTab(*Sec); } @@ -945,467 +945,467 @@ Error RelocSectionWithSymtabBase<SymTabType>::initialize( setSection(*Sec); } else - setSection(nullptr); + setSection(nullptr); return Error::success(); -} - -template <class SymTabType> -void RelocSectionWithSymtabBase<SymTabType>::finalize() { - this->Link = Symbols ? Symbols->Index : 0; - - if (SecToApplyRel != nullptr) - this->Info = SecToApplyRel->Index; -} - -template <class ELFT> +} + +template <class SymTabType> +void RelocSectionWithSymtabBase<SymTabType>::finalize() { + this->Link = Symbols ? Symbols->Index : 0; + + if (SecToApplyRel != nullptr) + this->Info = SecToApplyRel->Index; +} + +template <class ELFT> static void setAddend(Elf_Rel_Impl<ELFT, false> &, uint64_t) {} - -template <class ELFT> -static void setAddend(Elf_Rel_Impl<ELFT, true> &Rela, uint64_t Addend) { - Rela.r_addend = Addend; -} - -template <class RelRange, class T> -static void writeRel(const RelRange &Relocations, T *Buf) { - for (const auto &Reloc : Relocations) { - Buf->r_offset = Reloc.Offset; - setAddend(*Buf, Reloc.Addend); - Buf->setSymbolAndType(Reloc.RelocSymbol ? Reloc.RelocSymbol->Index : 0, - Reloc.Type, false); - ++Buf; - } -} - -template <class ELFT> + +template <class ELFT> +static void setAddend(Elf_Rel_Impl<ELFT, true> &Rela, uint64_t Addend) { + Rela.r_addend = Addend; +} + +template <class RelRange, class T> +static void writeRel(const RelRange &Relocations, T *Buf) { + for (const auto &Reloc : Relocations) { + Buf->r_offset = Reloc.Offset; + setAddend(*Buf, Reloc.Addend); + Buf->setSymbolAndType(Reloc.RelocSymbol ? Reloc.RelocSymbol->Index : 0, + Reloc.Type, false); + ++Buf; + } +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; - if (Sec.Type == SHT_REL) - writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf)); - else - writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf)); + uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + if (Sec.Type == SHT_REL) + writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf)); + else + writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf)); return Error::success(); -} - +} + Error RelocationSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error RelocationSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -Error RelocationSection::removeSymbols( - function_ref<bool(const Symbol &)> ToRemove) { - for (const Relocation &Reloc : Relocations) - if (Reloc.RelocSymbol && ToRemove(*Reloc.RelocSymbol)) - return createStringError( - llvm::errc::invalid_argument, - "not stripping symbol '%s' because it is named in a relocation", - Reloc.RelocSymbol->Name.data()); - return Error::success(); -} - -void RelocationSection::markSymbols() { - for (const Relocation &Reloc : Relocations) - if (Reloc.RelocSymbol) - Reloc.RelocSymbol->Referenced = true; -} - -void RelocationSection::replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &FromTo) { - // Update the target section if it was replaced. - if (SectionBase *To = FromTo.lookup(SecToApplyRel)) - SecToApplyRel = To; -} - +} + +Error RelocationSection::removeSymbols( + function_ref<bool(const Symbol &)> ToRemove) { + for (const Relocation &Reloc : Relocations) + if (Reloc.RelocSymbol && ToRemove(*Reloc.RelocSymbol)) + return createStringError( + llvm::errc::invalid_argument, + "not stripping symbol '%s' because it is named in a relocation", + Reloc.RelocSymbol->Name.data()); + return Error::success(); +} + +void RelocationSection::markSymbols() { + for (const Relocation &Reloc : Relocations) + if (Reloc.RelocSymbol) + Reloc.RelocSymbol->Referenced = true; +} + +void RelocationSection::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) { + // Update the target section if it was replaced. + if (SectionBase *To = FromTo.lookup(SecToApplyRel)) + SecToApplyRel = To; +} + Error SectionWriter::visit(const DynamicRelocationSection &Sec) { - llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); + llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset); return Error::success(); -} - +} + Error DynamicRelocationSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -Error DynamicRelocationSection::removeSectionReferences( - bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { - if (ToRemove(Symbols)) { - if (!AllowBrokenLinks) - return createStringError( - llvm::errc::invalid_argument, - "symbol table '%s' cannot be removed because it is " - "referenced by the relocation section '%s'", - Symbols->Name.data(), this->Name.data()); - Symbols = nullptr; - } - - // SecToApplyRel contains a section referenced by sh_info field. It keeps - // a section to which the relocation section applies. When we remove any - // sections we also remove their relocation sections. Since we do that much - // earlier, this assert should never be triggered. - assert(!SecToApplyRel || !ToRemove(SecToApplyRel)); - return Error::success(); -} - -Error Section::removeSectionReferences( - bool AllowBrokenDependency, - function_ref<bool(const SectionBase *)> ToRemove) { - if (ToRemove(LinkSection)) { - if (!AllowBrokenDependency) - return createStringError(llvm::errc::invalid_argument, - "section '%s' cannot be removed because it is " - "referenced by the section '%s'", - LinkSection->Name.data(), this->Name.data()); - LinkSection = nullptr; - } - return Error::success(); -} - -void GroupSection::finalize() { - this->Info = Sym ? Sym->Index : 0; - this->Link = SymTab ? SymTab->Index : 0; -} - -Error GroupSection::removeSectionReferences( - bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { - if (ToRemove(SymTab)) { - if (!AllowBrokenLinks) - return createStringError( - llvm::errc::invalid_argument, - "section '.symtab' cannot be removed because it is " - "referenced by the group section '%s'", - this->Name.data()); - SymTab = nullptr; - Sym = nullptr; - } - llvm::erase_if(GroupMembers, ToRemove); - return Error::success(); -} - -Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { - if (ToRemove(*Sym)) - return createStringError(llvm::errc::invalid_argument, - "symbol '%s' cannot be removed because it is " - "referenced by the section '%s[%d]'", - Sym->Name.data(), this->Name.data(), this->Index); - return Error::success(); -} - -void GroupSection::markSymbols() { - if (Sym) - Sym->Referenced = true; -} - -void GroupSection::replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &FromTo) { - for (SectionBase *&Sec : GroupMembers) - if (SectionBase *To = FromTo.lookup(Sec)) - Sec = To; -} - -void GroupSection::onRemove() { - // As the header section of the group is removed, drop the Group flag in its - // former members. - for (SectionBase *Sec : GroupMembers) - Sec->Flags &= ~SHF_GROUP; -} - +} + +Error DynamicRelocationSection::removeSectionReferences( + bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(Symbols)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "symbol table '%s' cannot be removed because it is " + "referenced by the relocation section '%s'", + Symbols->Name.data(), this->Name.data()); + Symbols = nullptr; + } + + // SecToApplyRel contains a section referenced by sh_info field. It keeps + // a section to which the relocation section applies. When we remove any + // sections we also remove their relocation sections. Since we do that much + // earlier, this assert should never be triggered. + assert(!SecToApplyRel || !ToRemove(SecToApplyRel)); + return Error::success(); +} + +Error Section::removeSectionReferences( + bool AllowBrokenDependency, + function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(LinkSection)) { + if (!AllowBrokenDependency) + return createStringError(llvm::errc::invalid_argument, + "section '%s' cannot be removed because it is " + "referenced by the section '%s'", + LinkSection->Name.data(), this->Name.data()); + LinkSection = nullptr; + } + return Error::success(); +} + +void GroupSection::finalize() { + this->Info = Sym ? Sym->Index : 0; + this->Link = SymTab ? SymTab->Index : 0; +} + +Error GroupSection::removeSectionReferences( + bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) { + if (ToRemove(SymTab)) { + if (!AllowBrokenLinks) + return createStringError( + llvm::errc::invalid_argument, + "section '.symtab' cannot be removed because it is " + "referenced by the group section '%s'", + this->Name.data()); + SymTab = nullptr; + Sym = nullptr; + } + llvm::erase_if(GroupMembers, ToRemove); + return Error::success(); +} + +Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { + if (ToRemove(*Sym)) + return createStringError(llvm::errc::invalid_argument, + "symbol '%s' cannot be removed because it is " + "referenced by the section '%s[%d]'", + Sym->Name.data(), this->Name.data(), this->Index); + return Error::success(); +} + +void GroupSection::markSymbols() { + if (Sym) + Sym->Referenced = true; +} + +void GroupSection::replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) { + for (SectionBase *&Sec : GroupMembers) + if (SectionBase *To = FromTo.lookup(Sec)) + Sec = To; +} + +void GroupSection::onRemove() { + // As the header section of the group is removed, drop the Group flag in its + // former members. + for (SectionBase *Sec : GroupMembers) + Sec->Flags &= ~SHF_GROUP; +} + Error Section::initialize(SectionTableRef SecTable) { - if (Link == ELF::SHN_UNDEF) + if (Link == ELF::SHN_UNDEF) return Error::success(); Expected<SectionBase *> Sec = - SecTable.getSection(Link, "Link field value " + Twine(Link) + - " in section " + Name + " is invalid"); + SecTable.getSection(Link, "Link field value " + Twine(Link) + + " in section " + Name + " is invalid"); if (!Sec) return Sec.takeError(); LinkSection = *Sec; - if (LinkSection->Type == ELF::SHT_SYMTAB) - LinkSection = nullptr; + if (LinkSection->Type == ELF::SHT_SYMTAB) + LinkSection = nullptr; return Error::success(); -} - -void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; } - -void GnuDebugLinkSection::init(StringRef File) { - FileName = sys::path::filename(File); - // The format for the .gnu_debuglink starts with the file name and is - // followed by a null terminator and then the CRC32 of the file. The CRC32 - // should be 4 byte aligned. So we add the FileName size, a 1 for the null - // byte, and then finally push the size to alignment and add 4. - Size = alignTo(FileName.size() + 1, 4) + 4; - // The CRC32 will only be aligned if we align the whole section. - Align = 4; - Type = OriginalType = ELF::SHT_PROGBITS; - Name = ".gnu_debuglink"; - // For sections not found in segments, OriginalOffset is only used to - // establish the order that sections should go in. By using the maximum - // possible offset we cause this section to wind up at the end. - OriginalOffset = std::numeric_limits<uint64_t>::max(); -} - -GnuDebugLinkSection::GnuDebugLinkSection(StringRef File, - uint32_t PrecomputedCRC) - : FileName(File), CRC32(PrecomputedCRC) { - init(File); -} - -template <class ELFT> +} + +void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; } + +void GnuDebugLinkSection::init(StringRef File) { + FileName = sys::path::filename(File); + // The format for the .gnu_debuglink starts with the file name and is + // followed by a null terminator and then the CRC32 of the file. The CRC32 + // should be 4 byte aligned. So we add the FileName size, a 1 for the null + // byte, and then finally push the size to alignment and add 4. + Size = alignTo(FileName.size() + 1, 4) + 4; + // The CRC32 will only be aligned if we align the whole section. + Align = 4; + Type = OriginalType = ELF::SHT_PROGBITS; + Name = ".gnu_debuglink"; + // For sections not found in segments, OriginalOffset is only used to + // establish the order that sections should go in. By using the maximum + // possible offset we cause this section to wind up at the end. + OriginalOffset = std::numeric_limits<uint64_t>::max(); +} + +GnuDebugLinkSection::GnuDebugLinkSection(StringRef File, + uint32_t PrecomputedCRC) + : FileName(File), CRC32(PrecomputedCRC) { + init(File); +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) { - unsigned char *Buf = Out.getBufferStart() + Sec.Offset; - Elf_Word *CRC = - reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word)); - *CRC = Sec.CRC32; - llvm::copy(Sec.FileName, Buf); + unsigned char *Buf = Out.getBufferStart() + Sec.Offset; + Elf_Word *CRC = + reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word)); + *CRC = Sec.CRC32; + llvm::copy(Sec.FileName, Buf); return Error::success(); -} - +} + Error GnuDebugLinkSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error GnuDebugLinkSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) { - ELF::Elf32_Word *Buf = - reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset); - *Buf++ = Sec.FlagWord; - for (SectionBase *S : Sec.GroupMembers) - support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index); + ELF::Elf32_Word *Buf = + reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset); + *Buf++ = Sec.FlagWord; + for (SectionBase *S : Sec.GroupMembers) + support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index); return Error::success(); -} - +} + Error GroupSection::accept(SectionVisitor &Visitor) const { return Visitor.visit(*this); -} - +} + Error GroupSection::accept(MutableSectionVisitor &Visitor) { return Visitor.visit(*this); -} - -// Returns true IFF a section is wholly inside the range of a 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 = Sec.Size ? Sec.Size : 1; - - if (Sec.Type == SHT_NOBITS) { - if (!(Sec.Flags & SHF_ALLOC)) - return false; - - bool SectionIsTLS = Sec.Flags & SHF_TLS; - bool SegmentIsTLS = Seg.Type == PT_TLS; - if (SectionIsTLS != SegmentIsTLS) - return false; - - return Seg.VAddr <= Sec.Addr && - Seg.VAddr + Seg.MemSize >= Sec.Addr + 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 -// range. -static bool segmentOverlapsSegment(const Segment &Child, - const Segment &Parent) { - - return Parent.OriginalOffset <= Child.OriginalOffset && - Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset; -} - -static bool compareSegmentsByOffset(const Segment *A, const Segment *B) { - // Any segment without a parent segment should come before a segment - // that has a parent segment. - if (A->OriginalOffset < B->OriginalOffset) - return true; - if (A->OriginalOffset > B->OriginalOffset) - return false; - return A->Index < B->Index; -} - -void BasicELFBuilder::initFileHeader() { - Obj->Flags = 0x0; - Obj->Type = ET_REL; - Obj->OSABI = ELFOSABI_NONE; - Obj->ABIVersion = 0; - Obj->Entry = 0x0; - Obj->Machine = EM_NONE; - Obj->Version = 1; -} - -void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; } - -StringTableSection *BasicELFBuilder::addStrTab() { - auto &StrTab = Obj->addSection<StringTableSection>(); - StrTab.Name = ".strtab"; - - Obj->SectionNames = &StrTab; - return &StrTab; -} - -SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) { - auto &SymTab = Obj->addSection<SymbolTableSection>(); - - SymTab.Name = ".symtab"; - SymTab.Link = StrTab->Index; - - // The symbol table always needs a null symbol - SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); - - Obj->SymbolTable = &SymTab; - return &SymTab; -} - +} + +// Returns true IFF a section is wholly inside the range of a 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 = Sec.Size ? Sec.Size : 1; + + if (Sec.Type == SHT_NOBITS) { + if (!(Sec.Flags & SHF_ALLOC)) + return false; + + bool SectionIsTLS = Sec.Flags & SHF_TLS; + bool SegmentIsTLS = Seg.Type == PT_TLS; + if (SectionIsTLS != SegmentIsTLS) + return false; + + return Seg.VAddr <= Sec.Addr && + Seg.VAddr + Seg.MemSize >= Sec.Addr + 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 +// range. +static bool segmentOverlapsSegment(const Segment &Child, + const Segment &Parent) { + + return Parent.OriginalOffset <= Child.OriginalOffset && + Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset; +} + +static bool compareSegmentsByOffset(const Segment *A, const Segment *B) { + // Any segment without a parent segment should come before a segment + // that has a parent segment. + if (A->OriginalOffset < B->OriginalOffset) + return true; + if (A->OriginalOffset > B->OriginalOffset) + return false; + return A->Index < B->Index; +} + +void BasicELFBuilder::initFileHeader() { + Obj->Flags = 0x0; + Obj->Type = ET_REL; + Obj->OSABI = ELFOSABI_NONE; + Obj->ABIVersion = 0; + Obj->Entry = 0x0; + Obj->Machine = EM_NONE; + Obj->Version = 1; +} + +void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; } + +StringTableSection *BasicELFBuilder::addStrTab() { + auto &StrTab = Obj->addSection<StringTableSection>(); + StrTab.Name = ".strtab"; + + Obj->SectionNames = &StrTab; + return &StrTab; +} + +SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) { + auto &SymTab = Obj->addSection<SymbolTableSection>(); + + SymTab.Name = ".symtab"; + SymTab.Link = StrTab->Index; + + // The symbol table always needs a null symbol + SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); + + Obj->SymbolTable = &SymTab; + return &SymTab; +} + Error BasicELFBuilder::initSections() { - for (SectionBase &Sec : Obj->sections()) + for (SectionBase &Sec : Obj->sections()) if (Error Err = Sec.initialize(Obj->sections())) return Err; return Error::success(); -} - -void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { - auto Data = ArrayRef<uint8_t>( - reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()), - MemBuf->getBufferSize()); - auto &DataSection = Obj->addSection<Section>(Data); - DataSection.Name = ".data"; - DataSection.Type = ELF::SHT_PROGBITS; - DataSection.Size = Data.size(); - DataSection.Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE; - - std::string SanitizedFilename = MemBuf->getBufferIdentifier().str(); - std::replace_if(std::begin(SanitizedFilename), std::end(SanitizedFilename), - [](char C) { return !isalnum(C); }, '_'); - Twine Prefix = Twine("_binary_") + SanitizedFilename; - - SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection, - /*Value=*/0, NewSymbolVisibility, 0, 0); - SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection, - /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0); - SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr, - /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS, - 0); -} - +} + +void BinaryELFBuilder::addData(SymbolTableSection *SymTab) { + auto Data = ArrayRef<uint8_t>( + reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()), + MemBuf->getBufferSize()); + auto &DataSection = Obj->addSection<Section>(Data); + DataSection.Name = ".data"; + DataSection.Type = ELF::SHT_PROGBITS; + DataSection.Size = Data.size(); + DataSection.Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE; + + std::string SanitizedFilename = MemBuf->getBufferIdentifier().str(); + std::replace_if(std::begin(SanitizedFilename), std::end(SanitizedFilename), + [](char C) { return !isalnum(C); }, '_'); + Twine Prefix = Twine("_binary_") + SanitizedFilename; + + SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection, + /*Value=*/0, NewSymbolVisibility, 0, 0); + SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection, + /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0); + SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr, + /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS, + 0); +} + Expected<std::unique_ptr<Object>> BinaryELFBuilder::build() { - initFileHeader(); - initHeaderSegment(); - - SymbolTableSection *SymTab = addSymTab(addStrTab()); + initFileHeader(); + initHeaderSegment(); + + SymbolTableSection *SymTab = addSymTab(addStrTab()); if (Error Err = initSections()) return std::move(Err); - addData(SymTab); - - return std::move(Obj); -} - -// Adds sections from IHEX data file. Data should have been -// fully validated by this time. -void IHexELFBuilder::addDataSections() { - OwnedDataSection *Section = nullptr; - uint64_t SegmentAddr = 0, BaseAddr = 0; - uint32_t SecNo = 1; - - for (const IHexRecord &R : Records) { - uint64_t RecAddr; - switch (R.Type) { - case IHexRecord::Data: - // Ignore empty data records - if (R.HexData.empty()) - continue; - RecAddr = R.Addr + SegmentAddr + BaseAddr; - if (!Section || Section->Addr + Section->Size != RecAddr) - // OriginalOffset field is only used to sort section properly, so - // instead of keeping track of real offset in IHEX file, we use - // section number. - Section = &Obj->addSection<OwnedDataSection>( - ".sec" + std::to_string(SecNo++), RecAddr, - ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo); - Section->appendHexData(R.HexData); - break; - case IHexRecord::EndOfFile: - break; - case IHexRecord::SegmentAddr: - // 20-bit segment address. - SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4; - break; - case IHexRecord::StartAddr80x86: - case IHexRecord::StartAddr: - Obj->Entry = checkedGetHex<uint32_t>(R.HexData); - assert(Obj->Entry <= 0xFFFFFU); - break; - case IHexRecord::ExtendedAddr: - // 16-31 bits of linear base address - BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16; - break; - default: - llvm_unreachable("unknown record type"); - } - } -} - + addData(SymTab); + + return std::move(Obj); +} + +// Adds sections from IHEX data file. Data should have been +// fully validated by this time. +void IHexELFBuilder::addDataSections() { + OwnedDataSection *Section = nullptr; + uint64_t SegmentAddr = 0, BaseAddr = 0; + uint32_t SecNo = 1; + + for (const IHexRecord &R : Records) { + uint64_t RecAddr; + switch (R.Type) { + case IHexRecord::Data: + // Ignore empty data records + if (R.HexData.empty()) + continue; + RecAddr = R.Addr + SegmentAddr + BaseAddr; + if (!Section || Section->Addr + Section->Size != RecAddr) + // OriginalOffset field is only used to sort section properly, so + // instead of keeping track of real offset in IHEX file, we use + // section number. + Section = &Obj->addSection<OwnedDataSection>( + ".sec" + std::to_string(SecNo++), RecAddr, + ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo); + Section->appendHexData(R.HexData); + break; + case IHexRecord::EndOfFile: + break; + case IHexRecord::SegmentAddr: + // 20-bit segment address. + SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4; + break; + case IHexRecord::StartAddr80x86: + case IHexRecord::StartAddr: + Obj->Entry = checkedGetHex<uint32_t>(R.HexData); + assert(Obj->Entry <= 0xFFFFFU); + break; + case IHexRecord::ExtendedAddr: + // 16-31 bits of linear base address + BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16; + break; + default: + llvm_unreachable("unknown record type"); + } + } +} + Expected<std::unique_ptr<Object>> IHexELFBuilder::build() { - initFileHeader(); - initHeaderSegment(); - StringTableSection *StrTab = addStrTab(); - addSymTab(StrTab); + initFileHeader(); + initHeaderSegment(); + StringTableSection *StrTab = addStrTab(); + addSymTab(StrTab); if (Error Err = initSections()) return std::move(Err); - addDataSections(); - - return std::move(Obj); -} - -template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { - for (Segment &Parent : Obj.segments()) { - // Every segment will overlap with itself but we don't want a segment to - // be its own parent so we avoid that situation. - if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) { - // We want a canonical "most parental" segment but this requires - // inspecting the ParentSegment. - if (compareSegmentsByOffset(&Parent, &Child)) - if (Child.ParentSegment == nullptr || - compareSegmentsByOffset(&Parent, Child.ParentSegment)) { - Child.ParentSegment = &Parent; - } - } - } -} - + addDataSections(); + + return std::move(Obj); +} + +template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { + for (Segment &Parent : Obj.segments()) { + // Every segment will overlap with itself but we don't want a segment to + // be its own parent so we avoid that situation. + if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) { + // We want a canonical "most parental" segment but this requires + // inspecting the ParentSegment. + if (compareSegmentsByOffset(&Parent, &Child)) + if (Child.ParentSegment == nullptr || + compareSegmentsByOffset(&Parent, Child.ParentSegment)) { + Child.ParentSegment = &Parent; + } + } + } +} + template <class ELFT> Error ELFBuilder<ELFT>::findEhdrOffset() { - if (!ExtractPartition) + if (!ExtractPartition) return Error::success(); - - for (const SectionBase &Sec : Obj.sections()) { - if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) { - EhdrOffset = Sec.Offset; + + for (const SectionBase &Sec : Obj.sections()) { + if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) { + EhdrOffset = Sec.Offset; return Error::success(); - } - } + } + } return createStringError(errc::invalid_argument, "could not find partition named '" + *ExtractPartition + "'"); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) { - uint32_t Index = 0; + uint32_t Index = 0; Expected<typename ELFFile<ELFT>::Elf_Phdr_Range> Headers = HeadersFile.program_headers(); @@ -1413,114 +1413,114 @@ Error ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) { return Headers.takeError(); for (const typename ELFFile<ELFT>::Elf_Phdr &Phdr : *Headers) { - if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize()) + if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize()) return createStringError( errc::invalid_argument, "program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) + " and file size 0x" + Twine::utohexstr(Phdr.p_filesz) + " goes past the end of the file"); - - ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset, - (size_t)Phdr.p_filesz}; - Segment &Seg = Obj.addSegment(Data); - Seg.Type = Phdr.p_type; - Seg.Flags = Phdr.p_flags; - Seg.OriginalOffset = Phdr.p_offset + EhdrOffset; - Seg.Offset = Phdr.p_offset + EhdrOffset; - Seg.VAddr = Phdr.p_vaddr; - Seg.PAddr = Phdr.p_paddr; - Seg.FileSize = Phdr.p_filesz; - Seg.MemSize = Phdr.p_memsz; - Seg.Align = Phdr.p_align; - Seg.Index = Index++; - 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; - ElfHdr.Index = Index++; - ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset; - + + ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset, + (size_t)Phdr.p_filesz}; + Segment &Seg = Obj.addSegment(Data); + Seg.Type = Phdr.p_type; + Seg.Flags = Phdr.p_flags; + Seg.OriginalOffset = Phdr.p_offset + EhdrOffset; + Seg.Offset = Phdr.p_offset + EhdrOffset; + Seg.VAddr = Phdr.p_vaddr; + Seg.PAddr = Phdr.p_paddr; + Seg.FileSize = Phdr.p_filesz; + Seg.MemSize = Phdr.p_memsz; + Seg.Align = Phdr.p_align; + Seg.Index = Index++; + 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; + ElfHdr.Index = Index++; + ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset; + const typename ELFT::Ehdr &Ehdr = HeadersFile.getHeader(); - auto &PrHdr = Obj.ProgramHdrSegment; - PrHdr.Type = PT_PHDR; - PrHdr.Flags = 0; - // The spec requires us to have p_vaddr % p_align == p_offset % p_align. - // Whereas this works automatically for ElfHdr, here OriginalOffset is - // always non-zero and to ensure the equation we assign the same value to - // VAddr as well. - PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff; - PrHdr.PAddr = 0; - PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum; - // The spec requires us to naturally align all the fields. - PrHdr.Align = sizeof(Elf_Addr); - PrHdr.Index = Index++; - - // Now we do an O(n^2) loop through the segments in order to match up - // segments. - for (Segment &Child : Obj.segments()) - setParentSegment(Child); - setParentSegment(ElfHdr); - setParentSegment(PrHdr); + auto &PrHdr = Obj.ProgramHdrSegment; + PrHdr.Type = PT_PHDR; + PrHdr.Flags = 0; + // The spec requires us to have p_vaddr % p_align == p_offset % p_align. + // Whereas this works automatically for ElfHdr, here OriginalOffset is + // always non-zero and to ensure the equation we assign the same value to + // VAddr as well. + PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff; + PrHdr.PAddr = 0; + PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum; + // The spec requires us to naturally align all the fields. + PrHdr.Align = sizeof(Elf_Addr); + PrHdr.Index = Index++; + + // Now we do an O(n^2) loop through the segments in order to match up + // segments. + for (Segment &Child : Obj.segments()) + setParentSegment(Child); + setParentSegment(ElfHdr); + setParentSegment(PrHdr); return Error::success(); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) { - if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0) + if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0) return createStringError(errc::invalid_argument, "invalid alignment " + Twine(GroupSec->Align) + " of group section '" + GroupSec->Name + "'"); - SectionTableRef SecTable = Obj.sections(); - if (GroupSec->Link != SHN_UNDEF) { - auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>( - GroupSec->Link, - "link field value '" + Twine(GroupSec->Link) + "' in section '" + - GroupSec->Name + "' is invalid", - "link field value '" + Twine(GroupSec->Link) + "' in section '" + - GroupSec->Name + "' is not a symbol table"); + SectionTableRef SecTable = Obj.sections(); + if (GroupSec->Link != SHN_UNDEF) { + auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>( + GroupSec->Link, + "link field value '" + Twine(GroupSec->Link) + "' in section '" + + GroupSec->Name + "' is invalid", + "link field value '" + Twine(GroupSec->Link) + "' in section '" + + GroupSec->Name + "' is not a symbol table"); if (!SymTab) return SymTab.takeError(); Expected<Symbol *> Sym = (*SymTab)->getSymbolByIndex(GroupSec->Info); - if (!Sym) + if (!Sym) return createStringError(errc::invalid_argument, "info field value '" + Twine(GroupSec->Info) + "' in section '" + GroupSec->Name + "' is not a valid symbol index"); GroupSec->setSymTab(*SymTab); GroupSec->setSymbol(*Sym); - } - if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) || - GroupSec->Contents.empty()) + } + if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) || + GroupSec->Contents.empty()) return createStringError(errc::invalid_argument, "the content of the section " + GroupSec->Name + " is malformed"); - const ELF::Elf32_Word *Word = - reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data()); - const ELF::Elf32_Word *End = - Word + GroupSec->Contents.size() / sizeof(ELF::Elf32_Word); - GroupSec->setFlagWord(*Word++); - for (; Word != End; ++Word) { - uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word); + const ELF::Elf32_Word *Word = + reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data()); + const ELF::Elf32_Word *End = + Word + GroupSec->Contents.size() / sizeof(ELF::Elf32_Word); + GroupSec->setFlagWord(*Word++); + for (; Word != End; ++Word) { + uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word); Expected<SectionBase *> Sec = SecTable.getSection( - Index, "group member index " + Twine(Index) + " in section '" + + Index, "group member index " + Twine(Index) + " in section '" + GroupSec->Name + "' is invalid"); if (!Sec) return Sec.takeError(); GroupSec->addMember(*Sec); - } + } return Error::success(); -} - -template <class ELFT> +} + +template <class ELFT> Error ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) { Expected<const Elf_Shdr *> Shdr = ElfFile.getSection(SymTab->Index); if (!Shdr) @@ -1530,27 +1530,27 @@ Error ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) { if (!StrTabData) return StrTabData.takeError(); - ArrayRef<Elf_Word> ShndxData; - + ArrayRef<Elf_Word> ShndxData; + Expected<typename ELFFile<ELFT>::Elf_Sym_Range> Symbols = ElfFile.symbols(*Shdr); if (!Symbols) return Symbols.takeError(); for (const typename ELFFile<ELFT>::Elf_Sym &Sym : *Symbols) { - SectionBase *DefSection = nullptr; - + SectionBase *DefSection = nullptr; + Expected<StringRef> Name = Sym.getName(*StrTabData); if (!Name) return Name.takeError(); - if (Sym.st_shndx == SHN_XINDEX) { - if (SymTab->getShndxTable() == nullptr) + if (Sym.st_shndx == SHN_XINDEX) { + if (SymTab->getShndxTable() == nullptr) return createStringError(errc::invalid_argument, "symbol '" + *Name + "' has index SHN_XINDEX but no " "SHT_SYMTAB_SHNDX section exists"); - if (ShndxData.data() == nullptr) { + if (ShndxData.data() == nullptr) { Expected<const Elf_Shdr *> ShndxSec = ElfFile.getSection(SymTab->getShndxTable()->Index); if (!ShndxSec) @@ -1567,61 +1567,61 @@ Error ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) { errc::invalid_argument, "symbol section index table does not have the same number of " "entries as the symbol table"); - } + } Elf_Word Index = ShndxData[&Sym - Symbols->begin()]; Expected<SectionBase *> Sec = Obj.sections().getSection( - Index, + Index, "symbol '" + *Name + "' has invalid section index " + Twine(Index)); if (!Sec) return Sec.takeError(); DefSection = *Sec; - } else if (Sym.st_shndx >= SHN_LORESERVE) { - if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) { + } else if (Sym.st_shndx >= SHN_LORESERVE) { + if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) { return createStringError( errc::invalid_argument, "symbol '" + *Name + "' has unsupported value greater than or equal " "to SHN_LORESERVE: " + Twine(Sym.st_shndx)); - } - } else if (Sym.st_shndx != SHN_UNDEF) { + } + } else if (Sym.st_shndx != SHN_UNDEF) { Expected<SectionBase *> Sec = Obj.sections().getSection( Sym.st_shndx, "symbol '" + *Name + - "' is defined has invalid section index " + - Twine(Sym.st_shndx)); + "' is defined has invalid section index " + + Twine(Sym.st_shndx)); if (!Sec) return Sec.takeError(); DefSection = *Sec; - } - + } + SymTab->addSymbol(*Name, Sym.getBinding(), Sym.getType(), DefSection, - Sym.getValue(), Sym.st_other, Sym.st_shndx, Sym.st_size); - } + Sym.getValue(), Sym.st_other, Sym.st_shndx, Sym.st_size); + } return Error::success(); -} - -template <class ELFT> +} + +template <class ELFT> static void getAddend(uint64_t &, const Elf_Rel_Impl<ELFT, false> &) {} - -template <class ELFT> -static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl<ELFT, true> &Rela) { - ToSet = Rela.r_addend; -} - -template <class T> + +template <class ELFT> +static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl<ELFT, true> &Rela) { + ToSet = Rela.r_addend; +} + +template <class T> static Error initRelocations(RelocationSection *Relocs, SymbolTableSection *SymbolTable, T RelRange) { - for (const auto &Rel : RelRange) { - Relocation ToAdd; - ToAdd.Offset = Rel.r_offset; - getAddend(ToAdd.Addend, Rel); - ToAdd.Type = Rel.getType(false); - - if (uint32_t Sym = Rel.getSymbol(false)) { - if (!SymbolTable) + for (const auto &Rel : RelRange) { + Relocation ToAdd; + ToAdd.Offset = Rel.r_offset; + getAddend(ToAdd.Addend, Rel); + ToAdd.Type = Rel.getType(false); + + if (uint32_t Sym = Rel.getSymbol(false)) { + if (!SymbolTable) return createStringError( errc::invalid_argument, "'" + Relocs->Name + "': relocation references symbol with index " + @@ -1631,22 +1631,22 @@ static Error initRelocations(RelocationSection *Relocs, return SymByIndex.takeError(); ToAdd.RelocSymbol = *SymByIndex; - } - - Relocs->addRelocation(ToAdd); - } + } + + Relocs->addRelocation(ToAdd); + } return Error::success(); -} - +} + Expected<SectionBase *> SectionTableRef::getSection(uint32_t Index, Twine ErrMsg) { - if (Index == SHN_UNDEF || Index > Sections.size()) + if (Index == SHN_UNDEF || Index > Sections.size()) return createStringError(errc::invalid_argument, ErrMsg); - return Sections[Index - 1].get(); -} - -template <class T> + return Sections[Index - 1].get(); +} + +template <class T> Expected<T *> SectionTableRef::getSectionOfType(uint32_t Index, Twine IndexErrMsg, Twine TypeErrMsg) { @@ -1655,81 +1655,81 @@ Expected<T *> SectionTableRef::getSectionOfType(uint32_t Index, return BaseSec.takeError(); if (T *Sec = dyn_cast<T>(*BaseSec)) - return Sec; + return Sec; return createStringError(errc::invalid_argument, TypeErrMsg); -} - -template <class ELFT> +} + +template <class ELFT> Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) { - switch (Shdr.sh_type) { - case SHT_REL: - case SHT_RELA: - if (Shdr.sh_flags & SHF_ALLOC) { + switch (Shdr.sh_type) { + case SHT_REL: + case SHT_RELA: + if (Shdr.sh_flags & SHF_ALLOC) { if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection<DynamicRelocationSection>(*Data); else return Data.takeError(); - } - return Obj.addSection<RelocationSection>(); - case SHT_STRTAB: - // If a string table is allocated we don't want to mess with it. That would - // mean altering the memory image. There are no special link types or - // anything so we can just use a Section. - if (Shdr.sh_flags & SHF_ALLOC) { + } + return Obj.addSection<RelocationSection>(); + case SHT_STRTAB: + // If a string table is allocated we don't want to mess with it. That would + // mean altering the memory image. There are no special link types or + // anything so we can just use a Section. + if (Shdr.sh_flags & SHF_ALLOC) { if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection<Section>(*Data); else return Data.takeError(); - } - return Obj.addSection<StringTableSection>(); - case SHT_HASH: - case SHT_GNU_HASH: - // Hash tables should refer to SHT_DYNSYM which we're not going to change. - // Because of this we don't need to mess with the hash tables either. + } + return Obj.addSection<StringTableSection>(); + case SHT_HASH: + case SHT_GNU_HASH: + // Hash tables should refer to SHT_DYNSYM which we're not going to change. + // Because of this we don't need to mess with the hash tables either. if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection<Section>(*Data); else return Data.takeError(); - case SHT_GROUP: + case SHT_GROUP: if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection<GroupSection>(*Data); else return Data.takeError(); - case SHT_DYNSYM: + case SHT_DYNSYM: if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection<DynamicSymbolTableSection>(*Data); else return Data.takeError(); - case SHT_DYNAMIC: + case SHT_DYNAMIC: if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr)) return Obj.addSection<DynamicSection>(*Data); else return Data.takeError(); - case SHT_SYMTAB: { - auto &SymTab = Obj.addSection<SymbolTableSection>(); - Obj.SymbolTable = &SymTab; - return SymTab; - } - case SHT_SYMTAB_SHNDX: { - auto &ShndxSection = Obj.addSection<SectionIndexSection>(); - Obj.SectionIndexTable = &ShndxSection; - return ShndxSection; - } - case SHT_NOBITS: + case SHT_SYMTAB: { + auto &SymTab = Obj.addSection<SymbolTableSection>(); + Obj.SymbolTable = &SymTab; + return SymTab; + } + case SHT_SYMTAB_SHNDX: { + auto &ShndxSection = Obj.addSection<SectionIndexSection>(); + Obj.SectionIndexTable = &ShndxSection; + return ShndxSection; + } + case SHT_NOBITS: return Obj.addSection<Section>(ArrayRef<uint8_t>()); - default: { + default: { Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr); if (!Data) return Data.takeError(); - + Expected<StringRef> Name = ElfFile.getSectionName(Shdr); if (!Name) return Name.takeError(); if (Name->startswith(".zdebug") || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) { - uint64_t DecompressedSize, DecompressedAlign; - std::tie(DecompressedSize, DecompressedAlign) = + uint64_t DecompressedSize, DecompressedAlign; + std::tie(DecompressedSize, DecompressedAlign) = getDecompressedSizeAndAlignment<ELFT>(*Data); Expected<CompressedSection> NewSection = CompressedSection::create(*Data, DecompressedSize, DecompressedAlign); @@ -1737,25 +1737,25 @@ Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) { return NewSection.takeError(); return Obj.addSection<CompressedSection>(std::move(*NewSection)); - } - + } + return Obj.addSection<Section>(*Data); - } - } -} - + } + } +} + template <class ELFT> Error ELFBuilder<ELFT>::readSectionHeaders() { - uint32_t Index = 0; + uint32_t Index = 0; Expected<typename ELFFile<ELFT>::Elf_Shdr_Range> Sections = ElfFile.sections(); if (!Sections) return Sections.takeError(); for (const typename ELFFile<ELFT>::Elf_Shdr &Shdr : *Sections) { - if (Index == 0) { - ++Index; - continue; - } + if (Index == 0) { + ++Index; + continue; + } Expected<SectionBase &> Sec = makeSection(Shdr); if (!Sec) return Sec.takeError(); @@ -1777,68 +1777,68 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSectionHeaders() { Sec->Index = Index++; Sec->OriginalIndex = Sec->Index; Sec->OriginalData = - ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset, - (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size); - } + ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset, + (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size); + } return Error::success(); -} - +} + template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { uint32_t ShstrIndex = ElfFile.getHeader().e_shstrndx; if (ShstrIndex == SHN_XINDEX) { Expected<const Elf_Shdr *> Sec = ElfFile.getSection(0); if (!Sec) return Sec.takeError(); - + ShstrIndex = (*Sec)->sh_link; } - if (ShstrIndex == SHN_UNDEF) - Obj.HadShdrs = false; + if (ShstrIndex == SHN_UNDEF) + Obj.HadShdrs = false; else { Expected<StringTableSection *> Sec = - Obj.sections().template getSectionOfType<StringTableSection>( - ShstrIndex, - "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + - " is invalid", - "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + - " does not reference a string table"); + Obj.sections().template getSectionOfType<StringTableSection>( + ShstrIndex, + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " is invalid", + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " does not reference a string table"); if (!Sec) return Sec.takeError(); - + Obj.SectionNames = *Sec; } - // 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. - if (Obj.SectionIndexTable) + // 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. + if (Obj.SectionIndexTable) if (Error Err = Obj.SectionIndexTable->initialize(Obj.sections())) return Err; - - // Now that all of the sections have been added we can fill out some extra - // details about symbol tables. We need the symbol table filled out before - // any relocations. - if (Obj.SymbolTable) { + + // Now that all of the sections have been added we can fill out some extra + // details about symbol tables. We need the symbol table filled out before + // any relocations. + if (Obj.SymbolTable) { if (Error Err = Obj.SymbolTable->initialize(Obj.sections())) return Err; if (Error Err = initSymbolTable(Obj.SymbolTable)) return Err; - } else if (EnsureSymtab) { + } else if (EnsureSymtab) { if (Error Err = Obj.addNewSymbolTable()) return Err; - } - - // 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. + } + + // 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 (SectionBase &Sec : Obj.sections()) { - if (&Sec == Obj.SymbolTable) - continue; + if (&Sec == Obj.SymbolTable) + continue; if (Error Err = Sec.initialize(Obj.sections())) return Err; - if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) { + if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) { Expected<typename ELFFile<ELFT>::Elf_Shdr_Range> Sections = ElfFile.sections(); if (!Sections) @@ -1863,78 +1863,78 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) { if (Error Err = initRelocations(RelSec, Obj.SymbolTable, *Relas)) return Err; } - } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) { + } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) { if (Error Err = initGroupSection(GroupSec)) return Err; - } - } + } + } return Error::success(); -} - +} + template <class ELFT> Error ELFBuilder<ELFT>::build(bool EnsureSymtab) { if (Error E = readSectionHeaders()) return E; if (Error E = findEhdrOffset()) return E; - - // The ELFFile whose ELF headers and program headers are copied into the - // output file. Normally the same as ElfFile, but if we're extracting a - // loadable partition it will point to the partition's headers. + + // The ELFFile whose ELF headers and program headers are copied into the + // output file. Normally the same as ElfFile, but if we're extracting a + // loadable partition it will point to the partition's headers. Expected<ELFFile<ELFT>> HeadersFile = ELFFile<ELFT>::create(toStringRef( {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset})); if (!HeadersFile) return HeadersFile.takeError(); - + const typename ELFFile<ELFT>::Elf_Ehdr &Ehdr = HeadersFile->getHeader(); - Obj.OSABI = Ehdr.e_ident[EI_OSABI]; - Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION]; - Obj.Type = Ehdr.e_type; - Obj.Machine = Ehdr.e_machine; - Obj.Version = Ehdr.e_version; - Obj.Entry = Ehdr.e_entry; - Obj.Flags = Ehdr.e_flags; - + Obj.OSABI = Ehdr.e_ident[EI_OSABI]; + Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION]; + Obj.Type = Ehdr.e_type; + Obj.Machine = Ehdr.e_machine; + Obj.Version = Ehdr.e_version; + Obj.Entry = Ehdr.e_entry; + Obj.Flags = Ehdr.e_flags; + if (Error E = readSections(EnsureSymtab)) return E; return readProgramHeaders(*HeadersFile); -} - -Writer::~Writer() {} - -Reader::~Reader() {} - +} + +Writer::~Writer() {} + +Reader::~Reader() {} + Expected<std::unique_ptr<Object>> BinaryReader::create(bool /*EnsureSymtab*/) const { - return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build(); -} - -Expected<std::vector<IHexRecord>> IHexReader::parse() const { - SmallVector<StringRef, 16> Lines; - std::vector<IHexRecord> Records; - bool HasSections = false; - - MemBuf->getBuffer().split(Lines, '\n'); - Records.reserve(Lines.size()); - for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) { - StringRef Line = Lines[LineNo - 1].trim(); - if (Line.empty()) - continue; - - Expected<IHexRecord> R = IHexRecord::parse(Line); - if (!R) - return parseError(LineNo, R.takeError()); - if (R->Type == IHexRecord::EndOfFile) - break; - HasSections |= (R->Type == IHexRecord::Data); - Records.push_back(*R); - } - if (!HasSections) - return parseError(-1U, "no sections"); - - return std::move(Records); -} - + return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build(); +} + +Expected<std::vector<IHexRecord>> IHexReader::parse() const { + SmallVector<StringRef, 16> Lines; + std::vector<IHexRecord> Records; + bool HasSections = false; + + MemBuf->getBuffer().split(Lines, '\n'); + Records.reserve(Lines.size()); + for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) { + StringRef Line = Lines[LineNo - 1].trim(); + if (Line.empty()) + continue; + + Expected<IHexRecord> R = IHexRecord::parse(Line); + if (!R) + return parseError(LineNo, R.takeError()); + if (R->Type == IHexRecord::EndOfFile) + break; + HasSections |= (R->Type == IHexRecord::Data); + Records.push_back(*R); + } + if (!HasSections) + return parseError(-1U, "no sections"); + + return std::move(Records); +} + Expected<std::unique_ptr<Object>> IHexReader::create(bool /*EnsureSymtab*/) const { Expected<std::vector<IHexRecord>> Records = parse(); @@ -1942,375 +1942,375 @@ IHexReader::create(bool /*EnsureSymtab*/) const { return Records.takeError(); return IHexELFBuilder(*Records).build(); -} - +} + Expected<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); + auto Obj = std::make_unique<Object>(); + if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) { + ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition); if (Error Err = Builder.build(EnsureSymtab)) return std::move(Err); return std::move(Obj); - } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) { - ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition); + } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) { + ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition); if (Error Err = Builder.build(EnsureSymtab)) return std::move(Err); return std::move(Obj); - } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) { - ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition); + } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) { + ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition); if (Error Err = Builder.build(EnsureSymtab)) return std::move(Err); return std::move(Obj); - } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) { - ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition); + } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) { + ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition); if (Error Err = Builder.build(EnsureSymtab)) return std::move(Err); return std::move(Obj); - } + } return createStringError(errc::invalid_argument, "invalid file type"); -} - -template <class ELFT> void ELFWriter<ELFT>::writeEhdr() { - Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart()); - std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0); - Ehdr.e_ident[EI_MAG0] = 0x7f; - Ehdr.e_ident[EI_MAG1] = 'E'; - Ehdr.e_ident[EI_MAG2] = 'L'; - Ehdr.e_ident[EI_MAG3] = 'F'; - Ehdr.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; - Ehdr.e_ident[EI_DATA] = - ELFT::TargetEndianness == support::big ? ELFDATA2MSB : ELFDATA2LSB; - Ehdr.e_ident[EI_VERSION] = EV_CURRENT; - Ehdr.e_ident[EI_OSABI] = Obj.OSABI; - Ehdr.e_ident[EI_ABIVERSION] = Obj.ABIVersion; - - Ehdr.e_type = Obj.Type; - Ehdr.e_machine = Obj.Machine; - Ehdr.e_version = Obj.Version; - Ehdr.e_entry = Obj.Entry; - // We have to use the fully-qualified name llvm::size - // since some compilers complain on ambiguous resolution. - Ehdr.e_phnum = llvm::size(Obj.segments()); - Ehdr.e_phoff = (Ehdr.e_phnum != 0) ? Obj.ProgramHdrSegment.Offset : 0; - Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0; - Ehdr.e_flags = Obj.Flags; - Ehdr.e_ehsize = sizeof(Elf_Ehdr); - if (WriteSectionHeaders && Obj.sections().size() != 0) { - Ehdr.e_shentsize = sizeof(Elf_Shdr); - 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 - // number of section header table entries is contained in the sh_size field - // of the section header at index 0. - // """ - auto Shnum = Obj.sections().size() + 1; - if (Shnum >= SHN_LORESERVE) - Ehdr.e_shnum = 0; - else - Ehdr.e_shnum = Shnum; - // """ - // If the section name string table section index is greater than or equal - // to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX (0xffff) - // and the actual index of the section name string table section is - // contained in the sh_link field of the section header at index 0. - // """ - if (Obj.SectionNames->Index >= SHN_LORESERVE) - Ehdr.e_shstrndx = SHN_XINDEX; - else - Ehdr.e_shstrndx = Obj.SectionNames->Index; - } else { - Ehdr.e_shentsize = 0; - Ehdr.e_shoff = 0; - Ehdr.e_shnum = 0; - Ehdr.e_shstrndx = 0; - } -} - -template <class ELFT> void ELFWriter<ELFT>::writePhdrs() { - for (auto &Seg : Obj.segments()) - writePhdr(Seg); -} - -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.SHOff); - Shdr.sh_name = 0; - Shdr.sh_type = SHT_NULL; - Shdr.sh_flags = 0; - Shdr.sh_addr = 0; - Shdr.sh_offset = 0; - // See writeEhdr for why we do this. - uint64_t Shnum = Obj.sections().size() + 1; - if (Shnum >= SHN_LORESERVE) - Shdr.sh_size = Shnum; - else - Shdr.sh_size = 0; - // See writeEhdr for why we do this. - if (Obj.SectionNames != nullptr && Obj.SectionNames->Index >= SHN_LORESERVE) - Shdr.sh_link = Obj.SectionNames->Index; - else - Shdr.sh_link = 0; - Shdr.sh_info = 0; - Shdr.sh_addralign = 0; - Shdr.sh_entsize = 0; - - for (SectionBase &Sec : Obj.sections()) - writeShdr(Sec); -} - +} + +template <class ELFT> void ELFWriter<ELFT>::writeEhdr() { + Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart()); + std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0); + Ehdr.e_ident[EI_MAG0] = 0x7f; + Ehdr.e_ident[EI_MAG1] = 'E'; + Ehdr.e_ident[EI_MAG2] = 'L'; + Ehdr.e_ident[EI_MAG3] = 'F'; + Ehdr.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; + Ehdr.e_ident[EI_DATA] = + ELFT::TargetEndianness == support::big ? ELFDATA2MSB : ELFDATA2LSB; + Ehdr.e_ident[EI_VERSION] = EV_CURRENT; + Ehdr.e_ident[EI_OSABI] = Obj.OSABI; + Ehdr.e_ident[EI_ABIVERSION] = Obj.ABIVersion; + + Ehdr.e_type = Obj.Type; + Ehdr.e_machine = Obj.Machine; + Ehdr.e_version = Obj.Version; + Ehdr.e_entry = Obj.Entry; + // We have to use the fully-qualified name llvm::size + // since some compilers complain on ambiguous resolution. + Ehdr.e_phnum = llvm::size(Obj.segments()); + Ehdr.e_phoff = (Ehdr.e_phnum != 0) ? Obj.ProgramHdrSegment.Offset : 0; + Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0; + Ehdr.e_flags = Obj.Flags; + Ehdr.e_ehsize = sizeof(Elf_Ehdr); + if (WriteSectionHeaders && Obj.sections().size() != 0) { + Ehdr.e_shentsize = sizeof(Elf_Shdr); + 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 + // number of section header table entries is contained in the sh_size field + // of the section header at index 0. + // """ + auto Shnum = Obj.sections().size() + 1; + if (Shnum >= SHN_LORESERVE) + Ehdr.e_shnum = 0; + else + Ehdr.e_shnum = Shnum; + // """ + // If the section name string table section index is greater than or equal + // to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX (0xffff) + // and the actual index of the section name string table section is + // contained in the sh_link field of the section header at index 0. + // """ + if (Obj.SectionNames->Index >= SHN_LORESERVE) + Ehdr.e_shstrndx = SHN_XINDEX; + else + Ehdr.e_shstrndx = Obj.SectionNames->Index; + } else { + Ehdr.e_shentsize = 0; + Ehdr.e_shoff = 0; + Ehdr.e_shnum = 0; + Ehdr.e_shstrndx = 0; + } +} + +template <class ELFT> void ELFWriter<ELFT>::writePhdrs() { + for (auto &Seg : Obj.segments()) + writePhdr(Seg); +} + +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.SHOff); + Shdr.sh_name = 0; + Shdr.sh_type = SHT_NULL; + Shdr.sh_flags = 0; + Shdr.sh_addr = 0; + Shdr.sh_offset = 0; + // See writeEhdr for why we do this. + uint64_t Shnum = Obj.sections().size() + 1; + if (Shnum >= SHN_LORESERVE) + Shdr.sh_size = Shnum; + else + Shdr.sh_size = 0; + // See writeEhdr for why we do this. + if (Obj.SectionNames != nullptr && Obj.SectionNames->Index >= SHN_LORESERVE) + Shdr.sh_link = Obj.SectionNames->Index; + else + Shdr.sh_link = 0; + Shdr.sh_info = 0; + Shdr.sh_addralign = 0; + Shdr.sh_entsize = 0; + + for (SectionBase &Sec : Obj.sections()) + writeShdr(Sec); +} + template <class ELFT> Error ELFWriter<ELFT>::writeSectionData() { - for (SectionBase &Sec : Obj.sections()) - // Segments are responsible for writing their contents, so only write the - // section data if the section is not in a segment. Note that this renders - // sections in segments effectively immutable. - if (Sec.ParentSegment == nullptr) + for (SectionBase &Sec : Obj.sections()) + // Segments are responsible for writing their contents, so only write the + // section data if the section is not in a segment. Note that this renders + // sections in segments effectively immutable. + if (Sec.ParentSegment == nullptr) if (Error Err = Sec.accept(*SecWriter)) return Err; return Error::success(); -} - -template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() { - for (Segment &Seg : Obj.segments()) { - size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size()); - std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(), - Size); - } - - // Iterate over removed sections and overwrite their old data with zeroes. - for (auto &Sec : Obj.removedSections()) { - Segment *Parent = Sec.ParentSegment; - if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0) - continue; - uint64_t Offset = - Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset; - std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size); - } -} - -template <class ELFT> -ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH, - bool OnlyKeepDebug) - : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), - OnlyKeepDebug(OnlyKeepDebug) {} - +} + +template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() { + for (Segment &Seg : Obj.segments()) { + size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size()); + std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(), + Size); + } + + // Iterate over removed sections and overwrite their old data with zeroes. + for (auto &Sec : Obj.removedSections()) { + Segment *Parent = Sec.ParentSegment; + if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0) + continue; + uint64_t Offset = + Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset; + std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size); + } +} + +template <class ELFT> +ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH, + bool OnlyKeepDebug) + : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), + OnlyKeepDebug(OnlyKeepDebug) {} + Error Object::removeSections( bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) { - - auto Iter = std::stable_partition( - std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) { - if (ToRemove(*Sec)) - return false; - if (auto RelSec = dyn_cast<RelocationSectionBase>(Sec.get())) { - if (auto ToRelSec = RelSec->getSection()) - return !ToRemove(*ToRelSec); - } - return true; - }); - if (SymbolTable != nullptr && ToRemove(*SymbolTable)) - SymbolTable = nullptr; - if (SectionNames != nullptr && ToRemove(*SectionNames)) - SectionNames = nullptr; - if (SectionIndexTable != nullptr && ToRemove(*SectionIndexTable)) - SectionIndexTable = nullptr; - // Now make sure there are no remaining references to the sections that will - // be removed. Sometimes it is impossible to remove a reference so we emit - // an error here instead. - std::unordered_set<const SectionBase *> RemoveSections; - RemoveSections.reserve(std::distance(Iter, std::end(Sections))); - for (auto &RemoveSec : make_range(Iter, std::end(Sections))) { - for (auto &Segment : Segments) - Segment->removeSection(RemoveSec.get()); - RemoveSec->onRemove(); - RemoveSections.insert(RemoveSec.get()); - } - - // For each section that remains alive, we want to remove the dead references. - // This either might update the content of the section (e.g. remove symbols - // from symbol table that belongs to removed section) or trigger an error if - // a live section critically depends on a section being removed somehow - // (e.g. the removed section is referenced by a relocation). - for (auto &KeepSec : make_range(std::begin(Sections), Iter)) { + + auto Iter = std::stable_partition( + std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) { + if (ToRemove(*Sec)) + return false; + if (auto RelSec = dyn_cast<RelocationSectionBase>(Sec.get())) { + if (auto ToRelSec = RelSec->getSection()) + return !ToRemove(*ToRelSec); + } + return true; + }); + if (SymbolTable != nullptr && ToRemove(*SymbolTable)) + SymbolTable = nullptr; + if (SectionNames != nullptr && ToRemove(*SectionNames)) + SectionNames = nullptr; + if (SectionIndexTable != nullptr && ToRemove(*SectionIndexTable)) + SectionIndexTable = nullptr; + // Now make sure there are no remaining references to the sections that will + // be removed. Sometimes it is impossible to remove a reference so we emit + // an error here instead. + std::unordered_set<const SectionBase *> RemoveSections; + RemoveSections.reserve(std::distance(Iter, std::end(Sections))); + for (auto &RemoveSec : make_range(Iter, std::end(Sections))) { + for (auto &Segment : Segments) + Segment->removeSection(RemoveSec.get()); + RemoveSec->onRemove(); + RemoveSections.insert(RemoveSec.get()); + } + + // For each section that remains alive, we want to remove the dead references. + // This either might update the content of the section (e.g. remove symbols + // from symbol table that belongs to removed section) or trigger an error if + // a live section critically depends on a section being removed somehow + // (e.g. the removed section is referenced by a relocation). + for (auto &KeepSec : make_range(std::begin(Sections), Iter)) { if (Error E = KeepSec->removeSectionReferences( AllowBrokenLinks, [&RemoveSections](const SectionBase *Sec) { - return RemoveSections.find(Sec) != RemoveSections.end(); - })) - return E; - } - - // Transfer removed sections into the Object RemovedSections container for use - // later. - std::move(Iter, Sections.end(), std::back_inserter(RemovedSections)); - // Now finally get rid of them all together. - Sections.erase(Iter, std::end(Sections)); - return Error::success(); -} - -Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { - if (SymbolTable) - for (const SecPtr &Sec : Sections) - if (Error E = Sec->removeSymbols(ToRemove)) - return E; - return Error::success(); -} - + return RemoveSections.find(Sec) != RemoveSections.end(); + })) + return E; + } + + // Transfer removed sections into the Object RemovedSections container for use + // later. + std::move(Iter, Sections.end(), std::back_inserter(RemovedSections)); + // Now finally get rid of them all together. + Sections.erase(Iter, std::end(Sections)); + return Error::success(); +} + +Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) { + if (SymbolTable) + for (const SecPtr &Sec : Sections) + if (Error E = Sec->removeSymbols(ToRemove)) + return E; + return Error::success(); +} + Error Object::addNewSymbolTable() { - assert(!SymbolTable && "Object must not has a SymbolTable."); - - // Reuse an existing SHT_STRTAB section if it exists. - StringTableSection *StrTab = nullptr; - for (SectionBase &Sec : sections()) { - if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { - StrTab = static_cast<StringTableSection *>(&Sec); - - // Prefer a string table that is not the section header string table, if - // such a table exists. - if (SectionNames != &Sec) - break; - } - } - if (!StrTab) - StrTab = &addSection<StringTableSection>(); - - SymbolTableSection &SymTab = addSection<SymbolTableSection>(); - SymTab.Name = ".symtab"; - SymTab.Link = StrTab->Index; + assert(!SymbolTable && "Object must not has a SymbolTable."); + + // Reuse an existing SHT_STRTAB section if it exists. + StringTableSection *StrTab = nullptr; + for (SectionBase &Sec : sections()) { + if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) { + StrTab = static_cast<StringTableSection *>(&Sec); + + // Prefer a string table that is not the section header string table, if + // such a table exists. + if (SectionNames != &Sec) + break; + } + } + if (!StrTab) + StrTab = &addSection<StringTableSection>(); + + SymbolTableSection &SymTab = addSection<SymbolTableSection>(); + SymTab.Name = ".symtab"; + SymTab.Link = StrTab->Index; if (Error Err = SymTab.initialize(sections())) return Err; - SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); - - SymbolTable = &SymTab; + SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0); + + SymbolTable = &SymTab; return Error::success(); -} - -void Object::sortSections() { - // Use stable_sort to maintain the original ordering as closely as possible. - llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) { - // Put SHT_GROUP sections first, since group section headers must come - // before the sections they contain. This also matches what GNU objcopy - // does. - if (A->Type != B->Type && - (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP)) - return A->Type == ELF::SHT_GROUP; - // For all other sections, sort by offset order. - return A->OriginalOffset < B->OriginalOffset; - }); -} - -// 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 -// returns an Offset one past the end of the last segment. -static uint64_t layoutSegments(std::vector<Segment *> &Segments, - uint64_t Offset) { - assert(llvm::is_sorted(Segments, compareSegmentsByOffset)); - // The only way a segment should move is if a section was between two - // segments and that section was removed. If that section isn't in a segment - // then it's acceptable, but not ideal, to simply move it to after the - // segments. So we can simply layout segments one after the other accounting - // for alignment. - for (Segment *Seg : Segments) { - // We assume that segments have been ordered by OriginalOffset and Index - // such that a parent segment will always come before a child segment in - // OrderedSegments. This means that the Offset of the ParentSegment should - // already be set and we can set our offset relative to it. - if (Seg->ParentSegment != nullptr) { - Segment *Parent = Seg->ParentSegment; - Seg->Offset = - Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset; - } else { - Seg->Offset = - alignTo(Offset, std::max<uint64_t>(Seg->Align, 1), Seg->VAddr); - } - Offset = std::max(Offset, Seg->Offset + Seg->FileSize); - } - return Offset; -} - -// This function finds a consistent layout for a list of sections. It assumes -// that the ->ParentSegment of each section has already been laid out. The -// supplied starting Offset is used for the starting offset of any section that -// does not have a ParentSegment. It returns either the offset given if all -// sections had a ParentSegment or an offset one past the last section if there -// was a section that didn't have a ParentSegment. -template <class Range> -static uint64_t layoutSections(Range Sections, uint64_t Offset) { - // Now the offset of every segment has been set we can assign the offsets - // of each section. For sections that are covered by a segment we should use - // the segment's original offset and the section's original offset to compute - // the offset from the start of the segment. Using the offset from the start - // 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 &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, Sec.Align == 0 ? 1 : Sec.Align); - Sec.Offset = Offset; - if (Sec.Type != SHT_NOBITS) - Offset += Sec.Size; - } - } - return Offset; -} - -// Rewrite sh_offset after some sections are changed to SHT_NOBITS and thus -// occupy no space in the file. -static uint64_t layoutSectionsForOnlyKeepDebug(Object &Obj, uint64_t Off) { - uint32_t Index = 1; - for (auto &Sec : Obj.sections()) { - Sec.Index = Index++; - - auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD - ? Sec.ParentSegment->firstSection() - : nullptr; - - // The first section in a PT_LOAD has to have congruent offset and address - // modulo the alignment, which usually equals the maximum page size. - if (FirstSec && FirstSec == &Sec) - Off = alignTo(Off, Sec.ParentSegment->Align, Sec.Addr); - - // sh_offset is not significant for SHT_NOBITS sections, but the congruence - // rule must be followed if it is the first section in a PT_LOAD. Do not - // advance Off. - if (Sec.Type == SHT_NOBITS) { - Sec.Offset = Off; - continue; - } - - if (!FirstSec) { - // FirstSec being nullptr generally means that Sec does not have the - // SHF_ALLOC flag. - Off = Sec.Align ? alignTo(Off, Sec.Align) : Off; - } else if (FirstSec != &Sec) { - // The offset is relative to the first section in the PT_LOAD segment. Use - // sh_offset for non-SHF_ALLOC sections. - Off = Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset; - } - Sec.Offset = Off; - Off += Sec.Size; - } - return Off; -} - +} + +void Object::sortSections() { + // Use stable_sort to maintain the original ordering as closely as possible. + llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) { + // Put SHT_GROUP sections first, since group section headers must come + // before the sections they contain. This also matches what GNU objcopy + // does. + if (A->Type != B->Type && + (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP)) + return A->Type == ELF::SHT_GROUP; + // For all other sections, sort by offset order. + return A->OriginalOffset < B->OriginalOffset; + }); +} + +// 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 +// returns an Offset one past the end of the last segment. +static uint64_t layoutSegments(std::vector<Segment *> &Segments, + uint64_t Offset) { + assert(llvm::is_sorted(Segments, compareSegmentsByOffset)); + // The only way a segment should move is if a section was between two + // segments and that section was removed. If that section isn't in a segment + // then it's acceptable, but not ideal, to simply move it to after the + // segments. So we can simply layout segments one after the other accounting + // for alignment. + for (Segment *Seg : Segments) { + // We assume that segments have been ordered by OriginalOffset and Index + // such that a parent segment will always come before a child segment in + // OrderedSegments. This means that the Offset of the ParentSegment should + // already be set and we can set our offset relative to it. + if (Seg->ParentSegment != nullptr) { + Segment *Parent = Seg->ParentSegment; + Seg->Offset = + Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset; + } else { + Seg->Offset = + alignTo(Offset, std::max<uint64_t>(Seg->Align, 1), Seg->VAddr); + } + Offset = std::max(Offset, Seg->Offset + Seg->FileSize); + } + return Offset; +} + +// This function finds a consistent layout for a list of sections. It assumes +// that the ->ParentSegment of each section has already been laid out. The +// supplied starting Offset is used for the starting offset of any section that +// does not have a ParentSegment. It returns either the offset given if all +// sections had a ParentSegment or an offset one past the last section if there +// was a section that didn't have a ParentSegment. +template <class Range> +static uint64_t layoutSections(Range Sections, uint64_t Offset) { + // Now the offset of every segment has been set we can assign the offsets + // of each section. For sections that are covered by a segment we should use + // the segment's original offset and the section's original offset to compute + // the offset from the start of the segment. Using the offset from the start + // 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 &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, Sec.Align == 0 ? 1 : Sec.Align); + Sec.Offset = Offset; + if (Sec.Type != SHT_NOBITS) + Offset += Sec.Size; + } + } + return Offset; +} + +// Rewrite sh_offset after some sections are changed to SHT_NOBITS and thus +// occupy no space in the file. +static uint64_t layoutSectionsForOnlyKeepDebug(Object &Obj, uint64_t Off) { + uint32_t Index = 1; + for (auto &Sec : Obj.sections()) { + Sec.Index = Index++; + + auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD + ? Sec.ParentSegment->firstSection() + : nullptr; + + // The first section in a PT_LOAD has to have congruent offset and address + // modulo the alignment, which usually equals the maximum page size. + if (FirstSec && FirstSec == &Sec) + Off = alignTo(Off, Sec.ParentSegment->Align, Sec.Addr); + + // sh_offset is not significant for SHT_NOBITS sections, but the congruence + // rule must be followed if it is the first section in a PT_LOAD. Do not + // advance Off. + if (Sec.Type == SHT_NOBITS) { + Sec.Offset = Off; + continue; + } + + if (!FirstSec) { + // FirstSec being nullptr generally means that Sec does not have the + // SHF_ALLOC flag. + Off = Sec.Align ? alignTo(Off, Sec.Align) : Off; + } else if (FirstSec != &Sec) { + // The offset is relative to the first section in the PT_LOAD segment. Use + // sh_offset for non-SHF_ALLOC sections. + Off = Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset; + } + Sec.Offset = Off; + Off += Sec.Size; + } + return Off; +} + // Rewrite p_offset and p_filesz of non-PT_PHDR segments after sh_offset values // have been updated. -static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments, - uint64_t HdrEnd) { - uint64_t MaxOffset = 0; - for (Segment *Seg : Segments) { +static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments, + uint64_t HdrEnd) { + uint64_t MaxOffset = 0; + for (Segment *Seg : Segments) { // An empty segment contains no section (see sectionWithinSegment). If it // has a parent segment, copy the parent segment's offset field. This works // for empty PT_TLS. We don't handle empty segments without a parent for @@ -2318,377 +2318,377 @@ static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments, if (Seg->ParentSegment != nullptr && Seg->MemSize == 0) Seg->Offset = Seg->ParentSegment->Offset; - const SectionBase *FirstSec = Seg->firstSection(); - if (Seg->Type == PT_PHDR || !FirstSec) - continue; - - uint64_t Offset = FirstSec->Offset; - uint64_t FileSize = 0; - for (const SectionBase *Sec : Seg->Sections) { - uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size; - if (Sec->Offset + Size > Offset) - FileSize = std::max(FileSize, Sec->Offset + Size - Offset); - } - - // If the segment includes EHDR and program headers, don't make it smaller - // than the headers. - if (Seg->Offset < HdrEnd && HdrEnd <= Seg->Offset + Seg->FileSize) { - FileSize += Offset - Seg->Offset; - Offset = Seg->Offset; - FileSize = std::max(FileSize, HdrEnd - Offset); - } - - Seg->Offset = Offset; - Seg->FileSize = FileSize; - MaxOffset = std::max(MaxOffset, Offset + FileSize); - } - return MaxOffset; -} - -template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() { - Segment &ElfHdr = Obj.ElfHdrSegment; - ElfHdr.Type = PT_PHDR; - ElfHdr.Flags = 0; - ElfHdr.VAddr = 0; - ElfHdr.PAddr = 0; - ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr); - ElfHdr.Align = 0; -} - -template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { - // 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 its offset properly set. - std::vector<Segment *> OrderedSegments; - for (Segment &Segment : Obj.segments()) - OrderedSegments.push_back(&Segment); - OrderedSegments.push_back(&Obj.ElfHdrSegment); - OrderedSegments.push_back(&Obj.ProgramHdrSegment); - orderSegments(OrderedSegments); - - uint64_t Offset; - if (OnlyKeepDebug) { - // For --only-keep-debug, the sections that did not preserve contents were - // changed to SHT_NOBITS. We now rewrite sh_offset fields of sections, and - // then rewrite p_offset/p_filesz of program headers. - uint64_t HdrEnd = - sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr); - Offset = layoutSectionsForOnlyKeepDebug(Obj, HdrEnd); - Offset = std::max(Offset, - layoutSegmentsForOnlyKeepDebug(OrderedSegments, HdrEnd)); - } else { - // Offset is used as the start offset of the first segment to be laid out. - // Since the ELF Header (ElfHdrSegment) must be at the start of the file, - // we start at offset 0. - Offset = layoutSegments(OrderedSegments, 0); - Offset = layoutSections(Obj.sections(), Offset); - } - // If we need to write the section header table out then we need to align the - // Offset so that SHOffset is valid. - if (WriteSectionHeaders) - Offset = alignTo(Offset, sizeof(Elf_Addr)); - 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.SHOff; - size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr. - return Obj.SHOff + ShdrCount * sizeof(Elf_Shdr); -} - -template <class ELFT> Error ELFWriter<ELFT>::write() { - // Segment data must be written first, so that the ELF header and program - // header tables can overwrite it, if covered by a segment. - writeSegmentData(); - writeEhdr(); - writePhdrs(); + const SectionBase *FirstSec = Seg->firstSection(); + if (Seg->Type == PT_PHDR || !FirstSec) + continue; + + uint64_t Offset = FirstSec->Offset; + uint64_t FileSize = 0; + for (const SectionBase *Sec : Seg->Sections) { + uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size; + if (Sec->Offset + Size > Offset) + FileSize = std::max(FileSize, Sec->Offset + Size - Offset); + } + + // If the segment includes EHDR and program headers, don't make it smaller + // than the headers. + if (Seg->Offset < HdrEnd && HdrEnd <= Seg->Offset + Seg->FileSize) { + FileSize += Offset - Seg->Offset; + Offset = Seg->Offset; + FileSize = std::max(FileSize, HdrEnd - Offset); + } + + Seg->Offset = Offset; + Seg->FileSize = FileSize; + MaxOffset = std::max(MaxOffset, Offset + FileSize); + } + return MaxOffset; +} + +template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() { + Segment &ElfHdr = Obj.ElfHdrSegment; + ElfHdr.Type = PT_PHDR; + ElfHdr.Flags = 0; + ElfHdr.VAddr = 0; + ElfHdr.PAddr = 0; + ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr); + ElfHdr.Align = 0; +} + +template <class ELFT> void ELFWriter<ELFT>::assignOffsets() { + // 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 its offset properly set. + std::vector<Segment *> OrderedSegments; + for (Segment &Segment : Obj.segments()) + OrderedSegments.push_back(&Segment); + OrderedSegments.push_back(&Obj.ElfHdrSegment); + OrderedSegments.push_back(&Obj.ProgramHdrSegment); + orderSegments(OrderedSegments); + + uint64_t Offset; + if (OnlyKeepDebug) { + // For --only-keep-debug, the sections that did not preserve contents were + // changed to SHT_NOBITS. We now rewrite sh_offset fields of sections, and + // then rewrite p_offset/p_filesz of program headers. + uint64_t HdrEnd = + sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr); + Offset = layoutSectionsForOnlyKeepDebug(Obj, HdrEnd); + Offset = std::max(Offset, + layoutSegmentsForOnlyKeepDebug(OrderedSegments, HdrEnd)); + } else { + // Offset is used as the start offset of the first segment to be laid out. + // Since the ELF Header (ElfHdrSegment) must be at the start of the file, + // we start at offset 0. + Offset = layoutSegments(OrderedSegments, 0); + Offset = layoutSections(Obj.sections(), Offset); + } + // If we need to write the section header table out then we need to align the + // Offset so that SHOffset is valid. + if (WriteSectionHeaders) + Offset = alignTo(Offset, sizeof(Elf_Addr)); + 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.SHOff; + size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr. + return Obj.SHOff + ShdrCount * sizeof(Elf_Shdr); +} + +template <class ELFT> Error ELFWriter<ELFT>::write() { + // Segment data must be written first, so that the ELF header and program + // header tables can overwrite it, if covered by a segment. + writeSegmentData(); + writeEhdr(); + writePhdrs(); if (Error E = writeSectionData()) return E; - if (WriteSectionHeaders) - writeShdrs(); - 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 - // to do that. - if (Obj.SectionNames == nullptr && WriteSectionHeaders) - return createStringError(llvm::errc::invalid_argument, - "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 - // if we need large indexes or not. We can assign indexes first and check as - // we go to see if we will actully need large indexes. - bool NeedsLargeIndexes = false; - if (Obj.sections().size() >= SHN_LORESERVE) { - SectionTableRef Sections = Obj.sections(); - NeedsLargeIndexes = + if (WriteSectionHeaders) + writeShdrs(); + 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 + // to do that. + if (Obj.SectionNames == nullptr && WriteSectionHeaders) + return createStringError(llvm::errc::invalid_argument, + "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 + // if we need large indexes or not. We can assign indexes first and check as + // we go to see if we will actully need large indexes. + bool NeedsLargeIndexes = false; + if (Obj.sections().size() >= SHN_LORESERVE) { + SectionTableRef Sections = Obj.sections(); + NeedsLargeIndexes = any_of(drop_begin(Sections, SHN_LORESERVE), [](const SectionBase &Sec) { return Sec.HasSymbol; }); - // TODO: handle case where only one section needs the large index table but - // only needs it because the large index table hasn't been removed yet. - } - - if (NeedsLargeIndexes) { - // This means we definitely need to have a section index table but if we - // already have one then we should use it instead of making a new one. - if (Obj.SymbolTable != nullptr && Obj.SectionIndexTable == nullptr) { - // Addition of a section to the end does not invalidate the indexes of - // other sections and assigns the correct index to the new section. - auto &Shndx = Obj.addSection<SectionIndexSection>(); - Obj.SymbolTable->setShndxTable(&Shndx); - Shndx.setSymTab(Obj.SymbolTable); - } - } else { - // Since we don't need SectionIndexTable we should remove it and all - // references to it. - if (Obj.SectionIndexTable != nullptr) { - // We do not support sections referring to the section index table. - if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/, - [this](const SectionBase &Sec) { - return &Sec == Obj.SectionIndexTable; - })) - return E; - } - } - - // 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 SectionBase &Sec : Obj.sections()) - Obj.SectionNames->addString(Sec.Name); - - initEhdrSegment(); - - // Before we can prepare for layout the indexes need to be finalized. - // 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 = std::make_unique<ELFSectionSizer<ELFT>>(); - for (SectionBase &Sec : Obj.sections()) { - Sec.Index = Index++; + // TODO: handle case where only one section needs the large index table but + // only needs it because the large index table hasn't been removed yet. + } + + if (NeedsLargeIndexes) { + // This means we definitely need to have a section index table but if we + // already have one then we should use it instead of making a new one. + if (Obj.SymbolTable != nullptr && Obj.SectionIndexTable == nullptr) { + // Addition of a section to the end does not invalidate the indexes of + // other sections and assigns the correct index to the new section. + auto &Shndx = Obj.addSection<SectionIndexSection>(); + Obj.SymbolTable->setShndxTable(&Shndx); + Shndx.setSymTab(Obj.SymbolTable); + } + } else { + // Since we don't need SectionIndexTable we should remove it and all + // references to it. + if (Obj.SectionIndexTable != nullptr) { + // We do not support sections referring to the section index table. + if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/, + [this](const SectionBase &Sec) { + return &Sec == Obj.SectionIndexTable; + })) + return E; + } + } + + // 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 SectionBase &Sec : Obj.sections()) + Obj.SectionNames->addString(Sec.Name); + + initEhdrSegment(); + + // Before we can prepare for layout the indexes need to be finalized. + // 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 = std::make_unique<ELFSectionSizer<ELFT>>(); + for (SectionBase &Sec : Obj.sections()) { + Sec.Index = Index++; if (Error Err = Sec.accept(*SecSizer)) return Err; - } - - // The symbol table does not update all other sections on update. For - // instance, symbol names are not added as new symbols are added. This means - // that some sections, like .strtab, don't yet have their final size. - if (Obj.SymbolTable != nullptr) - Obj.SymbolTable->prepareForLayout(); - - // Now that all strings are added we want to finalize string table builders, - // because that affects section sizes which in turn affects section offsets. - for (SectionBase &Sec : Obj.sections()) - if (auto StrTab = dyn_cast<StringTableSection>(&Sec)) - StrTab->prepareForLayout(); - - assignOffsets(); - - // layoutSections could have modified section indexes, so we need - // to fill the index table after assignOffsets. - if (Obj.SymbolTable != nullptr) - Obj.SymbolTable->fillShndxTable(); - - // Finally now that all offsets and indexes have been set we can finalize any - // remaining issues. - uint64_t Offset = Obj.SHOff + sizeof(Elf_Shdr); - for (SectionBase &Sec : Obj.sections()) { - Sec.HeaderOffset = Offset; - Offset += sizeof(Elf_Shdr); - if (WriteSectionHeaders) - Sec.NameIndex = Obj.SectionNames->findIndex(Sec.Name); - Sec.finalize(); - } - - if (Error E = Buf.allocate(totalSize())) - return E; - SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf); - return Error::success(); -} - -Error BinaryWriter::write() { - for (const SectionBase &Sec : Obj.allocSections()) + } + + // The symbol table does not update all other sections on update. For + // instance, symbol names are not added as new symbols are added. This means + // that some sections, like .strtab, don't yet have their final size. + if (Obj.SymbolTable != nullptr) + Obj.SymbolTable->prepareForLayout(); + + // Now that all strings are added we want to finalize string table builders, + // because that affects section sizes which in turn affects section offsets. + for (SectionBase &Sec : Obj.sections()) + if (auto StrTab = dyn_cast<StringTableSection>(&Sec)) + StrTab->prepareForLayout(); + + assignOffsets(); + + // layoutSections could have modified section indexes, so we need + // to fill the index table after assignOffsets. + if (Obj.SymbolTable != nullptr) + Obj.SymbolTable->fillShndxTable(); + + // Finally now that all offsets and indexes have been set we can finalize any + // remaining issues. + uint64_t Offset = Obj.SHOff + sizeof(Elf_Shdr); + for (SectionBase &Sec : Obj.sections()) { + Sec.HeaderOffset = Offset; + Offset += sizeof(Elf_Shdr); + if (WriteSectionHeaders) + Sec.NameIndex = Obj.SectionNames->findIndex(Sec.Name); + Sec.finalize(); + } + + if (Error E = Buf.allocate(totalSize())) + return E; + SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf); + return Error::success(); +} + +Error BinaryWriter::write() { + for (const SectionBase &Sec : Obj.allocSections()) if (Error Err = Sec.accept(*SecWriter)) return Err; - return Buf.commit(); -} - -Error BinaryWriter::finalize() { - // Compute the section LMA based on its sh_offset and the containing segment's - // p_offset and p_paddr. Also compute the minimum LMA of all non-empty - // sections as MinAddr. In the output, the contents between address 0 and - // MinAddr will be skipped. - uint64_t MinAddr = UINT64_MAX; - for (SectionBase &Sec : Obj.allocSections()) { - if (Sec.ParentSegment != nullptr) - Sec.Addr = - Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr; - if (Sec.Size > 0) - MinAddr = std::min(MinAddr, Sec.Addr); - } - - // 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 - // its last non-empty section, to match GNU objcopy's behaviour. - TotalSize = 0; - for (SectionBase &Sec : Obj.allocSections()) - if (Sec.Type != SHT_NOBITS && Sec.Size > 0) { - Sec.Offset = Sec.Addr - MinAddr; - TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); - } - - if (Error E = Buf.allocate(TotalSize)) - return E; - SecWriter = std::make_unique<BinarySectionWriter>(Buf); - return Error::success(); -} - -bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs, - const SectionBase *Rhs) const { - return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) < - (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU); -} - -uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) { - IHexLineData HexData; - uint8_t Data[4] = {}; - // We don't write entry point record if entry is zero. - if (Obj.Entry == 0) - return 0; - - if (Obj.Entry <= 0xFFFFFU) { - Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF; - support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry), - support::big); - HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data); - } else { - support::endian::write(Data, static_cast<uint32_t>(Obj.Entry), - support::big); - HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data); - } - memcpy(Buf, HexData.data(), HexData.size()); - return HexData.size(); -} - -uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) { - IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {}); - memcpy(Buf, HexData.data(), HexData.size()); - return HexData.size(); -} - -Error IHexWriter::write() { - IHexSectionWriter Writer(Buf); - // Write sections. - for (const SectionBase *Sec : Sections) + return Buf.commit(); +} + +Error BinaryWriter::finalize() { + // Compute the section LMA based on its sh_offset and the containing segment's + // p_offset and p_paddr. Also compute the minimum LMA of all non-empty + // sections as MinAddr. In the output, the contents between address 0 and + // MinAddr will be skipped. + uint64_t MinAddr = UINT64_MAX; + for (SectionBase &Sec : Obj.allocSections()) { + if (Sec.ParentSegment != nullptr) + Sec.Addr = + Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr; + if (Sec.Size > 0) + MinAddr = std::min(MinAddr, Sec.Addr); + } + + // 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 + // its last non-empty section, to match GNU objcopy's behaviour. + TotalSize = 0; + for (SectionBase &Sec : Obj.allocSections()) + if (Sec.Type != SHT_NOBITS && Sec.Size > 0) { + Sec.Offset = Sec.Addr - MinAddr; + TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); + } + + if (Error E = Buf.allocate(TotalSize)) + return E; + SecWriter = std::make_unique<BinarySectionWriter>(Buf); + return Error::success(); +} + +bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs, + const SectionBase *Rhs) const { + return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) < + (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU); +} + +uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) { + IHexLineData HexData; + uint8_t Data[4] = {}; + // We don't write entry point record if entry is zero. + if (Obj.Entry == 0) + return 0; + + if (Obj.Entry <= 0xFFFFFU) { + Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF; + support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry), + support::big); + HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data); + } else { + support::endian::write(Data, static_cast<uint32_t>(Obj.Entry), + support::big); + HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data); + } + memcpy(Buf, HexData.data(), HexData.size()); + return HexData.size(); +} + +uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) { + IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {}); + memcpy(Buf, HexData.data(), HexData.size()); + return HexData.size(); +} + +Error IHexWriter::write() { + IHexSectionWriter Writer(Buf); + // Write sections. + for (const SectionBase *Sec : Sections) if (Error Err = Sec->accept(Writer)) return Err; - - uint64_t Offset = Writer.getBufferOffset(); - // Write entry point address. - Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset); - // Write EOF. - Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset); - assert(Offset == TotalSize); - return Buf.commit(); -} - -Error IHexWriter::checkSection(const SectionBase &Sec) { - uint64_t Addr = sectionPhysicalAddr(&Sec); - if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1)) - return createStringError( - errc::invalid_argument, + + uint64_t Offset = Writer.getBufferOffset(); + // Write entry point address. + Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset); + // Write EOF. + Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset); + assert(Offset == TotalSize); + return Buf.commit(); +} + +Error IHexWriter::checkSection(const SectionBase &Sec) { + uint64_t Addr = sectionPhysicalAddr(&Sec); + if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1)) + return createStringError( + errc::invalid_argument, "Section '%s' address range [0x%llx, 0x%llx] is not 32 bit", Sec.Name.c_str(), Addr, Addr + Sec.Size - 1); - return Error::success(); -} - -Error IHexWriter::finalize() { - bool UseSegments = false; - auto ShouldWrite = [](const SectionBase &Sec) { - return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS); - }; - auto IsInPtLoad = [](const SectionBase &Sec) { - return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD; - }; - - // We can't write 64-bit addresses. - if (addressOverflows32bit(Obj.Entry)) - return createStringError(errc::invalid_argument, - "Entry point address 0x%llx overflows 32 bits.", - Obj.Entry); - - // If any section we're to write has segment then we - // switch to using physical addresses. Otherwise we - // use section virtual address. - for (const SectionBase &Sec : Obj.sections()) - if (ShouldWrite(Sec) && IsInPtLoad(Sec)) { - UseSegments = true; - break; - } - - for (const SectionBase &Sec : Obj.sections()) - if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) { - if (Error E = checkSection(Sec)) - return E; - Sections.insert(&Sec); - } - - IHexSectionWriterBase LengthCalc(Buf); - for (const SectionBase *Sec : Sections) + return Error::success(); +} + +Error IHexWriter::finalize() { + bool UseSegments = false; + auto ShouldWrite = [](const SectionBase &Sec) { + return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS); + }; + auto IsInPtLoad = [](const SectionBase &Sec) { + return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD; + }; + + // We can't write 64-bit addresses. + if (addressOverflows32bit(Obj.Entry)) + return createStringError(errc::invalid_argument, + "Entry point address 0x%llx overflows 32 bits.", + Obj.Entry); + + // If any section we're to write has segment then we + // switch to using physical addresses. Otherwise we + // use section virtual address. + for (const SectionBase &Sec : Obj.sections()) + if (ShouldWrite(Sec) && IsInPtLoad(Sec)) { + UseSegments = true; + break; + } + + for (const SectionBase &Sec : Obj.sections()) + if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) { + if (Error E = checkSection(Sec)) + return E; + Sections.insert(&Sec); + } + + IHexSectionWriterBase LengthCalc(Buf); + for (const SectionBase *Sec : Sections) if (Error Err = Sec->accept(LengthCalc)) return Err; - - // We need space to write section records + StartAddress record - // (if start adress is not zero) + EndOfFile record. - TotalSize = LengthCalc.getBufferOffset() + - (Obj.Entry ? IHexRecord::getLineLength(4) : 0) + - IHexRecord::getLineLength(0); - if (Error E = Buf.allocate(TotalSize)) - return E; - return Error::success(); -} - -template class ELFBuilder<ELF64LE>; -template class ELFBuilder<ELF64BE>; -template class ELFBuilder<ELF32LE>; -template class ELFBuilder<ELF32BE>; - -template class ELFWriter<ELF64LE>; -template class ELFWriter<ELF64BE>; -template class ELFWriter<ELF32LE>; -template class ELFWriter<ELF32BE>; - -} // end namespace elf -} // end namespace objcopy -} // end namespace llvm + + // We need space to write section records + StartAddress record + // (if start adress is not zero) + EndOfFile record. + TotalSize = LengthCalc.getBufferOffset() + + (Obj.Entry ? IHexRecord::getLineLength(4) : 0) + + IHexRecord::getLineLength(0); + if (Error E = Buf.allocate(TotalSize)) + return E; + return Error::success(); +} + +template class ELFBuilder<ELF64LE>; +template class ELFBuilder<ELF64BE>; +template class ELFBuilder<ELF32LE>; +template class ELFBuilder<ELF32BE>; + +template class ELFWriter<ELF64LE>; +template class ELFWriter<ELF64BE>; +template class ELFWriter<ELF32LE>; +template class ELFWriter<ELF32BE>; + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h index 0205c2d4f3..8a0ceb67d7 100644 --- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h +++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h @@ -1,79 +1,79 @@ -//===- Object.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_OBJECT_H -#define LLVM_TOOLS_OBJCOPY_OBJECT_H - -#include "Buffer.h" -#include "CopyConfig.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/MC/StringTableBuilder.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileOutputBuffer.h" -#include <cstddef> -#include <cstdint> -#include <functional> -#include <memory> -#include <set> -#include <vector> - -namespace llvm { -enum class DebugCompressionType; -namespace objcopy { -namespace elf { - -class SectionBase; -class Section; -class OwnedDataSection; -class StringTableSection; -class SymbolTableSection; -class RelocationSection; -class DynamicRelocationSection; -class GnuDebugLinkSection; -class GroupSection; -class SectionIndexSection; -class CompressedSection; -class DecompressedSection; -class Segment; -class Object; -struct Symbol; - -class SectionTableRef { - MutableArrayRef<std::unique_ptr<SectionBase>> Sections; - -public: - using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>; - - explicit SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs) - : Sections(Secs) {} - SectionTableRef(const SectionTableRef &) = default; - - iterator begin() const { return iterator(Sections.data()); } - iterator end() const { return iterator(Sections.data() + Sections.size()); } - size_t size() const { return Sections.size(); } - +//===- Object.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_OBJECT_H +#define LLVM_TOOLS_OBJCOPY_OBJECT_H + +#include "Buffer.h" +#include "CopyConfig.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileOutputBuffer.h" +#include <cstddef> +#include <cstdint> +#include <functional> +#include <memory> +#include <set> +#include <vector> + +namespace llvm { +enum class DebugCompressionType; +namespace objcopy { +namespace elf { + +class SectionBase; +class Section; +class OwnedDataSection; +class StringTableSection; +class SymbolTableSection; +class RelocationSection; +class DynamicRelocationSection; +class GnuDebugLinkSection; +class GroupSection; +class SectionIndexSection; +class CompressedSection; +class DecompressedSection; +class Segment; +class Object; +struct Symbol; + +class SectionTableRef { + MutableArrayRef<std::unique_ptr<SectionBase>> Sections; + +public: + using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>; + + explicit SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs) + : Sections(Secs) {} + SectionTableRef(const SectionTableRef &) = default; + + iterator begin() const { return iterator(Sections.data()); } + iterator end() const { return iterator(Sections.data() + Sections.size()); } + size_t size() const { return Sections.size(); } + Expected<SectionBase *> getSection(uint32_t Index, Twine ErrMsg); - - template <class T> + + template <class T> Expected<T *> getSectionOfType(uint32_t Index, Twine IndexErrMsg, Twine TypeErrMsg); -}; - -enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE }; - -class SectionVisitor { -public: - virtual ~SectionVisitor() = default; - +}; + +enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE }; + +class SectionVisitor { +public: + virtual ~SectionVisitor() = default; + virtual Error visit(const Section &Sec) = 0; virtual Error visit(const OwnedDataSection &Sec) = 0; virtual Error visit(const StringTableSection &Sec) = 0; @@ -85,12 +85,12 @@ public: virtual Error visit(const SectionIndexSection &Sec) = 0; virtual Error visit(const CompressedSection &Sec) = 0; virtual Error visit(const DecompressedSection &Sec) = 0; -}; - -class MutableSectionVisitor { -public: - virtual ~MutableSectionVisitor() = default; - +}; + +class MutableSectionVisitor { +public: + virtual ~MutableSectionVisitor() = default; + virtual Error visit(Section &Sec) = 0; virtual Error visit(OwnedDataSection &Sec) = 0; virtual Error visit(StringTableSection &Sec) = 0; @@ -102,15 +102,15 @@ public: virtual Error visit(SectionIndexSection &Sec) = 0; virtual Error visit(CompressedSection &Sec) = 0; virtual Error visit(DecompressedSection &Sec) = 0; -}; - -class SectionWriter : public SectionVisitor { -protected: - Buffer &Out; - -public: - virtual ~SectionWriter() = default; - +}; + +class SectionWriter : public SectionVisitor { +protected: + Buffer &Out; + +public: + virtual ~SectionWriter() = default; + Error visit(const Section &Sec) override; Error visit(const OwnedDataSection &Sec) override; Error visit(const StringTableSection &Sec) override; @@ -122,19 +122,19 @@ public: virtual Error visit(const SectionIndexSection &Sec) override = 0; virtual Error visit(const CompressedSection &Sec) override = 0; virtual Error visit(const DecompressedSection &Sec) override = 0; - - explicit SectionWriter(Buffer &Buf) : Out(Buf) {} -}; - -template <class ELFT> class ELFSectionWriter : public SectionWriter { -private: - using Elf_Word = typename ELFT::Word; - using Elf_Rel = typename ELFT::Rel; - using Elf_Rela = typename ELFT::Rela; - using Elf_Sym = typename ELFT::Sym; - -public: - virtual ~ELFSectionWriter() {} + + explicit SectionWriter(Buffer &Buf) : Out(Buf) {} +}; + +template <class ELFT> class ELFSectionWriter : public SectionWriter { +private: + using Elf_Word = typename ELFT::Word; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Sym = typename ELFT::Sym; + +public: + virtual ~ELFSectionWriter() {} Error visit(const SymbolTableSection &Sec) override; Error visit(const RelocationSection &Sec) override; Error visit(const GnuDebugLinkSection &Sec) override; @@ -142,19 +142,19 @@ public: Error visit(const SectionIndexSection &Sec) override; Error visit(const CompressedSection &Sec) override; Error visit(const DecompressedSection &Sec) override; - - explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {} -}; - -template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor { -private: - using Elf_Rel = typename ELFT::Rel; - using Elf_Rela = typename ELFT::Rela; - using Elf_Sym = typename ELFT::Sym; - using Elf_Word = typename ELFT::Word; - using Elf_Xword = typename ELFT::Xword; - -public: + + explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {} +}; + +template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor { +private: + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Sym = typename ELFT::Sym; + using Elf_Word = typename ELFT::Word; + using Elf_Xword = typename ELFT::Xword; + +public: Error visit(Section &Sec) override; Error visit(OwnedDataSection &Sec) override; Error visit(StringTableSection &Sec) override; @@ -166,19 +166,19 @@ public: Error visit(SectionIndexSection &Sec) override; Error visit(CompressedSection &Sec) override; Error visit(DecompressedSection &Sec) override; -}; - -#define MAKE_SEC_WRITER_FRIEND \ - friend class SectionWriter; \ - friend class IHexSectionWriterBase; \ - friend class IHexSectionWriter; \ - template <class ELFT> friend class ELFSectionWriter; \ - template <class ELFT> friend class ELFSectionSizer; - -class BinarySectionWriter : public SectionWriter { -public: - virtual ~BinarySectionWriter() {} - +}; + +#define MAKE_SEC_WRITER_FRIEND \ + friend class SectionWriter; \ + friend class IHexSectionWriterBase; \ + friend class IHexSectionWriter; \ + template <class ELFT> friend class ELFSectionWriter; \ + template <class ELFT> friend class ELFSectionSizer; + +class BinarySectionWriter : public SectionWriter { +public: + virtual ~BinarySectionWriter() {} + Error visit(const SymbolTableSection &Sec) override; Error visit(const RelocationSection &Sec) override; Error visit(const GnuDebugLinkSection &Sec) override; @@ -186,766 +186,766 @@ public: Error visit(const SectionIndexSection &Sec) override; Error visit(const CompressedSection &Sec) override; Error visit(const DecompressedSection &Sec) override; - - explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {} -}; - -using IHexLineData = SmallVector<char, 64>; - -struct IHexRecord { - // Memory address of the record. - uint16_t Addr; - // Record type (see below). - uint16_t Type; - // Record data in hexadecimal form. - StringRef HexData; - - // Helper method to get file length of the record - // including newline character - static size_t getLength(size_t DataSize) { - // :LLAAAATT[DD...DD]CC' - return DataSize * 2 + 11; - } - - // Gets length of line in a file (getLength + CRLF). - static size_t getLineLength(size_t DataSize) { - return getLength(DataSize) + 2; - } - - // Given type, address and data returns line which can - // be written to output file. - static IHexLineData getLine(uint8_t Type, uint16_t Addr, - ArrayRef<uint8_t> Data); - - // Parses the line and returns record if possible. - // Line should be trimmed from whitespace characters. - static Expected<IHexRecord> parse(StringRef Line); - - // Calculates checksum of stringified record representation - // S must NOT contain leading ':' and trailing whitespace - // characters - static uint8_t getChecksum(StringRef S); - - enum Type { - // Contains data and a 16-bit starting address for the data. - // The byte count specifies number of data bytes in the record. - Data = 0, - // Must occur exactly once per file in the last line of the file. - // The data field is empty (thus byte count is 00) and the address - // field is typically 0000. - EndOfFile = 1, - // The data field contains a 16-bit segment base address (thus byte - // count is always 02) compatible with 80x86 real mode addressing. - // The address field (typically 0000) is ignored. The segment address - // from the most recent 02 record is multiplied by 16 and added to each - // subsequent data record address to form the physical starting address - // for the data. This allows addressing up to one megabyte of address - // space. - SegmentAddr = 2, - // or 80x86 processors, specifies the initial content of the CS:IP - // registers. The address field is 0000, the byte count is always 04, - // the first two data bytes are the CS value, the latter two are the - // IP value. - StartAddr80x86 = 3, - // Allows for 32 bit addressing (up to 4GiB). The record's address field - // is ignored (typically 0000) and its byte count is always 02. The two - // data bytes (big endian) specify the upper 16 bits of the 32 bit - // absolute address for all subsequent type 00 records - ExtendedAddr = 4, - // The address field is 0000 (not used) and the byte count is always 04. - // The four data bytes represent a 32-bit address value. In the case of - // 80386 and higher CPUs, this address is loaded into the EIP register. - StartAddr = 5, - // We have no other valid types - InvalidType = 6 - }; -}; - -// Base class for IHexSectionWriter. This class implements writing algorithm, -// but doesn't actually write records. It is used for output buffer size -// calculation in IHexWriter::finalize. -class IHexSectionWriterBase : public BinarySectionWriter { - // 20-bit segment address - uint32_t SegmentAddr = 0; - // Extended linear address - uint32_t BaseAddr = 0; - - // Write segment address corresponding to 'Addr' - uint64_t writeSegmentAddr(uint64_t Addr); - // Write extended linear (base) address corresponding to 'Addr' - uint64_t writeBaseAddr(uint64_t Addr); - -protected: - // Offset in the output buffer - uint64_t Offset = 0; - - void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data); - virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data); - -public: - explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {} - - uint64_t getBufferOffset() const { return Offset; } + + explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {} +}; + +using IHexLineData = SmallVector<char, 64>; + +struct IHexRecord { + // Memory address of the record. + uint16_t Addr; + // Record type (see below). + uint16_t Type; + // Record data in hexadecimal form. + StringRef HexData; + + // Helper method to get file length of the record + // including newline character + static size_t getLength(size_t DataSize) { + // :LLAAAATT[DD...DD]CC' + return DataSize * 2 + 11; + } + + // Gets length of line in a file (getLength + CRLF). + static size_t getLineLength(size_t DataSize) { + return getLength(DataSize) + 2; + } + + // Given type, address and data returns line which can + // be written to output file. + static IHexLineData getLine(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data); + + // Parses the line and returns record if possible. + // Line should be trimmed from whitespace characters. + static Expected<IHexRecord> parse(StringRef Line); + + // Calculates checksum of stringified record representation + // S must NOT contain leading ':' and trailing whitespace + // characters + static uint8_t getChecksum(StringRef S); + + enum Type { + // Contains data and a 16-bit starting address for the data. + // The byte count specifies number of data bytes in the record. + Data = 0, + // Must occur exactly once per file in the last line of the file. + // The data field is empty (thus byte count is 00) and the address + // field is typically 0000. + EndOfFile = 1, + // The data field contains a 16-bit segment base address (thus byte + // count is always 02) compatible with 80x86 real mode addressing. + // The address field (typically 0000) is ignored. The segment address + // from the most recent 02 record is multiplied by 16 and added to each + // subsequent data record address to form the physical starting address + // for the data. This allows addressing up to one megabyte of address + // space. + SegmentAddr = 2, + // or 80x86 processors, specifies the initial content of the CS:IP + // registers. The address field is 0000, the byte count is always 04, + // the first two data bytes are the CS value, the latter two are the + // IP value. + StartAddr80x86 = 3, + // Allows for 32 bit addressing (up to 4GiB). The record's address field + // is ignored (typically 0000) and its byte count is always 02. The two + // data bytes (big endian) specify the upper 16 bits of the 32 bit + // absolute address for all subsequent type 00 records + ExtendedAddr = 4, + // The address field is 0000 (not used) and the byte count is always 04. + // The four data bytes represent a 32-bit address value. In the case of + // 80386 and higher CPUs, this address is loaded into the EIP register. + StartAddr = 5, + // We have no other valid types + InvalidType = 6 + }; +}; + +// Base class for IHexSectionWriter. This class implements writing algorithm, +// but doesn't actually write records. It is used for output buffer size +// calculation in IHexWriter::finalize. +class IHexSectionWriterBase : public BinarySectionWriter { + // 20-bit segment address + uint32_t SegmentAddr = 0; + // Extended linear address + uint32_t BaseAddr = 0; + + // Write segment address corresponding to 'Addr' + uint64_t writeSegmentAddr(uint64_t Addr); + // Write extended linear (base) address corresponding to 'Addr' + uint64_t writeBaseAddr(uint64_t Addr); + +protected: + // Offset in the output buffer + uint64_t Offset = 0; + + void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data); + virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data); + +public: + explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {} + + uint64_t getBufferOffset() const { return Offset; } Error visit(const Section &Sec) final; Error visit(const OwnedDataSection &Sec) final; Error visit(const StringTableSection &Sec) override; Error visit(const DynamicRelocationSection &Sec) final; - using BinarySectionWriter::visit; -}; - -// Real IHEX section writer -class IHexSectionWriter : public IHexSectionWriterBase { -public: - IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {} - - void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override; + using BinarySectionWriter::visit; +}; + +// Real IHEX section writer +class IHexSectionWriter : public IHexSectionWriterBase { +public: + IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {} + + void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override; Error visit(const StringTableSection &Sec) override; -}; - -class Writer { -protected: - Object &Obj; - Buffer &Buf; - -public: - virtual ~Writer(); - virtual Error finalize() = 0; - virtual Error write() = 0; - - Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {} -}; - -template <class ELFT> class ELFWriter : public Writer { -private: - using Elf_Addr = typename ELFT::Addr; - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Phdr = typename ELFT::Phdr; - using Elf_Ehdr = typename ELFT::Ehdr; - - void initEhdrSegment(); - - void writeEhdr(); - void writePhdr(const Segment &Seg); - void writeShdr(const SectionBase &Sec); - - void writePhdrs(); - void writeShdrs(); +}; + +class Writer { +protected: + Object &Obj; + Buffer &Buf; + +public: + virtual ~Writer(); + virtual Error finalize() = 0; + virtual Error write() = 0; + + Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {} +}; + +template <class ELFT> class ELFWriter : public Writer { +private: + using Elf_Addr = typename ELFT::Addr; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Phdr = typename ELFT::Phdr; + using Elf_Ehdr = typename ELFT::Ehdr; + + void initEhdrSegment(); + + void writeEhdr(); + void writePhdr(const Segment &Seg); + void writeShdr(const SectionBase &Sec); + + void writePhdrs(); + void writeShdrs(); Error writeSectionData(); - void writeSegmentData(); - - void assignOffsets(); - - std::unique_ptr<ELFSectionWriter<ELFT>> SecWriter; - - size_t totalSize() const; - -public: - virtual ~ELFWriter() {} - bool WriteSectionHeaders; - - // For --only-keep-debug, select an alternative section/segment layout - // algorithm. - bool OnlyKeepDebug; - - Error finalize() override; - Error write() override; - ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug); -}; - -class BinaryWriter : public Writer { -private: - std::unique_ptr<BinarySectionWriter> SecWriter; - - uint64_t TotalSize = 0; - -public: - ~BinaryWriter() {} - Error finalize() override; - Error write() override; - BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} -}; - -class IHexWriter : public Writer { - struct SectionCompare { - bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const; - }; - - std::set<const SectionBase *, SectionCompare> Sections; - size_t TotalSize = 0; - - Error checkSection(const SectionBase &Sec); - uint64_t writeEntryPointRecord(uint8_t *Buf); - uint64_t writeEndOfFileRecord(uint8_t *Buf); - -public: - ~IHexWriter() {} - Error finalize() override; - Error write() override; - IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} -}; - -class SectionBase { -public: - std::string Name; - Segment *ParentSegment = nullptr; - uint64_t HeaderOffset = 0; - uint32_t Index = 0; - + void writeSegmentData(); + + void assignOffsets(); + + std::unique_ptr<ELFSectionWriter<ELFT>> SecWriter; + + size_t totalSize() const; + +public: + virtual ~ELFWriter() {} + bool WriteSectionHeaders; + + // For --only-keep-debug, select an alternative section/segment layout + // algorithm. + bool OnlyKeepDebug; + + Error finalize() override; + Error write() override; + ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug); +}; + +class BinaryWriter : public Writer { +private: + std::unique_ptr<BinarySectionWriter> SecWriter; + + uint64_t TotalSize = 0; + +public: + ~BinaryWriter() {} + Error finalize() override; + Error write() override; + BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} +}; + +class IHexWriter : public Writer { + struct SectionCompare { + bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const; + }; + + std::set<const SectionBase *, SectionCompare> Sections; + size_t TotalSize = 0; + + Error checkSection(const SectionBase &Sec); + uint64_t writeEntryPointRecord(uint8_t *Buf); + uint64_t writeEndOfFileRecord(uint8_t *Buf); + +public: + ~IHexWriter() {} + Error finalize() override; + Error write() override; + IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} +}; + +class SectionBase { +public: + std::string Name; + Segment *ParentSegment = nullptr; + uint64_t HeaderOffset = 0; + uint32_t Index = 0; + uint32_t OriginalIndex = 0; - uint64_t OriginalFlags = 0; - uint64_t OriginalType = ELF::SHT_NULL; - uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); - - uint64_t Addr = 0; - uint64_t Align = 1; - uint32_t EntrySize = 0; - uint64_t Flags = 0; - uint64_t Info = 0; - uint64_t Link = ELF::SHN_UNDEF; - uint64_t NameIndex = 0; - uint64_t Offset = 0; - uint64_t Size = 0; - uint64_t Type = ELF::SHT_NULL; - ArrayRef<uint8_t> OriginalData; + uint64_t OriginalFlags = 0; + uint64_t OriginalType = ELF::SHT_NULL; + uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); + + uint64_t Addr = 0; + uint64_t Align = 1; + uint32_t EntrySize = 0; + uint64_t Flags = 0; + uint64_t Info = 0; + uint64_t Link = ELF::SHN_UNDEF; + uint64_t NameIndex = 0; + uint64_t Offset = 0; + uint64_t Size = 0; + uint64_t Type = ELF::SHT_NULL; + ArrayRef<uint8_t> OriginalData; bool HasSymbol = false; - - SectionBase() = default; - SectionBase(const SectionBase &) = default; - - virtual ~SectionBase() = default; - + + SectionBase() = default; + SectionBase(const SectionBase &) = default; + + virtual ~SectionBase() = default; + virtual Error initialize(SectionTableRef SecTable); - virtual void finalize(); - // Remove references to these sections. The list of sections must be sorted. - virtual Error - removeSectionReferences(bool AllowBrokenLinks, - function_ref<bool(const SectionBase *)> ToRemove); - virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); + virtual void finalize(); + // Remove references to these sections. The list of sections must be sorted. + virtual Error + removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove); + virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); virtual Error accept(SectionVisitor &Visitor) const = 0; virtual Error accept(MutableSectionVisitor &Visitor) = 0; - virtual void markSymbols(); - virtual void - replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &); - // Notify the section that it is subject to removal. - virtual void onRemove(); -}; - -class Segment { -private: - struct SectionCompare { - bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const { - // Some sections might have the same address if one of them is empty. To - // fix this we can use the lexicographic ordering on ->Addr and the + virtual void markSymbols(); + virtual void + replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &); + // Notify the section that it is subject to removal. + virtual void onRemove(); +}; + +class Segment { +private: + struct SectionCompare { + bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const { + // Some sections might have the same address if one of them is empty. To + // fix this we can use the lexicographic ordering on ->Addr and the // original index. - if (Lhs->OriginalOffset == Rhs->OriginalOffset) + if (Lhs->OriginalOffset == Rhs->OriginalOffset) return Lhs->OriginalIndex < Rhs->OriginalIndex; - return Lhs->OriginalOffset < Rhs->OriginalOffset; - } - }; - -public: - uint32_t Type = 0; - uint32_t Flags = 0; - uint64_t Offset = 0; - uint64_t VAddr = 0; - uint64_t PAddr = 0; - uint64_t FileSize = 0; - uint64_t MemSize = 0; - uint64_t Align = 0; - - uint32_t Index = 0; - uint64_t OriginalOffset = 0; - Segment *ParentSegment = nullptr; - ArrayRef<uint8_t> Contents; - std::set<const SectionBase *, SectionCompare> Sections; - - explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} - Segment() = default; - - const SectionBase *firstSection() const { - if (!Sections.empty()) - return *Sections.begin(); - return nullptr; - } - - void removeSection(const SectionBase *Sec) { Sections.erase(Sec); } - void addSection(const SectionBase *Sec) { Sections.insert(Sec); } - - ArrayRef<uint8_t> getContents() const { return Contents; } -}; - -class Section : public SectionBase { - MAKE_SEC_WRITER_FRIEND - - ArrayRef<uint8_t> Contents; - SectionBase *LinkSection = nullptr; - -public: - explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {} - + return Lhs->OriginalOffset < Rhs->OriginalOffset; + } + }; + +public: + uint32_t Type = 0; + uint32_t Flags = 0; + uint64_t Offset = 0; + uint64_t VAddr = 0; + uint64_t PAddr = 0; + uint64_t FileSize = 0; + uint64_t MemSize = 0; + uint64_t Align = 0; + + uint32_t Index = 0; + uint64_t OriginalOffset = 0; + Segment *ParentSegment = nullptr; + ArrayRef<uint8_t> Contents; + std::set<const SectionBase *, SectionCompare> Sections; + + explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} + Segment() = default; + + const SectionBase *firstSection() const { + if (!Sections.empty()) + return *Sections.begin(); + return nullptr; + } + + void removeSection(const SectionBase *Sec) { Sections.erase(Sec); } + void addSection(const SectionBase *Sec) { Sections.insert(Sec); } + + ArrayRef<uint8_t> getContents() const { return Contents; } +}; + +class Section : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + ArrayRef<uint8_t> Contents; + SectionBase *LinkSection = nullptr; + +public: + explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {} + Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; Error removeSectionReferences( bool AllowBrokenLinks, - function_ref<bool(const SectionBase *)> ToRemove) override; + function_ref<bool(const SectionBase *)> ToRemove) override; Error initialize(SectionTableRef SecTable) override; - void finalize() override; -}; - -class OwnedDataSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - - std::vector<uint8_t> Data; - -public: - OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data) - : Data(std::begin(Data), std::end(Data)) { - Name = SecName.str(); - Type = OriginalType = ELF::SHT_PROGBITS; - Size = Data.size(); - OriginalOffset = std::numeric_limits<uint64_t>::max(); - } - - OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags, - uint64_t SecOff) { - Name = SecName.str(); - Type = OriginalType = ELF::SHT_PROGBITS; - Addr = SecAddr; - Flags = OriginalFlags = SecFlags; - OriginalOffset = SecOff; - } - - void appendHexData(StringRef HexData); + void finalize() override; +}; + +class OwnedDataSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + std::vector<uint8_t> Data; + +public: + OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data) + : Data(std::begin(Data), std::end(Data)) { + Name = SecName.str(); + Type = OriginalType = ELF::SHT_PROGBITS; + Size = Data.size(); + OriginalOffset = std::numeric_limits<uint64_t>::max(); + } + + OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags, + uint64_t SecOff) { + Name = SecName.str(); + Type = OriginalType = ELF::SHT_PROGBITS; + Addr = SecAddr; + Flags = OriginalFlags = SecFlags; + OriginalOffset = SecOff; + } + + void appendHexData(StringRef HexData); Error accept(SectionVisitor &Sec) const override; Error accept(MutableSectionVisitor &Visitor) override; -}; - -class CompressedSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - - DebugCompressionType CompressionType; - uint64_t DecompressedSize; - uint64_t DecompressedAlign; - SmallVector<char, 128> CompressedData; - -public: +}; + +class CompressedSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + DebugCompressionType CompressionType; + uint64_t DecompressedSize; + uint64_t DecompressedAlign; + SmallVector<char, 128> CompressedData; + +public: static Expected<CompressedSection> create(const SectionBase &Sec, DebugCompressionType CompressionType); static Expected<CompressedSection> create(ArrayRef<uint8_t> CompressedData, uint64_t DecompressedSize, uint64_t DecompressedAlign); - - uint64_t getDecompressedSize() const { return DecompressedSize; } - uint64_t getDecompressedAlign() const { return DecompressedAlign; } - + + uint64_t getDecompressedSize() const { return DecompressedSize; } + uint64_t getDecompressedAlign() const { return DecompressedAlign; } + Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; - - static bool classof(const SectionBase *S) { - return (S->OriginalFlags & ELF::SHF_COMPRESSED) || - (StringRef(S->Name).startswith(".zdebug")); - } + + static bool classof(const SectionBase *S) { + return (S->OriginalFlags & ELF::SHF_COMPRESSED) || + (StringRef(S->Name).startswith(".zdebug")); + } private: CompressedSection(const SectionBase &Sec, DebugCompressionType CompressionType, Error &Err); CompressedSection(ArrayRef<uint8_t> CompressedData, uint64_t DecompressedSize, uint64_t DecompressedAlign); -}; - -class DecompressedSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - -public: - explicit DecompressedSection(const CompressedSection &Sec) - : SectionBase(Sec) { - Size = Sec.getDecompressedSize(); - Align = Sec.getDecompressedAlign(); - Flags = OriginalFlags = (Flags & ~ELF::SHF_COMPRESSED); - if (StringRef(Name).startswith(".zdebug")) - Name = "." + Name.substr(2); - } - +}; + +class DecompressedSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + +public: + explicit DecompressedSection(const CompressedSection &Sec) + : SectionBase(Sec) { + Size = Sec.getDecompressedSize(); + Align = Sec.getDecompressedAlign(); + Flags = OriginalFlags = (Flags & ~ELF::SHF_COMPRESSED); + if (StringRef(Name).startswith(".zdebug")) + Name = "." + Name.substr(2); + } + Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; -}; - -// There are two types of string tables that can exist, dynamic and not dynamic. -// In the dynamic case the string table is allocated. Changing a dynamic string -// table would mean altering virtual addresses and thus the memory image. So -// dynamic string tables should not have an interface to modify them or -// reconstruct them. This type lets us reconstruct a string table. To avoid -// this class being used for dynamic string tables (which has happened) the -// classof method checks that the particular instance is not allocated. This -// then agrees with the makeSection method used to construct most sections. -class StringTableSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - - StringTableBuilder StrTabBuilder; - -public: - StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) { - Type = OriginalType = ELF::SHT_STRTAB; - } - - void addString(StringRef Name); - uint32_t findIndex(StringRef Name) const; - void prepareForLayout(); +}; + +// There are two types of string tables that can exist, dynamic and not dynamic. +// In the dynamic case the string table is allocated. Changing a dynamic string +// table would mean altering virtual addresses and thus the memory image. So +// dynamic string tables should not have an interface to modify them or +// reconstruct them. This type lets us reconstruct a string table. To avoid +// this class being used for dynamic string tables (which has happened) the +// classof method checks that the particular instance is not allocated. This +// then agrees with the makeSection method used to construct most sections. +class StringTableSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + StringTableBuilder StrTabBuilder; + +public: + StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) { + Type = OriginalType = ELF::SHT_STRTAB; + } + + void addString(StringRef Name); + uint32_t findIndex(StringRef Name) const; + void prepareForLayout(); Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; - - static bool classof(const SectionBase *S) { - if (S->OriginalFlags & ELF::SHF_ALLOC) - return false; - return S->OriginalType == ELF::SHT_STRTAB; - } -}; - -// Symbols have a st_shndx field that normally stores an index but occasionally -// stores a different special value. This enum keeps track of what the st_shndx -// field means. Most of the values are just copies of the special SHN_* values. -// SYMBOL_SIMPLE_INDEX means that the st_shndx is just an index of a section. -enum SymbolShndxType { - SYMBOL_SIMPLE_INDEX = 0, - SYMBOL_ABS = ELF::SHN_ABS, - SYMBOL_COMMON = ELF::SHN_COMMON, - SYMBOL_LOPROC = ELF::SHN_LOPROC, - SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS, - SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON, - SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2, - SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4, - SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8, - SYMBOL_HIPROC = ELF::SHN_HIPROC, - SYMBOL_LOOS = ELF::SHN_LOOS, - SYMBOL_HIOS = ELF::SHN_HIOS, - SYMBOL_XINDEX = ELF::SHN_XINDEX, -}; - -struct Symbol { - uint8_t Binding; - SectionBase *DefinedIn = nullptr; - SymbolShndxType ShndxType; - uint32_t Index; - std::string Name; - uint32_t NameIndex; - uint64_t Size; - uint8_t Type; - uint64_t Value; - uint8_t Visibility; - bool Referenced = false; - - uint16_t getShndx() const; - bool isCommon() const; -}; - -class SectionIndexSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - -private: - std::vector<uint32_t> Indexes; - SymbolTableSection *Symbols = nullptr; - -public: - virtual ~SectionIndexSection() {} - void addIndex(uint32_t Index) { - assert(Size > 0); + + static bool classof(const SectionBase *S) { + if (S->OriginalFlags & ELF::SHF_ALLOC) + return false; + return S->OriginalType == ELF::SHT_STRTAB; + } +}; + +// Symbols have a st_shndx field that normally stores an index but occasionally +// stores a different special value. This enum keeps track of what the st_shndx +// field means. Most of the values are just copies of the special SHN_* values. +// SYMBOL_SIMPLE_INDEX means that the st_shndx is just an index of a section. +enum SymbolShndxType { + SYMBOL_SIMPLE_INDEX = 0, + SYMBOL_ABS = ELF::SHN_ABS, + SYMBOL_COMMON = ELF::SHN_COMMON, + SYMBOL_LOPROC = ELF::SHN_LOPROC, + SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS, + SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON, + SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2, + SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4, + SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8, + SYMBOL_HIPROC = ELF::SHN_HIPROC, + SYMBOL_LOOS = ELF::SHN_LOOS, + SYMBOL_HIOS = ELF::SHN_HIOS, + SYMBOL_XINDEX = ELF::SHN_XINDEX, +}; + +struct Symbol { + uint8_t Binding; + SectionBase *DefinedIn = nullptr; + SymbolShndxType ShndxType; + uint32_t Index; + std::string Name; + uint32_t NameIndex; + uint64_t Size; + uint8_t Type; + uint64_t Value; + uint8_t Visibility; + bool Referenced = false; + + uint16_t getShndx() const; + bool isCommon() const; +}; + +class SectionIndexSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + +private: + std::vector<uint32_t> Indexes; + SymbolTableSection *Symbols = nullptr; + +public: + virtual ~SectionIndexSection() {} + void addIndex(uint32_t Index) { + assert(Size > 0); Indexes.push_back(Index); + } + + void reserve(size_t NumSymbols) { + Indexes.reserve(NumSymbols); + Size = NumSymbols * 4; } - - void reserve(size_t NumSymbols) { - Indexes.reserve(NumSymbols); - Size = NumSymbols * 4; - } - void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; } + void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; } Error initialize(SectionTableRef SecTable) override; - void finalize() override; + void finalize() override; Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; - - SectionIndexSection() { - Name = ".symtab_shndx"; - Align = 4; - EntrySize = 4; - Type = OriginalType = ELF::SHT_SYMTAB_SHNDX; - } -}; - -class SymbolTableSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - - void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } - void assignIndices(); - -protected: - std::vector<std::unique_ptr<Symbol>> Symbols; - StringTableSection *SymbolNames = nullptr; - SectionIndexSection *SectionIndexTable = nullptr; - - using SymPtr = std::unique_ptr<Symbol>; - -public: - SymbolTableSection() { Type = OriginalType = ELF::SHT_SYMTAB; } - - void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, - uint64_t Value, uint8_t Visibility, uint16_t Shndx, - uint64_t SymbolSize); - void prepareForLayout(); - // An 'empty' symbol table still contains a null symbol. - bool empty() const { return Symbols.size() == 1; } - void setShndxTable(SectionIndexSection *ShndxTable) { - SectionIndexTable = ShndxTable; - } - const SectionIndexSection *getShndxTable() const { return SectionIndexTable; } - void fillShndxTable(); - const SectionBase *getStrTab() const { return SymbolNames; } + + SectionIndexSection() { + Name = ".symtab_shndx"; + Align = 4; + EntrySize = 4; + Type = OriginalType = ELF::SHT_SYMTAB_SHNDX; + } +}; + +class SymbolTableSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } + void assignIndices(); + +protected: + std::vector<std::unique_ptr<Symbol>> Symbols; + StringTableSection *SymbolNames = nullptr; + SectionIndexSection *SectionIndexTable = nullptr; + + using SymPtr = std::unique_ptr<Symbol>; + +public: + SymbolTableSection() { Type = OriginalType = ELF::SHT_SYMTAB; } + + void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, + uint64_t Value, uint8_t Visibility, uint16_t Shndx, + uint64_t SymbolSize); + void prepareForLayout(); + // An 'empty' symbol table still contains a null symbol. + bool empty() const { return Symbols.size() == 1; } + void setShndxTable(SectionIndexSection *ShndxTable) { + SectionIndexTable = ShndxTable; + } + const SectionIndexSection *getShndxTable() const { return SectionIndexTable; } + void fillShndxTable(); + const SectionBase *getStrTab() const { return SymbolNames; } Expected<const Symbol *> getSymbolByIndex(uint32_t Index) const; Expected<Symbol *> getSymbolByIndex(uint32_t Index); - void updateSymbols(function_ref<void(Symbol &)> Callable); - + void updateSymbols(function_ref<void(Symbol &)> Callable); + Error removeSectionReferences( bool AllowBrokenLinks, - function_ref<bool(const SectionBase *)> ToRemove) override; + function_ref<bool(const SectionBase *)> ToRemove) override; Error initialize(SectionTableRef SecTable) override; - void finalize() override; + void finalize() override; Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; - Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; - void replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &FromTo) override; - - static bool classof(const SectionBase *S) { - return S->OriginalType == ELF::SHT_SYMTAB; - } -}; - -struct Relocation { - Symbol *RelocSymbol = nullptr; - uint64_t Offset; - uint64_t Addend; - uint32_t Type; -}; - -// All relocation sections denote relocations to apply to another section. -// However, some relocation sections use a dynamic symbol table and others use -// a regular symbol table. Because the types of the two symbol tables differ in -// our system (because they should behave differently) we can't uniformly -// represent all relocations with the same base class if we expose an interface -// that mentions the symbol table type. So we split the two base types into two -// different classes, one which handles the section the relocation is applied to -// and another which handles the symbol table type. The symbol table type is -// taken as a type parameter to the class (see RelocSectionWithSymtabBase). -class RelocationSectionBase : public SectionBase { -protected: - SectionBase *SecToApplyRel = nullptr; - -public: - const SectionBase *getSection() const { return SecToApplyRel; } - void setSection(SectionBase *Sec) { SecToApplyRel = Sec; } - - static bool classof(const SectionBase *S) { - return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; - } -}; - -// Takes the symbol table type to use as a parameter so that we can deduplicate -// that code between the two symbol table types. -template <class SymTabType> -class RelocSectionWithSymtabBase : public RelocationSectionBase { - void setSymTab(SymTabType *SymTab) { Symbols = SymTab; } - -protected: - RelocSectionWithSymtabBase() = default; - - SymTabType *Symbols = nullptr; - -public: + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + + static bool classof(const SectionBase *S) { + return S->OriginalType == ELF::SHT_SYMTAB; + } +}; + +struct Relocation { + Symbol *RelocSymbol = nullptr; + uint64_t Offset; + uint64_t Addend; + uint32_t Type; +}; + +// All relocation sections denote relocations to apply to another section. +// However, some relocation sections use a dynamic symbol table and others use +// a regular symbol table. Because the types of the two symbol tables differ in +// our system (because they should behave differently) we can't uniformly +// represent all relocations with the same base class if we expose an interface +// that mentions the symbol table type. So we split the two base types into two +// different classes, one which handles the section the relocation is applied to +// and another which handles the symbol table type. The symbol table type is +// taken as a type parameter to the class (see RelocSectionWithSymtabBase). +class RelocationSectionBase : public SectionBase { +protected: + SectionBase *SecToApplyRel = nullptr; + +public: + const SectionBase *getSection() const { return SecToApplyRel; } + void setSection(SectionBase *Sec) { SecToApplyRel = Sec; } + + static bool classof(const SectionBase *S) { + return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; + } +}; + +// Takes the symbol table type to use as a parameter so that we can deduplicate +// that code between the two symbol table types. +template <class SymTabType> +class RelocSectionWithSymtabBase : public RelocationSectionBase { + void setSymTab(SymTabType *SymTab) { Symbols = SymTab; } + +protected: + RelocSectionWithSymtabBase() = default; + + SymTabType *Symbols = nullptr; + +public: Error initialize(SectionTableRef SecTable) override; - void finalize() override; -}; - -class RelocationSection - : public RelocSectionWithSymtabBase<SymbolTableSection> { - MAKE_SEC_WRITER_FRIEND - - std::vector<Relocation> Relocations; - -public: - void addRelocation(Relocation Rel) { Relocations.push_back(Rel); } + void finalize() override; +}; + +class RelocationSection + : public RelocSectionWithSymtabBase<SymbolTableSection> { + MAKE_SEC_WRITER_FRIEND + + std::vector<Relocation> Relocations; + +public: + void addRelocation(Relocation Rel) { Relocations.push_back(Rel); } Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; Error removeSectionReferences( bool AllowBrokenLinks, - function_ref<bool(const SectionBase *)> ToRemove) override; - Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; - void markSymbols() override; - void replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &FromTo) override; - - static bool classof(const SectionBase *S) { - if (S->OriginalFlags & ELF::SHF_ALLOC) - return false; - return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; - } -}; - -// TODO: The way stripping and groups interact is complicated -// and still needs to be worked on. - -class GroupSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - const SymbolTableSection *SymTab = nullptr; - Symbol *Sym = nullptr; - ELF::Elf32_Word FlagWord; - SmallVector<SectionBase *, 3> GroupMembers; - -public: - // TODO: Contents is present in several classes of the hierarchy. - // This needs to be refactored to avoid duplication. - ArrayRef<uint8_t> Contents; - - explicit GroupSection(ArrayRef<uint8_t> Data) : Contents(Data) {} - - void setSymTab(const SymbolTableSection *SymTabSec) { SymTab = SymTabSec; } - void setSymbol(Symbol *S) { Sym = S; } - void setFlagWord(ELF::Elf32_Word W) { FlagWord = W; } - void addMember(SectionBase *Sec) { GroupMembers.push_back(Sec); } - + function_ref<bool(const SectionBase *)> ToRemove) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void markSymbols() override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + + static bool classof(const SectionBase *S) { + if (S->OriginalFlags & ELF::SHF_ALLOC) + return false; + return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; + } +}; + +// TODO: The way stripping and groups interact is complicated +// and still needs to be worked on. + +class GroupSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + const SymbolTableSection *SymTab = nullptr; + Symbol *Sym = nullptr; + ELF::Elf32_Word FlagWord; + SmallVector<SectionBase *, 3> GroupMembers; + +public: + // TODO: Contents is present in several classes of the hierarchy. + // This needs to be refactored to avoid duplication. + ArrayRef<uint8_t> Contents; + + explicit GroupSection(ArrayRef<uint8_t> Data) : Contents(Data) {} + + void setSymTab(const SymbolTableSection *SymTabSec) { SymTab = SymTabSec; } + void setSymbol(Symbol *S) { Sym = S; } + void setFlagWord(ELF::Elf32_Word W) { FlagWord = W; } + void addMember(SectionBase *Sec) { GroupMembers.push_back(Sec); } + Error accept(SectionVisitor &) const override; Error accept(MutableSectionVisitor &Visitor) override; - void finalize() override; - Error removeSectionReferences( - bool AllowBrokenLinks, - function_ref<bool(const SectionBase *)> ToRemove) override; - Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; - void markSymbols() override; - void replaceSectionReferences( - const DenseMap<SectionBase *, SectionBase *> &FromTo) override; - void onRemove() override; - - static bool classof(const SectionBase *S) { - return S->OriginalType == ELF::SHT_GROUP; - } -}; - -class DynamicSymbolTableSection : public Section { -public: - explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {} - - static bool classof(const SectionBase *S) { - return S->OriginalType == ELF::SHT_DYNSYM; - } -}; - -class DynamicSection : public Section { -public: - explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {} - - static bool classof(const SectionBase *S) { - return S->OriginalType == ELF::SHT_DYNAMIC; - } -}; - -class DynamicRelocationSection - : public RelocSectionWithSymtabBase<DynamicSymbolTableSection> { - MAKE_SEC_WRITER_FRIEND - -private: - ArrayRef<uint8_t> Contents; - -public: - explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {} - + void finalize() override; + Error removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void markSymbols() override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + void onRemove() override; + + static bool classof(const SectionBase *S) { + return S->OriginalType == ELF::SHT_GROUP; + } +}; + +class DynamicSymbolTableSection : public Section { +public: + explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {} + + static bool classof(const SectionBase *S) { + return S->OriginalType == ELF::SHT_DYNSYM; + } +}; + +class DynamicSection : public Section { +public: + explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {} + + static bool classof(const SectionBase *S) { + return S->OriginalType == ELF::SHT_DYNAMIC; + } +}; + +class DynamicRelocationSection + : public RelocSectionWithSymtabBase<DynamicSymbolTableSection> { + MAKE_SEC_WRITER_FRIEND + +private: + ArrayRef<uint8_t> Contents; + +public: + explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {} + Error accept(SectionVisitor &) const override; Error accept(MutableSectionVisitor &Visitor) override; - Error removeSectionReferences( - bool AllowBrokenLinks, - function_ref<bool(const SectionBase *)> ToRemove) override; - - static bool classof(const SectionBase *S) { - if (!(S->OriginalFlags & ELF::SHF_ALLOC)) - return false; - return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; - } -}; - -class GnuDebugLinkSection : public SectionBase { - MAKE_SEC_WRITER_FRIEND - -private: - StringRef FileName; - uint32_t CRC32; - - void init(StringRef File); - -public: - // If we add this section from an external source we can use this ctor. - explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC); + Error removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + + static bool classof(const SectionBase *S) { + if (!(S->OriginalFlags & ELF::SHF_ALLOC)) + return false; + return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA; + } +}; + +class GnuDebugLinkSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + +private: + StringRef FileName; + uint32_t CRC32; + + void init(StringRef File); + +public: + // If we add this section from an external source we can use this ctor. + explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC); Error accept(SectionVisitor &Visitor) const override; Error accept(MutableSectionVisitor &Visitor) override; -}; - -class Reader { -public: - virtual ~Reader(); +}; + +class Reader { +public: + virtual ~Reader(); virtual Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const = 0; -}; - -using object::Binary; -using object::ELFFile; -using object::ELFObjectFile; -using object::OwningBinary; - -class BasicELFBuilder { -protected: - std::unique_ptr<Object> Obj; - - void initFileHeader(); - void initHeaderSegment(); - StringTableSection *addStrTab(); - SymbolTableSection *addSymTab(StringTableSection *StrTab); +}; + +using object::Binary; +using object::ELFFile; +using object::ELFObjectFile; +using object::OwningBinary; + +class BasicELFBuilder { +protected: + std::unique_ptr<Object> Obj; + + void initFileHeader(); + void initHeaderSegment(); + StringTableSection *addStrTab(); + SymbolTableSection *addSymTab(StringTableSection *StrTab); Error initSections(); - -public: - BasicELFBuilder() : Obj(std::make_unique<Object>()) {} -}; - -class BinaryELFBuilder : public BasicELFBuilder { - MemoryBuffer *MemBuf; - uint8_t NewSymbolVisibility; - void addData(SymbolTableSection *SymTab); - -public: - BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility) - : BasicELFBuilder(), MemBuf(MB), - NewSymbolVisibility(NewSymbolVisibility) {} - + +public: + BasicELFBuilder() : Obj(std::make_unique<Object>()) {} +}; + +class BinaryELFBuilder : public BasicELFBuilder { + MemoryBuffer *MemBuf; + uint8_t NewSymbolVisibility; + void addData(SymbolTableSection *SymTab); + +public: + BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility) + : BasicELFBuilder(), MemBuf(MB), + NewSymbolVisibility(NewSymbolVisibility) {} + Expected<std::unique_ptr<Object>> build(); -}; - -class IHexELFBuilder : public BasicELFBuilder { - const std::vector<IHexRecord> &Records; - - void addDataSections(); - -public: - IHexELFBuilder(const std::vector<IHexRecord> &Records) - : BasicELFBuilder(), Records(Records) {} - +}; + +class IHexELFBuilder : public BasicELFBuilder { + const std::vector<IHexRecord> &Records; + + void addDataSections(); + +public: + IHexELFBuilder(const std::vector<IHexRecord> &Records) + : BasicELFBuilder(), Records(Records) {} + Expected<std::unique_ptr<Object>> build(); -}; - -template <class ELFT> class ELFBuilder { -private: - using Elf_Addr = typename ELFT::Addr; - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Word = typename ELFT::Word; - - const ELFFile<ELFT> &ElfFile; - Object &Obj; - size_t EhdrOffset = 0; - Optional<StringRef> ExtractPartition; - - void setParentSegment(Segment &Child); +}; + +template <class ELFT> class ELFBuilder { +private: + using Elf_Addr = typename ELFT::Addr; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Word = typename ELFT::Word; + + const ELFFile<ELFT> &ElfFile; + Object &Obj; + size_t EhdrOffset = 0; + Optional<StringRef> ExtractPartition; + + void setParentSegment(Segment &Child); Error readProgramHeaders(const ELFFile<ELFT> &HeadersFile); Error initGroupSection(GroupSection *GroupSec); Error initSymbolTable(SymbolTableSection *SymTab); @@ -953,149 +953,149 @@ private: Error readSections(bool EnsureSymtab); Error findEhdrOffset(); Expected<SectionBase &> makeSection(const Elf_Shdr &Shdr); - -public: - ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj, - Optional<StringRef> ExtractPartition) + +public: + ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj, + Optional<StringRef> ExtractPartition) : ElfFile(ElfObj.getELFFile()), Obj(Obj), - ExtractPartition(ExtractPartition) {} - + ExtractPartition(ExtractPartition) {} + Error build(bool EnsureSymtab); -}; - -class BinaryReader : public Reader { - MemoryBuffer *MemBuf; - uint8_t NewSymbolVisibility; - -public: - BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility) - : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {} +}; + +class BinaryReader : public Reader { + MemoryBuffer *MemBuf; + uint8_t NewSymbolVisibility; + +public: + BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility) + : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {} Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const override; -}; - -class IHexReader : public Reader { - MemoryBuffer *MemBuf; - - Expected<std::vector<IHexRecord>> parse() const; - Error parseError(size_t LineNo, Error E) const { - return LineNo == -1U - ? createFileError(MemBuf->getBufferIdentifier(), std::move(E)) - : createFileError(MemBuf->getBufferIdentifier(), LineNo, - std::move(E)); - } - template <typename... Ts> - Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const { - Error E = createStringError(errc::invalid_argument, Fmt, Vals...); - return parseError(LineNo, std::move(E)); - } - -public: - IHexReader(MemoryBuffer *MB) : MemBuf(MB) {} - +}; + +class IHexReader : public Reader { + MemoryBuffer *MemBuf; + + Expected<std::vector<IHexRecord>> parse() const; + Error parseError(size_t LineNo, Error E) const { + return LineNo == -1U + ? createFileError(MemBuf->getBufferIdentifier(), std::move(E)) + : createFileError(MemBuf->getBufferIdentifier(), LineNo, + std::move(E)); + } + template <typename... Ts> + Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const { + Error E = createStringError(errc::invalid_argument, Fmt, Vals...); + return parseError(LineNo, std::move(E)); + } + +public: + IHexReader(MemoryBuffer *MB) : MemBuf(MB) {} + Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const override; -}; - -class ELFReader : public Reader { - Binary *Bin; - Optional<StringRef> ExtractPartition; - -public: +}; + +class ELFReader : public Reader { + Binary *Bin; + Optional<StringRef> ExtractPartition; + +public: Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const override; - explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition) - : Bin(B), ExtractPartition(ExtractPartition) {} -}; - -class Object { -private: - using SecPtr = std::unique_ptr<SectionBase>; - using SegPtr = std::unique_ptr<Segment>; - - std::vector<SecPtr> Sections; - 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< - pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>; - - template <class T> - using ConstRange = iterator_range<pointee_iterator< - typename std::vector<std::unique_ptr<T>>::const_iterator>>; - - // It is often the case that the ELF header and the program header table are - // not present in any segment. This could be a problem during file layout, - // because other segments may get assigned an offset where either of the - // two should reside, which will effectively corrupt the resulting binary. - // Other than that we use these segments to track program header offsets - // when they may not follow the ELF header. - Segment ElfHdrSegment; - Segment ProgramHdrSegment; - - uint8_t OSABI; - uint8_t ABIVersion; - uint64_t Entry; - 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; - - void sortSections(); - SectionTableRef sections() { return SectionTableRef(Sections); } - 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; }); - return SecIt == Sections.end() ? nullptr : SecIt->get(); - } - SectionTableRef removedSections() { return SectionTableRef(RemovedSections); } - - Range<Segment> segments() { return make_pointee_range(Segments); } - ConstRange<Segment> segments() const { return make_pointee_range(Segments); } - - Error removeSections(bool AllowBrokenLinks, - 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 = 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; - } + explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition) + : Bin(B), ExtractPartition(ExtractPartition) {} +}; + +class Object { +private: + using SecPtr = std::unique_ptr<SectionBase>; + using SegPtr = std::unique_ptr<Segment>; + + std::vector<SecPtr> Sections; + 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< + pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>; + + template <class T> + using ConstRange = iterator_range<pointee_iterator< + typename std::vector<std::unique_ptr<T>>::const_iterator>>; + + // It is often the case that the ELF header and the program header table are + // not present in any segment. This could be a problem during file layout, + // because other segments may get assigned an offset where either of the + // two should reside, which will effectively corrupt the resulting binary. + // Other than that we use these segments to track program header offsets + // when they may not follow the ELF header. + Segment ElfHdrSegment; + Segment ProgramHdrSegment; + + uint8_t OSABI; + uint8_t ABIVersion; + uint64_t Entry; + 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; + + void sortSections(); + SectionTableRef sections() { return SectionTableRef(Sections); } + 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; }); + return SecIt == Sections.end() ? nullptr : SecIt->get(); + } + SectionTableRef removedSections() { return SectionTableRef(RemovedSections); } + + Range<Segment> segments() { return make_pointee_range(Segments); } + ConstRange<Segment> segments() const { return make_pointee_range(Segments); } + + Error removeSections(bool AllowBrokenLinks, + 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 = 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; + } Error addNewSymbolTable(); - Segment &addSegment(ArrayRef<uint8_t> 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 -} // end namespace objcopy -} // end namespace llvm - -#endif // LLVM_TOOLS_OBJCOPY_OBJECT_H + Segment &addSegment(ArrayRef<uint8_t> 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 +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_OBJECT_H |