aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/InputSection.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
commitc0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch)
treef42add1021b9f2ac6a69ac7cf6c4499962739a45 /lld/ELF/InputSection.cpp
parent344a3780b2e33f6ca763666c380202b18aab72a3 (diff)
downloadsrc-c0981da47d5696fe36474fcf86b4ce03ae3ff818.tar.gz
src-c0981da47d5696fe36474fcf86b4ce03ae3ff818.zip
Diffstat (limited to 'lld/ELF/InputSection.cpp')
-rw-r--r--lld/ELF/InputSection.cpp152
1 files changed, 73 insertions, 79 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 1f9fa961fc26..74d4dd309c79 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -70,9 +70,6 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags,
if (sectionKind == SectionBase::Merge && rawData.size() > UINT32_MAX)
error(toString(this) + ": section too large");
- numRelocations = 0;
- areRelocsRela = false;
-
// The ELF spec states that a value of 0 means the section has
// no alignment constraints.
uint32_t v = std::max<uint32_t>(alignment, 1);
@@ -88,7 +85,22 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags,
if (!zlib::isAvailable())
error(toString(file) + ": contains a compressed section, " +
"but zlib is not available");
- parseCompressedHeader();
+ switch (config->ekind) {
+ case ELF32LEKind:
+ parseCompressedHeader<ELF32LE>();
+ break;
+ case ELF32BEKind:
+ parseCompressedHeader<ELF32BE>();
+ break;
+ case ELF64LEKind:
+ parseCompressedHeader<ELF64LE>();
+ break;
+ case ELF64BEKind:
+ parseCompressedHeader<ELF64BE>();
+ break;
+ default:
+ llvm_unreachable("unknown ELFT");
+ }
}
}
@@ -102,32 +114,14 @@ static uint64_t getFlags(uint64_t flags) {
return flags;
}
-// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
-// March 2017) fail to infer section types for sections starting with
-// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
-// SHF_INIT_ARRAY. As a result, the following assembler directive
-// creates ".init_array.100" with SHT_PROGBITS, for example.
-//
-// .section .init_array.100, "aw"
-//
-// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle
-// incorrect inputs as if they were correct from the beginning.
-static uint64_t getType(uint64_t type, StringRef name) {
- if (type == SHT_PROGBITS && name.startswith(".init_array."))
- return SHT_INIT_ARRAY;
- if (type == SHT_PROGBITS && name.startswith(".fini_array."))
- return SHT_FINI_ARRAY;
- return type;
-}
-
template <class ELFT>
InputSectionBase::InputSectionBase(ObjFile<ELFT> &file,
const typename ELFT::Shdr &hdr,
StringRef name, Kind sectionKind)
- : InputSectionBase(&file, getFlags(hdr.sh_flags),
- getType(hdr.sh_type, name), hdr.sh_entsize, hdr.sh_link,
- hdr.sh_info, hdr.sh_addralign,
- getSectionContents(file, hdr), name, sectionKind) {
+ : InputSectionBase(&file, getFlags(hdr.sh_flags), hdr.sh_type,
+ hdr.sh_entsize, hdr.sh_link, hdr.sh_info,
+ hdr.sh_addralign, getSectionContents(file, hdr), name,
+ sectionKind) {
// We reject object files having insanely large alignments even though
// they are allowed by the spec. I think 4GB is a reasonable limitation.
// We might want to relax this in the future.
@@ -165,6 +159,25 @@ uint64_t InputSectionBase::getOffsetInFile() const {
return secStart - fileStart;
}
+template <class ELFT> RelsOrRelas<ELFT> InputSectionBase::relsOrRelas() const {
+ if (relSecIdx == 0)
+ return {};
+ RelsOrRelas<ELFT> ret;
+ const ELFFile<ELFT> obj = cast<ELFFileBase>(file)->getObj<ELFT>();
+ typename ELFT::Shdr shdr = cantFail(obj.sections())[relSecIdx];
+ if (shdr.sh_type == SHT_REL) {
+ ret.rels = makeArrayRef(reinterpret_cast<const typename ELFT::Rel *>(
+ obj.base() + shdr.sh_offset),
+ shdr.sh_size / sizeof(typename ELFT::Rel));
+ } else {
+ assert(shdr.sh_type == SHT_RELA);
+ ret.relas = makeArrayRef(reinterpret_cast<const typename ELFT::Rela *>(
+ obj.base() + shdr.sh_offset),
+ shdr.sh_size / sizeof(typename ELFT::Rela));
+ }
+ return ret;
+}
+
uint64_t SectionBase::getOffset(uint64_t offset) const {
switch (kind()) {
case Output: {
@@ -210,10 +223,7 @@ OutputSection *SectionBase::getOutputSection() {
// When a section is compressed, `rawData` consists with a header followed
// by zlib-compressed data. This function parses a header to initialize
// `uncompressedSize` member and remove the header from `rawData`.
-void InputSectionBase::parseCompressedHeader() {
- using Chdr64 = typename ELF64LE::Chdr;
- using Chdr32 = typename ELF32LE::Chdr;
-
+template <typename ELFT> void InputSectionBase::parseCompressedHeader() {
// Old-style header
if (name.startswith(".zdebug")) {
if (!toStringRef(rawData).startswith("ZLIB")) {
@@ -239,32 +249,13 @@ void InputSectionBase::parseCompressedHeader() {
assert(flags & SHF_COMPRESSED);
flags &= ~(uint64_t)SHF_COMPRESSED;
- // New-style 64-bit header
- if (config->is64) {
- if (rawData.size() < sizeof(Chdr64)) {
- error(toString(this) + ": corrupted compressed section");
- return;
- }
-
- auto *hdr = reinterpret_cast<const Chdr64 *>(rawData.data());
- if (hdr->ch_type != ELFCOMPRESS_ZLIB) {
- error(toString(this) + ": unsupported compression type");
- return;
- }
-
- uncompressedSize = hdr->ch_size;
- alignment = std::max<uint32_t>(hdr->ch_addralign, 1);
- rawData = rawData.slice(sizeof(*hdr));
- return;
- }
-
- // New-style 32-bit header
- if (rawData.size() < sizeof(Chdr32)) {
+ // New-style header
+ if (rawData.size() < sizeof(typename ELFT::Chdr)) {
error(toString(this) + ": corrupted compressed section");
return;
}
- auto *hdr = reinterpret_cast<const Chdr32 *>(rawData.data());
+ auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(rawData.data());
if (hdr->ch_type != ELFCOMPRESS_ZLIB) {
error(toString(this) + ": unsupported compression type");
return;
@@ -293,32 +284,21 @@ Defined *InputSectionBase::getEnclosingFunction(uint64_t offset) {
return nullptr;
}
-// Returns a source location string. Used to construct an error message.
+// Returns an object file location string. Used to construct an error message.
template <class ELFT>
std::string InputSectionBase::getLocation(uint64_t offset) {
- std::string secAndOffset = (name + "+0x" + utohexstr(offset)).str();
+ std::string secAndOffset =
+ (name + "+0x" + Twine::utohexstr(offset) + ")").str();
// We don't have file for synthetic sections.
if (getFile<ELFT>() == nullptr)
- return (config->outputFile + ":(" + secAndOffset + ")")
- .str();
-
- // First check if we can get desired values from debugging information.
- if (Optional<DILineInfo> info = getFile<ELFT>()->getDILineInfo(this, offset))
- return info->FileName + ":" + std::to_string(info->Line) + ":(" +
- secAndOffset + ")";
-
- // File->sourceFile contains STT_FILE symbol that contains a
- // source file name. If it's missing, we use an object file name.
- std::string srcFile = std::string(getFile<ELFT>()->sourceFile);
- if (srcFile.empty())
- srcFile = toString(file);
+ return (config->outputFile + ":(" + secAndOffset).str();
+ std::string file = toString(getFile<ELFT>());
if (Defined *d = getEnclosingFunction<ELFT>(offset))
- return srcFile + ":(function " + toString(*d) + ": " + secAndOffset + ")";
+ return file + ":(function " + toString(*d) + ": " + secAndOffset;
- // If there's no symbol, print out the offset in the section.
- return (srcFile + ":(" + secAndOffset + ")");
+ return file + ":(" + secAndOffset;
}
// This function is intended to be used for constructing an error message.
@@ -515,6 +495,7 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a,
switch (type) {
// Unresolved branch relocations to weak references resolve to next
// instruction, this will be either 2 or 4 bytes on from P.
+ case R_ARM_THM_JUMP8:
case R_ARM_THM_JUMP11:
return p + 2 + a;
case R_ARM_CALL:
@@ -802,6 +783,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_PLT_PC:
case R_PPC64_CALL_PLT:
return sym.getPltVA() + a - p;
+ case R_PLT_GOTPLT:
+ return sym.getPltVA() + a - in.gotPlt->getVA();
case R_PPC32_PLTREL:
// R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30
// stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for
@@ -836,7 +819,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
// --noinhibit-exec, even a non-weak undefined reference may reach here.
// Just return A, which matches R_ABS, and the behavior of some dynamic
// loaders.
- if (sym.isUndefined() || sym.isLazy())
+ if (sym.isUndefined())
return a;
return getTlsTpOffset(sym) + a;
case R_RELAX_TLS_GD_TO_LE_NEG:
@@ -850,6 +833,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
return in.got->getGlobalDynAddr(sym) + a;
case R_TLSDESC_PC:
return in.got->getGlobalDynAddr(sym) + a - p;
+ case R_TLSDESC_GOTPLT:
+ return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA();
case R_AARCH64_TLSDESC_PAGE:
return getAArch64Page(in.got->getGlobalDynAddr(sym) + a) -
getAArch64Page(p);
@@ -1016,12 +1001,15 @@ void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) {
}
auto *sec = cast<InputSection>(this);
- if (config->relocatable)
+ if (config->relocatable) {
relocateNonAllocForRelocatable(sec, buf);
- else if (sec->areRelocsRela)
- sec->relocateNonAlloc<ELFT>(buf, sec->template relas<ELFT>());
- else
- sec->relocateNonAlloc<ELFT>(buf, sec->template rels<ELFT>());
+ } else {
+ const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
+ if (rels.areRelocsRel())
+ sec->relocateNonAlloc<ELFT>(buf, rels.rels);
+ else
+ sec->relocateNonAlloc<ELFT>(buf, rels.relas);
+ }
}
void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
@@ -1335,10 +1323,11 @@ static unsigned getReloc(IntTy begin, IntTy size, const ArrayRef<RelTy> &rels,
// .eh_frame is a sequence of CIE or FDE records.
// This function splits an input section into records and returns them.
template <class ELFT> void EhInputSection::split() {
- if (areRelocsRela)
- split<ELFT>(relas<ELFT>());
+ const RelsOrRelas<ELFT> rels = relsOrRelas<ELFT>();
+ if (rels.areRelocsRel())
+ split<ELFT>(rels.rels);
else
- split<ELFT>(rels<ELFT>());
+ split<ELFT>(rels.relas);
}
template <class ELFT, class RelTy>
@@ -1475,6 +1464,11 @@ template void InputSection::writeTo<ELF32BE>(uint8_t *);
template void InputSection::writeTo<ELF64LE>(uint8_t *);
template void InputSection::writeTo<ELF64BE>(uint8_t *);
+template RelsOrRelas<ELF32LE> InputSectionBase::relsOrRelas<ELF32LE>() const;
+template RelsOrRelas<ELF32BE> InputSectionBase::relsOrRelas<ELF32BE>() const;
+template RelsOrRelas<ELF64LE> InputSectionBase::relsOrRelas<ELF64LE>() const;
+template RelsOrRelas<ELF64BE> InputSectionBase::relsOrRelas<ELF64BE>() const;
+
template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &,
const ELF32LE::Shdr &, StringRef);
template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> &,