aboutsummaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:05:49 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:05:49 +0000
commite2fd426bdafe9f5c10066d3926ece6e342184a67 (patch)
treebfbbb5fd38554e6b8988b7a217e9fd0623728d7d /ELF
parent84c4061b34e048f47e5eb4fbabc1558495e8157c (diff)
downloadsrc-e2fd426bdafe9f5c10066d3926ece6e342184a67.tar.gz
src-e2fd426bdafe9f5c10066d3926ece6e342184a67.zip
Vendor import of lld trunk r351319 (just before the release_80 branchvendor/lld/lld-trunk-r351319
Notes
Notes: svn path=/vendor/lld/dist/; revision=343179 svn path=/vendor/lld/lld-trunk-r351319/; revision=343180; tag=vendor/lld/lld-trunk-r351319
Diffstat (limited to 'ELF')
-rw-r--r--ELF/AArch64ErrataFix.cpp27
-rw-r--r--ELF/Arch/AArch64.cpp37
-rw-r--r--ELF/Arch/AMDGPU.cpp1
-rw-r--r--ELF/Arch/ARM.cpp124
-rw-r--r--ELF/Arch/AVR.cpp3
-rw-r--r--ELF/Arch/Hexagon.cpp195
-rw-r--r--ELF/Arch/MSP430.cpp94
-rw-r--r--ELF/Arch/Mips.cpp13
-rw-r--r--ELF/Arch/PPC.cpp5
-rw-r--r--ELF/Arch/PPC64.cpp473
-rw-r--r--ELF/Arch/RISCV.cpp279
-rw-r--r--ELF/Arch/SPARCV9.cpp1
-rw-r--r--ELF/Arch/X86.cpp25
-rw-r--r--ELF/Arch/X86_64.cpp50
-rw-r--r--ELF/CMakeLists.txt4
-rw-r--r--ELF/CallGraphSort.cpp51
-rw-r--r--ELF/Config.h11
-rw-r--r--ELF/DWARF.cpp (renamed from ELF/GdbIndex.cpp)40
-rw-r--r--ELF/DWARF.h (renamed from ELF/GdbIndex.h)69
-rw-r--r--ELF/Driver.cpp378
-rw-r--r--ELF/Driver.h3
-rw-r--r--ELF/DriverUtils.cpp5
-rw-r--r--ELF/EhFrame.cpp4
-rw-r--r--ELF/ICF.cpp32
-rw-r--r--ELF/InputFiles.cpp111
-rw-r--r--ELF/InputFiles.h12
-rw-r--r--ELF/InputSection.cpp459
-rw-r--r--ELF/InputSection.h38
-rw-r--r--ELF/LTO.cpp48
-rw-r--r--ELF/LTO.h2
-rw-r--r--ELF/LinkerScript.cpp55
-rw-r--r--ELF/LinkerScript.h12
-rw-r--r--ELF/MapFile.cpp11
-rw-r--r--ELF/MarkLive.cpp15
-rw-r--r--ELF/Options.td21
-rw-r--r--ELF/OutputSections.cpp28
-rw-r--r--ELF/OutputSections.h6
-rw-r--r--ELF/Relocations.cpp363
-rw-r--r--ELF/Relocations.h39
-rw-r--r--ELF/ScriptLexer.cpp9
-rw-r--r--ELF/ScriptLexer.h1
-rw-r--r--ELF/ScriptParser.cpp153
-rw-r--r--ELF/SymbolTable.cpp250
-rw-r--r--ELF/SymbolTable.h34
-rw-r--r--ELF/Symbols.cpp60
-rw-r--r--ELF/Symbols.h66
-rw-r--r--ELF/SyntheticSections.cpp506
-rw-r--r--ELF/SyntheticSections.h137
-rw-r--r--ELF/Target.cpp13
-rw-r--r--ELF/Target.h64
-rw-r--r--ELF/Thunks.cpp298
-rw-r--r--ELF/Writer.cpp697
52 files changed, 3708 insertions, 1724 deletions
diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp
index 7551919cf86f..ac753cb58265 100644
--- a/ELF/AArch64ErrataFix.cpp
+++ b/ELF/AArch64ErrataFix.cpp
@@ -356,7 +356,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off,
}
uint64_t PatchOff = 0;
- const uint8_t *Buf = IS->Data.begin();
+ const uint8_t *Buf = IS->data().begin();
const ulittle32_t *InstBuf = reinterpret_cast<const ulittle32_t *>(Buf + Off);
uint32_t Instr1 = *InstBuf++;
uint32_t Instr2 = *InstBuf++;
@@ -411,7 +411,7 @@ uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) {
// Copy the instruction that we will be replacing with a branch in the
// Patchee Section.
- write32le(Buf, read32le(Patchee->Data.begin() + PatcheeOffset));
+ write32le(Buf, read32le(Patchee->data().begin() + PatcheeOffset));
// Apply any relocation transferred from the original PatcheeSection.
// For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc
@@ -451,7 +451,7 @@ void AArch64Err843419Patcher::init() {
continue;
if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def))
continue;
- if (auto *Sec = dyn_cast<InputSection>(Def->Section))
+ if (auto *Sec = dyn_cast_or_null<InputSection>(Def->Section))
if (Sec->Flags & SHF_EXECINSTR)
SectionMap[Sec].push_back(Def);
}
@@ -487,7 +487,8 @@ void AArch64Err843419Patcher::insertPatches(
InputSectionDescription &ISD, std::vector<Patch843419Section *> &Patches) {
uint64_t ISLimit;
uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff;
- uint64_t PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing();
+ uint64_t OutSecAddr = ISD.Sections.front()->getParent()->Addr;
// Set the OutSecOff of patches to the place where we want to insert them.
// We use a similar strategy to Thunk placement. Place patches roughly
@@ -498,12 +499,12 @@ void AArch64Err843419Patcher::insertPatches(
ISLimit = IS->OutSecOff + IS->getSize();
if (ISLimit > PatchUpperBound) {
while (PatchIt != PatchEnd) {
- if ((*PatchIt)->getLDSTAddr() >= PrevISLimit)
+ if ((*PatchIt)->getLDSTAddr() - OutSecAddr >= PrevISLimit)
break;
(*PatchIt)->OutSecOff = PrevISLimit;
++PatchIt;
}
- PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing();
}
PrevISLimit = ISLimit;
}
@@ -538,20 +539,24 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset,
InputSection *IS,
std::vector<Patch843419Section *> &Patches) {
// There may be a relocation at the same offset that we are patching. There
- // are three cases that we need to consider.
+ // are four cases that we need to consider.
// Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this
// instance of the erratum on a previous patch and altered the relocation. We
// have nothing more to do.
- // Case 2: A load/store register (unsigned immediate) class relocation. There
+ // Case 2: A TLS Relaxation R_RELAX_TLS_IE_TO_LE. In this case the ADRP that
+ // we read will be transformed into a MOVZ later so we actually don't match
+ // the sequence and have nothing more to do.
+ // Case 3: A load/store register (unsigned immediate) class relocation. There
// are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and
// they are both absolute. We need to add the same relocation to the patch,
// and replace the relocation with a R_AARCH_JUMP26 branch relocation.
- // Case 3: No relocation. We must create a new R_AARCH64_JUMP26 branch
+ // Case 4: No relocation. We must create a new R_AARCH64_JUMP26 branch
// relocation at the offset.
auto RelIt = std::find_if(
IS->Relocations.begin(), IS->Relocations.end(),
[=](const Relocation &R) { return R.Offset == PatcheeOffset; });
- if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26)
+ if (RelIt != IS->Relocations.end() &&
+ (RelIt->Type == R_AARCH64_JUMP26 || RelIt->Expr == R_RELAX_TLS_IE_TO_LE))
return;
log("detected cortex-a53-843419 erratum sequence starting at " +
@@ -598,7 +603,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
auto DataSym = std::next(CodeSym);
uint64_t Off = (*CodeSym)->Value;
uint64_t Limit =
- (DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value;
+ (DataSym == MapSyms.end()) ? IS->data().size() : (*DataSym)->Value;
while (Off < Limit) {
uint64_t StartAddr = IS->getVA(Off);
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
index c7b3c0801de2..08ffe2a08c0f 100644
--- a/ELF/Arch/AArch64.cpp
+++ b/ELF/Arch/AArch64.cpp
@@ -41,6 +41,7 @@ public:
int32_t Index, unsigned RelOff) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
bool usesOnlyLowPageBits(RelType Type) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
@@ -57,6 +58,7 @@ AArch64::AArch64() {
RelativeRel = R_AARCH64_RELATIVE;
IRelativeRel = R_AARCH64_IRELATIVE;
GotRel = R_AARCH64_GLOB_DAT;
+ NoneRel = R_AARCH64_NONE;
PltRel = R_AARCH64_JUMP_SLOT;
TlsDescRel = R_AARCH64_TLSDESC;
TlsGotRel = R_AARCH64_TLS_TPREL64;
@@ -66,22 +68,18 @@ AArch64::AArch64() {
PltHeaderSize = 32;
DefaultMaxPageSize = 65536;
- // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
- // 1 of the tls structures and the tcb size is 16.
- TcbSize = 16;
- NeedsThunks = true;
+ // Align to the 2 MiB page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes 2 MiB-aligned allocations.
+ DefaultImageBase = 0x200000;
- // See comment in Arch/ARM.cpp for a more detailed explanation of
- // ThunkSectionSpacing. For AArch64 the only branches we are permitted to
- // Thunk have a range of +/- 128 MiB
- ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000;
+ NeedsThunks = true;
}
RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_AARCH64_TLSDESC_ADR_PAGE21:
- return R_TLSDESC_PAGE;
+ return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_TLSDESC_ADD_LO12:
return R_TLSDESC;
@@ -107,13 +105,13 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
case R_AARCH64_LD_PREL_LO19:
return R_PC;
case R_AARCH64_ADR_PREL_PG_HI21:
- return R_PAGE_PC;
+ return R_AARCH64_PAGE_PC;
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return R_GOT;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- return R_GOT_PAGE_PC;
+ return R_AARCH64_GOT_PAGE_PC;
case R_AARCH64_NONE:
return R_NONE;
default:
@@ -125,7 +123,7 @@ RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const {
if (Expr == R_RELAX_TLS_GD_TO_IE) {
if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
- return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
+ return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
return R_RELAX_TLS_GD_TO_IE_ABS;
}
return Expr;
@@ -156,7 +154,7 @@ RelType AArch64::getDynRel(RelType Type) const {
}
void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
- write64le(Buf, InX::Plt->getVA());
+ write64le(Buf, In.Plt->getVA());
}
void AArch64::writePltHeader(uint8_t *Buf) const {
@@ -172,8 +170,8 @@ void AArch64::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t Got = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
@@ -208,6 +206,13 @@ bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return !inBranchRange(Type, BranchAddr, Dst);
}
+uint32_t AArch64::getThunkSectionSpacing() const {
+ // See comment in Arch/ARM.cpp for a more detailed explanation of
+ // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to
+ // Thunk have a range of +/- 128 MiB
+ return (128 * 1024 * 1024) - 0x30000;
+}
+
bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
return true;
@@ -338,7 +343,7 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
or32le(Loc, (Val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- checkInt(Loc, Val, 24, Type);
+ checkUInt(Loc, Val, 24, Type);
or32AArch64Imm(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp
index 48b27f23510c..a7c6c84ceecd 100644
--- a/ELF/Arch/AMDGPU.cpp
+++ b/ELF/Arch/AMDGPU.cpp
@@ -35,6 +35,7 @@ public:
AMDGPU::AMDGPU() {
RelativeRel = R_AMDGPU_RELATIVE64;
GotRel = R_AMDGPU_ABS64;
+ NoneRel = R_AMDGPU_NONE;
GotEntrySize = 8;
}
diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp
index acf9a615f20b..120caca671af 100644
--- a/ELF/Arch/ARM.cpp
+++ b/ELF/Arch/ARM.cpp
@@ -40,6 +40,7 @@ public:
void addPltHeaderSymbols(InputSection &ISD) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
@@ -50,6 +51,7 @@ ARM::ARM() {
RelativeRel = R_ARM_RELATIVE;
IRelativeRel = R_ARM_IRELATIVE;
GotRel = R_ARM_GLOB_DAT;
+ NoneRel = R_ARM_NONE;
PltRel = R_ARM_JUMP_SLOT;
TlsGotRel = R_ARM_TLS_TPOFF32;
TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
@@ -59,41 +61,8 @@ ARM::ARM() {
GotPltEntrySize = 4;
PltEntrySize = 16;
PltHeaderSize = 32;
- TrapInstr = 0xd4d4d4d4;
- // ARM uses Variant 1 TLS
- TcbSize = 8;
+ TrapInstr = {0xd4, 0xd4, 0xd4, 0xd4};
NeedsThunks = true;
-
- // The placing of pre-created ThunkSections is controlled by the
- // ThunkSectionSpacing parameter. The aim is to place the
- // ThunkSection such that all branches from the InputSections prior to the
- // ThunkSection can reach a Thunk placed at the end of the ThunkSection.
- // Graphically:
- // | up to ThunkSectionSpacing .text input sections |
- // | ThunkSection |
- // | up to ThunkSectionSpacing .text input sections |
- // | ThunkSection |
-
- // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to
- // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W
- // ARM B, BL, BLX range +/- 32MiB
- // Thumb B.W, BL, BLX range +/- 16MiB
- // Thumb B<cc>.W range +/- 1MiB
- // If a branch cannot reach a pre-created ThunkSection a new one will be
- // created so we can handle the rare cases of a Thumb 2 conditional branch.
- // We intentionally use a lower size for ThunkSectionSpacing than the maximum
- // branch range so the end of the ThunkSection is more likely to be within
- // range of the branch instruction that is furthest away. The value we shorten
- // ThunkSectionSpacing by is set conservatively to allow us to create 16,384
- // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to
- // one of the Thunks going out of range.
-
- // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and
- // J2 bits to be used to extend the branch range. On earlier Architectures
- // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If
- // support for the earlier encodings is added then when they are used the
- // ThunkSectionSpacing will need lowering.
- ThunkSectionSpacing = 0x1000000 - 0x30000;
}
uint32_t ARM::calcEFlags() const {
@@ -165,6 +134,12 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S,
return R_NONE;
case R_ARM_TLS_LE32:
return R_TLS;
+ case R_ARM_V4BX:
+ // V4BX is just a marker to indicate there's a "bx rN" instruction at the
+ // given address. It can be used to implement a special linker mode which
+ // rewrites ARMv4T inputs to ARMv4. Since we support only ARMv4 input and
+ // not ARMv4 output, we can just ignore it.
+ return R_HINT;
default:
return R_ABS;
}
@@ -177,7 +152,7 @@ RelType ARM::getDynRel(RelType Type) const {
}
void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const {
- write32le(Buf, InX::Plt->getVA());
+ write32le(Buf, In.Plt->getVA());
}
void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const {
@@ -198,8 +173,8 @@ static void writePltHeaderLong(uint8_t *Buf) {
0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary
0xd4, 0xd4, 0xd4, 0xd4};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t L1 = InX::Plt->getVA() + 8;
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t L1 = In.Plt->getVA() + 8;
write32le(Buf + 16, GotPlt - L1 - 8);
}
@@ -217,7 +192,7 @@ void ARM::writePltHeader(uint8_t *Buf) const {
0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4)
};
- uint64_t Offset = InX::GotPlt->getVA() - InX::Plt->getVA() - 4;
+ uint64_t Offset = In.GotPlt->getVA() - In.Plt->getVA() - 4;
if (!llvm::isUInt<27>(Offset)) {
// We cannot encode the Offset, use the long form.
writePltHeaderLong(Buf);
@@ -227,10 +202,10 @@ void ARM::writePltHeader(uint8_t *Buf) const {
write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff));
write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff));
write32le(Buf + 12, PltData[3] | (Offset & 0xfff));
- write32le(Buf + 16, TrapInstr); // Pad to 32-byte boundary
- write32le(Buf + 20, TrapInstr);
- write32le(Buf + 24, TrapInstr);
- write32le(Buf + 28, TrapInstr);
+ memcpy(Buf + 16, TrapInstr.data(), 4); // Pad to 32-byte boundary
+ memcpy(Buf + 20, TrapInstr.data(), 4);
+ memcpy(Buf + 24, TrapInstr.data(), 4);
+ memcpy(Buf + 28, TrapInstr.data(), 4);
}
void ARM::addPltHeaderSymbols(InputSection &IS) const {
@@ -279,7 +254,7 @@ void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff));
write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff));
write32le(Buf + 8, PltData[2] | (Offset & 0xfff));
- write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary
+ memcpy(Buf + 12, TrapInstr.data(), 4); // Pad to 16-byte boundary
}
void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const {
@@ -324,6 +299,40 @@ bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return false;
}
+uint32_t ARM::getThunkSectionSpacing() const {
+ // The placing of pre-created ThunkSections is controlled by the value
+ // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to
+ // place the ThunkSection such that all branches from the InputSections
+ // prior to the ThunkSection can reach a Thunk placed at the end of the
+ // ThunkSection. Graphically:
+ // | up to ThunkSectionSpacing .text input sections |
+ // | ThunkSection |
+ // | up to ThunkSectionSpacing .text input sections |
+ // | ThunkSection |
+
+ // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This
+ // is to match the most common expected case of a Thumb 2 encoded BL, BLX or
+ // B.W:
+ // ARM B, BL, BLX range +/- 32MiB
+ // Thumb B.W, BL, BLX range +/- 16MiB
+ // Thumb B<cc>.W range +/- 1MiB
+ // If a branch cannot reach a pre-created ThunkSection a new one will be
+ // created so we can handle the rare cases of a Thumb 2 conditional branch.
+ // We intentionally use a lower size for ThunkSectionSpacing than the maximum
+ // branch range so the end of the ThunkSection is more likely to be within
+ // range of the branch instruction that is furthest away. The value we shorten
+ // ThunkSectionSpacing by is set conservatively to allow us to create 16,384
+ // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to
+ // one of the Thunks going out of range.
+
+ // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch
+ // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except
+ // ARMv6T2) the range is +/- 4MiB.
+
+ return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000
+ : 0x400000 - 0x7500;
+}
+
bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
uint64_t Range;
uint64_t InstrSize;
@@ -342,7 +351,7 @@ bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
break;
case R_ARM_THM_JUMP24:
case R_ARM_THM_CALL:
- Range = 0x1000000;
+ Range = Config->ARMJ1J2BranchEncoding ? 0x1000000 : 0x400000;
InstrSize = 2;
break;
default:
@@ -447,11 +456,23 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
// Bit 12 is 0 for BLX, 1 for BL
write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
+ if (!Config->ARMJ1J2BranchEncoding) {
+ // Older Arm architectures do not support R_ARM_THM_JUMP24 and have
+ // different encoding rules and range due to J1 and J2 always being 1.
+ checkInt(Loc, Val, 23, Type);
+ write16le(Loc,
+ 0xf000 | // opcode
+ ((Val >> 12) & 0x07ff)); // imm11
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0xd000) | // opcode
+ 0x2800 | // J1 == J2 == 1
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ }
// Fall through as rest of encoding is the same as B.W
LLVM_FALLTHROUGH;
case R_ARM_THM_JUMP24:
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
- // FIXME: Use of I1 and I2 require v6T2ops
checkInt(Loc, Val, 25, Type);
write16le(Loc,
0xf000 | // opcode
@@ -470,14 +491,12 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
case R_ARM_MOVT_ABS:
case R_ARM_MOVT_PREL:
- checkInt(Loc, Val, 32, Type);
write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
(((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
break;
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVT_PREL:
// Encoding T1: A = imm4:i:imm3:imm8
- checkInt(Loc, Val, 32, Type);
write16le(Loc,
0xf2c0 | // opcode
((Val >> 17) & 0x0400) | // i
@@ -542,10 +561,19 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
((Lo & 0x07ff) << 1)); // imm11:0
}
case R_ARM_THM_CALL:
+ if (!Config->ARMJ1J2BranchEncoding) {
+ // Older Arm architectures do not support R_ARM_THM_JUMP24 and have
+ // different encoding rules and range due to J1 and J2 always being 1.
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<22>(((Hi & 0x7ff) << 12) | // imm11
+ ((Lo & 0x7ff) << 1)); // imm11:0
+ break;
+ }
+ LLVM_FALLTHROUGH;
case R_ARM_THM_JUMP24: {
// Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
// I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
- // FIXME: I1 and I2 require v6T2ops
uint16_t Hi = read16le(Buf);
uint16_t Lo = read16le(Buf + 2);
return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp
index 02ac770127b9..637da3778bd2 100644
--- a/ELF/Arch/AVR.cpp
+++ b/ELF/Arch/AVR.cpp
@@ -43,12 +43,15 @@ using namespace lld::elf;
namespace {
class AVR final : public TargetInfo {
public:
+ AVR();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
+AVR::AVR() { NoneRel = R_AVR_NONE; }
+
RelExpr AVR::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
return R_ABS;
diff --git a/ELF/Arch/Hexagon.cpp b/ELF/Arch/Hexagon.cpp
index ff5e862bafa2..b4d33be2ad39 100644
--- a/ELF/Arch/Hexagon.cpp
+++ b/ELF/Arch/Hexagon.cpp
@@ -9,6 +9,7 @@
#include "InputFiles.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/BinaryFormat/ELF.h"
@@ -25,15 +26,48 @@ using namespace lld::elf;
namespace {
class Hexagon final : public TargetInfo {
public:
+ Hexagon();
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
};
} // namespace
-// Support V60 only at the moment.
-uint32_t Hexagon::calcEFlags() const { return 0x60; }
+Hexagon::Hexagon() {
+ PltRel = R_HEX_JMP_SLOT;
+ RelativeRel = R_HEX_RELATIVE;
+ GotRel = R_HEX_GLOB_DAT;
+ GotEntrySize = 4;
+ // The zero'th GOT entry is reserved for the address of _DYNAMIC. The
+ // next 3 are reserved for the dynamic loader.
+ GotPltHeaderEntriesNum = 4;
+ GotPltEntrySize = 4;
+
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+
+ // Hexagon Linux uses 64K pages by default.
+ DefaultMaxPageSize = 0x10000;
+ NoneRel = R_HEX_NONE;
+}
+
+uint32_t Hexagon::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+
+ // The architecture revision must always be equal to or greater than
+ // greatest revision in the list of inputs.
+ uint32_t Ret = 0;
+ for (InputFile *F : ObjectFiles) {
+ uint32_t EFlags = cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags;
+ if (EFlags > Ret)
+ Ret = EFlags;
+ }
+ return Ret;
+}
static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
uint32_t Result = 0;
@@ -53,29 +87,143 @@ static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
+ case R_HEX_B9_PCREL:
+ case R_HEX_B9_PCREL_X:
+ case R_HEX_B13_PCREL:
case R_HEX_B15_PCREL:
case R_HEX_B15_PCREL_X:
+ case R_HEX_6_PCREL_X:
+ case R_HEX_32_PCREL:
+ return R_PC;
case R_HEX_B22_PCREL:
+ case R_HEX_PLT_B22_PCREL:
case R_HEX_B22_PCREL_X:
case R_HEX_B32_PCREL_X:
- return R_PC;
+ return R_PLT_PC;
+ case R_HEX_GOT_11_X:
+ case R_HEX_GOT_16_X:
+ case R_HEX_GOT_32_6_X:
+ return R_HEXAGON_GOT;
default:
return R_ABS;
}
}
+static uint32_t findMaskR6(uint32_t Insn) {
+ // There are (arguably too) many relocation masks for the DSP's
+ // R_HEX_6_X type. The table below is used to select the correct mask
+ // for the given instruction.
+ struct InstructionMask {
+ uint32_t CmpMask;
+ uint32_t RelocMask;
+ };
+
+ static const InstructionMask R6[] = {
+ {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f},
+ {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80},
+ {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0},
+ {0x42000000, 0x000020f8}, {0x43000000, 0x000007e0},
+ {0x44000000, 0x000020f8}, {0x45000000, 0x000007e0},
+ {0x46000000, 0x000020f8}, {0x47000000, 0x000007e0},
+ {0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000},
+ {0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60},
+ {0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60},
+ {0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f},
+ {0xad000000, 0x0000003f}, {0xaf000000, 0x00030078},
+ {0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0},
+ {0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}};
+
+ // Duplex forms have a fixed mask and parse bits 15:14 are always
+ // zero. Non-duplex insns will always have at least one bit set in the
+ // parse field.
+ if ((0xC000 & Insn) == 0x0)
+ return 0x03f00000;
+
+ for (InstructionMask I : R6)
+ if ((0xff000000 & Insn) == I.CmpMask)
+ return I.RelocMask;
+
+ error("unrecognized instruction for R_HEX_6 relocation: 0x" +
+ utohexstr(Insn));
+ return 0;
+}
+
+static uint32_t findMaskR8(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0xde000000)
+ return 0x00e020e8;
+ if ((0xff000000 & Insn) == 0x3c000000)
+ return 0x0000207f;
+ return 0x00001fe0;
+}
+
+static uint32_t findMaskR11(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0xa1000000)
+ return 0x060020ff;
+ return 0x06003fe0;
+}
+
+static uint32_t findMaskR16(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0x48000000)
+ return 0x061f20ff;
+ if ((0xff000000 & Insn) == 0x49000000)
+ return 0x061f3fe0;
+ if ((0xff000000 & Insn) == 0x78000000)
+ return 0x00df3fe0;
+ if ((0xff000000 & Insn) == 0xb0000000)
+ return 0x0fe03fe0;
+
+ error("unrecognized instruction for R_HEX_16_X relocation: 0x" +
+ utohexstr(Insn));
+ return 0;
+}
+
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_HEX_NONE:
break;
+ case R_HEX_6_PCREL_X:
+ case R_HEX_6_X:
+ or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val));
+ break;
+ case R_HEX_8_X:
+ or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val));
+ break;
+ case R_HEX_9_X:
+ or32le(Loc, applyMask(0x00003fe0, Val & 0x3f));
+ break;
+ case R_HEX_10_X:
+ or32le(Loc, applyMask(0x00203fe0, Val & 0x3f));
+ break;
+ case R_HEX_11_X:
+ case R_HEX_GOT_11_X:
+ or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f));
+ break;
case R_HEX_12_X:
or32le(Loc, applyMask(0x000007e0, Val));
break;
+ case R_HEX_16_X: // These relocs only have 6 effective bits.
+ case R_HEX_GOT_16_X:
+ or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f));
+ break;
+ case R_HEX_32:
+ case R_HEX_32_PCREL:
+ or32le(Loc, Val);
+ break;
case R_HEX_32_6_X:
+ case R_HEX_GOT_32_6_X:
or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
break;
+ case R_HEX_B9_PCREL:
+ or32le(Loc, applyMask(0x003000fe, Val >> 2));
+ break;
+ case R_HEX_B9_PCREL_X:
+ or32le(Loc, applyMask(0x003000fe, Val & 0x3f));
+ break;
+ case R_HEX_B13_PCREL:
+ or32le(Loc, applyMask(0x00202ffe, Val >> 2));
+ break;
case R_HEX_B15_PCREL:
or32le(Loc, applyMask(0x00df20fe, Val >> 2));
break;
@@ -83,6 +231,7 @@ void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
or32le(Loc, applyMask(0x00df20fe, Val & 0x3f));
break;
case R_HEX_B22_PCREL:
+ case R_HEX_PLT_B22_PCREL:
or32le(Loc, applyMask(0x1ff3ffe, Val >> 2));
break;
case R_HEX_B22_PCREL_X:
@@ -91,12 +240,52 @@ void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_HEX_B32_PCREL_X:
or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
break;
+ case R_HEX_HI16:
+ or32le(Loc, applyMask(0x00c03fff, Val >> 16));
+ break;
+ case R_HEX_LO16:
+ or32le(Loc, applyMask(0x00c03fff, Val));
+ break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
break;
}
}
+void Hexagon::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0
+ 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn
+ 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
+ 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
+ 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
+ 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ // Offset from PLT0 to the GOT.
+ uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA();
+ relocateOne(Buf, R_HEX_B32_PCREL_X, Off);
+ relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off);
+}
+
+void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) }
+ 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14)
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr);
+ relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr);
+}
+
TargetInfo *elf::getHexagonTargetInfo() {
static Hexagon Target;
return &Target;
diff --git a/ELF/Arch/MSP430.cpp b/ELF/Arch/MSP430.cpp
new file mode 100644
index 000000000000..fe0c0fe64daf
--- /dev/null
+++ b/ELF/Arch/MSP430.cpp
@@ -0,0 +1,94 @@
+//===- MSP430.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The MSP430 is a 16-bit microcontroller RISC architecture. The instruction set
+// has only 27 core instructions orthogonally augmented with a variety
+// of addressing modes for source and destination operands. Entire address space
+// of MSP430 is 64KB (the extended MSP430X architecture is not considered here).
+// A typical MSP430 MCU has several kilobytes of RAM and ROM, plenty
+// of peripherals and is generally optimized for a low power consumption.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class MSP430 final : public TargetInfo {
+public:
+ MSP430();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+MSP430::MSP430() {
+ // mov.b #0, r3
+ TrapInstr = {0x43, 0x43, 0x43, 0x43};
+}
+
+RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_MSP430_10_PCREL:
+ case R_MSP430_16_PCREL:
+ case R_MSP430_16_PCREL_BYTE:
+ case R_MSP430_2X_PCREL:
+ case R_MSP430_RL_PCREL:
+ case R_MSP430_SYM_DIFF:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+void MSP430::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_MSP430_8:
+ checkIntUInt(Loc, Val, 8, Type);
+ *Loc = Val;
+ break;
+ case R_MSP430_16:
+ case R_MSP430_16_PCREL:
+ case R_MSP430_16_BYTE:
+ case R_MSP430_16_PCREL_BYTE:
+ checkIntUInt(Loc, Val, 16, Type);
+ write16le(Loc, Val);
+ break;
+ case R_MSP430_32:
+ checkIntUInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ case R_MSP430_10_PCREL: {
+ int16_t Offset = ((int16_t)Val >> 1) - 1;
+ checkInt(Loc, Offset, 10, Type);
+ write16le(Loc, (read16le(Loc) & 0xFC00) | (Offset & 0x3FF));
+ break;
+ }
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ }
+}
+
+TargetInfo *elf::getMSP430TargetInfo() {
+ static MSP430 Target;
+ return &Target;
+}
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index dc70401c0b0e..23b0c1dd8a2d 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -53,9 +53,12 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
PltEntrySize = 16;
PltHeaderSize = 32;
CopyRel = R_MIPS_COPY;
+ NoneRel = R_MIPS_NONE;
PltRel = R_MIPS_JUMP_SLOT;
NeedsThunks = true;
- TrapInstr = 0xefefefef;
+
+ // Set `sigrie 1` as a trap instruction.
+ write32(TrapInstr.data(), 0x04170001);
if (ELFT::Is64Bits) {
RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
@@ -185,7 +188,7 @@ template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
template <class ELFT>
void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &) const {
- uint64_t VA = InX::Plt->getVA();
+ uint64_t VA = In.Plt->getVA();
if (isMicroMips())
VA |= 1;
write32<ELFT::TargetEndianness>(Buf, VA);
@@ -239,8 +242,8 @@ static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
if (isMicroMips()) {
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(Buf, 0, PltHeaderSize);
@@ -292,7 +295,7 @@ template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
- uint64_t GotPlt = InX::GotPlt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
writeValue<E>(Buf, GotPlt + 0x8000, 16, 16);
writeValue<E>(Buf + 4, GotPlt, 16, 0);
writeValue<E>(Buf + 8, GotPlt, 16, 0);
diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp
index 20cae0e59cf4..767378067341 100644
--- a/ELF/Arch/PPC.cpp
+++ b/ELF/Arch/PPC.cpp
@@ -29,6 +29,7 @@ public:
} // namespace
PPC::PPC() {
+ NoneRel = R_PPC_NONE;
GotBaseSymOff = 0x8000;
GotBaseSymInGotPlt = false;
}
@@ -36,6 +37,7 @@ PPC::PPC() {
RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
+ case R_PPC_REL14:
case R_PPC_REL24:
case R_PPC_REL32:
return R_PC;
@@ -61,6 +63,9 @@ void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC_REL32:
write32be(Loc, Val);
break;
+ case R_PPC_REL14:
+ write32be(Loc, read32be(Loc) | (Val & 0xFFFC));
+ break;
case R_PPC_PLTREL24:
case R_PPC_REL24:
write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp
index fa3bf6c62a0d..8a320c9a4e9e 100644
--- a/ELF/Arch/PPC64.cpp
+++ b/ELF/Arch/PPC64.cpp
@@ -23,12 +23,49 @@ using namespace lld::elf;
static uint64_t PPC64TocOffset = 0x8000;
static uint64_t DynamicThreadPointerOffset = 0x8000;
+// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform
+// instructions that can be used as part of the initial exec TLS sequence.
+enum XFormOpcd {
+ LBZX = 87,
+ LHZX = 279,
+ LWZX = 23,
+ LDX = 21,
+ STBX = 215,
+ STHX = 407,
+ STWX = 151,
+ STDX = 149,
+ ADD = 266,
+};
+
+enum DFormOpcd {
+ LBZ = 34,
+ LBZU = 35,
+ LHZ = 40,
+ LHZU = 41,
+ LHAU = 43,
+ LWZ = 32,
+ LWZU = 33,
+ LFSU = 49,
+ LD = 58,
+ LFDU = 51,
+ STB = 38,
+ STBU = 39,
+ STH = 44,
+ STHU = 45,
+ STW = 36,
+ STWU = 37,
+ STFSU = 53,
+ STFDU = 55,
+ STD = 62,
+ ADDI = 14
+};
+
uint64_t elf::getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
// TOC starts where the first of these sections starts. We always create a
// .got when we see a relocation that uses it, so for us the start is always
// the .got.
- uint64_t TocVA = InX::Got->getVA();
+ uint64_t TocVA = In.Got->getVA();
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
@@ -37,6 +74,31 @@ uint64_t elf::getPPC64TocBase() {
return TocVA + PPC64TocOffset;
}
+unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) {
+ // The offset is encoded into the 3 most significant bits of the st_other
+ // field, with some special values described in section 3.4.1 of the ABI:
+ // 0 --> Zero offset between the GEP and LEP, and the function does NOT use
+ // the TOC pointer (r2). r2 will hold the same value on returning from
+ // the function as it did on entering the function.
+ // 1 --> Zero offset between the GEP and LEP, and r2 should be treated as a
+ // caller-saved register for all callers.
+ // 2-6 --> The binary logarithm of the offset eg:
+ // 2 --> 2^2 = 4 bytes --> 1 instruction.
+ // 6 --> 2^6 = 64 bytes --> 16 instructions.
+ // 7 --> Reserved.
+ uint8_t GepToLep = (StOther >> 5) & 7;
+ if (GepToLep < 2)
+ return 0;
+
+ // The value encoded in the st_other bits is the
+ // log-base-2(offset).
+ if (GepToLep < 7)
+ return 1 << GepToLep;
+
+ error("reserved value of 7 in the 3 most-significant-bits of st_other");
+ return 0;
+}
+
namespace {
class PPC64 final : public TargetInfo {
public:
@@ -51,11 +113,16 @@ public:
void writeGotHeader(uint8_t *Buf) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const override;
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const override;
};
} // namespace
@@ -71,8 +138,64 @@ static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t highest(uint64_t V) { return V >> 48; }
static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
+// Extracts the 'PO' field of an instruction encoding.
+static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); }
+
+static bool isDQFormInstruction(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case 56:
+ // The only instruction with a primary opcode of 56 is `lq`.
+ return true;
+ case 61:
+ // There are both DS and DQ instruction forms with this primary opcode.
+ // Namely `lxv` and `stxv` are the DQ-forms that use it.
+ // The DS 'XO' bits being set to 01 is restricted to DQ form.
+ return (Encoding & 3) == 0x1;
+ }
+}
+
+static bool isInstructionUpdateForm(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case LBZU:
+ case LHAU:
+ case LHZU:
+ case LWZU:
+ case LFSU:
+ case LFDU:
+ case STBU:
+ case STHU:
+ case STWU:
+ case STFSU:
+ case STFDU:
+ return true;
+ // LWA has the same opcode as LD, and the DS bits is what differentiates
+ // between LD/LDU/LWA
+ case LD:
+ case STD:
+ return (Encoding & 3) == 1;
+ }
+}
+
+// There are a number of places when we either want to read or write an
+// instruction when handling a half16 relocation type. On big-endian the buffer
+// pointer is pointing into the middle of the word we want to extract, and on
+// little-endian it is pointing to the start of the word. These 2 helpers are to
+// simplify reading and writing in that context.
+static void writeInstrFromHalf16(uint8_t *Loc, uint32_t Instr) {
+ write32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0), Instr);
+}
+
+static uint32_t readInstrFromHalf16(const uint8_t *Loc) {
+ return read32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0));
+}
+
PPC64::PPC64() {
GotRel = R_PPC64_GLOB_DAT;
+ NoneRel = R_PPC64_NONE;
PltRel = R_PPC64_JMP_SLOT;
RelativeRel = R_PPC64_RELATIVE;
IRelativeRel = R_PPC64_IRELATIVE;
@@ -85,14 +208,14 @@ PPC64::PPC64() {
GotPltHeaderEntriesNum = 2;
PltHeaderSize = 60;
NeedsThunks = true;
- TcbSize = 8;
- TlsTpOffset = 0x7000;
TlsModuleIndexRel = R_PPC64_DTPMOD64;
TlsOffsetRel = R_PPC64_DTPREL64;
TlsGotRel = R_PPC64_TPREL64;
+ NeedsMoreStackNonSplit = false;
+
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
DefaultMaxPageSize = 65536;
@@ -107,8 +230,7 @@ PPC64::PPC64() {
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
- TrapInstr =
- (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
+ write32(TrapInstr.data(), 0x7fe00008);
}
static uint32_t getEFlags(InputFile *File) {
@@ -146,27 +268,29 @@ void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// bl __tls_get_addr(x@tlsgd) into nop
// nop into addi r3, r3, x@tprel@l
- uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
-
switch (Type) {
case R_PPC64_GOT_TLSGD16_HA:
- write32(Loc - EndianOffset, 0x60000000); // nop
+ writeInstrFromHalf16(Loc, 0x60000000); // nop
break;
+ case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO:
- write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13
+ writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13
relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
break;
case R_PPC64_TLSGD:
write32(Loc, 0x60000000); // nop
write32(Loc + 4, 0x38630000); // addi r3, r3
- relocateOne(Loc + 4 + EndianOffset, R_PPC64_TPREL16_LO, Val);
+ // Since we are relocating a half16 type relocation and Loc + 4 points to
+ // the start of an instruction we need to advance the buffer by an extra
+ // 2 bytes on BE.
+ relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0),
+ R_PPC64_TPREL16_LO, Val);
break;
default:
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
}
}
-
void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement.
// The local dynamic code sequence for a global `x` will look like:
@@ -183,13 +307,12 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// bl __tls_get_addr(x@tlsgd) into nop
// nop into addi r3, r3, 4096
- uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
switch (Type) {
case R_PPC64_GOT_TLSLD16_HA:
- write32(Loc - EndianOffset, 0x60000000); // nop
+ writeInstrFromHalf16(Loc, 0x60000000); // nop
break;
case R_PPC64_GOT_TLSLD16_LO:
- write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0
+ writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13, 0
break;
case R_PPC64_TLSLD:
write32(Loc, 0x60000000); // nop
@@ -212,9 +335,90 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
}
+static unsigned getDFormOp(unsigned SecondaryOp) {
+ switch (SecondaryOp) {
+ case LBZX:
+ return LBZ;
+ case LHZX:
+ return LHZ;
+ case LWZX:
+ return LWZ;
+ case LDX:
+ return LD;
+ case STBX:
+ return STB;
+ case STHX:
+ return STH;
+ case STWX:
+ return STW;
+ case STDX:
+ return STD;
+ case ADD:
+ return ADDI;
+ default:
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ return 0;
+ }
+}
+
+void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // The initial exec code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x
+ // ld r9, x@got@tprel@l(r9) R_PPC64_GOT_TPREL16_LO_DS x
+ // add r9, r9, x@tls R_PPC64_TLS x
+
+ // Relaxing to local exec entails converting:
+ // addis r9, r2, x@got@tprel@ha into nop
+ // ld r9, x@got@tprel@l(r9) into addis r9, r13, x@tprel@ha
+ // add r9, r9, x@tls into addi r9, r9, x@tprel@l
+
+ // x@tls R_PPC64_TLS is a relocation which does not compute anything,
+ // it is replaced with r13 (thread pointer).
+
+ // The add instruction in the initial exec sequence has multiple variations
+ // that need to be handled. If we are building an address it will use an add
+ // instruction, if we are accessing memory it will use any of the X-form
+ // indexed load or store instructions.
+
+ unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0;
+ switch (Type) {
+ case R_PPC64_GOT_TPREL16_HA:
+ write32(Loc - Offset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS: {
+ uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10
+ write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13
+ relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
+ break;
+ }
+ case R_PPC64_TLS: {
+ uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc));
+ if (PrimaryOp != 31)
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
+ uint32_t DFormOp = getDFormOp(SecondaryOp);
+ write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
+ relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
+ break;
+ }
+ default:
+ llvm_unreachable("unknown relocation for IE to LE");
+ break;
+ }
+}
+
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
+ case R_PPC64_GOT16:
+ case R_PPC64_GOT16_DS:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_HI:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ return R_GOT_OFF;
case R_PPC64_TOC16:
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_HA:
@@ -224,6 +428,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
return R_GOTREL;
case R_PPC64_TOC:
return R_PPC_TOC;
+ case R_PPC64_REL14:
case R_PPC64_REL24:
return R_PPC_CALL_PLT;
case R_PPC64_REL16_LO:
@@ -279,7 +484,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_TLSLD:
return R_TLSLD_HINT;
case R_PPC64_TLS:
- return R_HINT;
+ return R_TLSIE_HINT;
default:
return R_ABS;
}
@@ -308,16 +513,16 @@ void PPC64::writePltHeader(uint8_t *Buf) const {
// The 'bcl' instruction will set the link register to the address of the
// following instruction ('mflr r11'). Here we store the offset from that
// instruction to the first entry in the GotPlt section.
- int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8);
+ int64_t GotPltOffset = In.GotPlt->getVA() - (In.Plt->getVA() + 8);
write64(Buf + 52, GotPltOffset);
}
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- int32_t Offset = PltHeaderSize + Index * PltEntrySize;
- // bl __glink_PLTresolve
- write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
+ int32_t Offset = PltHeaderSize + Index * PltEntrySize;
+ // bl __glink_PLTresolve
+ write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
@@ -328,30 +533,36 @@ static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
switch (Type) {
// TOC biased relocation.
+ case R_PPC64_GOT16:
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSLD16:
case R_PPC64_TOC16:
return {R_PPC64_ADDR16, TocBiasedVal};
+ case R_PPC64_GOT16_DS:
case R_PPC64_TOC16_DS:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_DTPREL16_DS:
return {R_PPC64_ADDR16_DS, TocBiasedVal};
+ case R_PPC64_GOT16_HA:
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TPREL16_HA:
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_TOC16_HA:
return {R_PPC64_ADDR16_HA, TocBiasedVal};
+ case R_PPC64_GOT16_HI:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_TOC16_HI:
return {R_PPC64_ADDR16_HI, TocBiasedVal};
+ case R_PPC64_GOT16_LO:
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_TOC16_LO:
return {R_PPC64_ADDR16_LO, TocBiasedVal};
+ case R_PPC64_GOT16_LO_DS:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_LO_DS:
@@ -386,9 +597,27 @@ static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
}
}
+static bool isTocOptType(RelType Type) {
+ switch (Type) {
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ return true;
+ default:
+ return false;
+ }
+}
+
void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
- // For a TOC-relative relocation, proceed in terms of the corresponding
- // ADDR16 relocation type.
+ // We need to save the original relocation type to use in diagnostics, and
+ // use the original type to determine if we should toc-optimize the
+ // instructions being relocated.
+ RelType OriginalType = Type;
+ bool ShouldTocOptimize = isTocOptType(Type);
+ // For dynamic thread pointer relative, toc-relative, and got-indirect
+ // relocations, proceed in terms of the corresponding ADDR16 relocation type.
std::tie(Type, Val) = toAddr16Rel(Type, Val);
switch (Type) {
@@ -401,18 +630,25 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
case R_PPC64_ADDR16:
case R_PPC64_TPREL16:
- checkInt(Loc, Val, 16, Type);
+ checkInt(Loc, Val, 16, OriginalType);
write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- case R_PPC64_TPREL16_DS:
- checkInt(Loc, Val, 16, Type);
- write16(Loc, (read16(Loc) & 3) | (Val & ~3));
- break;
+ case R_PPC64_TPREL16_DS: {
+ checkInt(Loc, Val, 16, OriginalType);
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint16_t Mask = isDQFormInstruction(readInstrFromHalf16(Loc)) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
case R_PPC64_TPREL16_HA:
- write16(Loc, ha(Val));
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0)
+ writeInstrFromHalf16(Loc, 0x60000000);
+ else
+ write16(Loc, ha(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
@@ -438,12 +674,40 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC64_ADDR16_LO:
case R_PPC64_REL16_LO:
case R_PPC64_TPREL16_LO:
+ // When the high-adjusted part of a toc relocation evalutes to 0, it is
+ // changed into a nop. The lo part then needs to be updated to use the
+ // toc-pointer register r2, as the base register.
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
+ uint32_t Instr = readInstrFromHalf16(Loc);
+ if (isInstructionUpdateForm(Instr))
+ error(getErrorLocation(Loc) +
+ "can't toc-optimize an update instruction: 0x" +
+ utohexstr(Instr));
+ Instr = (Instr & 0xFFE00000) | 0x00020000;
+ writeInstrFromHalf16(Loc, Instr);
+ }
write16(Loc, lo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
- case R_PPC64_TPREL16_LO_DS:
- write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3));
- break;
+ case R_PPC64_TPREL16_LO_DS: {
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint32_t Inst = readInstrFromHalf16(Loc);
+ uint16_t Mask = isDQFormInstruction(Inst) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
+ // When the high-adjusted part of a toc relocation evalutes to 0, it is
+ // changed into a nop. The lo part then needs to be updated to use the toc
+ // pointer register r2, as the base register.
+ if (isInstructionUpdateForm(Inst))
+ error(getErrorLocation(Loc) +
+ "Can't toc-optimize an update instruction: 0x" +
+ Twine::utohexstr(Inst));
+ Inst = (Inst & 0xFFE0000F) | 0x00020000;
+ writeInstrFromHalf16(Loc, Inst);
+ }
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
checkInt(Loc, Val, 32, Type);
@@ -454,9 +718,17 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC64_TOC:
write64(Loc, Val);
break;
+ case R_PPC64_REL14: {
+ uint32_t Mask = 0x0000FFFC;
+ checkInt(Loc, Val, 16, Type);
+ checkAlignment(Loc, Val, 4, Type);
+ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
+ break;
+ }
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
- checkInt(Loc, Val, 24, Type);
+ checkInt(Loc, Val, 26, Type);
+ checkAlignment(Loc, Val, 4, Type);
write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
@@ -470,9 +742,30 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const {
- // If a function is in the plt it needs to be called through
- // a call stub.
- return Type == R_PPC64_REL24 && S.isInPlt();
+ if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24)
+ return false;
+
+ // If a function is in the Plt it needs to be called with a call-stub.
+ if (S.isInPlt())
+ return true;
+
+ // If a symbol is a weak undefined and we are compiling an executable
+ // it doesn't need a range-extending thunk since it can't be called.
+ if (S.isUndefWeak() && !Config->Shared)
+ return false;
+
+ // If the offset exceeds the range of the branch type then it will need
+ // a range-extending thunk.
+ return !inBranchRange(Type, BranchAddr, S.getVA());
+}
+
+bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+ int64_t Offset = Dst - Src;
+ if (Type == R_PPC64_REL14)
+ return isInt<16>(Offset);
+ if (Type == R_PPC64_REL24)
+ return isInt<26>(Offset);
+ llvm_unreachable("unsupported relocation type used in branch");
}
RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
@@ -511,9 +804,8 @@ void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC64_GOT_TLSGD16_LO: {
// Relax from addi r3, rA, sym@got@tlsgd@l to
// ld r3, sym@got@tprel@l(rA)
- uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
- uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16));
- write32(Loc - EndianOffset, 0xE8600000 | InputRegister);
+ uint32_t InputRegister = (readInstrFromHalf16(Loc) & (0x1f << 16));
+ writeInstrFromHalf16(Loc, 0xE8600000 | InputRegister);
relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
return;
}
@@ -526,6 +818,113 @@ void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
}
+// The prologue for a split-stack function is expected to look roughly
+// like this:
+// .Lglobal_entry_point:
+// # TOC pointer initalization.
+// ...
+// .Llocal_entry_point:
+// # load the __private_ss member of the threads tcbhead.
+// ld r0,-0x7000-64(r13)
+// # subtract the functions stack size from the stack pointer.
+// addis r12, r1, ha(-stack-frame size)
+// addi r12, r12, l(-stack-frame size)
+// # compare needed to actual and branch to allocate_more_stack if more
+// # space is needed, otherwise fallthrough to 'normal' function body.
+// cmpld cr7,r12,r0
+// blt- cr7, .Lallocate_more_stack
+//
+// -) The allocate_more_stack block might be placed after the split-stack
+// prologue and the `blt-` replaced with a `bge+ .Lnormal_func_body`
+// instead.
+// -) If either the addis or addi is not needed due to the stack size being
+// smaller then 32K or a multiple of 64K they will be replaced with a nop,
+// but there will always be 2 instructions the linker can overwrite for the
+// adjusted stack size.
+//
+// The linkers job here is to increase the stack size used in the addis/addi
+// pair by split-stack-size-adjust.
+// addis r12, r1, ha(-stack-frame size - split-stack-adjust-size)
+// addi r12, r12, l(-stack-frame size - split-stack-adjust-size)
+bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const {
+ // If the caller has a global entry point adjust the buffer past it. The start
+ // of the split-stack prologue will be at the local entry point.
+ Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther);
+
+ // At the very least we expect to see a load of some split-stack data from the
+ // tcb, and 2 instructions that calculate the ending stack address this
+ // function will require. If there is not enough room for at least 3
+ // instructions it can't be a split-stack prologue.
+ if (Loc + 12 >= End)
+ return false;
+
+ // First instruction must be `ld r0, -0x7000-64(r13)`
+ if (read32(Loc) != 0xe80d8fc0)
+ return false;
+
+ int16_t HiImm = 0;
+ int16_t LoImm = 0;
+ // First instruction can be either an addis if the frame size is larger then
+ // 32K, or an addi if the size is less then 32K.
+ int32_t FirstInstr = read32(Loc + 4);
+ if (getPrimaryOpCode(FirstInstr) == 15) {
+ HiImm = FirstInstr & 0xFFFF;
+ } else if (getPrimaryOpCode(FirstInstr) == 14) {
+ LoImm = FirstInstr & 0xFFFF;
+ } else {
+ return false;
+ }
+
+ // Second instruction is either an addi or a nop. If the first instruction was
+ // an addi then LoImm is set and the second instruction must be a nop.
+ uint32_t SecondInstr = read32(Loc + 8);
+ if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) {
+ LoImm = SecondInstr & 0xFFFF;
+ } else if (SecondInstr != 0x60000000) {
+ return false;
+ }
+
+ // The register operands of the first instruction should be the stack-pointer
+ // (r1) as the input (RA) and r12 as the output (RT). If the second
+ // instruction is not a nop, then it should use r12 as both input and output.
+ auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT,
+ uint8_t ExpectedRA) {
+ return ((Instr & 0x3E00000) >> 21 == ExpectedRT) &&
+ ((Instr & 0x1F0000) >> 16 == ExpectedRA);
+ };
+ if (!CheckRegOperands(FirstInstr, 12, 1))
+ return false;
+ if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12))
+ return false;
+
+ int32_t StackFrameSize = (HiImm * 65536) + LoImm;
+ // Check that the adjusted size doesn't overflow what we can represent with 2
+ // instructions.
+ if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) {
+ error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows");
+ return false;
+ }
+
+ int32_t AdjustedStackFrameSize =
+ StackFrameSize - Config->SplitStackAdjustSize;
+
+ LoImm = AdjustedStackFrameSize & 0xFFFF;
+ HiImm = (AdjustedStackFrameSize + 0x8000) >> 16;
+ if (HiImm) {
+ write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm);
+ // If the low immediate is zero the second instruction will be a nop.
+ SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000;
+ write32(Loc + 8, SecondInstr);
+ } else {
+ // addi r12, r1, imm
+ write32(Loc + 4, (0x39810000) | (uint16_t)LoImm);
+ write32(Loc + 8, 0x60000000);
+ }
+
+ return true;
+}
+
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
diff --git a/ELF/Arch/RISCV.cpp b/ELF/Arch/RISCV.cpp
new file mode 100644
index 000000000000..461e8d35c3e6
--- /dev/null
+++ b/ELF/Arch/RISCV.cpp
@@ -0,0 +1,279 @@
+//===- RISCV.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Target.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+
+class RISCV final : public TargetInfo {
+public:
+ RISCV();
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+
+} // end anonymous namespace
+
+RISCV::RISCV() { NoneRel = R_RISCV_NONE; }
+
+static uint32_t getEFlags(InputFile *F) {
+ if (Config->Is64)
+ return cast<ObjFile<ELF64LE>>(F)->getObj().getHeader()->e_flags;
+ return cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags;
+}
+
+uint32_t RISCV::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+
+ uint32_t Target = getEFlags(ObjectFiles.front());
+
+ for (InputFile *F : ObjectFiles) {
+ uint32_t EFlags = getEFlags(F);
+ if (EFlags & EF_RISCV_RVC)
+ Target |= EF_RISCV_RVC;
+
+ if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI))
+ error(toString(F) +
+ ": cannot link object files with different floating-point ABI");
+
+ if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE))
+ error(toString(F) +
+ ": cannot link object files with different EF_RISCV_RVE");
+ }
+
+ return Target;
+}
+
+RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_RISCV_JAL:
+ case R_RISCV_BRANCH:
+ case R_RISCV_CALL:
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
+ case R_RISCV_32_PCREL:
+ return R_PC;
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ return R_RISCV_PC_INDIRECT;
+ case R_RISCV_RELAX:
+ case R_RISCV_ALIGN:
+ return R_HINT;
+ default:
+ return R_ABS;
+ }
+}
+
+// Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63.
+static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) {
+ return (V & ((1ULL << (Begin + 1)) - 1)) >> End;
+}
+
+void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
+ const uint64_t Val) const {
+ switch (Type) {
+ case R_RISCV_32:
+ write32le(Loc, Val);
+ return;
+ case R_RISCV_64:
+ write64le(Loc, Val);
+ return;
+
+ case R_RISCV_RVC_BRANCH: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 8, Type);
+ checkAlignment(Loc, Val, 2, Type);
+ uint16_t Insn = read16le(Loc) & 0xE383;
+ uint16_t Imm8 = extractBits(Val, 8, 8) << 12;
+ uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10;
+ uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5;
+ uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3;
+ uint16_t Imm5 = extractBits(Val, 5, 5) << 2;
+ Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5;
+
+ write16le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_RVC_JUMP: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 11, Type);
+ checkAlignment(Loc, Val, 2, Type);
+ uint16_t Insn = read16le(Loc) & 0xE003;
+ uint16_t Imm11 = extractBits(Val, 11, 11) << 12;
+ uint16_t Imm4 = extractBits(Val, 4, 4) << 11;
+ uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9;
+ uint16_t Imm10 = extractBits(Val, 10, 10) << 8;
+ uint16_t Imm6 = extractBits(Val, 6, 6) << 7;
+ uint16_t Imm7 = extractBits(Val, 7, 7) << 6;
+ uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3;
+ uint16_t Imm5 = extractBits(Val, 5, 5) << 2;
+ Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5;
+
+ write16le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_RVC_LUI: {
+ int32_t Imm = ((Val + 0x800) >> 12);
+ checkUInt(Loc, Imm, 6, Type);
+ if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0`
+ write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000);
+ } else {
+ uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12;
+ uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2;
+ write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12);
+ }
+ return;
+ }
+
+ case R_RISCV_JAL: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 20, Type);
+ checkAlignment(Loc, Val, 2, Type);
+
+ uint32_t Insn = read32le(Loc) & 0xFFF;
+ uint32_t Imm20 = extractBits(Val, 20, 20) << 31;
+ uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21;
+ uint32_t Imm11 = extractBits(Val, 11, 11) << 20;
+ uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12;
+ Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12;
+
+ write32le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_BRANCH: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 12, Type);
+ checkAlignment(Loc, Val, 2, Type);
+
+ uint32_t Insn = read32le(Loc) & 0x1FFF07F;
+ uint32_t Imm12 = extractBits(Val, 12, 12) << 31;
+ uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25;
+ uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8;
+ uint32_t Imm11 = extractBits(Val, 11, 11) << 7;
+ Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11;
+
+ write32le(Loc, Insn);
+ return;
+ }
+
+ // auipc + jalr pair
+ case R_RISCV_CALL: {
+ checkInt(Loc, Val, 32, Type);
+ if (isInt<32>(Val)) {
+ relocateOne(Loc, R_RISCV_PCREL_HI20, Val);
+ relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val);
+ }
+ return;
+ }
+
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_HI20: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000));
+ return;
+ }
+
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_LO12_I: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ uint32_t Lo = Val - (Hi & 0xFFFFF000);
+ write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20));
+ return;
+ }
+
+ case R_RISCV_PCREL_LO12_S:
+ case R_RISCV_LO12_S: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ uint32_t Lo = Val - (Hi & 0xFFFFF000);
+ uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25;
+ uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7;
+ write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0);
+ return;
+ }
+
+ case R_RISCV_ADD8:
+ *Loc += Val;
+ return;
+ case R_RISCV_ADD16:
+ write16le(Loc, read16le(Loc) + Val);
+ return;
+ case R_RISCV_ADD32:
+ write32le(Loc, read32le(Loc) + Val);
+ return;
+ case R_RISCV_ADD64:
+ write64le(Loc, read64le(Loc) + Val);
+ return;
+ case R_RISCV_SUB6:
+ *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f);
+ return;
+ case R_RISCV_SUB8:
+ *Loc -= Val;
+ return;
+ case R_RISCV_SUB16:
+ write16le(Loc, read16le(Loc) - Val);
+ return;
+ case R_RISCV_SUB32:
+ write32le(Loc, read32le(Loc) - Val);
+ return;
+ case R_RISCV_SUB64:
+ write64le(Loc, read64le(Loc) - Val);
+ return;
+ case R_RISCV_SET6:
+ *Loc = (*Loc & 0xc0) | (Val & 0x3f);
+ return;
+ case R_RISCV_SET8:
+ *Loc = Val;
+ return;
+ case R_RISCV_SET16:
+ write16le(Loc, Val);
+ return;
+ case R_RISCV_SET32:
+ case R_RISCV_32_PCREL:
+ write32le(Loc, Val);
+ return;
+
+ case R_RISCV_ALIGN:
+ case R_RISCV_RELAX:
+ return; // Ignored (for now)
+ case R_RISCV_NONE:
+ return; // Do nothing
+
+ // These are handled by the dynamic linker
+ case R_RISCV_RELATIVE:
+ case R_RISCV_COPY:
+ case R_RISCV_JUMP_SLOT:
+ // GP-relative relocations are only produced after relaxation, which
+ // we don't support for now
+ case R_RISCV_GPREL_I:
+ case R_RISCV_GPREL_S:
+ default:
+ error(getErrorLocation(Loc) +
+ "unimplemented relocation: " + toString(Type));
+ return;
+ }
+}
+
+TargetInfo *elf::getRISCVTargetInfo() {
+ static RISCV Target;
+ return &Target;
+}
diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp
index 36f5c836930e..831aa2028e7f 100644
--- a/ELF/Arch/SPARCV9.cpp
+++ b/ELF/Arch/SPARCV9.cpp
@@ -35,6 +35,7 @@ public:
SPARCV9::SPARCV9() {
CopyRel = R_SPARC_COPY;
GotRel = R_SPARC_GLOB_DAT;
+ NoneRel = R_SPARC_NONE;
PltRel = R_SPARC_JMP_SLOT;
RelativeRel = R_SPARC_RELATIVE;
GotEntrySize = 8;
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
index 19a0b6017f1a..e910375d2fc7 100644
--- a/ELF/Arch/X86.cpp
+++ b/ELF/Arch/X86.cpp
@@ -48,6 +48,7 @@ public:
X86::X86() {
CopyRel = R_386_COPY;
GotRel = R_386_GLOB_DAT;
+ NoneRel = R_386_NONE;
PltRel = R_386_JUMP_SLOT;
IRelativeRel = R_386_IRELATIVE;
RelativeRel = R_386_RELATIVE;
@@ -59,7 +60,11 @@ X86::X86() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
- TrapInstr = 0xcccccccc; // 0xcc = INT3
+ TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
+
+ // Align to the non-PAE large page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes large, superpage-aligned allocations.
+ DefaultImageBase = 0x400000;
}
static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; }
@@ -152,7 +157,7 @@ RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data,
}
void X86::writeGotPltHeader(uint8_t *Buf) const {
- write32le(Buf, InX::Dynamic->getVA());
+ write32le(Buf, In.Dynamic->getVA());
}
void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
@@ -183,8 +188,8 @@ void X86::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, V, sizeof(V));
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
- uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ uint32_t GotPlt = In.GotPlt->getVA() - Ebx;
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
return;
@@ -196,7 +201,7 @@ void X86::writePltHeader(uint8_t *Buf) const {
0x90, 0x90, 0x90, 0x90, // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint32_t GotPlt = InX::GotPlt->getVA();
+ uint32_t GotPlt = In.GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
}
@@ -213,7 +218,7 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
if (Config->Pic) {
// jmp *foo@GOT(%ebx)
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
Buf[1] = 0xa3;
write32le(Buf + 2, GotPltEntryAddr - Ebx);
} else {
@@ -447,8 +452,8 @@ void RetpolinePic::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, Insn, sizeof(Insn));
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
- uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ uint32_t GotPlt = In.GotPlt->getVA() - Ebx;
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 9, GotPlt + 8);
}
@@ -467,7 +472,7 @@ void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
};
memcpy(Buf, Insn, sizeof(Insn));
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
unsigned Off = getPltEntryOffset(Index);
write32le(Buf + 3, GotPltEntryAddr - Ebx);
write32le(Buf + 8, -Off - 12 + 32);
@@ -506,7 +511,7 @@ void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, Insn, sizeof(Insn));
- uint32_t GotPlt = InX::GotPlt->getVA();
+ uint32_t GotPlt = In.GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
}
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
index d4bdb3730c58..06314155dcc9 100644
--- a/ELF/Arch/X86_64.cpp
+++ b/ELF/Arch/X86_64.cpp
@@ -43,8 +43,8 @@ public:
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
- bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const override;
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const override;
private:
void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
@@ -55,6 +55,7 @@ private:
template <class ELFT> X86_64<ELFT>::X86_64() {
CopyRel = R_X86_64_COPY;
GotRel = R_X86_64_GLOB_DAT;
+ NoneRel = R_X86_64_NONE;
PltRel = R_X86_64_JUMP_SLOT;
RelativeRel = R_X86_64_RELATIVE;
IRelativeRel = R_X86_64_IRELATIVE;
@@ -66,7 +67,7 @@ template <class ELFT> X86_64<ELFT>::X86_64() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
- TrapInstr = 0xcccccccc; // 0xcc = INT3
+ TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
// Align to the large page size (known as a superpage or huge page).
// FreeBSD automatically promotes large, superpage-aligned allocations.
@@ -124,7 +125,7 @@ template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
// required, but it is documented in the psabi and the glibc dynamic linker
// seems to use it (note that this is relevant for linking ld.so, not any
// other program).
- write64le(Buf, InX::Dynamic->getVA());
+ write64le(Buf, In.Dynamic->getVA());
}
template <class ELFT>
@@ -140,8 +141,8 @@ template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
0x0f, 0x1f, 0x40, 0x00, // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
}
@@ -481,23 +482,27 @@ namespace {
// B) Or a load of a stack pointer offset with an lea to r10 or r11.
template <>
bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const {
+ uint8_t *End,
+ uint8_t StOther) const {
+ if (Loc + 8 >= End)
+ return false;
+
// Replace "cmp %fs:0x70,%rsp" and subsequent branch
// with "stc, nopl 0x0(%rax,%rax,1)"
- if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) {
+ if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 0) {
memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8);
return true;
}
- // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10"
- if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) {
- memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7);
- return true;
- }
-
- // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11"
- if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) {
- memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7);
+ // Adjust "lea X(%rsp),%rYY" to lea "(X - 0x4000)(%rsp),%rYY" where rYY could
+ // be r10 or r11. The lea instruction feeds a subsequent compare which checks
+ // if there is X available stack space. Making X larger effectively reserves
+ // that much additional space. The stack grows downward so subtract the value.
+ if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 ||
+ memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) {
+ // The offset bytes are encoded four bytes after the start of the
+ // instruction.
+ write32le(Loc + 4, read32le(Loc + 4) - 0x4000);
return true;
}
return false;
@@ -505,7 +510,8 @@ bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
template <>
bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const {
+ uint8_t *End,
+ uint8_t StOther) const {
llvm_unreachable("Target doesn't support split stacks.");
}
@@ -566,8 +572,8 @@ template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, Insn, sizeof(Insn));
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
write32le(Buf + 2, GotPlt - Plt - 6 + 8);
write32le(Buf + 9, GotPlt - Plt - 13 + 16);
}
@@ -586,7 +592,7 @@ void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
};
memcpy(Buf, Insn, sizeof(Insn));
- uint64_t Off = TargetInfo::getPltEntryOffset(Index);
+ uint64_t Off = getPltEntryOffset(Index);
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
write32le(Buf + 8, -Off - 12 + 32);
@@ -629,7 +635,7 @@ void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
memcpy(Buf, Insn, sizeof(Insn));
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
- write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12);
+ write32le(Buf + 8, -getPltEntryOffset(Index) - 12);
}
template <class ELFT> static TargetInfo *getTargetInfo() {
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index fb2f53a72025..a1c23b0d49ac 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -15,17 +15,19 @@ add_lld_library(lldELF
Arch/Hexagon.cpp
Arch/Mips.cpp
Arch/MipsArchTree.cpp
+ Arch/MSP430.cpp
Arch/PPC.cpp
Arch/PPC64.cpp
+ Arch/RISCV.cpp
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
CallGraphSort.cpp
+ DWARF.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
Filesystem.cpp
- GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
diff --git a/ELF/CallGraphSort.cpp b/ELF/CallGraphSort.cpp
index 33ac159a6e26..2a7d78664b8e 100644
--- a/ELF/CallGraphSort.cpp
+++ b/ELF/CallGraphSort.cpp
@@ -57,10 +57,7 @@ struct Edge {
};
struct Cluster {
- Cluster(int Sec, size_t S) {
- Sections.push_back(Sec);
- Size = S;
- }
+ Cluster(int Sec, size_t S) : Sections{Sec}, Size(S) {}
double getDensity() const {
if (Size == 0)
@@ -72,7 +69,7 @@ struct Cluster {
size_t Size = 0;
uint64_t Weight = 0;
uint64_t InitialWeight = 0;
- std::vector<Edge> Preds;
+ Edge BestPred = {-1, 0};
};
class CallGraphSort {
@@ -96,12 +93,14 @@ constexpr int MAX_DENSITY_DEGRADATION = 8;
constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
} // end anonymous namespace
+typedef std::pair<const InputSectionBase *, const InputSectionBase *>
+ SectionPair;
+
// Take the edge list in Config->CallGraphProfile, resolve symbol names to
// Symbols, and generate a graph between InputSections with the provided
// weights.
CallGraphSort::CallGraphSort() {
- llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
- uint64_t> &Profile = Config->CallGraphProfile;
+ MapVector<SectionPair, uint64_t> &Profile = Config->CallGraphProfile;
DenseMap<const InputSectionBase *, int> SecToCluster;
auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
@@ -114,7 +113,7 @@ CallGraphSort::CallGraphSort() {
};
// Create the graph.
- for (const auto &C : Profile) {
+ for (std::pair<SectionPair, uint64_t> &C : Profile) {
const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl);
const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl);
uint64_t Weight = C.second;
@@ -136,8 +135,12 @@ CallGraphSort::CallGraphSort() {
if (From == To)
continue;
- // Add an edge
- Clusters[To].Preds.push_back({From, Weight});
+ // Remember the best edge.
+ Cluster &ToC = Clusters[To];
+ if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) {
+ ToC.BestPred.From = From;
+ ToC.BestPred.Weight = Weight;
+ }
}
for (Cluster &C : Clusters)
C.InitialWeight = C.Weight;
@@ -146,9 +149,7 @@ CallGraphSort::CallGraphSort() {
// It's bad to merge clusters which would degrade the density too much.
static bool isNewDensityBad(Cluster &A, Cluster &B) {
double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size);
- if (NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION)
- return true;
- return false;
+ return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION;
}
static void mergeClusters(Cluster &Into, Cluster &From) {
@@ -167,9 +168,9 @@ void CallGraphSort::groupClusters() {
std::vector<int> SortedSecs(Clusters.size());
std::vector<Cluster *> SecToCluster(Clusters.size());
- for (int SI = 0, SE = Clusters.size(); SI != SE; ++SI) {
- SortedSecs[SI] = SI;
- SecToCluster[SI] = &Clusters[SI];
+ for (size_t I = 0; I < Clusters.size(); ++I) {
+ SortedSecs[I] = I;
+ SecToCluster[I] = &Clusters[I];
}
std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
@@ -181,21 +182,11 @@ void CallGraphSort::groupClusters() {
// been merged into another cluster yet.
Cluster &C = Clusters[SI];
- int BestPred = -1;
- uint64_t BestWeight = 0;
-
- for (Edge &E : C.Preds) {
- if (BestPred == -1 || E.Weight > BestWeight) {
- BestPred = E.From;
- BestWeight = E.Weight;
- }
- }
-
- // don't consider merging if the edge is unlikely.
- if (BestWeight * 10 <= C.InitialWeight)
+ // Don't consider merging if the edge is unlikely.
+ if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight)
continue;
- Cluster *PredC = SecToCluster[BestPred];
+ Cluster *PredC = SecToCluster[C.BestPred.From];
if (PredC == &C)
continue;
@@ -229,7 +220,7 @@ DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
groupClusters();
// Generate order.
- llvm::DenseMap<const InputSectionBase *, int> OrderMap;
+ DenseMap<const InputSectionBase *, int> OrderMap;
ssize_t CurOrder = 1;
for (const Cluster &C : Clusters)
diff --git a/ELF/Config.h b/ELF/Config.h
index 622324c13e2d..8fb760e592eb 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -47,7 +47,7 @@ enum class ICFLevel { None, Safe, All };
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
-enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll };
+enum class UnresolvedPolicy { ReportError, Warn, Ignore };
// For --orphan-handling.
enum class OrphanHandlingPolicy { Place, Warn, Error };
@@ -127,6 +127,7 @@ struct Configuration {
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool CallGraphProfileSort;
bool CheckSections;
bool CompressDebugSections;
bool Cref;
@@ -134,11 +135,13 @@ struct Configuration {
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
+ bool EmitLLVM;
bool EmitRelocs;
bool EnableNewDtags;
bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
+ bool FormatBinary = false;
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
@@ -170,19 +173,24 @@ struct Configuration {
bool Trace;
bool ThinLTOEmitImportsFiles;
bool ThinLTOIndexOnly;
+ bool TocOptimize;
bool UndefinedVersion;
bool UseAndroidRelrTags = false;
bool WarnBackrefs;
bool WarnCommon;
+ bool WarnIfuncTextrel;
bool WarnMissingEntry;
bool WarnSymbolOrdering;
bool WriteAddends;
bool ZCombreloc;
bool ZCopyreloc;
bool ZExecstack;
+ bool ZGlobal;
bool ZHazardplt;
bool ZInitfirst;
+ bool ZInterpose;
bool ZKeepTextSectionPrefix;
+ bool ZNodefaultlib;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
@@ -212,6 +220,7 @@ struct Configuration {
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
+ int32_t SplitStackAdjustSize;
// The following config options do not directly correspond to any
// particualr command line options.
diff --git a/ELF/GdbIndex.cpp b/ELF/DWARF.cpp
index 85449a200647..17e1a4d600eb 100644
--- a/ELF/GdbIndex.cpp
+++ b/ELF/DWARF.cpp
@@ -1,4 +1,4 @@
-//===- GdbIndex.cpp -------------------------------------------------------===//
+//===- DWARF.cpp ----------------------------------------------------------===//
//
// The LLVM Linker
//
@@ -14,8 +14,9 @@
//
//===----------------------------------------------------------------------===//
-#include "GdbIndex.h"
+#include "DWARF.h"
#include "Symbols.h"
+#include "Target.h"
#include "lld/Common/Memory.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -29,24 +30,28 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) {
for (InputSectionBase *Sec : Obj->getSections()) {
if (!Sec)
continue;
- if (LLDDWARFSection *M = StringSwitch<LLDDWARFSection *>(Sec->Name)
- .Case(".debug_info", &InfoSection)
- .Case(".debug_ranges", &RangeSection)
- .Case(".debug_line", &LineSection)
- .Default(nullptr)) {
- Sec->maybeDecompress();
- M->Data = toStringRef(Sec->Data);
+
+ if (LLDDWARFSection *M =
+ StringSwitch<LLDDWARFSection *>(Sec->Name)
+ .Case(".debug_addr", &AddrSection)
+ .Case(".debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case(".debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case(".debug_info", &InfoSection)
+ .Case(".debug_ranges", &RangeSection)
+ .Case(".debug_rnglists", &RngListsSection)
+ .Case(".debug_line", &LineSection)
+ .Default(nullptr)) {
+ M->Data = toStringRef(Sec->data());
M->Sec = Sec;
continue;
}
+
if (Sec->Name == ".debug_abbrev")
- AbbrevSection = toStringRef(Sec->Data);
- else if (Sec->Name == ".debug_gnu_pubnames")
- GnuPubNamesSection = toStringRef(Sec->Data);
- else if (Sec->Name == ".debug_gnu_pubtypes")
- GnuPubTypesSection = toStringRef(Sec->Data);
+ AbbrevSection = toStringRef(Sec->data());
else if (Sec->Name == ".debug_str")
- StrSection = toStringRef(Sec->Data);
+ StrSection = toStringRef(Sec->data());
+ else if (Sec->Name == ".debug_line_str")
+ LineStringSection = toStringRef(Sec->data());
}
}
@@ -73,7 +78,10 @@ LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos,
// Broken debug info can point to a non-Defined symbol.
auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel));
if (!DR) {
- error("unsupported relocation target while parsing debug info");
+ RelType Type = Rel.getType(Config->IsMips64EL);
+ if (Type != Target->NoneRel)
+ error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" +
+ llvm::utohexstr(Rel.r_offset) + " has unsupported target");
return None;
}
uint64_t Val = DR->Value + getAddend<ELFT>(Rel);
diff --git a/ELF/GdbIndex.h b/ELF/DWARF.h
index eba1ba22f879..8ecf02c77fb4 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/DWARF.h
@@ -1,4 +1,4 @@
-//===- GdbIndex.h --------------------------------------------*- C++ -*-===//
+//===- DWARF.h -----------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -7,10 +7,11 @@
//
//===-------------------------------------------------------------------===//
-#ifndef LLD_ELF_GDB_INDEX_H
-#define LLD_ELF_GDB_INDEX_H
+#ifndef LLD_ELF_DWARF_H
+#define LLD_ELF_DWARF_H
#include "InputFiles.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/ELF.h"
@@ -24,44 +25,66 @@ struct LLDDWARFSection final : public llvm::DWARFSection {
};
template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
- LLDDWARFSection InfoSection;
- LLDDWARFSection RangeSection;
- LLDDWARFSection LineSection;
- StringRef AbbrevSection;
- StringRef GnuPubNamesSection;
- StringRef GnuPubTypesSection;
- StringRef StrSection;
-
- template <class RelTy>
- llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec,
- uint64_t Pos,
- ArrayRef<RelTy> Rels) const;
-
public:
explicit LLDDwarfObj(ObjFile<ELFT> *Obj);
- const llvm::DWARFSection &getInfoSection() const override {
- return InfoSection;
+
+ void forEachInfoSections(
+ llvm::function_ref<void(const llvm::DWARFSection &)> F) const override {
+ F(InfoSection);
}
+
const llvm::DWARFSection &getRangeSection() const override {
return RangeSection;
}
+
+ const llvm::DWARFSection &getRnglistsSection() const override {
+ return RngListsSection;
+ }
+
const llvm::DWARFSection &getLineSection() const override {
return LineSection;
}
- StringRef getFileName() const override { return ""; }
- StringRef getAbbrevSection() const override { return AbbrevSection; }
- StringRef getStringSection() const override { return StrSection; }
- StringRef getGnuPubNamesSection() const override {
+
+ const llvm::DWARFSection &getAddrSection() const override {
+ return AddrSection;
+ }
+
+ const llvm::DWARFSection &getGnuPubNamesSection() const override {
return GnuPubNamesSection;
}
- StringRef getGnuPubTypesSection() const override {
+
+ const llvm::DWARFSection &getGnuPubTypesSection() const override {
return GnuPubTypesSection;
}
+
+ StringRef getFileName() const override { return ""; }
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ StringRef getStringSection() const override { return StrSection; }
+ StringRef getLineStringSection() const override { return LineStringSection; }
+
bool isLittleEndian() const override {
return ELFT::TargetEndianness == llvm::support::little;
}
+
llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec,
uint64_t Pos) const override;
+
+private:
+ template <class RelTy>
+ llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec,
+ uint64_t Pos,
+ ArrayRef<RelTy> Rels) const;
+
+ LLDDWARFSection GnuPubNamesSection;
+ LLDDWARFSection GnuPubTypesSection;
+ LLDDWARFSection InfoSection;
+ LLDDWARFSection RangeSection;
+ LLDDWARFSection RngListsSection;
+ LLDDWARFSection LineSection;
+ LLDDWARFSection AddrSection;
+ StringRef AbbrevSection;
+ StringRef StrSection;
+ StringRef LineStringSection;
};
} // namespace elf
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 693dba64ab5a..13b6119e2dc9 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -63,6 +63,7 @@ using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::sys;
+using namespace llvm::support;
using namespace lld;
using namespace lld::elf;
@@ -74,7 +75,7 @@ static void setConfigs(opt::InputArgList &Args);
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = sys::path::filename(Args[0]);
+ errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
@@ -84,7 +85,6 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
InputSections.clear();
OutputSections.clear();
- Tar = nullptr;
BinaryFiles.clear();
BitcodeFiles.clear();
ObjectFiles.clear();
@@ -94,6 +94,10 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
Driver = make<LinkerDriver>();
Script = make<LinkerScript>();
Symtab = make<SymbolTable>();
+
+ Tar = nullptr;
+ memset(&In, 0, sizeof(In));
+
Config->ProgName = Args[0];
Driver->main(Args);
@@ -125,9 +129,11 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
.Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Case("elf32lriscv", {ELF32LEKind, EM_RISCV})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
+ .Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
.Case("elf64lppc", {ELF64LEKind, EM_PPC64})
.Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
@@ -183,7 +189,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
return;
MemoryBufferRef MBRef = *Buffer;
- if (InBinary) {
+ if (Config->FormatBinary) {
Files.push_back(make<BinaryFile>(MBRef));
return;
}
@@ -218,7 +224,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
return;
}
case file_magic::elf_shared_object:
- if (Config->Relocatable) {
+ if (Config->Static || Config->Relocatable) {
error("attempted static link of dynamic object " + Path);
return;
}
@@ -269,14 +275,17 @@ static void initLLVM() {
// Some command line options or some combinations of them are not allowed.
// This function checks for such errors.
-static void checkOptions(opt::InputArgList &Args) {
+static void checkOptions() {
// The MIPS ABI as of 2016 does not support the GNU-style symbol lookup
// table which is a relatively new feature.
if (Config->EMachine == EM_MIPS && Config->GnuHash)
- error("the .gnu.hash section is not compatible with the MIPS target.");
+ error("the .gnu.hash section is not compatible with the MIPS target");
if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64)
- error("--fix-cortex-a53-843419 is only supported on AArch64 targets.");
+ error("--fix-cortex-a53-843419 is only supported on AArch64 targets");
+
+ if (Config->TocOptimize && Config->EMachine != EM_PPC64)
+ error("--toc-optimize is only supported on the PowerPC64 target");
if (Config->Pie && Config->Shared)
error("-shared and -pie may not be used together");
@@ -336,12 +345,13 @@ static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
return Default;
}
-static bool isKnown(StringRef S) {
+static bool isKnownZFlag(StringRef S) {
return S == "combreloc" || S == "copyreloc" || S == "defs" ||
- S == "execstack" || S == "hazardplt" || S == "initfirst" ||
+ S == "execstack" || S == "global" || S == "hazardplt" ||
+ S == "initfirst" || S == "interpose" ||
S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
- S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" ||
- S == "nodlopen" || S == "noexecstack" ||
+ S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" ||
+ S == "nodelete" || S == "nodlopen" || S == "noexecstack" ||
S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" ||
S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" ||
S == "rodynamic" || S == "text" || S == "wxneeded" ||
@@ -351,7 +361,7 @@ static bool isKnown(StringRef S) {
// Report an error for an unknown -z option.
static void checkZOptions(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_z))
- if (!isKnown(Arg->getValue()))
+ if (!isKnownZFlag(Arg->getValue()))
error("unknown -z value: " + StringRef(Arg->getValue()));
}
@@ -386,31 +396,30 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
message(getLLDVersion() + " (compatible with GNU linkers)");
- // The behavior of -v or --version is a bit strange, but this is
- // needed for compatibility with GNU linkers.
- if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT))
- return;
- if (Args.hasArg(OPT_version))
- return;
-
if (const char *Path = getReproduceOption(Args)) {
// Note that --reproduce is a debug option so you can ignore it
// if you are trying to understand the whole picture of the code.
Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
TarWriter::create(Path, path::stem(Path));
if (ErrOrWriter) {
- Tar = ErrOrWriter->get();
+ Tar = std::move(*ErrOrWriter);
Tar->append("response.txt", createResponseFile(Args));
Tar->append("version.txt", getLLDVersion() + "\n");
- make<std::unique_ptr<TarWriter>>(std::move(*ErrOrWriter));
} else {
- error(Twine("--reproduce: failed to open ") + Path + ": " +
- toString(ErrOrWriter.takeError()));
+ error("--reproduce: " + toString(ErrOrWriter.takeError()));
}
}
readConfigs(Args);
checkZOptions(Args);
+
+ // The behavior of -v or --version is a bit strange, but this is
+ // needed for compatibility with GNU linkers.
+ if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT))
+ return;
+ if (Args.hasArg(OPT_version))
+ return;
+
initLLVM();
createFiles(Args);
if (errorCount())
@@ -418,7 +427,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
inferMachineType();
setConfigs(Args);
- checkOptions(Args);
+ checkOptions();
if (errorCount())
return;
@@ -448,9 +457,6 @@ static std::string getRpath(opt::InputArgList &Args) {
// Determines what we should do if there are remaining unresolved
// symbols after the name resolution.
static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
- if (Args.hasArg(OPT_relocatable))
- return UnresolvedPolicy::IgnoreAll;
-
UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols,
OPT_warn_unresolved_symbols, true)
? UnresolvedPolicy::ReportError
@@ -497,14 +503,11 @@ static Target2Policy getTarget2(opt::InputArgList &Args) {
}
static bool isOutputFormatBinary(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_oformat)) {
- StringRef S = Arg->getValue();
- if (S == "binary")
- return true;
- if (S.startswith("elf"))
- return false;
+ StringRef S = Args.getLastArgValue(OPT_oformat, "elf");
+ if (S == "binary")
+ return true;
+ if (!S.startswith("elf"))
error("unknown --oformat value: " + S);
- }
return false;
}
@@ -645,38 +648,56 @@ static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) {
static void readCallGraph(MemoryBufferRef MB) {
// Build a map from symbol name to section
- DenseMap<StringRef, const Symbol *> SymbolNameToSymbol;
+ DenseMap<StringRef, Symbol *> Map;
for (InputFile *File : ObjectFiles)
for (Symbol *Sym : File->getSymbols())
- SymbolNameToSymbol[Sym->getName()] = Sym;
+ Map[Sym->getName()] = Sym;
+
+ auto FindSection = [&](StringRef Name) -> InputSectionBase * {
+ Symbol *Sym = Map.lookup(Name);
+ if (!Sym) {
+ if (Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Name);
+ return nullptr;
+ }
+ maybeWarnUnorderableSymbol(Sym);
+
+ if (Defined *DR = dyn_cast_or_null<Defined>(Sym))
+ return dyn_cast_or_null<InputSectionBase>(DR->Section);
+ return nullptr;
+ };
- for (StringRef L : args::getLines(MB)) {
+ for (StringRef Line : args::getLines(MB)) {
SmallVector<StringRef, 3> Fields;
- L.split(Fields, ' ');
+ Line.split(Fields, ' ');
uint64_t Count;
- if (Fields.size() != 3 || !to_integer(Fields[2], Count))
- fatal(MB.getBufferIdentifier() + ": parse error");
- const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]);
- const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]);
- if (Config->WarnSymbolOrdering) {
- if (!FromSym)
- warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]);
- if (!ToSym)
- warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]);
+
+ if (Fields.size() != 3 || !to_integer(Fields[2], Count)) {
+ error(MB.getBufferIdentifier() + ": parse error");
+ return;
+ }
+
+ if (InputSectionBase *From = FindSection(Fields[0]))
+ if (InputSectionBase *To = FindSection(Fields[1]))
+ Config->CallGraphProfile[std::make_pair(From, To)] += Count;
+ }
+}
+
+template <class ELFT> static void readCallGraphsFromObjectFiles() {
+ for (auto File : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+
+ for (const Elf_CGProfile_Impl<ELFT> &CGPE : Obj->CGProfile) {
+ auto *FromSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_from));
+ auto *ToSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_to));
+ if (!FromSym || !ToSym)
+ continue;
+
+ auto *From = dyn_cast_or_null<InputSectionBase>(FromSym->Section);
+ auto *To = dyn_cast_or_null<InputSectionBase>(ToSym->Section);
+ if (From && To)
+ Config->CallGraphProfile[{From, To}] += CGPE.cgp_weight;
}
- if (!FromSym || !ToSym || Count == 0)
- continue;
- warnUnorderableSymbol(FromSym);
- warnUnorderableSymbol(ToSym);
- const Defined *FromSymD = dyn_cast<Defined>(FromSym);
- const Defined *ToSymD = dyn_cast<Defined>(ToSym);
- if (!FromSymD || !ToSymD)
- continue;
- const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section);
- const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section);
- if (!FromSB || !ToSB)
- continue;
- Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count;
}
}
@@ -753,7 +774,10 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr =
Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
+ Config->EmitLLVM = Args.hasArg(OPT_plugin_opt_emit_llvm, false);
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
+ Config->CallGraphProfileSort = Args.hasFlag(
+ OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true);
Config->EnableNewDtags =
Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
Config->Entry = Args.getLastArgValue(OPT_entry);
@@ -808,6 +832,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
Config->SoName = Args.getLastArgValue(OPT_soname);
Config->SortSection = getSortSection(Args);
+ Config->SplitStackAdjustSize = args::getInteger(Args, OPT_split_stack_adjust_size, 16384);
Config->Strip = getStrip(Args);
Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
Config->Target1Rel = Args.hasFlag(OPT_target1_rel, OPT_target1_abs, false);
@@ -837,15 +862,20 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->WarnBackrefs =
Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false);
+ Config->WarnIfuncTextrel =
+ Args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false);
Config->WarnSymbolOrdering =
Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true);
Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true);
Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
+ Config->ZGlobal = hasZOption(Args, "global");
Config->ZHazardplt = hasZOption(Args, "hazardplt");
Config->ZInitfirst = hasZOption(Args, "initfirst");
+ Config->ZInterpose = hasZOption(Args, "interpose");
Config->ZKeepTextSectionPrefix = getZFlag(
Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
+ Config->ZNodefaultlib = hasZOption(Args, "nodefaultlib");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
Config->ZNow = getZFlag(Args, "now", "lazy", false);
@@ -876,6 +906,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
if (Config->ThinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
+ if (Config->SplitStackAdjustSize < 0)
+ error("--split-stack-adjust-size: size must be >= 0");
+
// Parse ELF{32,64}{LE,BE} and CPU type.
if (auto *Arg = Args.getLastArg(OPT_m)) {
StringRef S = Arg->getValue();
@@ -964,22 +997,17 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
// This function initialize such members. See Config.h for the details
// of these values.
static void setConfigs(opt::InputArgList &Args) {
- ELFKind Kind = Config->EKind;
- uint16_t Machine = Config->EMachine;
+ ELFKind K = Config->EKind;
+ uint16_t M = Config->EMachine;
Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
- Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
- Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
- Config->Endianness =
- Config->IsLE ? support::endianness::little : support::endianness::big;
- Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
+ Config->Is64 = (K == ELF64LEKind || K == ELF64BEKind);
+ Config->IsLE = (K == ELF32LEKind || K == ELF64LEKind);
+ Config->Endianness = Config->IsLE ? endianness::little : endianness::big;
+ Config->IsMips64EL = (K == ELF64LEKind && M == EM_MIPS);
Config->Pic = Config->Pie || Config->Shared;
Config->Wordsize = Config->Is64 ? 8 : 4;
- // There is an ILP32 ABI for x86-64, although it's not very popular.
- // It is called the x32 ABI.
- bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
-
// ELF defines two different ways to store relocation addends as shown below:
//
// Rel: Addends are stored to the location where relocations are applied.
@@ -993,8 +1021,9 @@ static void setConfigs(opt::InputArgList &Args) {
// You cannot choose which one, Rel or Rela, you want to use. Instead each
// ABI defines which one you need to use. The following expression expresses
// that.
- Config->IsRela =
- (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS;
+ Config->IsRela = M == EM_AARCH64 || M == EM_AMDGPU || M == EM_HEXAGON ||
+ M == EM_PPC || M == EM_PPC64 || M == EM_RISCV ||
+ M == EM_X86_64;
// If the output uses REL relocations we must store the dynamic relocation
// addends to the output sections. We also store addends for RELA relocations
@@ -1004,10 +1033,13 @@ static void setConfigs(opt::InputArgList &Args) {
Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs,
OPT_no_apply_dynamic_relocs, false) ||
!Config->IsRela;
+
+ Config->TocOptimize =
+ Args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, M == EM_PPC64);
}
// Returns a value of "-format" option.
-static bool getBinaryOption(StringRef S) {
+static bool isFormatBinary(StringRef S) {
if (S == "binary")
return true;
if (S == "elf" || S == "default")
@@ -1034,7 +1066,10 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
StringRef From;
StringRef To;
std::tie(From, To) = StringRef(Arg->getValue()).split('=');
- readDefsym(From, MemoryBufferRef(To, "-defsym"));
+ if (From.empty() || To.empty())
+ error("-defsym: syntax error: " + StringRef(Arg->getValue()));
+ else
+ readDefsym(From, MemoryBufferRef(To, "-defsym"));
break;
}
case OPT_script:
@@ -1049,7 +1084,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
Config->AsNeeded = true;
break;
case OPT_format:
- InBinary = getBinaryOption(Arg->getValue());
+ Config->FormatBinary = isFormatBinary(Arg->getValue());
break;
case OPT_no_as_needed:
Config->AsNeeded = false;
@@ -1220,33 +1255,34 @@ template <class ELFT> static void handleUndefined(StringRef Name) {
Symtab->fetchLazy<ELFT>(Sym);
}
-template <class ELFT> static bool shouldDemote(Symbol &Sym) {
- // If all references to a DSO happen to be weak, the DSO is not added to
- // DT_NEEDED. If that happens, we need to eliminate shared symbols created
- // from the DSO. Otherwise, they become dangling references that point to a
- // non-existent DSO.
- if (auto *S = dyn_cast<SharedSymbol>(&Sym))
- return !S->getFile<ELFT>().IsNeeded;
-
- // We are done processing archives, so lazy symbols that were used but not
- // found can be converted to undefined. We could also just delete the other
- // lazy symbols, but that seems to be more work than it is worth.
- return Sym.isLazy() && Sym.IsUsedInRegularObj;
+template <class ELFT> static void handleLibcall(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym || !Sym->isLazy())
+ return;
+
+ MemoryBufferRef MB;
+ if (auto *LO = dyn_cast<LazyObject>(Sym))
+ MB = LO->File->MB;
+ else
+ MB = cast<LazyArchive>(Sym)->getMemberBuffer();
+
+ if (isBitcode(MB))
+ Symtab->fetchLazy<ELFT>(Sym);
}
-// Some files, such as .so or files between -{start,end}-lib may be removed
-// after their symbols are added to the symbol table. If that happens, we
-// need to remove symbols that refer files that no longer exist, so that
-// they won't appear in the symbol table of the output file.
-//
-// We remove symbols by demoting them to undefined symbol.
-template <class ELFT> static void demoteSymbols() {
+// If all references to a DSO happen to be weak, the DSO is not added
+// to DT_NEEDED. If that happens, we need to eliminate shared symbols
+// created from the DSO. Otherwise, they become dangling references
+// that point to a non-existent DSO.
+template <class ELFT> static void demoteSharedSymbols() {
for (Symbol *Sym : Symtab->getSymbols()) {
- if (shouldDemote<ELFT>(*Sym)) {
- bool Used = Sym->Used;
- replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding,
- Sym->StOther, Sym->Type);
- Sym->Used = Used;
+ if (auto *S = dyn_cast<SharedSymbol>(Sym)) {
+ if (!S->getFile<ELFT>().IsNeeded) {
+ bool Used = S->Used;
+ replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
+ S->Type);
+ S->Used = Used;
+ }
}
}
}
@@ -1315,6 +1351,85 @@ static void findKeepUniqueSections(opt::InputArgList &Args) {
}
}
+template <class ELFT> static Symbol *addUndefined(StringRef Name) {
+ return Symtab->addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, 0, false,
+ nullptr);
+}
+
+// The --wrap option is a feature to rename symbols so that you can write
+// wrappers for existing functions. If you pass `-wrap=foo`, all
+// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
+// expected to write `wrap_foo` function as a wrapper). The original
+// symbol becomes accessible as `real_foo`, so you can call that from your
+// wrapper.
+//
+// This data structure is instantiated for each -wrap option.
+struct WrappedSymbol {
+ Symbol *Sym;
+ Symbol *Real;
+ Symbol *Wrap;
+};
+
+// Handles -wrap option.
+//
+// This function instantiates wrapper symbols. At this point, they seem
+// like they are not being used at all, so we explicitly set some flags so
+// that LTO won't eliminate them.
+template <class ELFT>
+static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) {
+ std::vector<WrappedSymbol> V;
+ DenseSet<StringRef> Seen;
+
+ for (auto *Arg : Args.filtered(OPT_wrap)) {
+ StringRef Name = Arg->getValue();
+ if (!Seen.insert(Name).second)
+ continue;
+
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ continue;
+
+ Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
+ Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
+ V.push_back({Sym, Real, Wrap});
+
+ // We want to tell LTO not to inline symbols to be overwritten
+ // because LTO doesn't know the final symbol contents after renaming.
+ Real->CanInline = false;
+ Sym->CanInline = false;
+
+ // Tell LTO not to eliminate these symbols.
+ Sym->IsUsedInRegularObj = true;
+ Wrap->IsUsedInRegularObj = true;
+ }
+ return V;
+}
+
+// Do renaming for -wrap by updating pointers to symbols.
+//
+// When this function is executed, only InputFiles and symbol table
+// contain pointers to symbol objects. We visit them to replace pointers,
+// so that wrapped symbols are swapped as instructed by the command line.
+template <class ELFT> static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
+ DenseMap<Symbol *, Symbol *> Map;
+ for (const WrappedSymbol &W : Wrapped) {
+ Map[W.Sym] = W.Wrap;
+ Map[W.Real] = W.Sym;
+ }
+
+ // Update pointers in input files.
+ parallelForEach(ObjectFiles, [&](InputFile *File) {
+ std::vector<Symbol *> &Syms = File->getMutableSymbols();
+ for (size_t I = 0, E = Syms.size(); I != E; ++I)
+ if (Symbol *S = Map.lookup(Syms[I]))
+ Syms[I] = S;
+ });
+
+ // Update pointers in the symbol table.
+ for (const WrappedSymbol &W : Wrapped)
+ Symtab->wrap(W.Sym, W.Real, W.Wrap);
+}
+
static const char *LibcallRoutineNames[] = {
#define HANDLE_LIBCALL(code, name) name,
#include "llvm/IR/RuntimeLibcalls.def"
@@ -1325,6 +1440,8 @@ static const char *LibcallRoutineNames[] = {
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Target = getTarget();
+ InX<ELFT>::VerSym = nullptr;
+ InX<ELFT>::VerNeed = nullptr;
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@@ -1380,8 +1497,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Some symbols (such as __ehdr_start) are defined lazily only when there
// are undefined symbols for them, so we add these to trigger that logic.
- for (StringRef Sym : Script->ReferencedSymbols)
- Symtab->addUndefined<ELFT>(Sym);
+ for (StringRef Name : Script->ReferencedSymbols)
+ addUndefined<ELFT>(Name);
// Handle the `--undefined <sym>` options.
for (StringRef S : Config->Undefined)
@@ -1396,11 +1513,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// in a bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
//
- // With this the symbol table should be complete. After this, no new names
- // except a few linker-synthesized ones will be added to the symbol table.
+ // However, adding all libcall symbols to the link can have undesired
+ // consequences. For example, the libgcc implementation of
+ // __sync_val_compare_and_swap_8 on 32-bit ARM pulls in an .init_array entry
+ // that aborts the program if the Linux kernel does not support 64-bit
+ // atomics, which would prevent the program from running even if it does not
+ // use 64-bit atomics.
+ //
+ // Therefore, we only add libcall symbols to the link before LTO if we have
+ // to, i.e. if the symbol's definition is in bitcode. Any other required
+ // libcall symbols will be added to the link after LTO when we add the LTO
+ // object file to the link.
if (!BitcodeFiles.empty())
for (const char *S : LibcallRoutineNames)
- handleUndefined<ELFT>(S);
+ handleLibcall<ELFT>(S);
// Return if there were name resolution errors.
if (errorCount())
@@ -1424,6 +1550,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
Out::ElfHeader->Size = sizeof(typename ELFT::Ehdr);
+ // Create wrapped symbols for -wrap option.
+ std::vector<WrappedSymbol> Wrapped = addWrappedSymbols<ELFT>(Args);
+
// We need to create some reserved symbols such as _end. Create them.
if (!Config->Relocatable)
addReservedSymbols();
@@ -1436,12 +1565,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (!Config->Relocatable)
Symtab->scanVersionScript();
- // Create wrapped symbols for -wrap option.
- for (auto *Arg : Args.filtered(OPT_wrap))
- Symtab->addSymbolWrap<ELFT>(Arg->getValue());
-
// Do link-time optimization if given files are LLVM bitcode files.
// This compiles bitcode files into real object files.
+ //
+ // With this the symbol table should be complete. After this, no new names
+ // except a few linker-synthesized ones will be added to the symbol table.
Symtab->addCombinedLTOObject<ELFT>();
if (errorCount())
return;
@@ -1452,8 +1580,15 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->ThinLTOIndexOnly)
return;
+ // Likewise, --plugin-opt=emit-llvm is an option to make LTO create
+ // an output file in bitcode and exit, so that you can just get a
+ // combined bitcode file.
+ if (Config->EmitLLVM)
+ return;
+
// Apply symbol renames for -wrap.
- Symtab->applySymbolWrap();
+ if (!Wrapped.empty())
+ wrapSymbols<ELFT>(Wrapped);
// Now that we have a complete list of input files.
// Beyond this point, no new files are added.
@@ -1481,27 +1616,19 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// supports them.
if (Config->ARMHasBlx == false)
warn("lld uses blx instruction, no object with architecture supporting "
- "feature detected.");
- if (Config->ARMJ1J2BranchEncoding == false)
- warn("lld uses extended branch encoding, no object with architecture "
- "supporting feature detected.");
- if (Config->ARMHasMovtMovw == false)
- warn("lld may use movt/movw, no object with architecture supporting "
- "feature detected.");
+ "feature detected");
}
// This adds a .comment section containing a version string. We have to add it
- // before decompressAndMergeSections because the .comment section is a
- // mergeable section.
+ // before mergeSections because the .comment section is a mergeable section.
if (!Config->Relocatable)
InputSections.push_back(createCommentSection());
// Do size optimizations: garbage collection, merging of SHF_MERGE sections
// and identical code folding.
- decompressSections();
splitSections<ELFT>();
markLive<ELFT>();
- demoteSymbols<ELFT>();
+ demoteSharedSymbols<ELFT>();
mergeSections();
if (Config->ICF != ICFLevel::None) {
findKeepUniqueSections<ELFT>(Args);
@@ -1509,9 +1636,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
}
// Read the callgraph now that we know what was gced or icfed
- if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
- if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- readCallGraph(*Buffer);
+ if (Config->CallGraphProfileSort) {
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
+ readCallGraphsFromObjectFiles<ELFT>();
+ }
// Write the result to the file.
writeResult<ELFT>();
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 99e194d9b66c..81d7f608e588 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -42,9 +42,6 @@ private:
// True if we are in --start-lib and --end-lib.
bool InLib = false;
- // True if we are in -format=binary and -format=elf.
- bool InBinary = false;
-
std::vector<InputFile *> Files;
};
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index 698e06edfe63..e51d02e38da1 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -139,8 +139,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
}
void elf::printHelp() {
- ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld",
- false /*ShowHidden*/, true /*ShowAllAliases*/);
+ ELFOptTable().PrintHelp(
+ outs(), (Config->ProgName + " [options] file...").str().c_str(), "lld",
+ false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index 20b32c0a96e6..95d444bdc2a1 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -44,7 +44,7 @@ public:
private:
template <class P> void failOn(const P *Loc, const Twine &Msg) {
fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
- IS->getObjMsg((const uint8_t *)Loc - IS->Data.data()));
+ IS->getObjMsg((const uint8_t *)Loc - IS->data().data()));
}
uint8_t readByte();
@@ -59,7 +59,7 @@ private:
}
size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
- return EhReader(S, S->Data.slice(Off)).readEhRecordSize();
+ return EhReader(S, S->data().slice(Off)).readEhRecordSize();
}
// .eh_frame section is a sequence of records. Each record starts with
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index 075938bd16b9..e917ae76a689 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -252,7 +252,10 @@ bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
auto *DA = dyn_cast<Defined>(&SA);
auto *DB = dyn_cast<Defined>(&SB);
- if (!DA || !DB)
+
+ // Placeholder symbols generated by linker scripts look the same now but
+ // may have different values later.
+ if (!DA || !DB || DA->ScriptDefined || DB->ScriptDefined)
return false;
// Relocations referring to absolute symbols are constant-equal if their
@@ -298,7 +301,7 @@ bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
template <class ELFT>
bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
- A->getSize() != B->getSize() || A->Data != B->Data)
+ A->getSize() != B->getSize() || A->data() != B->data())
return false;
// If two sections have different output sections, we cannot merge them.
@@ -420,6 +423,21 @@ void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
++Cnt;
}
+// Combine the hashes of the sections referenced by the given section into its
+// hash.
+template <class ELFT, class RelTy>
+static void combineRelocHashes(InputSection *IS, ArrayRef<RelTy> Rels) {
+ uint32_t Hash = IS->Class[1];
+ for (RelTy Rel : Rels) {
+ Symbol &S = IS->template getFile<ELFT>()->getRelocTargetSym(Rel);
+ if (auto *D = dyn_cast<Defined>(&S))
+ if (auto *RelSec = dyn_cast_or_null<InputSection>(D->Section))
+ Hash ^= RelSec->Class[1];
+ }
+ // Set MSB to 1 to avoid collisions with non-hash IDs.
+ IS->Class[0] = Hash | (1U << 31);
+}
+
static void print(const Twine &S) {
if (Config->PrintIcfSections)
message(S);
@@ -435,8 +453,14 @@ template <class ELFT> void ICF<ELFT>::run() {
// Initially, we use hash values to partition sections.
parallelForEach(Sections, [&](InputSection *S) {
- // Set MSB to 1 to avoid collisions with non-hash IDs.
- S->Class[0] = xxHash64(S->Data) | (1U << 31);
+ S->Class[1] = xxHash64(S->data());
+ });
+
+ parallelForEach(Sections, [&](InputSection *S) {
+ if (S->AreRelocsRela)
+ combineRelocHashes<ELFT>(S, S->template relas<ELFT>());
+ else
+ combineRelocHashes<ELFT>(S, S->template rels<ELFT>());
});
// From now on, sections in Sections vector are ordered so that sections
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 0eb605a556ae..e4d1dec7cbcb 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -46,7 +46,7 @@ std::vector<LazyObjFile *> elf::LazyObjFiles;
std::vector<InputFile *> elf::ObjectFiles;
std::vector<InputFile *> elf::SharedFiles;
-TarWriter *elf::Tar;
+std::unique_ptr<TarWriter> elf::Tar;
InputFile::InputFile(Kind K, MemoryBufferRef M)
: MB(M), GroupId(NextGroupId), FileKind(K) {
@@ -125,11 +125,7 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
- const DWARFObject &Obj = Dwarf->getDWARFObj();
- DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE,
- Config->Wordsize);
-
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) {
+ for (std::unique_ptr<DWARFUnit> &CU : Dwarf->compile_units()) {
auto Report = [](Error Err) {
handleAllErrors(std::move(Err),
[](ErrorInfoBase &Info) { warn(Info.message()); });
@@ -416,6 +412,11 @@ void ObjFile<ELFT>::initializeSections(
continue;
const Elf_Shdr &Sec = ObjSections[I];
+ if (Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
+ CGProfile = check(
+ this->getObj().template getSectionContentsAsArray<Elf_CGProfile>(
+ &Sec));
+
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
@@ -442,6 +443,10 @@ void ObjFile<ELFT>::initializeSections(
bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
this->Sections[I] = &InputSection::Discarded;
+ // We only support GRP_COMDAT type of group. Get the all entries of the
+ // section here to let getShtGroupEntries to check the type early for us.
+ ArrayRef<Elf_Word> Entries = getShtGroupEntries(Sec);
+
// If it is a new section group, we want to keep group members.
// Group leader sections, which contain indices of group members, are
// discarded because they are useless beyond this point. The only
@@ -454,7 +459,7 @@ void ObjFile<ELFT>::initializeSections(
}
// Otherwise, discard group members.
- for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
+ for (uint32_t SecIndex : Entries) {
if (SecIndex >= Size)
fatal(toString(this) +
": invalid section index in group: " + Twine(SecIndex));
@@ -478,11 +483,13 @@ void ObjFile<ELFT>::initializeSections(
// .ARM.exidx sections have a reverse dependency on the InputSection they
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
if (Sec.sh_flags & SHF_LINK_ORDER) {
- if (Sec.sh_link >= this->Sections.size())
+ InputSectionBase *LinkSec = nullptr;
+ if (Sec.sh_link < this->Sections.size())
+ LinkSec = this->Sections[Sec.sh_link];
+ if (!LinkSec)
fatal(toString(this) +
": invalid sh_link index: " + Twine(Sec.sh_link));
- InputSectionBase *LinkSec = this->Sections[Sec.sh_link];
InputSection *IS = cast<InputSection>(this->Sections[I]);
LinkSec->DependentSections.push_back(IS);
if (!isa<InputSection>(LinkSec))
@@ -598,7 +605,7 @@ InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
// as a given section.
static InputSection *toRegularSection(MergeInputSection *Sec) {
return make<InputSection>(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment,
- Sec->Data, Sec->Name);
+ Sec->data(), Sec->Name);
}
template <class ELFT>
@@ -618,9 +625,9 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// FIXME: Retain the first attribute section we see. The eglibc ARM
// dynamic loaders require the presence of an attribute section for dlopen
// to work. In a full implementation we would merge all attribute sections.
- if (InX::ARMAttributes == nullptr) {
- InX::ARMAttributes = make<InputSection>(*this, Sec, Name);
- return InX::ARMAttributes;
+ if (In.ARMAttributes == nullptr) {
+ In.ARMAttributes = make<InputSection>(*this, Sec, Name);
+ return In.ARMAttributes;
}
return &InputSection::Discarded;
}
@@ -638,8 +645,16 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// This section contains relocation information.
// If -r is given, we do not interpret or apply relocation
// but just copy relocation sections to output.
- if (Config->Relocatable)
- return make<InputSection>(*this, Sec, Name);
+ if (Config->Relocatable) {
+ InputSection *RelocSec = make<InputSection>(*this, Sec, Name);
+ // We want to add a dependency to target, similar like we do for
+ // -emit-relocs below. This is useful for the case when linker script
+ // contains the "/DISCARD/". It is perhaps uncommon to use a script with
+ // -r, but we faced it in the Linux kernel and have to handle such case
+ // and not to crash.
+ Target->DependentSections.push_back(RelocSec);
+ return RelocSec;
+ }
if (Target->FirstRelocation)
fatal(toString(this) +
@@ -704,7 +719,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// for split stack will include a .note.GNU-split-stack section.
if (Name == ".note.GNU-split-stack") {
if (Config->Relocatable) {
- error("Cannot mix split-stack and non-split-stack in a relocatable link");
+ error("cannot mix split-stack and non-split-stack in a relocatable link");
return &InputSection::Discarded;
}
this->SplitStack = true;
@@ -806,7 +821,7 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
if (Sec == &InputSection::Discarded)
return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
/*CanOmitFromDynSym=*/false, this);
- return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec,
+ return Symtab->addDefined(Name, StOther, Type, Value, Size, Binding, Sec,
this);
}
}
@@ -940,8 +955,7 @@ std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() {
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
Verdef += CurVerdef->vd_next;
unsigned VerdefIndex = CurVerdef->vd_ndx;
- if (Verdefs.size() <= VerdefIndex)
- Verdefs.resize(VerdefIndex + 1);
+ Verdefs.resize(VerdefIndex + 1);
Verdefs[VerdefIndex] = CurVerdef;
}
@@ -993,25 +1007,25 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
for (size_t I = 0; I < Syms.size(); ++I) {
const Elf_Sym &Sym = Syms[I];
- StringRef Name = CHECK(Sym.getName(this->StringTable), this);
- if (Sym.isUndefined()) {
- Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
- Sym.st_other, Sym.getType(),
- /*CanOmitFromDynSym=*/false, this);
- S->ExportDynamic = true;
- continue;
- }
-
// ELF spec requires that all local symbols precede weak or global
// symbols in each symbol table, and the index of first non-local symbol
// is stored to sh_info. If a local symbol appears after some non-local
// symbol, that's a violation of the spec.
+ StringRef Name = CHECK(Sym.getName(this->StringTable), this);
if (Sym.getBinding() == STB_LOCAL) {
warn("found local symbol '" + Name +
"' in global part of symbol table in file " + toString(this));
continue;
}
+ if (Sym.isUndefined()) {
+ Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
+ Sym.st_other, Sym.getType(),
+ /*CanOmitFromDynSym=*/false, this);
+ S->ExportDynamic = true;
+ continue;
+ }
+
// MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly
// assigns VER_NDX_LOCAL to this section global symbol. Here is a
// workaround for this bug.
@@ -1054,6 +1068,9 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
+ case Triple::amdgcn:
+ case Triple::r600:
+ return EM_AMDGPU;
case Triple::arm:
case Triple::thumb:
return EM_ARM;
@@ -1064,9 +1081,12 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
case Triple::mips64:
case Triple::mips64el:
return EM_MIPS;
+ case Triple::msp430:
+ return EM_MSP430;
case Triple::ppc:
return EM_PPC;
case Triple::ppc64:
+ case Triple::ppc64le:
return EM_PPC64;
case Triple::x86:
return T.isOSIAMCU() ? EM_IAMCU : EM_386;
@@ -1178,7 +1198,7 @@ static ELFKind getELFKind(MemoryBufferRef MB) {
}
void BinaryFile::parse() {
- ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
+ ArrayRef<uint8_t> Data = arrayRefFromStringRef(MB.getBuffer());
auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
8, Data, ".data");
Sections.push_back(Section);
@@ -1192,11 +1212,11 @@ void BinaryFile::parse() {
if (!isAlnum(S[I]))
S[I] = '_';
- Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0,
+ Symtab->addDefined(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0,
STB_GLOBAL, Section, nullptr);
- Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
+ Symtab->addDefined(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
Data.size(), 0, STB_GLOBAL, Section, nullptr);
- Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
+ Symtab->addDefined(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
}
@@ -1262,25 +1282,11 @@ template <class ELFT> void LazyObjFile::parse() {
return;
}
- switch (getELFKind(this->MB)) {
- case ELF32LEKind:
- addElfSymbols<ELF32LE>();
- return;
- case ELF32BEKind:
- addElfSymbols<ELF32BE>();
+ if (getELFKind(this->MB) != Config->EKind) {
+ error("incompatible file: " + this->MB.getBufferIdentifier());
return;
- case ELF64LEKind:
- addElfSymbols<ELF64LE>();
- return;
- case ELF64BEKind:
- addElfSymbols<ELF64BE>();
- return;
- default:
- llvm_unreachable("getELFKind");
}
-}
-template <class ELFT> void LazyObjFile::addElfSymbols() {
ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer()));
ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this);
@@ -1305,12 +1311,9 @@ std::string elf::replaceThinLTOSuffix(StringRef Path) {
StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first;
StringRef Repl = Config->ThinLTOObjectSuffixReplace.second;
- if (!Path.endswith(Suffix)) {
- error("-thinlto-object-suffix-replace=" + Suffix + ";" + Repl +
- " was given, but " + Path + " does not end with the suffix");
- return "";
- }
- return (Path.drop_back(Suffix.size()) + Repl).str();
+ if (Path.consume_back(Suffix))
+ return (Path + Repl).str();
+ return Path;
}
template void ArchiveFile::parse<ELF32LE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 0db3203b0ba2..5094ddd804a5 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -50,7 +50,7 @@ class Symbol;
// If -reproduce option is given, all input files are written
// to this tar archive.
-extern llvm::TarWriter *Tar;
+extern std::unique_ptr<llvm::TarWriter> Tar;
// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
@@ -86,7 +86,9 @@ public:
// Returns object file symbols. It is a runtime error to call this
// function on files of other types.
- ArrayRef<Symbol *> getSymbols() {
+ ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
+
+ std::vector<Symbol *> &getMutableSymbols() {
assert(FileKind == BinaryKind || FileKind == ObjKind ||
FileKind == BitcodeKind);
return Symbols;
@@ -169,6 +171,7 @@ template <class ELFT> class ObjFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::CGProfile Elf_CGProfile;
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
@@ -218,6 +221,9 @@ public:
// Pointer to this input file's .llvm_addrsig section, if it has one.
const Elf_Shdr *AddrsigSec = nullptr;
+ // SHT_LLVM_CALL_GRAPH_PROFILE table
+ ArrayRef<Elf_CGProfile> CGProfile;
+
private:
void
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
@@ -272,8 +278,6 @@ public:
bool AddedToLink = false;
private:
- template <class ELFT> void addElfSymbols();
-
uint64_t OffsetInArchive;
};
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 54fb57cf9888..839bff7011eb 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -21,7 +21,6 @@
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
-#include "llvm/Object/Decompressor.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
@@ -64,11 +63,11 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
StringRef Name, Kind SectionKind)
: SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
Link),
- File(File), Data(Data) {
+ File(File), RawData(Data) {
// In order to reduce memory allocation, we assume that mergeable
// sections are smaller than 4 GiB, which is not an unreasonable
// assumption as of 2017.
- if (SectionKind == SectionBase::Merge && Data.size() > UINT32_MAX)
+ if (SectionKind == SectionBase::Merge && RawData.size() > UINT32_MAX)
error(toString(this) + ": section too large");
NumRelocations = 0;
@@ -80,6 +79,17 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
if (!isPowerOf2_64(V))
fatal(toString(File) + ": section sh_addralign is not a power of 2");
this->Alignment = V;
+
+ // In ELF, each section can be compressed by zlib, and if compressed,
+ // section name may be mangled by appending "z" (e.g. ".zdebug_info").
+ // If that's the case, demangle section name so that we can handle a
+ // section as if it weren't compressed.
+ if ((Flags & SHF_COMPRESSED) || Name.startswith(".zdebug")) {
+ if (!zlib::isAvailable())
+ error(toString(File) + ": contains a compressed section, " +
+ "but zlib is not available");
+ parseCompressedHeader();
+ }
}
// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
@@ -128,13 +138,25 @@ InputSectionBase::InputSectionBase(ObjFile<ELFT> &File,
size_t InputSectionBase::getSize() const {
if (auto *S = dyn_cast<SyntheticSection>(this))
return S->getSize();
+ if (UncompressedSize >= 0)
+ return UncompressedSize;
+ return RawData.size();
+}
+
+void InputSectionBase::uncompress() const {
+ size_t Size = UncompressedSize;
+ UncompressedBuf.reset(new char[Size]);
- return Data.size();
+ if (Error E =
+ zlib::uncompress(toStringRef(RawData), UncompressedBuf.get(), Size))
+ fatal(toString(this) +
+ ": uncompress failed: " + llvm::toString(std::move(E)));
+ RawData = makeArrayRef((uint8_t *)UncompressedBuf.get(), Size);
}
uint64_t InputSectionBase::getOffsetInFile() const {
const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
- const uint8_t *SecStart = Data.begin();
+ const uint8_t *SecStart = data().begin();
return SecStart - FileStart;
}
@@ -180,34 +202,70 @@ OutputSection *SectionBase::getOutputSection() {
return Sec ? Sec->getParent() : nullptr;
}
-// Decompress section contents if required. Note that this function
-// is called from parallelForEach, so it must be thread-safe.
-void InputSectionBase::maybeDecompress() {
- if (DecompressBuf)
- return;
- if (!(Flags & SHF_COMPRESSED) && !Name.startswith(".zdebug"))
- return;
+// 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() {
+ typedef typename ELF64LE::Chdr Chdr64;
+ typedef typename ELF32LE::Chdr Chdr32;
- // Decompress a section.
- Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
- Config->IsLE, Config->Is64));
+ // Old-style header
+ if (Name.startswith(".zdebug")) {
+ if (!toStringRef(RawData).startswith("ZLIB")) {
+ error(toString(this) + ": corrupted compressed section header");
+ return;
+ }
+ RawData = RawData.slice(4);
- size_t Size = Dec.getDecompressedSize();
- DecompressBuf.reset(new char[Size + Name.size()]());
- if (Error E = Dec.decompress({DecompressBuf.get(), Size}))
- fatal(toString(this) +
- ": decompress failed: " + llvm::toString(std::move(E)));
+ if (RawData.size() < 8) {
+ error(toString(this) + ": corrupted compressed section header");
+ return;
+ }
+
+ UncompressedSize = read64be(RawData.data());
+ RawData = RawData.slice(8);
+
+ // Restore the original section name.
+ // (e.g. ".zdebug_info" -> ".debug_info")
+ Name = Saver.save("." + Name.substr(2));
+ return;
+ }
- Data = makeArrayRef((uint8_t *)DecompressBuf.get(), Size);
+ assert(Flags & SHF_COMPRESSED);
Flags &= ~(uint64_t)SHF_COMPRESSED;
- // A section name may have been altered if compressed. If that's
- // the case, restore the original name. (i.e. ".zdebug_" -> ".debug_")
- if (Name.startswith(".zdebug")) {
- DecompressBuf[Size] = '.';
- memcpy(&DecompressBuf[Size + 1], Name.data() + 2, Name.size() - 2);
- Name = StringRef(&DecompressBuf[Size], Name.size() - 1);
+ // 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;
+ RawData = RawData.slice(sizeof(*Hdr));
+ return;
}
+
+ // New-style 32-bit header
+ if (RawData.size() < sizeof(Chdr32)) {
+ error(toString(this) + ": corrupted compressed section");
+ return;
+ }
+
+ auto *Hdr = reinterpret_cast<const Chdr32 *>(RawData.data());
+ if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
+ error(toString(this) + ": unsupported compression type");
+ return;
+ }
+
+ UncompressedSize = Hdr->ch_size;
+ RawData = RawData.slice(sizeof(*Hdr));
}
InputSection *InputSectionBase::getLinkOrderDep() const {
@@ -230,14 +288,17 @@ Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
// Returns a source 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();
+
// We don't have file for synthetic sections.
if (getFile<ELFT>() == nullptr)
- return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")")
+ 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);
+ 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.
@@ -246,10 +307,10 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
SrcFile = toString(File);
if (Defined *D = getEnclosingFunction<ELFT>(Offset))
- return SrcFile + ":(function " + toString(*D) + ")";
+ return SrcFile + ":(function " + toString(*D) + ": " + SecAndOffset + ")";
// If there's no symbol, print out the offset in the section.
- return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
+ return (SrcFile + ":(" + SecAndOffset + ")");
}
// This function is intended to be used for constructing an error message.
@@ -259,9 +320,6 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
//
// Returns an empty string if there's no way to get line info.
std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) {
- // Synthetic sections don't have input files.
- if (!File)
- return "";
return File->getSrcMsg(Sym, *this, Offset);
}
@@ -275,9 +333,6 @@ std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) {
//
// path/to/foo.o:(function bar) in archive path/to/bar.a
std::string InputSectionBase::getObjMsg(uint64_t Off) {
- // Synthetic sections don't have input files.
- if (!File)
- return ("<internal>:(" + Name + "+0x" + utohexstr(Off) + ")").str();
std::string Filename = File->getName();
std::string Archive;
@@ -362,7 +417,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
// Output section VA is zero for -r, so r_offset is an offset within the
// section, but for --emit-relocs it is an virtual address.
P->r_offset = Sec->getVA(Rel.r_offset);
- P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type,
+ P->setSymbolAndType(In.SymTab->getSymbolIndex(&Sym), Type,
Config->IsMips64EL);
if (Sym.Type == STT_SECTION) {
@@ -380,14 +435,14 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
error("STT_SECTION symbol should be defined");
continue;
}
- SectionBase *Section = D->Section;
- if (Section == &InputSection::Discarded) {
+ SectionBase *Section = D->Section->Repl;
+ if (!Section->Live) {
P->setSymbolAndType(0, 0, false);
continue;
}
int64_t Addend = getAddend<ELFT>(Rel);
- const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
+ const uint8_t *BufLoc = Sec->data().begin() + Rel.r_offset;
if (!RelTy::IsRela)
Addend = Target->getImplicitAddend(BufLoc, Type);
@@ -487,6 +542,62 @@ static uint64_t getARMStaticBase(const Symbol &Sym) {
return OS->PtLoad->FirstSec->Addr;
}
+// For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually
+// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
+// is calculated using PCREL_HI20's symbol.
+//
+// This function returns the R_RISCV_PCREL_HI20 relocation from
+// R_RISCV_PCREL_LO12's symbol and addend.
+static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
+ const Defined *D = cast<Defined>(Sym);
+ InputSection *IS = cast<InputSection>(D->Section);
+
+ if (Addend != 0)
+ warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
+ IS->getObjMsg(D->Value) + " is ignored");
+
+ // Relocations are sorted by offset, so we can use std::equal_range to do
+ // binary search.
+ auto Range = std::equal_range(IS->Relocations.begin(), IS->Relocations.end(),
+ D->Value, RelocationOffsetComparator{});
+ for (auto It = std::get<0>(Range); It != std::get<1>(Range); ++It)
+ if (isRelExprOneOf<R_PC>(It->Expr))
+ return &*It;
+
+ error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) +
+ " without an associated R_RISCV_PCREL_HI20 relocation");
+ return nullptr;
+}
+
+// A TLS symbol's virtual address is relative to the TLS segment. Add a
+// target-specific adjustment to produce a thread-pointer-relative offset.
+static int64_t getTlsTpOffset() {
+ switch (Config->EMachine) {
+ case EM_ARM:
+ case EM_AARCH64:
+ // Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
+ // followed by a variable amount of alignment padding, followed by the TLS
+ // segment.
+ //
+ // NB: While the ARM/AArch64 ABI formally has a 2-word TCB size, lld
+ // effectively increases the TCB size to 8 words for Android compatibility.
+ // It accomplishes this by increasing the segment's alignment.
+ return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
+ case EM_386:
+ case EM_X86_64:
+ // Variant 2. The TLS segment is located just before the thread pointer.
+ return -Out::TlsPhdr->p_memsz;
+ case EM_PPC64:
+ // The thread pointer points to a fixed offset from the start of the
+ // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
+ // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
+ // program's TLS segment.
+ return -0x7000;
+ default:
+ llvm_unreachable("unhandled Config->EMachine");
+ }
+}
+
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
@@ -501,38 +612,37 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
case R_ARM_SBREL:
return Sym.getVA(A) - getARMStaticBase(Sym);
case R_GOT:
+ case R_GOT_PLT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return Sym.getGotVA() + A;
case R_GOTONLY_PC:
- return InX::Got->getVA() + A - P;
+ return In.Got->getVA() + A - P;
case R_GOTONLY_PC_FROM_END:
- return InX::Got->getVA() + A - P + InX::Got->getSize();
+ return In.Got->getVA() + A - P + In.Got->getSize();
case R_GOTREL:
- return Sym.getVA(A) - InX::Got->getVA();
+ return Sym.getVA(A) - In.Got->getVA();
case R_GOTREL_FROM_END:
- return Sym.getVA(A) - InX::Got->getVA() - InX::Got->getSize();
+ return Sym.getVA(A) - In.Got->getVA() - In.Got->getSize();
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
- return Sym.getGotOffset() + A - InX::Got->getSize();
+ return Sym.getGotOffset() + A - In.Got->getSize();
case R_TLSLD_GOT_OFF:
case R_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return Sym.getGotOffset() + A;
- case R_GOT_PAGE_PC:
- case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+ case R_AARCH64_GOT_PAGE_PC:
+ case R_AARCH64_GOT_PAGE_PC_PLT:
+ case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P);
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
return Sym.getGotVA() + A - P;
- case R_HINT:
- case R_NONE:
- case R_TLSDESC_CALL:
- case R_TLSLD_HINT:
- llvm_unreachable("cannot relocate hint relocs");
+ case R_HEXAGON_GOT:
+ return Sym.getGotVA() - In.GotPlt->getVA();
case R_MIPS_GOTREL:
- return Sym.getVA(A) - InX::MipsGot->getGp(File);
+ return Sym.getVA(A) - In.MipsGot->getGp(File);
case R_MIPS_GOT_GP:
- return InX::MipsGot->getGp(File) + A;
+ return In.MipsGot->getGp(File) + A;
case R_MIPS_GOT_GP_PC: {
// R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
// is _gp_disp symbol. In that case we should use the following
@@ -541,7 +651,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// microMIPS variants of these relocations use slightly different
// expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
// to correctly handle less-sugnificant bit of the microMIPS symbol.
- uint64_t V = InX::MipsGot->getGp(File) + A - P;
+ uint64_t V = In.MipsGot->getGp(File) + A - P;
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
V += 4;
if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
@@ -552,31 +662,34 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
- return InX::MipsGot->getVA() +
- InX::MipsGot->getPageEntryOffset(File, Sym, A) -
- InX::MipsGot->getGp(File);
+ return In.MipsGot->getVA() + In.MipsGot->getPageEntryOffset(File, Sym, A) -
+ In.MipsGot->getGp(File);
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
// should be applied to the GOT entry content not to the GOT entry offset.
// That is why we use separate expression type.
- return InX::MipsGot->getVA() +
- InX::MipsGot->getSymEntryOffset(File, Sym, A) -
- InX::MipsGot->getGp(File);
+ return In.MipsGot->getVA() + In.MipsGot->getSymEntryOffset(File, Sym, A) -
+ In.MipsGot->getGp(File);
case R_MIPS_TLSGD:
- return InX::MipsGot->getVA() + InX::MipsGot->getGlobalDynOffset(File, Sym) -
- InX::MipsGot->getGp(File);
+ return In.MipsGot->getVA() + In.MipsGot->getGlobalDynOffset(File, Sym) -
+ In.MipsGot->getGp(File);
case R_MIPS_TLSLD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) -
- InX::MipsGot->getGp(File);
- case R_PAGE_PC:
- case R_PLT_PAGE_PC: {
- uint64_t Dest;
- if (Sym.isUndefWeak())
- Dest = getAArch64Page(A);
- else
- Dest = getAArch64Page(Sym.getVA(A));
- return Dest - getAArch64Page(P);
+ return In.MipsGot->getVA() + In.MipsGot->getTlsIndexOffset(File) -
+ In.MipsGot->getGp(File);
+ case R_AARCH64_PAGE_PC: {
+ uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A);
+ return getAArch64Page(Val) - getAArch64Page(P);
+ }
+ case R_AARCH64_PLT_PAGE_PC: {
+ uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A;
+ return getAArch64Page(Val) - getAArch64Page(P);
+ }
+ case R_RISCV_PC_INDIRECT: {
+ if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A))
+ return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),
+ *HiRel->Sym, HiRel->Expr);
+ return 0;
}
case R_PC: {
uint64_t Dest;
@@ -608,16 +721,12 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
return 0;
// PPC64 V2 ABI describes two entry points to a function. The global entry
- // point sets up the TOC base pointer. When calling a local function, the
- // call should branch to the local entry point rather than the global entry
- // point. Section 3.4.1 describes using the 3 most significant bits of the
- // st_other field to find out how many instructions there are between the
- // local and global entry point.
- uint8_t StOther = (Sym.StOther >> 5) & 7;
- if (StOther == 0 || StOther == 1)
- return SymVA - P;
-
- return SymVA - P + (1LL << StOther);
+ // point is used for calls where the caller and callee (may) have different
+ // TOC base pointers and r2 needs to be modified to hold the TOC base for
+ // the callee. For local calls the caller and callee share the same
+ // TOC base and so the TOC pointer initialization code should be skipped by
+ // branching to the local entry point.
+ return SymVA - P + getPPC64GlobalEntryToLocalEntryOffset(Sym.StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
@@ -634,48 +743,32 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
-
- // For TLS variant 1 the TCB is a fixed size, whereas for TLS variant 2 the
- // TCB is on unspecified size and content. Targets that implement variant 1
- // should set TcbSize.
- if (Target->TcbSize) {
- // PPC64 V2 ABI has the thread pointer offset into the middle of the TLS
- // storage area by TlsTpOffset for efficient addressing TCB and up to
- // 4KB – 8 B of other thread library information (placed before the TCB).
- // Subtracting this offset will get the address of the first TLS block.
- if (Target->TlsTpOffset)
- return Sym.getVA(A) - Target->TlsTpOffset;
-
- // If thread pointer is not offset into the middle, the first thing in the
- // TLS storage area is the TCB. Add the TcbSize to get the address of the
- // first TLS block.
- return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
- }
- return Sym.getVA(A) - Out::TlsPhdr->p_memsz;
+ return Sym.getVA(A) + getTlsTpOffset();
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
case R_SIZE:
return Sym.getSize() + A;
case R_TLSDESC:
- return InX::Got->getGlobalDynAddr(Sym) + A;
- case R_TLSDESC_PAGE:
- return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) -
+ return In.Got->getGlobalDynAddr(Sym) + A;
+ case R_AARCH64_TLSDESC_PAGE:
+ return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) -
getAArch64Page(P);
case R_TLSGD_GOT:
- return InX::Got->getGlobalDynOffset(Sym) + A;
+ return In.Got->getGlobalDynOffset(Sym) + A;
case R_TLSGD_GOT_FROM_END:
- return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize();
+ return In.Got->getGlobalDynOffset(Sym) + A - In.Got->getSize();
case R_TLSGD_PC:
- return InX::Got->getGlobalDynAddr(Sym) + A - P;
+ return In.Got->getGlobalDynAddr(Sym) + A - P;
case R_TLSLD_GOT_FROM_END:
- return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
+ return In.Got->getTlsIndexOff() + A - In.Got->getSize();
case R_TLSLD_GOT:
- return InX::Got->getTlsIndexOff() + A;
+ return In.Got->getTlsIndexOff() + A;
case R_TLSLD_PC:
- return InX::Got->getTlsIndexVA() + A - P;
+ return In.Got->getTlsIndexVA() + A - P;
+ default:
+ llvm_unreachable("invalid expression");
}
- llvm_unreachable("Invalid expression");
}
// This function applies relocations to sections without SHF_ALLOC bit.
@@ -808,10 +901,10 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
case R_RELAX_TLS_GD_TO_LE_NEG:
Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
break;
+ case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
- case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
@@ -848,16 +941,20 @@ static void switchMorestackCallsToMorestackNonSplit(
// __morestack inside that function should be switched to
// __morestack_non_split.
Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
+ if (!MoreStackNonSplit) {
+ error("Mixing split-stack objects requires a definition of "
+ "__morestack_non_split");
+ return;
+ }
// Sort both collections to compare addresses efficiently.
- llvm::sort(MorestackCalls.begin(), MorestackCalls.end(),
- [](const Relocation *L, const Relocation *R) {
- return L->Offset < R->Offset;
- });
+ llvm::sort(MorestackCalls, [](const Relocation *L, const Relocation *R) {
+ return L->Offset < R->Offset;
+ });
std::vector<Defined *> Functions(Prologues.begin(), Prologues.end());
- llvm::sort(
- Functions.begin(), Functions.end(),
- [](const Defined *L, const Defined *R) { return L->Value < R->Value; });
+ llvm::sort(Functions, [](const Defined *L, const Defined *R) {
+ return L->Value < R->Value;
+ });
auto It = MorestackCalls.begin();
for (Defined *F : Functions) {
@@ -872,8 +969,8 @@ static void switchMorestackCallsToMorestackNonSplit(
}
}
-static bool enclosingPrologueAdjusted(uint64_t Offset,
- const DenseSet<Defined *> &Prologues) {
+static bool enclosingPrologueAttempted(uint64_t Offset,
+ const DenseSet<Defined *> &Prologues) {
for (Defined *F : Prologues)
if (F->Value <= Offset && Offset < F->Value + F->Size)
return true;
@@ -889,7 +986,7 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
uint8_t *End) {
if (!getFile<ELFT>()->SplitStack)
return;
- DenseSet<Defined *> AdjustedPrologues;
+ DenseSet<Defined *> Prologues;
std::vector<Relocation *> MorestackCalls;
for (Relocation &Rel : Relocations) {
@@ -898,15 +995,9 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
if (Rel.Sym->isLocal())
continue;
- Defined *D = dyn_cast<Defined>(Rel.Sym);
- // A reference to an undefined symbol was an error, and should not
- // have gotten to this point.
- if (!D)
- continue;
-
// Ignore calls into the split-stack api.
- if (D->getName().startswith("__morestack")) {
- if (D->getName().equals("__morestack"))
+ if (Rel.Sym->getName().startswith("__morestack")) {
+ if (Rel.Sym->getName().equals("__morestack"))
MorestackCalls.push_back(&Rel);
continue;
}
@@ -914,24 +1005,36 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
// A relocation to non-function isn't relevant. Sometimes
// __morestack is not marked as a function, so this check comes
// after the name check.
- if (D->Type != STT_FUNC)
+ if (Rel.Sym->Type != STT_FUNC)
continue;
- if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues))
+ // If the callee's-file was compiled with split stack, nothing to do. In
+ // this context, a "Defined" symbol is one "defined by the binary currently
+ // being produced". So an "undefined" symbol might be provided by a shared
+ // library. It is not possible to tell how such symbols were compiled, so be
+ // conservative.
+ if (Defined *D = dyn_cast<Defined>(Rel.Sym))
+ if (InputSection *IS = cast_or_null<InputSection>(D->Section))
+ if (!IS || !IS->getFile<ELFT>() || IS->getFile<ELFT>()->SplitStack)
+ continue;
+
+ if (enclosingPrologueAttempted(Rel.Offset, Prologues))
continue;
if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
- if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) {
- AdjustedPrologues.insert(F);
+ Prologues.insert(F);
+ if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value),
+ End, F->StOther))
continue;
- }
+ if (!getFile<ELFT>()->SomeNoSplitStack)
+ error(lld::toString(this) + ": " + F->getName() +
+ " (with -fsplit-stack) calls " + Rel.Sym->getName() +
+ " (without -fsplit-stack), but couldn't adjust its prologue");
}
- if (!getFile<ELFT>()->SomeNoSplitStack)
- error("function call at " + getErrorLocation(Buf + Rel.Offset) +
- "crosses a split-stack boundary, but unable " +
- "to adjust the enclosing function's prologue");
}
- switchMorestackCallsToMorestackNonSplit(AdjustedPrologues, MorestackCalls);
+
+ if (Target->NeedsMoreStackNonSplit)
+ switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls);
}
template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
@@ -960,10 +1063,23 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
return;
}
+ // If this is a compressed section, uncompress section contents directly
+ // to the buffer.
+ if (UncompressedSize >= 0 && !UncompressedBuf) {
+ size_t Size = UncompressedSize;
+ if (Error E = zlib::uncompress(toStringRef(RawData),
+ (char *)(Buf + OutSecOff), Size))
+ fatal(toString(this) +
+ ": uncompress failed: " + llvm::toString(std::move(E)));
+ uint8_t *BufEnd = Buf + OutSecOff + Size;
+ relocate<ELFT>(Buf, BufEnd);
+ return;
+ }
+
// Copy section contents from source object file to output file
// and then apply relocations.
- memcpy(Buf + OutSecOff, Data.data(), Data.size());
- uint8_t *BufEnd = Buf + OutSecOff + Data.size();
+ memcpy(Buf + OutSecOff, data().data(), data().size());
+ uint8_t *BufEnd = Buf + OutSecOff + data().size();
relocate<ELFT>(Buf, BufEnd);
}
@@ -1014,7 +1130,7 @@ template <class ELFT> void EhInputSection::split() {
template <class ELFT, class RelTy>
void EhInputSection::split(ArrayRef<RelTy> Rels) {
unsigned RelI = 0;
- for (size_t Off = 0, End = Data.size(); Off != End;) {
+ for (size_t Off = 0, End = data().size(); Off != End;) {
size_t Size = readEhRecordSize(this, Off);
Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
// The empty record is the end marker.
@@ -1094,65 +1210,32 @@ void MergeInputSection::splitIntoPieces() {
assert(Pieces.empty());
if (Flags & SHF_STRINGS)
- splitStrings(Data, Entsize);
+ splitStrings(data(), Entsize);
else
- splitNonStrings(Data, Entsize);
-
- OffsetMap.reserve(Pieces.size());
- for (size_t I = 0, E = Pieces.size(); I != E; ++I)
- OffsetMap[Pieces[I].InputOff] = I;
-}
-
-template <class It, class T, class Compare>
-static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
- size_t Size = std::distance(First, Last);
- assert(Size != 0);
- while (Size != 1) {
- size_t H = Size / 2;
- const It MI = First + H;
- Size -= H;
- First = Comp(Value, *MI) ? First : First + H;
- }
- return Comp(Value, *First) ? First : First + 1;
-}
-
-// Do binary search to get a section piece at a given input offset.
-static SectionPiece *findSectionPiece(MergeInputSection *Sec, uint64_t Offset) {
- if (Sec->Data.size() <= Offset)
- fatal(toString(Sec) + ": entry is past the end of the section");
-
- // Find the element this offset points to.
- auto I = fastUpperBound(
- Sec->Pieces.begin(), Sec->Pieces.end(), Offset,
- [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
- --I;
- return &*I;
+ splitNonStrings(data(), Entsize);
}
SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
- // Find a piece starting at a given offset.
- auto It = OffsetMap.find(Offset);
- if (It != OffsetMap.end())
- return &Pieces[It->second];
+ if (this->data().size() <= Offset)
+ fatal(toString(this) + ": offset is outside the section");
// If Offset is not at beginning of a section piece, it is not in the map.
- // In that case we need to search from the original section piece vector.
- return findSectionPiece(this, Offset);
+ // In that case we need to do a binary search of the original section piece vector.
+ auto It2 =
+ llvm::upper_bound(Pieces, Offset, [](uint64_t Offset, SectionPiece P) {
+ return Offset < P.InputOff;
+ });
+ return &It2[-1];
}
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
- // Find a string starting at a given offset.
- auto It = OffsetMap.find(Offset);
- if (It != OffsetMap.end())
- return Pieces[It->second].OutputOff;
-
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
const SectionPiece &Piece =
- *findSectionPiece(const_cast<MergeInputSection *>(this), Offset);
+ *(const_cast<MergeInputSection *>(this)->getSectionPiece (Offset));
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 4db01e035e32..34f411e87200 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -115,7 +115,12 @@ public:
return cast_or_null<ObjFile<ELFT>>(File);
}
- ArrayRef<uint8_t> Data;
+ ArrayRef<uint8_t> data() const {
+ if (UncompressedSize >= 0 && !UncompressedBuf)
+ uncompress();
+ return RawData;
+ }
+
uint64_t getOffsetInFile() const;
// True if this section has already been placed to a linker script
@@ -169,11 +174,6 @@ public:
template <class ELFT>
Defined *getEnclosingFunction(uint64_t Offset);
- // Compilers emit zlib-compressed debug sections if the -gz option
- // is given. This function checks if this section is compressed, and
- // if so, decompress in memory.
- void maybeDecompress();
-
// Returns a source location string. Used to construct an error message.
template <class ELFT> std::string getLocation(uint64_t Offset);
std::string getSrcMsg(const Symbol &Sym, uint64_t Offset);
@@ -200,15 +200,21 @@ public:
template <typename T> llvm::ArrayRef<T> getDataAs() const {
- size_t S = Data.size();
+ size_t S = data().size();
assert(S % sizeof(T) == 0);
- return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ return llvm::makeArrayRef<T>((const T *)data().data(), S / sizeof(T));
}
-private:
- // A pointer that owns decompressed data if a section is compressed by zlib.
+protected:
+ void parseCompressedHeader();
+ void uncompress() const;
+
+ mutable ArrayRef<uint8_t> RawData;
+
+ // A pointer that owns uncompressed data if a section is compressed by zlib.
// Since the feature is not used often, this is usually a nullptr.
- std::unique_ptr<char[]> DecompressBuf;
+ mutable std::unique_ptr<char[]> UncompressedBuf;
+ int64_t UncompressedSize = -1;
};
// SectionPiece represents a piece of splittable section contents.
@@ -247,7 +253,6 @@ public:
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<SectionPiece> Pieces;
- llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
// Returns I'th piece's data. This function is very hot when
// string merging is enabled, so we want to inline.
@@ -255,8 +260,8 @@ public:
llvm::CachedHashStringRef getData(size_t I) const {
size_t Begin = Pieces[I].InputOff;
size_t End =
- (Pieces.size() - 1 == I) ? Data.size() : Pieces[I + 1].InputOff;
- return {toStringRef(Data.slice(Begin, End - Begin)), Pieces[I].Hash};
+ (Pieces.size() - 1 == I) ? data().size() : Pieces[I + 1].InputOff;
+ return {toStringRef(data().slice(Begin, End - Begin)), Pieces[I].Hash};
}
// Returns the SectionPiece at a given input section offset.
@@ -277,7 +282,9 @@ struct EhSectionPiece {
unsigned FirstRelocation)
: InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {}
- ArrayRef<uint8_t> data() { return {Sec->Data.data() + this->InputOff, Size}; }
+ ArrayRef<uint8_t> data() {
+ return {Sec->data().data() + this->InputOff, Size};
+ }
size_t InputOff;
ssize_t OutputOff = -1;
@@ -353,6 +360,7 @@ private:
// The list of all input sections.
extern std::vector<InputSectionBase *> InputSections;
+
} // namespace elf
std::string toString(const elf::InputSectionBase *);
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index ef58932e86cc..ca44581780e4 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -67,9 +67,10 @@ static std::string getThinLTOOutputFile(StringRef ModulePath) {
static lto::Config createConfig() {
lto::Config C;
- // LLD supports the new relocations.
+ // LLD supports the new relocations and address-significance tables.
C.Options = InitTargetOptionsFromCodeGenFlags();
C.Options.RelaxELFRelocations = true;
+ C.Options.EmitAddrsig = true;
// Always emit a section per function/datum with LTO.
C.Options.FunctionSections = true;
@@ -87,6 +88,7 @@ static lto::Config createConfig() {
C.DiagHandler = diagnosticHandler;
C.OptLevel = Config->LTOO;
C.CPU = GetCPUStr();
+ C.MAttrs = GetMAttrs();
// Set up a custom pipeline if we've been asked to.
C.OptPipeline = Config->LTONewPmPasses;
@@ -101,6 +103,14 @@ static lto::Config createConfig() {
C.DebugPassManager = Config->LTODebugPassManager;
C.DwoDir = Config->DwoDir;
+ if (Config->EmitLLVM) {
+ C.PostInternalizeModuleHook = [](size_t Task, const Module &M) {
+ if (std::unique_ptr<raw_fd_ostream> OS = openFile(Config->OutputFile))
+ WriteBitcodeToFile(M, *OS, false);
+ return false;
+ };
+ }
+
if (Config->SaveTemps)
checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
/*UseInputModulePath*/ true));
@@ -108,18 +118,14 @@ static lto::Config createConfig() {
}
BitcodeCompiler::BitcodeCompiler() {
+ // Initialize IndexFile.
+ if (!Config->ThinLTOIndexOnlyArg.empty())
+ IndexFile = openFile(Config->ThinLTOIndexOnlyArg);
+
// Initialize LTOObj.
lto::ThinBackend Backend;
-
if (Config->ThinLTOIndexOnly) {
- StringRef Path = Config->ThinLTOIndexOnlyArg;
- if (!Path.empty())
- IndexFile = openFile(Path);
-
- auto OnIndexWrite = [&](const std::string &Identifier) {
- ObjectToIndexFileState[Identifier] = true;
- };
-
+ auto OnIndexWrite = [&](StringRef S) { ThinIndices.erase(S); };
Backend = lto::createWriteIndexesThinBackend(
Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second,
Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite);
@@ -132,10 +138,10 @@ BitcodeCompiler::BitcodeCompiler() {
// Initialize UsedStartStop.
for (Symbol *Sym : Symtab->getSymbols()) {
- StringRef Name = Sym->getName();
+ StringRef S = Sym->getName();
for (StringRef Prefix : {"__start_", "__stop_"})
- if (Name.startswith(Prefix))
- UsedStartStop.insert(Name.substr(Prefix.size()));
+ if (S.startswith(Prefix))
+ UsedStartStop.insert(S.substr(Prefix.size()));
}
}
@@ -151,7 +157,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
bool IsExec = !Config->Shared && !Config->Relocatable;
if (Config->ThinLTOIndexOnly)
- ObjectToIndexFileState.insert({Obj.getName(), false});
+ ThinIndices.insert(Obj.getName());
ArrayRef<Symbol *> Syms = F.getSymbols();
ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols();
@@ -240,15 +246,11 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
Cache));
// Emit empty index files for non-indexed files
- if (Config->ThinLTOIndexOnly) {
- for (auto &Identifier : ObjectToIndexFileState)
- if (!Identifier.getValue()) {
- std::string Path = getThinLTOOutputFile(Identifier.getKey());
- openFile(Path + ".thinlto.bc");
-
- if (Config->ThinLTOEmitImportsFiles)
- openFile(Path + ".imports");
- }
+ for (StringRef S : ThinIndices) {
+ std::string Path = getThinLTOOutputFile(S);
+ openFile(Path + ".thinlto.bc");
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
}
// If LazyObjFile has not been added to link, emit empty index files.
diff --git a/ELF/LTO.h b/ELF/LTO.h
index 8803078eb1df..a190da3e5996 100644
--- a/ELF/LTO.h
+++ b/ELF/LTO.h
@@ -55,7 +55,7 @@ private:
std::vector<std::unique_ptr<MemoryBuffer>> Files;
llvm::DenseSet<StringRef> UsedStartStop;
std::unique_ptr<llvm::raw_fd_ostream> IndexFile;
- llvm::StringMap<bool> ObjectToIndexFileState;
+ llvm::DenseSet<StringRef> ThinIndices;
};
} // namespace elf
} // namespace lld
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index abdd899da487..fbc025416205 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -116,7 +116,8 @@ void LinkerScript::expandMemoryRegions(uint64_t Size) {
if (Ctx->MemRegion)
expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name,
Ctx->OutSec->Name);
- if (Ctx->LMARegion)
+ // Only expand the LMARegion if it is different from MemRegion.
+ if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion)
expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name,
Ctx->OutSec->Name);
}
@@ -168,7 +169,7 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
// Define a symbol.
Symbol *Sym;
uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility,
/*CanOmitFromDynSym*/ false,
/*File*/ nullptr);
ExprValue Value = Cmd->Expression();
@@ -201,13 +202,14 @@ static void declareSymbol(SymbolAssignment *Cmd) {
// We can't calculate final value right now.
Symbol *Sym;
uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility,
/*CanOmitFromDynSym*/ false,
/*File*/ nullptr);
replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility,
STT_NOTYPE, 0, 0, nullptr);
Cmd->Sym = cast<Defined>(Sym);
Cmd->Provide = false;
+ Sym->ScriptDefined = true;
}
// This method is used to handle INSERT AFTER statement. Here we rebuild
@@ -413,18 +415,16 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
void LinkerScript::discard(ArrayRef<InputSection *> V) {
for (InputSection *S : V) {
- if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
- S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn ||
- S == InX::RelrDyn)
+ if (S == In.ShStrTab || S == In.RelaDyn || S == In.RelrDyn)
error("discarding " + S->Name + " section is not allowed");
// You can discard .hash and .gnu.hash sections by linker scripts. Since
// they are synthesized sections, we need to handle them differently than
// other regular sections.
- if (S == InX::GnuHashTab)
- InX::GnuHashTab = nullptr;
- if (S == InX::HashTab)
- InX::HashTab = nullptr;
+ if (S == In.GnuHashTab)
+ In.GnuHashTab = nullptr;
+ if (S == In.HashTab)
+ In.HashTab = nullptr;
S->Assigned = false;
S->Live = false;
@@ -700,6 +700,7 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Alignment) {
}
void LinkerScript::output(InputSection *S) {
+ assert(Ctx->OutSec == S->getParent());
uint64_t Before = advance(0, 1);
uint64_t Pos = advance(S->getSize(), S->Alignment);
S->OutSecOff = Pos - S->getSize() - Ctx->OutSec->Addr;
@@ -750,6 +751,13 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) {
return nullptr;
}
+static OutputSection *findFirstSection(PhdrEntry *Load) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->PtLoad == Load)
+ return Sec;
+ return nullptr;
+}
+
// This function assigns offsets to input sections and an output section
// for a single sections command (e.g. ".text { *(.text); }").
void LinkerScript::assignOffsets(OutputSection *Sec) {
@@ -775,8 +783,11 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
// will set the LMA such that the difference between VMA and LMA for the
// section is the same as the preceding output section in the same region
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+ // This, however, should only be done by the first "non-header" section
+ // in the segment.
if (PhdrEntry *L = Ctx->OutSec->PtLoad)
- L->LMAOffset = Ctx->LMAOffset;
+ if (Sec == findFirstSection(L))
+ L->LMAOffset = Ctx->LMAOffset;
// We can call this method multiple times during the creation of
// thunks and want to start over calculation each time.
@@ -805,21 +816,8 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
// Handle a single input section description command.
// It calculates and assigns the offsets for each section and also
// updates the output section size.
- auto *Cmd = cast<InputSectionDescription>(Base);
- for (InputSection *Sec : Cmd->Sections) {
- // We tentatively added all synthetic sections at the beginning and
- // removed empty ones afterwards (because there is no way to know
- // whether they were going be empty or not other than actually running
- // linker scripts.) We need to ignore remains of empty sections.
- if (auto *S = dyn_cast<SyntheticSection>(Sec))
- if (S->empty())
- continue;
-
- if (!Sec->Live)
- continue;
- assert(Ctx->OutSec == Sec->getParent());
+ for (InputSection *Sec : cast<InputSectionDescription>(Base)->Sections)
output(Sec);
- }
}
}
@@ -953,13 +951,6 @@ void LinkerScript::adjustSectionsAfterSorting() {
}
}
-static OutputSection *findFirstSection(PhdrEntry *Load) {
- for (OutputSection *Sec : OutputSections)
- if (Sec->PtLoad == Load)
- return Sec;
- return nullptr;
-}
-
static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) {
// If there is no SECTIONS or if the linkerscript is explicit about program
// headers, do our best to allocate them.
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 3b790dd4669f..51161981efc8 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -30,12 +30,13 @@ namespace lld {
namespace elf {
class Defined;
-class Symbol;
-class InputSectionBase;
class InputSection;
-class OutputSection;
class InputSectionBase;
+class InputSectionBase;
+class OutputSection;
class SectionBase;
+class Symbol;
+class ThunkSection;
// This represents an r-value in the linker script.
struct ExprValue {
@@ -145,7 +146,9 @@ struct MemoryRegion {
// Also it may be surrounded with SORT() command, so contains sorting rules.
struct SectionPattern {
SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2)
- : ExcludedFilePat(Pat1), SectionPat(Pat2) {}
+ : ExcludedFilePat(Pat1), SectionPat(Pat2),
+ SortOuter(SortSectionPolicy::Default),
+ SortInner(SortSectionPolicy::Default) {}
StringMatcher ExcludedFilePat;
StringMatcher SectionPat;
@@ -153,7 +156,6 @@ struct SectionPattern {
SortSectionPolicy SortInner;
};
-class ThunkSection;
struct InputSectionDescription : BaseCommand {
InputSectionDescription(StringRef FilePattern)
: BaseCommand(InputSectionKind), FilePat(FilePattern) {}
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index 54fddfb7b299..b0dc6203008d 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -126,7 +126,7 @@ static void printEhFrame(raw_ostream &OS, OutputSection *OSec) {
};
// Gather section pieces.
- for (const CieRecord *Rec : InX::EhFrame->getCieRecords()) {
+ for (const CieRecord *Rec : In.EhFrame->getCieRecords()) {
Add(*Rec->Cie);
for (const EhSectionPiece *Fde : Rec->Fdes)
Add(*Fde);
@@ -163,17 +163,18 @@ void elf::writeMapFile() {
OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
<< " Size Align Out In Symbol\n";
+ OutputSection* OSec = nullptr;
for (BaseCommand *Base : Script->SectionCommands) {
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
if (Cmd->Provide && !Cmd->Sym)
continue;
- //FIXME: calculate and print LMA.
- writeHeader(OS, Cmd->Addr, 0, Cmd->Size, 1);
+ uint64_t LMA = OSec ? OSec->getLMA() + Cmd->Addr - OSec->getVA(0) : 0;
+ writeHeader(OS, Cmd->Addr, LMA, Cmd->Size, 1);
OS << Cmd->CommandString << '\n';
continue;
}
- auto *OSec = cast<OutputSection>(Base);
+ OSec = cast<OutputSection>(Base);
writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
OS << OSec->Name << '\n';
@@ -181,7 +182,7 @@ void elf::writeMapFile() {
for (BaseCommand *Base : OSec->SectionCommands) {
if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
for (InputSection *IS : ISD->Sections) {
- if (IS == InX::EhFrame) {
+ if (IS == In.EhFrame) {
printEhFrame(OS, OSec);
continue;
}
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index a8371e212c3e..8d0ec091c327 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -45,7 +45,7 @@ using namespace lld::elf;
template <class ELFT>
static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rel &Rel) {
- return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
+ return Target->getImplicitAddend(Sec.data().begin() + Rel.r_offset,
Rel.getType(Config->IsMips64EL));
}
@@ -250,9 +250,10 @@ template <class ELFT> static void doGcSections() {
if (Sec->Flags & SHF_LINK_ORDER)
continue;
- if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec))
+
+ if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec)) {
Enqueue(Sec, 0);
- else if (isValidCIdentifier(Sec->Name)) {
+ } else if (isValidCIdentifier(Sec->Name)) {
CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec);
}
@@ -267,10 +268,16 @@ template <class ELFT> static void doGcSections() {
// input sections. This function make some or all of them on
// so that they are emitted to the output file.
template <class ELFT> void elf::markLive() {
- // If -gc-sections is missing, no sections are removed.
if (!Config->GcSections) {
+ // If -gc-sections is missing, no sections are removed.
for (InputSectionBase *Sec : InputSections)
Sec->Live = true;
+
+ // If a DSO defines a symbol referenced in a regular object, it is needed.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (auto *S = dyn_cast<SharedSymbol>(Sym))
+ if (S->IsUsedInRegularObj && !S->isWeak())
+ S->getFile<ELFT>().IsNeeded = true;
return;
}
diff --git a/ELF/Options.td b/ELF/Options.td
index 04a4f8ffbe28..e43a21b923d3 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -42,6 +42,12 @@ defm compress_debug_sections:
defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
+defm split_stack_adjust_size
+ : Eq<"split-stack-adjust-size",
+ "Specify adjustment to stack size when a split-stack function calls a "
+ "non-split-stack function">,
+ MetaVarName<"<value>">;
+
defm library_path:
Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
@@ -68,6 +74,10 @@ defm as_needed: B<"as-needed",
defm call_graph_ordering_file:
Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
+defm call_graph_profile_sort: B<"call-graph-profile-sort",
+ "Reorder sections with call graph profile (default)",
+ "Do not reorder sections with call graph profile">;
+
// -chroot doesn't have a help text because it is an internal option.
def chroot: Separate<["--", "-"], "chroot">;
@@ -132,7 +142,7 @@ def error_unresolved_symbols: F<"error-unresolved-symbols">,
defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
defm execute_only: B<"execute-only",
- "Do not mark executable sections readable",
+ "Mark executable sections unreadable",
"Mark executable sections readable (default)">;
defm export_dynamic: B<"export-dynamic",
@@ -315,6 +325,10 @@ defm threads: B<"threads",
"Run the linker multi-threaded (default)",
"Do not run the linker multi-threaded">;
+defm toc_optimize : B<"toc-optimize",
+ "(PowerPC64) Enable TOC related optimizations (default)",
+ "(PowerPC64) Disable TOC related optimizations">;
+
def trace: F<"trace">, HelpText<"Print the names of the input files">;
defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
@@ -348,6 +362,10 @@ defm warn_common: B<"warn-common",
"Warn about duplicate common symbols",
"Do not warn about duplicate common symbols (default)">;
+defm warn_ifunc_textrel: B<"warn-ifunc-textrel",
+ "Warn about using ifunc symbols with text relocations",
+ "Do not warn about using ifunc symbols with text relocations (default)">;
+
defm warn_symbol_ordering: B<"warn-symbol-ordering",
"Warn about problems with the symbol ordering file (default)",
"Do not warn about problems with the symbol ordering file">;
@@ -440,6 +458,7 @@ def: F<"plugin-opt=debug-pass-manager">,
def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">,
HelpText<"Directory to store .dwo files when LTO and debug fission are used">;
+def plugin_opt_emit_llvm: F<"plugin-opt=emit-llvm">;
def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">;
def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 8253b18b486c..c1442c078736 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -25,6 +25,7 @@
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
@@ -32,7 +33,6 @@ using namespace lld::elf;
uint8_t Out::First;
PhdrEntry *Out::TlsPhdr;
-OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
OutputSection *Out::ProgramHeaders;
OutputSection *Out::PreinitArray;
@@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) {
Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
- unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
+ unsigned Mask = SHF_TLS | SHF_LINK_ORDER;
if ((Flags & Mask) != (IS->Flags & Mask))
error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +
@@ -171,11 +171,12 @@ void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
-static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
+static void fill(uint8_t *Buf, size_t Size,
+ const std::array<uint8_t, 4> &Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
- memcpy(Buf + I, &Filler, 4);
- memcpy(Buf + I, &Filler, Size - I);
+ memcpy(Buf + I, Filler.data(), 4);
+ memcpy(Buf + I, Filler.data(), Size - I);
}
// Compress section contents if this section contains debug info.
@@ -236,8 +237,9 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
// Write leading padding.
std::vector<InputSection *> Sections = getInputSections(this);
- uint32_t Filler = getFiller();
- if (Filler)
+ std::array<uint8_t, 4> Filler = getFiller();
+ bool NonZeroFiller = read32(Filler.data()) != 0;
+ if (NonZeroFiller)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
parallelForEachN(0, Sections.size(), [&](size_t I) {
@@ -245,7 +247,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
IS->writeTo<ELFT>(Buf);
// Fill gaps between sections.
- if (Filler) {
+ if (NonZeroFiller) {
uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
@@ -270,13 +272,13 @@ static void finalizeShtGroup(OutputSection *OS,
// sh_link field for SHT_GROUP sections should contain the section index of
// the symbol table.
- OS->Link = InX::SymTab->getParent()->SectionIndex;
+ OS->Link = In.SymTab->getParent()->SectionIndex;
// sh_info then contain index of an entry in symbol table section which
// provides signature of the section group.
ObjFile<ELFT> *Obj = Section->getFile<ELFT>();
ArrayRef<Symbol *> Symbols = Obj->getSymbols();
- OS->Info = InX::SymTab->getSymbolIndex(Symbols[Section->Info]);
+ OS->Info = In.SymTab->getSymbolIndex(Symbols[Section->Info]);
}
template <class ELFT> void OutputSection::finalize() {
@@ -308,7 +310,7 @@ template <class ELFT> void OutputSection::finalize() {
if (isa<SyntheticSection>(First))
return;
- Link = InX::SymTab->getParent()->SectionIndex;
+ Link = In.SymTab->getParent()->SectionIndex;
// sh_info for SHT_REL[A] sections should contain the section header index of
// the section to which the relocation applies.
InputSectionBase *S = First->getRelocatedSection();
@@ -406,12 +408,12 @@ void OutputSection::sortInitFini() {
sort([](InputSectionBase *S) { return getPriority(S->Name); });
}
-uint32_t OutputSection::getFiller() {
+std::array<uint8_t, 4> OutputSection::getFiller() {
if (Filler)
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
- return 0;
+ return {0, 0, 0, 0};
}
template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index efb6aabe9743..113bf6836926 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -17,6 +17,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
+#include <array>
namespace lld {
namespace elf {
@@ -94,7 +95,7 @@ public:
Expr SubalignExpr;
std::vector<BaseCommand *> SectionCommands;
std::vector<StringRef> Phdrs;
- llvm::Optional<uint32_t> Filler;
+ llvm::Optional<std::array<uint8_t, 4>> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
@@ -117,7 +118,7 @@ private:
std::vector<uint8_t> ZDebugHeader;
llvm::SmallVector<char, 1> CompressedData;
- uint32_t getFiller();
+ std::array<uint8_t, 4> getFiller();
};
int getPriority(StringRef S);
@@ -130,7 +131,6 @@ std::vector<InputSection *> getInputSections(OutputSection* OS);
struct Out {
static uint8_t First;
static PhdrEntry *TlsPhdr;
- static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
static OutputSection *ProgramHeaders;
static OutputSection *PreinitArray;
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 467219ad0542..812468896f0d 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -50,6 +50,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/SmallSet.h"
@@ -65,6 +66,14 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+static Optional<std::string> getLinkerScriptLocation(const Symbol &Sym) {
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
+ if (Cmd->Sym == &Sym)
+ return Cmd->Location;
+ return None;
+}
+
// Construct a message in the following format.
//
// >>> defined in /home/alice/src/foo.o
@@ -72,8 +81,13 @@ using namespace lld::elf;
// >>> /home/alice/src/bar.o:(.text+0x1)
static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
uint64_t Off) {
- std::string Msg =
- "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
+ std::string Msg = "\n>>> defined in ";
+ if (Sym.File)
+ Msg += toString(Sym.File);
+ else if (Optional<std::string> Loc = getLinkerScriptLocation(Sym))
+ Msg += *Loc;
+
+ Msg += "\n>>> referenced by ";
std::string Src = S.getSrcMsg(Sym, Off);
if (!Src.empty())
Msg += Src + "\n>>> ";
@@ -90,12 +104,12 @@ static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- InX::MipsGot->addTlsIndex(*C.File);
+ In.MipsGot->addTlsIndex(*C.File);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
if (Expr == R_MIPS_TLSGD) {
- InX::MipsGot->addDynTlsEntry(*C.File, Sym);
+ In.MipsGot->addDynTlsEntry(*C.File, Sym);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -128,17 +142,17 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) {
if (Dyn)
- InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest);
+ In.RelaDyn->addReloc(Type, In.Got, Off, Dest);
else
- InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
+ In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
// Local Dynamic is for access to module local TLS variables, while still
// being suitable for being dynamically loaded via dlopen.
// GOT[e0] is the module index, with a special value of 0 for the current
// module. GOT[e1] is unused. There only needs to be one module index entry.
- if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) {
- AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+ if (Expr == R_TLSLD_PC && In.Got->addTlsIndex()) {
+ AddTlsReloc(In.Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
NeedDynId ? nullptr : &Sym, NeedDynId);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
@@ -148,8 +162,8 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
// the module index and offset of symbol in TLS block we can fill these in
// using static GOT relocations.
if (Expr == R_TLSGD_PC) {
- if (InX::Got->addDynTlsEntry(Sym)) {
- uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId);
AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym,
NeedDynOff);
@@ -165,9 +179,6 @@ template <class ELFT>
static unsigned
handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
- if (!(C.Flags & SHF_ALLOC))
- return 0;
-
if (!Sym.isTls())
return 0;
@@ -176,12 +187,12 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (Config->EMachine == EM_MIPS)
return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
+ if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
- if (InX::Got->addDynTlsEntry(Sym)) {
- uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsDescRel, InX::Got, Off, !Sym.IsPreemptible, &Sym, 0});
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ In.RelaDyn->addReloc(
+ {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0});
}
if (Expr != R_TLSDESC_CALL)
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
@@ -199,9 +210,9 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
}
if (Expr == R_TLSLD_HINT)
return 1;
- if (InX::Got->addTlsIndex())
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got,
- InX::Got->getTlsIndexOff(), nullptr);
+ if (In.Got->addTlsIndex())
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got,
+ In.Got->getTlsIndexOff(), nullptr);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -223,29 +234,29 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
if (!Sym.isInGot()) {
- InX::Got->addEntry(Sym);
+ In.Got->addEntry(Sym);
uint64_t Off = Sym.getGotOffset();
- InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
+ In.Got->Relocations.push_back(
+ {R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
- R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
+ if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL,
+ R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
- if (InX::Got->addDynTlsEntry(Sym)) {
- uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym);
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym);
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
uint64_t OffsetOff = Off + Config->Wordsize;
if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff,
- &Sym);
+ In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym);
else
- InX::Got->Relocations.push_back(
+ In.Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
@@ -259,9 +270,9 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
Offset, Addend, &Sym});
if (!Sym.isInGot()) {
- InX::Got->addEntry(Sym);
- InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(),
- &Sym);
+ In.Got->addEntry(Sym);
+ In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(),
+ &Sym);
}
} else {
C.Relocations.push_back(
@@ -273,13 +284,14 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
// Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
// defined.
- if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) &&
+ if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_AARCH64_GOT_PAGE_PC,
+ R_GOT_OFF, R_TLSIE_HINT>(Expr) &&
!Config->Shared && !Sym.IsPreemptible) {
C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym});
return 1;
}
- if (Expr == R_TLSDESC_CALL)
+ if (Expr == R_TLSIE_HINT)
return 1;
return 0;
}
@@ -325,23 +337,25 @@ static bool isAbsoluteValue(const Symbol &Sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
+ R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
// returns false for TLS variables even though they need GOT, because
// TLS variables uses GOT differently than the regular variables.
static bool needsGot(RelExpr Expr) {
- return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_GOT_PAGE_PC, R_GOT_PC,
- R_GOT_FROM_END>(Expr);
+ return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
+ R_GOT_PLT>(Expr);
}
// True if this expression is of the form Sym - X, where X is a position in the
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC,
+ R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC,
R_RELAX_GOT_PC>(Expr);
}
@@ -357,18 +371,19 @@ static bool isRelExpr(RelExpr Expr) {
static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
- if (isRelExprOneOf<
- R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
- R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
- R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END,
- R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
- R_TLSLD_HINT>(E))
+ if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
+ R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
+ R_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC,
+ R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
+ R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT,
+ R_TLSLD_HINT, R_TLSIE_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
// only the low bits are used.
- if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
+ if (E == R_GOT || E == R_GOT_PLT || E == R_PLT || E == R_TLSDESC)
return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
if (Sym.IsPreemptible)
@@ -414,10 +429,14 @@ static RelExpr toPlt(RelExpr Expr) {
return R_PPC_CALL_PLT;
case R_PC:
return R_PLT_PC;
- case R_PAGE_PC:
- return R_PLT_PAGE_PC;
+ case R_AARCH64_PAGE_PC:
+ return R_AARCH64_PLT_PAGE_PC;
+ case R_AARCH64_GOT_PAGE_PC:
+ return R_AARCH64_GOT_PAGE_PC_PLT;
case R_ABS:
return R_PLT;
+ case R_GOT:
+ return R_GOT_PLT;
default:
return Expr;
}
@@ -466,7 +485,7 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
SmallSet<SharedSymbol *, 4> Ret;
for (const Elf_Sym &S : File.getGlobalELFSyms()) {
if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS ||
- S.st_value != SS.Value)
+ S.getType() == STT_TLS || S.st_value != SS.Value)
continue;
StringRef Name = check(S.getName(File.getStringTable()));
Symbol *Sym = Symtab->find(Name);
@@ -489,6 +508,7 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
Sym.PltIndex = Old.PltIndex;
Sym.GotIndex = Old.GotIndex;
Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex;
Sym.IsPreemptible = true;
Sym.ExportDynamic = true;
Sym.IsUsedInRegularObj = true;
@@ -549,9 +569,9 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss",
SymSize, SS.Alignment);
if (IsReadOnly)
- InX::BssRelRo->getParent()->addSection(Sec);
+ In.BssRelRo->getParent()->addSection(Sec);
else
- InX::Bss->getParent()->addSection(Sec);
+ In.Bss->getParent()->addSection(Sec);
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
@@ -559,7 +579,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
replaceWithDefined(*Sym, Sec, 0, Sym->Size);
- InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
+ In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -583,7 +603,7 @@ static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End,
if (PairTy == R_MIPS_NONE)
return 0;
- const uint8_t *Buf = Sec.Data.data();
+ const uint8_t *Buf = Sec.data().data();
uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
// To make things worse, paired relocations might not be contiguous in
@@ -611,7 +631,7 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End,
if (RelTy::IsRela) {
Addend = getAddend<ELFT>(Rel);
} else {
- const uint8_t *Buf = Sec.Data.data();
+ const uint8_t *Buf = Sec.data().data();
Addend = Target->getImplicitAddend(Buf + Rel.r_offset, Type);
}
@@ -627,9 +647,6 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End,
// Returns true if this function printed out an error message.
static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
uint64_t Offset) {
- if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll)
- return false;
-
if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak())
return false;
@@ -646,6 +663,10 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
Msg += Src + "\n>>> ";
Msg += Sec.getObjMsg(Offset);
+ if (Sym.getName().startswith("_ZTV"))
+ Msg += "\nthe vtable symbol may be undefined because the class is missing "
+ "its key function (see https://lld.llvm.org/missingkeyfunction)";
+
if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) ||
Config->NoinhibitExec) {
warn(Msg);
@@ -700,7 +721,7 @@ public:
while (I != Pieces.size() && Pieces[I].InputOff + Pieces[I].Size <= Off)
++I;
if (I == Pieces.size())
- return Off;
+ fatal(".eh_frame: relocation is not in any piece");
// Pieces must be contiguous, so there must be no holes in between.
assert(Pieces[I].InputOff <= Off && "Relocation not in any piece");
@@ -726,13 +747,13 @@ static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
// RelrDyn sections don't support odd offsets. Also, RelrDyn sections
// don't store the addend values, so we must write it to the relocated
// address.
- if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
+ if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
- InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
+ In.RelrDyn->Relocs.push_back({IS, OffsetInSec});
return;
}
- InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
- Expr, Type);
+ In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr,
+ Type);
}
template <class ELFT, class GotPltSection>
@@ -745,9 +766,16 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
}
template <class ELFT> static void addGotEntry(Symbol &Sym) {
- InX::Got->addEntry(Sym);
+ In.Got->addEntry(Sym);
+
+ RelExpr Expr;
+ if (Sym.isTls())
+ Expr = R_TLS;
+ else if (Sym.isGnuIFunc())
+ Expr = R_PLT;
+ else
+ Expr = R_ABS;
- RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
uint64_t Off = Sym.getGotOffset();
// If a GOT slot value can be calculated at link-time, which is now,
@@ -760,19 +788,19 @@ template <class ELFT> static void addGotEntry(Symbol &Sym) {
bool IsLinkTimeConstant =
!Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
if (IsLinkTimeConstant) {
- InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
+ In.Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
return;
}
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
- addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
+ addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel);
return;
}
- InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel,
- InX::Got, Off, &Sym, 0,
- Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel);
+ In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got,
+ Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS,
+ Target->GotRel);
}
// Return true if we can define a symbol in the executable that
@@ -825,7 +853,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
return;
} else if (RelType Rel = Target->getDynRel(Type)) {
- InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
+ In.RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -843,7 +871,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
- InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
return;
}
}
@@ -930,10 +958,9 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
"' cannot be preempted; recompile with -fPIE" +
getLocation(Sec, Sym, Offset));
if (!Sym.isInPlt())
- addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
- Sym);
+ addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
if (!Sym.isDefined())
- replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
+ replaceWithDefined(Sym, In.Plt, getPltEntryOffset(Sym.PltIndex), 0);
Sym.NeedsPltAddr = true;
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return;
@@ -967,7 +994,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
return;
- const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset;
+ const uint8_t *RelocatedAddr = Sec.data().begin() + Rel.r_offset;
RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr);
// Ignore "hint" relocations because they are only markers for relaxation.
@@ -985,18 +1012,28 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// all dynamic symbols that can be resolved within the executable will
// actually be resolved that way at runtime, because the main exectuable
// is always at the beginning of a search list. We can leverage that fact.
- if (Sym.isGnuIFunc())
+ if (Sym.isGnuIFunc()) {
+ if (!Config->ZText && Config->WarnIfuncTextrel) {
+ warn("using ifunc symbols when text relocations are allowed may produce "
+ "a binary that will segfault, if the object file is linked with "
+ "old version of glibc (glibc 2.28 and earlier). If this applies to "
+ "you, consider recompiling the object files without -fPIC and "
+ "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
+ "turn off this warning." +
+ getLocation(Sec, Sym, Offset));
+ }
Expr = toPlt(Expr);
- else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+ } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) {
Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
- else if (!Sym.IsPreemptible)
+ } else if (!Sym.IsPreemptible) {
Expr = fromPlt(Expr);
+ }
// This relocation does not require got entry, but it is relative to got and
// needs it to be created. Here we request for that.
if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
- InX::Got->HasGotOffRel = true;
+ In.Got->HasGotOffRel = true;
// Read an addend.
int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
@@ -1012,11 +1049,10 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
if (needsPlt(Expr) && !Sym.isInPlt()) {
if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
- addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt,
- Target->IRelativeRel, Sym);
- else
- addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
+ addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
Sym);
+ else
+ addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
}
// Create a GOT slot if a relocation needs GOT.
@@ -1029,7 +1065,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
} else if (!Sym.isInGot()) {
addGotEntry<ELFT>(Sym);
}
@@ -1047,6 +1083,11 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
for (auto I = Rels.begin(), End = Rels.end(); I != End;)
scanReloc<ELFT>(Sec, GetOffset, I, End);
+
+ // Sort relocations by offset to binary search for R_RISCV_PCREL_HI20
+ if (Config->EMachine == EM_RISCV)
+ std::stable_sort(Sec.Relocations.begin(), Sec.Relocations.end(),
+ RelocationOffsetComparator{});
}
template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
@@ -1056,6 +1097,43 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
scanRelocs<ELFT>(S, S.rels<ELFT>());
}
+static bool mergeCmp(const InputSection *A, const InputSection *B) {
+ // std::merge requires a strict weak ordering.
+ if (A->OutSecOff < B->OutSecOff)
+ return true;
+
+ if (A->OutSecOff == B->OutSecOff) {
+ auto *TA = dyn_cast<ThunkSection>(A);
+ auto *TB = dyn_cast<ThunkSection>(B);
+
+ // Check if Thunk is immediately before any specific Target
+ // InputSection for example Mips LA25 Thunks.
+ if (TA && TA->getTargetInputSection() == B)
+ return true;
+
+ // Place Thunk Sections without specific targets before
+ // non-Thunk Sections.
+ if (TA && !TB && !TA->getTargetInputSection())
+ return true;
+ }
+
+ return false;
+}
+
+// Call Fn on every executable InputSection accessed via the linker script
+// InputSectionDescription::Sections.
+static void forEachInputSectionDescription(
+ ArrayRef<OutputSection *> OutputSections,
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
+ for (OutputSection *OS : OutputSections) {
+ if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+ continue;
+ for (BaseCommand *BC : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC))
+ Fn(OS, ISD);
+ }
+}
+
// Thunk Implementation
//
// Thunks (sometimes called stubs, veneers or branch islands) are small pieces
@@ -1158,6 +1236,7 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) {
[](const std::pair<ThunkSection *, uint32_t> &TS) {
return TS.first->getSize() == 0;
});
+
// ISD->ThunkSections contains all created ThunkSections, including
// those inserted in previous passes. Extract the Thunks created this
// pass and order them in ascending OutSecOff.
@@ -1173,27 +1252,11 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) {
// Merge sorted vectors of Thunks and InputSections by OutSecOff
std::vector<InputSection *> Tmp;
Tmp.reserve(ISD->Sections.size() + NewThunks.size());
- auto MergeCmp = [](const InputSection *A, const InputSection *B) {
- // std::merge requires a strict weak ordering.
- if (A->OutSecOff < B->OutSecOff)
- return true;
- if (A->OutSecOff == B->OutSecOff) {
- auto *TA = dyn_cast<ThunkSection>(A);
- auto *TB = dyn_cast<ThunkSection>(B);
- // Check if Thunk is immediately before any specific Target
- // InputSection for example Mips LA25 Thunks.
- if (TA && TA->getTargetInputSection() == B)
- return true;
- if (TA && !TB && !TA->getTargetInputSection())
- // Place Thunk Sections without specific targets before
- // non-Thunk Sections.
- return true;
- }
- return false;
- };
+
std::merge(ISD->Sections.begin(), ISD->Sections.end(),
NewThunks.begin(), NewThunks.end(), std::back_inserter(Tmp),
- MergeCmp);
+ mergeCmp);
+
ISD->Sections = std::move(Tmp);
});
}
@@ -1237,20 +1300,23 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
// Find InputSectionRange within Target Output Section (TOS) that the
// InputSection (IS) that we need to precede is in.
OutputSection *TOS = IS->getParent();
- for (BaseCommand *BC : TOS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
- if (ISD->Sections.empty())
- continue;
- InputSection *first = ISD->Sections.front();
- InputSection *last = ISD->Sections.back();
- if (IS->OutSecOff >= first->OutSecOff &&
- IS->OutSecOff <= last->OutSecOff) {
- TS = addThunkSection(TOS, ISD, IS->OutSecOff);
- ThunkedSections[IS] = TS;
- break;
- }
- }
- return TS;
+ for (BaseCommand *BC : TOS->SectionCommands) {
+ auto *ISD = dyn_cast<InputSectionDescription>(BC);
+ if (!ISD || ISD->Sections.empty())
+ continue;
+
+ InputSection *First = ISD->Sections.front();
+ InputSection *Last = ISD->Sections.back();
+
+ if (IS->OutSecOff < First->OutSecOff || Last->OutSecOff < IS->OutSecOff)
+ continue;
+
+ TS = addThunkSection(TOS, ISD, IS->OutSecOff);
+ ThunkedSections[IS] = TS;
+ return TS;
+ }
+
+ return nullptr;
}
// Create one or more ThunkSections per OS that can be used to place Thunks.
@@ -1271,26 +1337,29 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
// allow for the creation of a short thunk.
void ThunkCreator::createInitialThunkSections(
ArrayRef<OutputSection *> OutputSections) {
+ uint32_t ThunkSectionSpacing = Target->getThunkSectionSpacing();
+
forEachInputSectionDescription(
OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
if (ISD->Sections.empty())
return;
+
uint32_t ISDBegin = ISD->Sections.front()->OutSecOff;
uint32_t ISDEnd =
ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize();
uint32_t LastThunkLowerBound = -1;
- if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2)
- LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing;
+ if (ISDEnd - ISDBegin > ThunkSectionSpacing * 2)
+ LastThunkLowerBound = ISDEnd - ThunkSectionSpacing;
uint32_t ISLimit;
uint32_t PrevISLimit = ISDBegin;
- uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing;
+ uint32_t ThunkUpperBound = ISDBegin + ThunkSectionSpacing;
for (const InputSection *IS : ISD->Sections) {
ISLimit = IS->OutSecOff + IS->getSize();
if (ISLimit > ThunkUpperBound) {
addThunkSection(OS, ISD, PrevISLimit);
- ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ ThunkUpperBound = PrevISLimit + ThunkSectionSpacing;
}
if (ISLimit > LastThunkLowerBound)
break;
@@ -1304,13 +1373,14 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
InputSectionDescription *ISD,
uint64_t Off) {
auto *TS = make<ThunkSection>(OS, Off);
- ISD->ThunkSections.push_back(std::make_pair(TS, Pass));
+ ISD->ThunkSections.push_back({TS, Pass});
return TS;
}
std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
uint64_t Src) {
std::vector<Thunk *> *ThunkVec = nullptr;
+
// We use (section, offset) pair to find the thunk position if possible so
// that we create only one thunk for aliased symbols or ICFed sections.
if (auto *D = dyn_cast<Defined>(&Sym))
@@ -1318,40 +1388,28 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}];
if (!ThunkVec)
ThunkVec = &ThunkedSymbols[&Sym];
+
// Check existing Thunks for Sym to see if they can be reused
- for (Thunk *ET : *ThunkVec)
- if (ET->isCompatibleWith(Type) &&
- Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA()))
- return std::make_pair(ET, false);
+ for (Thunk *T : *ThunkVec)
+ if (T->isCompatibleWith(Type) &&
+ Target->inBranchRange(Type, Src, T->getThunkTargetSym()->getVA()))
+ return std::make_pair(T, false);
+
// No existing compatible Thunk in range, create a new one
Thunk *T = addThunk(Type, Sym);
ThunkVec->push_back(T);
return std::make_pair(T, true);
}
-// Call Fn on every executable InputSection accessed via the linker script
-// InputSectionDescription::Sections.
-void ThunkCreator::forEachInputSectionDescription(
- ArrayRef<OutputSection *> OutputSections,
- llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
- for (OutputSection *OS : OutputSections) {
- if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
- continue;
- for (BaseCommand *BC : OS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(BC))
- Fn(OS, ISD);
- }
-}
-
// Return true if the relocation target is an in range Thunk.
// Return false if the relocation is not to a Thunk. If the relocation target
// was originally to a Thunk, but is no longer in range we revert the
// relocation back to its original non-Thunk target.
bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) {
- if (Thunk *ET = Thunks.lookup(Rel.Sym)) {
+ if (Thunk *T = Thunks.lookup(Rel.Sym)) {
if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA()))
return true;
- Rel.Sym = &ET->Destination;
+ Rel.Sym = &T->Destination;
if (Rel.Sym->isInPlt())
Rel.Expr = toPlt(Rel.Expr);
}
@@ -1385,11 +1443,13 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) {
// relocation out of range error.
bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
bool AddressesChanged = false;
- if (Pass == 0 && Target->ThunkSectionSpacing)
+
+ if (Pass == 0 && Target->getThunkSectionSpacing())
createInitialThunkSections(OutputSections);
- else if (Pass == 10)
- // With Thunk Size much smaller than branch range we expect to
- // converge quickly; if we get to 10 something has gone wrong.
+
+ // With Thunk Size much smaller than branch range we expect to
+ // converge quickly; if we get to 10 something has gone wrong.
+ if (Pass == 10)
fatal("thunk creation not converged");
// Create all the Thunks and insert them into synthetic ThunkSections. The
@@ -1412,9 +1472,11 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src,
*Rel.Sym))
continue;
+
Thunk *T;
bool IsNew;
std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
+
if (IsNew) {
// Find or create a ThunkSection for the new Thunk
ThunkSection *TS;
@@ -1425,13 +1487,16 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
TS->addThunk(T);
Thunks[T->getThunkTargetSym()] = T;
}
+
// Redirect relocation to Thunk, we never go via the PLT to a Thunk
Rel.Sym = T->getThunkTargetSym();
Rel.Expr = fromPlt(Rel.Expr);
}
+
for (auto &P : ISD->ThunkSections)
AddressesChanged |= P.first->assignOffsets();
});
+
for (auto &P : ThunkedSections)
AddressesChanged |= P.second->assignOffsets();
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index a4125111c4fe..d00e68bd36e6 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -33,16 +33,28 @@ enum RelExpr {
R_INVALID,
R_ABS,
R_ADDEND,
+ R_AARCH64_GOT_PAGE_PC,
+ // The expression is used for IFUNC support. Describes PC-relative
+ // address of the memory page of GOT entry. This entry is used for
+ // a redirection to IPLT.
+ R_AARCH64_GOT_PAGE_PC_PLT,
+ R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
+ R_AARCH64_PAGE_PC,
+ R_AARCH64_PLT_PAGE_PC,
+ R_AARCH64_TLSDESC_PAGE,
R_ARM_SBREL,
R_GOT,
+ // The expression is used for IFUNC support. Evaluates to GOT entry,
+ // containing redirection to the IPLT.
+ R_GOT_PLT,
R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END,
R_GOTREL,
R_GOTREL_FROM_END,
R_GOT_FROM_END,
R_GOT_OFF,
- R_GOT_PAGE_PC,
R_GOT_PC,
+ R_HEXAGON_GOT,
R_HINT,
R_MIPS_GOTREL,
R_MIPS_GOT_GP,
@@ -54,10 +66,8 @@ enum RelExpr {
R_MIPS_TLSLD,
R_NEG_TLS,
R_NONE,
- R_PAGE_PC,
R_PC,
R_PLT,
- R_PLT_PAGE_PC,
R_PLT_PC,
R_PPC_CALL,
R_PPC_CALL_PLT,
@@ -68,20 +78,20 @@ enum RelExpr {
R_RELAX_TLS_GD_TO_IE_ABS,
R_RELAX_TLS_GD_TO_IE_END,
R_RELAX_TLS_GD_TO_IE_GOT_OFF,
- R_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_RELAX_TLS_GD_TO_LE,
R_RELAX_TLS_GD_TO_LE_NEG,
R_RELAX_TLS_IE_TO_LE,
R_RELAX_TLS_LD_TO_LE,
R_RELAX_TLS_LD_TO_LE_ABS,
+ R_RISCV_PC_INDIRECT,
R_SIZE,
R_TLS,
R_TLSDESC,
R_TLSDESC_CALL,
- R_TLSDESC_PAGE,
R_TLSGD_GOT,
R_TLSGD_GOT_FROM_END,
R_TLSGD_PC,
+ R_TLSIE_HINT,
R_TLSLD_GOT,
R_TLSLD_GOT_FROM_END,
R_TLSLD_GOT_OFF,
@@ -128,6 +138,21 @@ struct Relocation {
Symbol *Sym;
};
+struct RelocationOffsetComparator {
+ bool operator()(const Relocation &Lhs, const Relocation &Rhs) {
+ return Lhs.Offset < Rhs.Offset;
+ }
+
+ // For std::lower_bound, std::upper_bound, std::equal_range.
+ bool operator()(const Relocation &Rel, uint64_t Val) {
+ return Rel.Offset < Val;
+ }
+
+ bool operator()(uint64_t Val, const Relocation &Rel) {
+ return Val < Rel.Offset;
+ }
+};
+
template <class ELFT> void scanRelocations(InputSectionBase &);
class ThunkSection;
@@ -155,10 +180,6 @@ private:
void createInitialThunkSections(ArrayRef<OutputSection *> OutputSections);
- void forEachInputSectionDescription(
- ArrayRef<OutputSection *> OutputSections,
- llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn);
-
std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src);
ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *,
diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp
index d4b1f6d99cc1..9a372c6d1c6f 100644
--- a/ELF/ScriptLexer.cpp
+++ b/ELF/ScriptLexer.cpp
@@ -244,6 +244,15 @@ StringRef ScriptLexer::peek() {
return Tok;
}
+StringRef ScriptLexer::peek2() {
+ skip();
+ StringRef Tok = next();
+ if (errorCount())
+ return "";
+ Pos = Pos - 2;
+ return Tok;
+}
+
bool ScriptLexer::consume(StringRef Tok) {
if (peek() == Tok) {
skip();
diff --git a/ELF/ScriptLexer.h b/ELF/ScriptLexer.h
index e7c8b28e49fd..fc6b5b1008a7 100644
--- a/ELF/ScriptLexer.h
+++ b/ELF/ScriptLexer.h
@@ -29,6 +29,7 @@ public:
bool atEOF();
StringRef next();
StringRef peek();
+ StringRef peek2();
void skip();
bool consume(StringRef Tok);
void expect(StringRef Expect);
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index ddb4a49a3e5e..eee3f0e330cc 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -72,13 +72,15 @@ private:
void readRegionAlias();
void readSearchDir();
void readSections();
+ void readTarget();
void readVersion();
void readVersionScriptCommand();
SymbolAssignment *readSymbolAssignment(StringRef Name);
ByteCommand *readByteCommand(StringRef Tok);
- uint32_t readFill();
- uint32_t parseFill(StringRef Tok);
+ std::array<uint8_t, 4> readFill();
+ std::array<uint8_t, 4> parseFill(StringRef Tok);
+ bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2);
void readSectionAddressType(OutputSection *Cmd);
OutputSection *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef OutSec);
@@ -92,6 +94,7 @@ private:
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
SymbolAssignment *readAssignment(StringRef Tok);
+ std::tuple<ELFKind, uint16_t, bool> readBfdName();
void readSort();
Expr readAssert();
Expr readConstant();
@@ -255,6 +258,8 @@ void ScriptParser::readLinkerScript() {
readSearchDir();
} else if (Tok == "SECTIONS") {
readSections();
+ } else if (Tok == "TARGET") {
+ readTarget();
} else if (Tok == "VERSION") {
readVersion();
} else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
@@ -266,6 +271,8 @@ void ScriptParser::readLinkerScript() {
}
void ScriptParser::readDefsym(StringRef Name) {
+ if (errorCount())
+ return;
Expr E = readExpr();
if (!atEOF())
setError("EOF expected, but got " + next());
@@ -378,10 +385,50 @@ void ScriptParser::readOutputArch() {
skip();
}
+std::tuple<ELFKind, uint16_t, bool> ScriptParser::readBfdName() {
+ StringRef S = unquote(next());
+ if (S == "elf32-i386")
+ return std::make_tuple(ELF32LEKind, EM_386, false);
+ if (S == "elf32-iamcu")
+ return std::make_tuple(ELF32LEKind, EM_IAMCU, false);
+ if (S == "elf32-littlearm")
+ return std::make_tuple(ELF32LEKind, EM_ARM, false);
+ if (S == "elf32-x86-64")
+ return std::make_tuple(ELF32LEKind, EM_X86_64, false);
+ if (S == "elf64-littleaarch64")
+ return std::make_tuple(ELF64LEKind, EM_AARCH64, false);
+ if (S == "elf64-powerpc")
+ return std::make_tuple(ELF64BEKind, EM_PPC64, false);
+ if (S == "elf64-powerpcle")
+ return std::make_tuple(ELF64LEKind, EM_PPC64, false);
+ if (S == "elf64-x86-64")
+ return std::make_tuple(ELF64LEKind, EM_X86_64, false);
+ if (S == "elf32-tradbigmips")
+ return std::make_tuple(ELF32BEKind, EM_MIPS, false);
+ if (S == "elf32-ntradbigmips")
+ return std::make_tuple(ELF32BEKind, EM_MIPS, true);
+ if (S == "elf32-tradlittlemips")
+ return std::make_tuple(ELF32LEKind, EM_MIPS, false);
+ if (S == "elf32-ntradlittlemips")
+ return std::make_tuple(ELF32LEKind, EM_MIPS, true);
+ if (S == "elf64-tradbigmips")
+ return std::make_tuple(ELF64BEKind, EM_MIPS, false);
+ if (S == "elf64-tradlittlemips")
+ return std::make_tuple(ELF64LEKind, EM_MIPS, false);
+
+ setError("unknown output format name: " + S);
+ return std::make_tuple(ELFNoneKind, EM_NONE, false);
+}
+
+// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
+// Currently we ignore big and little parameters.
void ScriptParser::readOutputFormat() {
- // Error checking only for now.
expect("(");
- skip();
+
+ std::tuple<ELFKind, uint16_t, bool> BfdTuple = readBfdName();
+ if (Config->EKind == ELFNoneKind)
+ std::tie(Config->EKind, Config->EMachine, Config->MipsN32Abi) = BfdTuple;
+
if (consume(")"))
return;
expect(",");
@@ -497,6 +544,9 @@ void ScriptParser::readSections() {
for (BaseCommand *Cmd : readOverlay())
V.push_back(Cmd);
continue;
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
}
if (BaseCommand *Cmd = readAssignment(Tok))
@@ -522,6 +572,23 @@ void ScriptParser::readSections() {
V.end());
}
+void ScriptParser::readTarget() {
+ // TARGET(foo) is an alias for "--format foo". Unlike GNU linkers,
+ // we accept only a limited set of BFD names (i.e. "elf" or "binary")
+ // for --format. We recognize only /^elf/ and "binary" in the linker
+ // script as well.
+ expect("(");
+ StringRef Tok = next();
+ expect(")");
+
+ if (Tok.startswith("elf"))
+ Config->FormatBinary = false;
+ else if (Tok == "binary")
+ Config->FormatBinary = true;
+ else
+ setError("unknown target: " + Tok);
+}
+
static int precedence(StringRef Op) {
return StringSwitch<int>(Op)
.Cases("*", "/", "%", 8)
@@ -672,13 +739,33 @@ Expr ScriptParser::readAssert() {
// alias for =fillexp section attribute, which is different from
// what GNU linkers do.
// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
-uint32_t ScriptParser::readFill() {
+std::array<uint8_t, 4> ScriptParser::readFill() {
expect("(");
- uint32_t V = parseFill(next());
+ std::array<uint8_t, 4> V = parseFill(next());
expect(")");
return V;
}
+// Tries to read the special directive for an output section definition which
+// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)" or "(OVERLAY)".
+// Tok1 and Tok2 are next 2 tokens peeked. See comment for readSectionAddressType below.
+bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2) {
+ if (Tok1 != "(")
+ return false;
+ if (Tok2 != "NOLOAD" && Tok2 != "COPY" && Tok2 != "INFO" && Tok2 != "OVERLAY")
+ return false;
+
+ expect("(");
+ if (consume("NOLOAD")) {
+ Cmd->Noload = true;
+ } else {
+ skip(); // This is "COPY", "INFO" or "OVERLAY".
+ Cmd->NonAlloc = true;
+ }
+ expect(")");
+ return true;
+}
+
// Reads an expression and/or the special directive for an output
// section definition. Directive is one of following: "(NOLOAD)",
// "(COPY)", "(INFO)" or "(OVERLAY)".
@@ -691,28 +778,12 @@ uint32_t ScriptParser::readFill() {
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
- if (consume("(")) {
- if (consume("NOLOAD")) {
- expect(")");
- Cmd->Noload = true;
- return;
- }
- if (consume("COPY") || consume("INFO") || consume("OVERLAY")) {
- expect(")");
- Cmd->NonAlloc = true;
- return;
- }
- Cmd->AddrExpr = readExpr();
- expect(")");
- } else {
- Cmd->AddrExpr = readExpr();
- }
+ if (readSectionDirective(Cmd, peek(), peek2()))
+ return;
- if (consume("(")) {
- expect("NOLOAD");
- expect(")");
- Cmd->Noload = true;
- }
+ Cmd->AddrExpr = readExpr();
+ if (peek() == "(" && !readSectionDirective(Cmd, "(", peek2()))
+ setError("unknown section directive: " + peek2());
}
static Expr checkAlignment(Expr E, std::string &Loc) {
@@ -778,10 +849,17 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
Cmd->Filler = readFill();
} else if (Tok == "SORT") {
readSort();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
} else if (peek() == "(") {
Cmd->SectionCommands.push_back(readInputSectionDescription(Tok));
} else {
- setError("unknown command " + Tok);
+ // We have a file name and no input sections description. It is not a
+ // commonly used syntax, but still acceptable. In that case, all sections
+ // from the file will be included.
+ auto *ISD = make<InputSectionDescription>(Tok);
+ ISD->SectionPatterns.push_back({{}, StringMatcher({"*"})});
+ Cmd->SectionCommands.push_back(ISD);
}
}
@@ -818,13 +896,13 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
// size, while ld.gold always handles it as a 32-bit big-endian number.
// We are compatible with ld.gold because it's easier to implement.
-uint32_t ScriptParser::parseFill(StringRef Tok) {
+std::array<uint8_t, 4> ScriptParser::parseFill(StringRef Tok) {
uint32_t V = 0;
if (!to_integer(Tok, V))
setError("invalid filler expression: " + Tok);
- uint32_t Buf;
- write32be(&Buf, V);
+ std::array<uint8_t, 4> Buf;
+ write32be(Buf.data(), V);
return Buf;
}
@@ -1404,7 +1482,11 @@ uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2,
void ScriptParser::readMemory() {
expect("{");
while (!errorCount() && !consume("}")) {
- StringRef Name = next();
+ StringRef Tok = next();
+ if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
+ }
uint32_t Flags = 0;
uint32_t NegFlags = 0;
@@ -1419,10 +1501,9 @@ void ScriptParser::readMemory() {
uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- MemoryRegion *MR =
- make<MemoryRegion>(Name, Origin, Length, Flags, NegFlags);
- if (!Script->MemoryRegions.insert({Name, MR}).second)
- setError("region '" + Name + "' already defined");
+ MemoryRegion *MR = make<MemoryRegion>(Tok, Origin, Length, Flags, NegFlags);
+ if (!Script->MemoryRegions.insert({Tok, MR}).second)
+ setError("region '" + Tok + "' already defined");
}
}
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index 1f5a84ec2c7d..7615e12199fa 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -94,8 +94,20 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
// DSOs are uniquified not by filename but by soname.
F->parseSoName();
- if (errorCount() || !SoNames.insert(F->SoName).second)
+ if (errorCount())
return;
+
+ // If a DSO appears more than once on the command line with and without
+ // --as-needed, --no-as-needed takes precedence over --as-needed because a
+ // user can add an extra DSO with --no-as-needed to force it to be added to
+ // the dependency list.
+ DenseMap<StringRef, InputFile *>::iterator It;
+ bool WasInserted;
+ std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F);
+ cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded;
+ if (!WasInserted)
+ return;
+
SharedFiles.push_back(F);
F->parseRest();
return;
@@ -139,77 +151,27 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() {
}
}
-Defined *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility,
- uint8_t Binding) {
- Symbol *Sym =
- addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
- return cast<Defined>(Sym);
-}
-
// Set a flag for --trace-symbol so that we can print out a log message
// if a new symbol with the same name is inserted into the symbol table.
void SymbolTable::trace(StringRef Name) {
SymMap.insert({CachedHashStringRef(Name), -1});
}
-// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
-// Used to implement --wrap.
-template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) {
- Symbol *Sym = find(Name);
- if (!Sym)
- return;
-
- // Do not wrap the same symbol twice.
- for (const WrappedSymbol &S : WrappedSymbols)
- if (S.Sym == Sym)
- return;
+void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+ // Swap symbols as instructed by -wrap.
+ int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())];
+ int &Idx2 = SymMap[CachedHashStringRef(Real->getName())];
+ int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())];
- Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
- Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
- WrappedSymbols.push_back({Sym, Real, Wrap});
+ Idx2 = Idx1;
+ Idx1 = Idx3;
- // We want to tell LTO not to inline symbols to be overwritten
- // because LTO doesn't know the final symbol contents after renaming.
- Real->CanInline = false;
- Sym->CanInline = false;
-
- // Tell LTO not to eliminate these symbols.
- Sym->IsUsedInRegularObj = true;
- Wrap->IsUsedInRegularObj = true;
-}
-
-// Apply symbol renames created by -wrap. The renames are created
-// before LTO in addSymbolWrap() to have a chance to inform LTO (if
-// LTO is running) not to include these symbols in IPO. Now that the
-// symbols are finalized, we can perform the replacement.
-void SymbolTable::applySymbolWrap() {
- // This function rotates 3 symbols:
- //
- // __real_sym becomes sym
- // sym becomes __wrap_sym
- // __wrap_sym becomes __real_sym
- //
- // The last part is special in that we don't want to change what references to
- // __wrap_sym point to, we just want have __real_sym in the symbol table.
-
- for (WrappedSymbol &W : WrappedSymbols) {
- // First, make a copy of __real_sym.
- Symbol *Real = nullptr;
- if (W.Real->isDefined()) {
- Real = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- memcpy(Real, W.Real, sizeof(SymbolUnion));
- }
-
- // Replace __real_sym with sym and sym with __wrap_sym.
- memcpy(W.Real, W.Sym, sizeof(SymbolUnion));
- memcpy(W.Sym, W.Wrap, sizeof(SymbolUnion));
-
- // We now have two copies of __wrap_sym. Drop one.
- W.Wrap->IsUsedInRegularObj = false;
-
- if (Real)
- SymVector.push_back(Real);
- }
+ // Now renaming is complete. No one refers Real symbol. We could leave
+ // Real as-is, but if Real is written to the symbol table, that may
+ // contain irrelevant values. So, we copy all values from Sym to Real.
+ StringRef S = Real->getName();
+ memcpy(Real, Sym, sizeof(SymbolUnion));
+ Real->setName(S);
}
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
@@ -221,7 +183,7 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
}
// Find an existing symbol or create and insert a new one.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
// <name>@@<version> means the symbol is the default version. In that
// case <name>@@<version> will be used to resolve references to <name>.
//
@@ -239,34 +201,34 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
if (SymIndex == -1) {
SymIndex = SymVector.size();
- IsNew = Traced = true;
+ IsNew = true;
+ Traced = true;
}
- Symbol *Sym;
- if (IsNew) {
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->Visibility = STV_DEFAULT;
- Sym->IsUsedInRegularObj = false;
- Sym->ExportDynamic = false;
- Sym->CanInline = true;
- Sym->Traced = Traced;
- Sym->VersionId = Config->DefaultSymbolVersion;
- SymVector.push_back(Sym);
- } else {
- Sym = SymVector[SymIndex];
- }
- return {Sym, IsNew};
+ if (!IsNew)
+ return {SymVector[SymIndex], false};
+
+ auto *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->SymbolKind = Symbol::PlaceholderKind;
+ Sym->Visibility = STV_DEFAULT;
+ Sym->IsUsedInRegularObj = false;
+ Sym->ExportDynamic = false;
+ Sym->CanInline = true;
+ Sym->Traced = Traced;
+ Sym->VersionId = Config->DefaultSymbolVersion;
+ SymVector.push_back(Sym);
+ return {Sym, true};
}
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
uint8_t Visibility,
bool CanOmitFromDynSym,
InputFile *File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = insertName(Name);
// Merge in the new symbol's visibility.
S->Visibility = getMinVisibility(S->Visibility, Visibility);
@@ -277,21 +239,9 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
if (!File || File->kind() == InputFile::ObjKind)
S->IsUsedInRegularObj = true;
- if (!WasInserted && S->Type != Symbol::UnknownType &&
- ((Type == STT_TLS) != S->isTls())) {
- error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " +
- toString(S->File) + "\n>>> defined in " + toString(File));
- }
-
return {S, WasInserted};
}
-template <class ELFT> Symbol *SymbolTable::addUndefined(StringRef Name) {
- return addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
-}
-
static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
template <class ELFT>
@@ -301,8 +251,7 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
Symbol *S;
bool WasInserted;
uint8_t Visibility = getVisibility(StOther);
- std::tie(S, WasInserted) =
- insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+ std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File);
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
@@ -314,10 +263,6 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (!Config->GcSections && Binding != STB_WEAK)
- if (auto *SS = dyn_cast<SharedSymbol>(S))
- SS->getFile<ELFT>().IsNeeded = true;
-
if (S->isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
@@ -450,7 +395,7 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
InputFile &File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
+ std::tie(S, WasInserted) = insert(N, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
int Cmp = compareDefined(S, WasInserted, Binding, N);
@@ -487,12 +432,6 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
return S;
}
-static void reportDuplicate(Symbol *Sym, InputFile *NewFile) {
- if (!Config->AllowMultipleDefinition)
- error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
- toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
-}
-
static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
InputSectionBase *ErrSec, uint64_t ErrOffset) {
if (Config->AllowMultipleDefinition)
@@ -500,7 +439,8 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
Defined *D = cast<Defined>(Sym);
if (!D->Section || !ErrSec) {
- reportDuplicate(Sym, NewFile);
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
return;
}
@@ -527,12 +467,12 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
error(Msg);
}
-Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File) {
+Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
+ std::tie(S, WasInserted) = insert(Name, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr,
Value, Name);
@@ -542,7 +482,7 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
else if (Cmp == 0)
reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
Value);
- return S;
+ return cast<Defined>(S);
}
template <typename ELFT>
@@ -554,7 +494,7 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// unchanged.
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
+ std::tie(S, WasInserted) = insert(Name, STV_DEFAULT,
/*CanOmitFromDynSym*/ true, &File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
@@ -562,19 +502,16 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted ||
- ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) {
- uint8_t Binding = S->Binding;
- bool WasUndefined = S->isUndefined();
- replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
+ auto Replace = [&](uint8_t Binding) {
+ replaceSymbol<SharedSymbol>(S, File, Name, Binding, Sym.st_other,
Sym.getType(), Sym.st_value, Sym.st_size,
Alignment, VerdefIndex);
- if (!WasInserted) {
- S->Binding = Binding;
- if (!S->isWeak() && !Config->GcSections && WasUndefined)
- File.IsNeeded = true;
- }
- }
+ };
+
+ if (WasInserted)
+ Replace(Sym.getBinding());
+ else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy()))
+ Replace(S->Binding);
}
Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
@@ -583,13 +520,13 @@ Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) =
- insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, &F);
+ insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F);
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding,
/*IsAbs*/ false, /*Value*/ 0, Name);
if (Cmp > 0)
replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr);
else if (Cmp == 0)
- reportDuplicate(S, &F);
+ reportDuplicate(S, &F, nullptr, 0);
return S;
}
@@ -602,18 +539,14 @@ Symbol *SymbolTable::find(StringRef Name) {
return SymVector[It->second];
}
-// This is used to handle lazy symbols. May replace existent
-// symbol with lazy version or request to Fetch it.
-template <class ELFT, typename LazyT, typename... ArgT>
-static void replaceOrFetchLazy(StringRef Name, InputFile &File,
- llvm::function_ref<InputFile *()> Fetch,
- ArgT &&... Arg) {
+template <class ELFT>
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = Symtab->insert(Name);
+ std::tie(S, WasInserted) = insertName(Name);
if (WasInserted) {
- replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
- std::forward<ArgT>(Arg)...);
+ replaceSymbol<LazyArchive>(S, File, STT_NOTYPE, Sym);
return;
}
if (!S->isUndefined())
@@ -622,26 +555,37 @@ static void replaceOrFetchLazy(StringRef Name, InputFile &File,
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
+ replaceSymbol<LazyArchive>(S, File, S->Type, Sym);
S->Binding = STB_WEAK;
return;
}
- if (InputFile *F = Fetch())
- Symtab->addFile<ELFT>(F);
+ if (InputFile *F = File.fetch(Sym))
+ addFile<ELFT>(F);
}
template <class ELFT>
-void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
- replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
- Sym);
-}
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insertName(Name);
+ if (WasInserted) {
+ replaceSymbol<LazyObject>(S, File, STT_NOTYPE, Name);
+ return;
+ }
+ if (!S->isUndefined())
+ return;
-template <class ELFT>
-void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
- Name);
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (S->isWeak()) {
+ replaceSymbol<LazyObject>(S, File, S->Type, Name);
+ S->Binding = STB_WEAK;
+ return;
+ }
+
+ if (InputFile *F = File.fetch())
+ addFile<ELFT>(F);
}
template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
@@ -822,16 +766,6 @@ template void SymbolTable::addFile<ELF32BE>(InputFile *);
template void SymbolTable::addFile<ELF64LE>(InputFile *);
template void SymbolTable::addFile<ELF64BE>(InputFile *);
-template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef);
-template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef);
-template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef);
-template void SymbolTable::addSymbolWrap<ELF64BE>(StringRef);
-
-template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef);
-
template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t,
uint8_t, bool, InputFile *);
template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t,
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 5e6d44dfe4f9..898185fc9612 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -37,22 +37,17 @@ class SymbolTable {
public:
template <class ELFT> void addFile(InputFile *File);
template <class ELFT> void addCombinedLTOObject();
- template <class ELFT> void addSymbolWrap(StringRef Name);
- void applySymbolWrap();
+ void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
- Defined *addAbsolute(StringRef Name,
- uint8_t Visibility = llvm::ELF::STV_HIDDEN,
- uint8_t Binding = llvm::ELF::STB_GLOBAL);
-
- template <class ELFT> Symbol *addUndefined(StringRef Name);
template <class ELFT>
Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
- Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File);
+
+ Defined *addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File);
template <class ELFT>
void addShared(StringRef Name, SharedFile<ELFT> &F,
@@ -72,10 +67,8 @@ public:
uint8_t Binding, uint8_t StOther, uint8_t Type,
InputFile &File);
- std::pair<Symbol *, bool> insert(StringRef Name);
- std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
- uint8_t Visibility, bool CanOmitFromDynSym,
- InputFile *File);
+ std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Visibility,
+ bool CanOmitFromDynSym, InputFile *File);
template <class ELFT> void fetchLazy(Symbol *Sym);
@@ -88,6 +81,8 @@ public:
void handleDynamicList();
private:
+ std::pair<Symbol *, bool> insertName(StringRef Name);
+
std::vector<Symbol *> findByVersion(SymbolVersion Ver);
std::vector<Symbol *> findAllByVersion(SymbolVersion Ver);
@@ -113,7 +108,7 @@ private:
llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
// Set of .so files to not link the same shared object file more than once.
- llvm::DenseSet<StringRef> SoNames;
+ llvm::DenseMap<StringRef, InputFile *> SoNames;
// A map from demangled symbol names to their symbol objects.
// This mapping is 1:N because two symbols with different versions
@@ -121,15 +116,6 @@ private:
// directive in version scripts.
llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> DemangledSyms;
- struct WrappedSymbol {
- Symbol *Sym;
- Symbol *Real;
- Symbol *Wrap;
- };
-
- // For -wrap.
- std::vector<WrappedSymbol> WrappedSymbols;
-
// For LTO.
std::unique_ptr<BitcodeCompiler> LTO;
};
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 4243cb1e80ef..a713ec539d82 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -38,6 +38,7 @@ Defined *ElfSym::GlobalOffsetTable;
Defined *ElfSym::MipsGp;
Defined *ElfSym::MipsGpDisp;
Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltStart;
Defined *ElfSym::RelaIpltEnd;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
@@ -90,10 +91,15 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
uint64_t VA = IS->getVA(Offset);
if (D.isTls() && !Config->Relocatable) {
- if (!Out::TlsPhdr)
+ // Use the address of the TLS segment's first section rather than the
+ // segment's address, because segment addresses aren't initialized until
+ // after sections are finalized. (e.g. Measuring the size of .rela.dyn
+ // for Android relocation packing requires knowing TLS symbol addresses
+ // during section finalization.)
+ if (!Out::TlsPhdr || !Out::TlsPhdr->FirstSec)
fatal(toString(D.File) +
" has an STT_TLS symbol but doesn't have an SHF_TLS section");
- return VA - Out::TlsPhdr->p_vaddr;
+ return VA - Out::TlsPhdr->FirstSec->Addr;
}
return VA;
}
@@ -102,7 +108,10 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
return 0;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
- llvm_unreachable("lazy symbol reached writer");
+ assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
+ return 0;
+ case Symbol::PlaceholderKind:
+ llvm_unreachable("placeholder symbol reached writer");
}
llvm_unreachable("invalid symbol kind");
}
@@ -112,7 +121,7 @@ uint64_t Symbol::getVA(int64_t Addend) const {
return OutVA + Addend;
}
-uint64_t Symbol::getGotVA() const { return InX::Got->getVA() + getGotOffset(); }
+uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); }
uint64_t Symbol::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
@@ -120,8 +129,8 @@ uint64_t Symbol::getGotOffset() const {
uint64_t Symbol::getGotPltVA() const {
if (this->IsInIgot)
- return InX::IgotPlt->getVA() + getGotPltOffset();
- return InX::GotPlt->getVA() + getGotPltOffset();
+ return In.IgotPlt->getVA() + getGotPltOffset();
+ return In.GotPlt->getVA() + getGotPltOffset();
}
uint64_t Symbol::getGotPltOffset() const {
@@ -130,15 +139,20 @@ uint64_t Symbol::getGotPltOffset() const {
return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
+uint64_t Symbol::getPPC64LongBranchOffset() const {
+ assert(PPC64BranchltIndex != 0xffff);
+ return PPC64BranchltIndex * Target->GotPltEntrySize;
+}
+
uint64_t Symbol::getPltVA() const {
- if (this->IsInIplt)
- return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
+ PltSection *Plt = IsInIplt ? In.Iplt : In.Plt;
+ return Plt->getVA() + Plt->HeaderSize + PltIndex * Target->PltEntrySize;
}
-uint64_t Symbol::getPltOffset() const {
- assert(!this->IsInIplt);
- return Target->getPltEntryOffset(PltIndex);
+uint64_t Symbol::getPPC64LongBranchTableVA() const {
+ assert(PPC64BranchltIndex != 0xffff);
+ return In.PPC64LongBranchTarget->getVA() +
+ PPC64BranchltIndex * Target->GotPltEntrySize;
}
uint64_t Symbol::getSize() const {
@@ -204,12 +218,21 @@ void Symbol::parseSymbolVersion() {
InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
+MemoryBufferRef LazyArchive::getMemberBuffer() {
+ Archive::Child C = CHECK(
+ Sym.getMember(), "could not get the member for symbol " + Sym.getName());
+
+ return CHECK(C.getMemoryBufferRef(),
+ "could not get the buffer for the member defining symbol " +
+ Sym.getName());
+}
+
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- if (VersionId == VER_NDX_LOCAL && isDefined())
+ if (VersionId == VER_NDX_LOCAL && isDefined() && !IsPreemptible)
return STB_LOCAL;
if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -243,10 +266,19 @@ void elf::printTraceSymbol(Symbol *Sym) {
message(toString(Sym->File) + S + Sym->getName());
}
-void elf::warnUnorderableSymbol(const Symbol *Sym) {
+void elf::maybeWarnUnorderableSymbol(const Symbol *Sym) {
if (!Config->WarnSymbolOrdering)
return;
+ // If UnresolvedPolicy::Ignore is used, no "undefined symbol" error/warning
+ // is emitted. It makes sense to not warn on undefined symbols.
+ //
+ // Note, ld.bfd --symbol-ordering-file= does not warn on undefined symbols,
+ // but we don't have to be compatible here.
+ if (Sym->isUndefined() &&
+ Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+ return;
+
const InputFile *File = Sym->File;
auto *D = dyn_cast<Defined>(Sym);
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 8c9513b9368b..4d55405d8936 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -22,6 +22,14 @@
namespace lld {
namespace elf {
+class Symbol;
+class InputFile;
+} // namespace elf
+
+std::string toString(const elf::Symbol &);
+std::string toString(const elf::InputFile *);
+
+namespace elf {
class ArchiveFile;
class BitcodeFile;
@@ -50,6 +58,7 @@ struct StringRefZ {
class Symbol {
public:
enum Kind {
+ PlaceholderKind,
DefinedKind,
SharedKind,
UndefinedKind,
@@ -70,6 +79,7 @@ public:
uint32_t DynsymIndex = 0;
uint32_t GotIndex = -1;
uint32_t PltIndex = -1;
+
uint32_t GlobalDynIndex = -1;
// This field is a index to the symbol's version definition.
@@ -78,6 +88,9 @@ public:
// Version definition index.
uint16_t VersionId;
+ // An index into the .branch_lt section on PPC64.
+ uint16_t PPC64BranchltIndex = -1;
+
// Symbol binding. This is not overwritten by replaceSymbol to track
// changes during resolution. In particular:
// - An undefined weak is still weak when it resolves to a shared library.
@@ -89,7 +102,7 @@ public:
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
- const uint8_t SymbolKind;
+ uint8_t SymbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
@@ -128,8 +141,12 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
- // True if this is an undefined weak symbol.
- bool isUndefWeak() const { return isWeak() && isUndefined(); }
+ // True if this is an undefined weak symbol. This only works once
+ // all input files have been added.
+ bool isUndefWeak() const {
+ // See comment on lazy symbols for details.
+ return isWeak() && (isUndefined() || isLazy());
+ }
StringRef getName() const {
if (NameSize == (uint32_t)-1)
@@ -137,10 +154,16 @@ public:
return {NameData, NameSize};
}
+ void setName(StringRef S) {
+ NameData = S.data();
+ NameSize = S.size();
+ }
+
void parseSymbolVersion();
bool isInGot() const { return GotIndex != -1U; }
bool isInPlt() const { return PltIndex != -1U; }
+ bool isInPPC64Branchlt() const { return PPC64BranchltIndex != 0xffff; }
uint64_t getVA(int64_t Addend = 0) const;
@@ -149,7 +172,8 @@ public:
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
- uint64_t getPltOffset() const;
+ uint64_t getPPC64LongBranchTableVA() const;
+ uint64_t getPPC64LongBranchOffset() const;
uint64_t getSize() const;
OutputSection *getOutputSection() const;
@@ -159,7 +183,8 @@ protected:
: File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
IsInIplt(false), IsInIgot(false), IsPreemptible(false),
- Used(!Config->GcSections), NeedsTocRestore(false) {}
+ Used(!Config->GcSections), NeedsTocRestore(false),
+ ScriptDefined(false) {}
public:
// True the symbol should point to its PLT entry.
@@ -182,12 +207,8 @@ public:
// PPC64 toc pointer.
unsigned NeedsTocRestore : 1;
- // The Type field may also have this value. It means that we have not yet seen
- // a non-Lazy symbol with this name, so we don't know what its type is. The
- // Type field is normally set to this value for Lazy symbols unless we saw a
- // weak undefined symbol first, in which case we need to remember the original
- // symbol's type in order to check for TLS mismatches.
- enum { UnknownType = 255 };
+ // True if this symbol is defined by a linker script.
+ unsigned ScriptDefined : 1;
bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
bool isTls() const { return Type == llvm::ELF::STT_TLS; }
@@ -286,6 +307,7 @@ public:
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
InputFile *fetch();
+ MemoryBufferRef getMemberBuffer();
private:
const llvm::object::Archive::Symbol Sym;
@@ -330,7 +352,8 @@ struct ElfSym {
static Defined *MipsGpDisp;
static Defined *MipsLocalGp;
- // __rela_iplt_end or __rel_iplt_end
+ // __rel{,a}_iplt_{start,end} symbols.
+ static Defined *RelaIpltStart;
static Defined *RelaIpltEnd;
};
@@ -349,6 +372,8 @@ void printTraceSymbol(Symbol *Sym);
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ using llvm::ELF::STT_TLS;
+
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
@@ -367,6 +392,19 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
S->ExportDynamic = Sym.ExportDynamic;
S->CanInline = Sym.CanInline;
S->Traced = Sym.Traced;
+ S->ScriptDefined = Sym.ScriptDefined;
+
+ // Symbols representing thread-local variables must be referenced by
+ // TLS-aware relocations, and non-TLS symbols must be reference by
+ // non-TLS relocations, so there's a clear distinction between TLS
+ // and non-TLS symbols. It is an error if the same symbol is defined
+ // as a TLS symbol in one file and as a non-TLS symbol in other file.
+ bool TlsMismatch = (Sym.Type == STT_TLS && S->Type != STT_TLS) ||
+ (Sym.Type != STT_TLS && S->Type == STT_TLS);
+
+ if (Sym.SymbolKind != Symbol::PlaceholderKind && TlsMismatch && !Sym.isLazy())
+ error("TLS attribute mismatch: " + toString(Sym) + "\n>>> defined in " +
+ toString(Sym.File) + "\n>>> defined in " + toString(S->File));
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
@@ -374,10 +412,8 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
printTraceSymbol(S);
}
-void warnUnorderableSymbol(const Symbol *Sym);
+void maybeWarnUnorderableSymbol(const Symbol *Sym);
} // namespace elf
-
-std::string toString(const elf::Symbol &B);
} // namespace lld
#endif
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index ae02434572c2..f459c1b6b479 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -30,10 +30,11 @@
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/SetOperations.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
-#include "llvm/Object/Decompressor.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MD5.h"
@@ -104,7 +105,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Create = true;
std::string Filename = toString(Sec->File);
- const size_t Size = Sec->Data.size();
+ const size_t Size = Sec->data().size();
// Older version of BFD (such as the default FreeBSD linker) concatenate
// .MIPS.abiflags instead of merging. To allow for this case (or potential
// zero padding) we ignore everything after the first Elf_Mips_ABIFlags
@@ -113,7 +114,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
return nullptr;
}
- auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->Data.data());
+ auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data());
if (S->version != 0) {
error(Filename + ": unexpected .MIPS.abiflags version " +
Twine(S->version));
@@ -153,7 +154,7 @@ template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = InX::MipsGot->getGp();
+ Reginfo.ri_gp_value = In.MipsGot->getGp();
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
}
@@ -176,7 +177,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
Sec->Live = false;
std::string Filename = toString(Sec->File);
- ArrayRef<uint8_t> D = Sec->Data;
+ ArrayRef<uint8_t> D = Sec->data();
while (!D.empty()) {
if (D.size() < sizeof(Elf_Mips_Options)) {
@@ -210,7 +211,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = InX::MipsGot->getGp();
+ Reginfo.ri_gp_value = In.MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
@@ -232,12 +233,12 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
for (InputSectionBase *Sec : Sections) {
Sec->Live = false;
- if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) {
+ if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) {
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
- auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->data().data());
Reginfo.ri_gprmask |= R->ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
@@ -260,8 +261,8 @@ Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
uint64_t Size, InputSectionBase &Section) {
auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
Value, Size, &Section);
- if (InX::SymTab)
- InX::SymTab->addSymbol(S);
+ if (In.SymTab)
+ In.SymTab->addSymbol(S);
return S;
}
@@ -502,7 +503,7 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
uint8_t *Buf = getParent()->Loc + OutSecOff;
std::vector<FdeData> Ret;
- uint64_t VA = InX::EhFrameHdr->getVA();
+ uint64_t VA = In.EhFrameHdr->getVA();
for (CieRecord *Rec : CieRecords) {
uint8_t Enc = getFdeEncoding(Rec->Cie);
for (EhSectionPiece *Fde : Rec->Fdes) {
@@ -937,7 +938,7 @@ template <class ELFT> void MipsGotSection::build() {
Symbol *S = P.first;
uint64_t Offset = P.second * Config->Wordsize;
if (S->IsPreemptible)
- InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
}
for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
Symbol *S = P.first;
@@ -945,7 +946,7 @@ template <class ELFT> void MipsGotSection::build() {
if (S == nullptr) {
if (!Config->Pic)
continue;
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
} else {
// When building a shared library we still need a dynamic relocation
// for the module index. Therefore only checking for
@@ -953,13 +954,13 @@ template <class ELFT> void MipsGotSection::build() {
// thread-locals that have been marked as local through a linker script)
if (!S->IsPreemptible && !Config->Pic)
continue;
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
// However, we can skip writing the TLS offset reloc for non-preemptible
// symbols since it is known even in shared libraries
if (!S->IsPreemptible)
continue;
Offset += Config->Wordsize;
- InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+ In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
}
}
@@ -971,7 +972,7 @@ template <class ELFT> void MipsGotSection::build() {
// Dynamic relocations for "global" entries.
for (const std::pair<Symbol *, size_t> &P : Got.Global) {
uint64_t Offset = P.second * Config->Wordsize;
- InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+ In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
}
if (!Config->Pic)
continue;
@@ -981,14 +982,14 @@ template <class ELFT> void MipsGotSection::build() {
size_t PageCount = L.second.Count;
for (size_t PI = 0; PI < PageCount; ++PI) {
uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
- InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
- int64_t(PI * 0x10000)});
+ In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+ int64_t(PI * 0x10000)});
}
}
for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
uint64_t Offset = P.second * Config->Wordsize;
- InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
- P.first.first, P.first.second});
+ In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
}
}
}
@@ -1200,21 +1201,21 @@ DynamicSection<ELFT>::DynamicSection()
// Add strings to .dynstr early so that .dynstr's size will be
// fixed early.
for (StringRef S : Config->FilterList)
- addInt(DT_FILTER, InX::DynStrTab->addString(S));
+ addInt(DT_FILTER, In.DynStrTab->addString(S));
for (StringRef S : Config->AuxiliaryList)
- addInt(DT_AUXILIARY, InX::DynStrTab->addString(S));
+ addInt(DT_AUXILIARY, In.DynStrTab->addString(S));
if (!Config->Rpath.empty())
addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- InX::DynStrTab->addString(Config->Rpath));
+ In.DynStrTab->addString(Config->Rpath));
for (InputFile *File : SharedFiles) {
SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
if (F->IsNeeded)
- addInt(DT_NEEDED, InX::DynStrTab->addString(F->SoName));
+ addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName));
}
if (!Config->SoName.empty())
- addInt(DT_SONAME, InX::DynStrTab->addString(Config->SoName));
+ addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName));
}
template <class ELFT>
@@ -1254,18 +1255,33 @@ void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) {
Entries.push_back({Tag, [=] { return Sym->getVA(); }});
}
+// A Linker script may assign the RELA relocation sections to the same
+// output section. When this occurs we cannot just use the OutputSection
+// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
+// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
+static uint64_t addPltRelSz() {
+ size_t Size = In.RelaPlt->getSize();
+ if (In.RelaIplt->getParent() == In.RelaPlt->getParent() &&
+ In.RelaIplt->Name == In.RelaPlt->Name)
+ Size += In.RelaIplt->getSize();
+ return Size;
+}
+
// Add remaining entries to complete .dynamic contents.
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
- if (this->Size)
- return; // Already finalized.
-
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t DtFlags = 0;
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
+ if (Config->ZGlobal)
+ DtFlags1 |= DF_1_GLOBAL;
if (Config->ZInitfirst)
DtFlags1 |= DF_1_INITFIRST;
+ if (Config->ZInterpose)
+ DtFlags1 |= DF_1_INTERPOSE;
+ if (Config->ZNodefaultlib)
+ DtFlags1 |= DF_1_NODEFLIB;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNodlopen)
@@ -1297,10 +1313,12 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
addInt(DT_DEBUG, 0);
- this->Link = InX::DynStrTab->getParent()->SectionIndex;
- if (!InX::RelaDyn->empty()) {
- addInSec(InX::RelaDyn->DynamicTag, InX::RelaDyn);
- addSize(InX::RelaDyn->SizeDynamicTag, InX::RelaDyn->getParent());
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ this->Link = Sec->SectionIndex;
+
+ if (!In.RelaDyn->empty()) {
+ addInSec(In.RelaDyn->DynamicTag, In.RelaDyn);
+ addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent());
bool IsRela = Config->IsRela;
addInt(IsRela ? DT_RELAENT : DT_RELENT,
@@ -1310,16 +1328,16 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// The problem is in the tight relation between dynamic
// relocations and GOT. So do not emit this tag on MIPS.
if (Config->EMachine != EM_MIPS) {
- size_t NumRelativeRels = InX::RelaDyn->getRelativeRelocCount();
+ size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount();
if (Config->ZCombreloc && NumRelativeRels)
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
- if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
+ if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) {
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
- InX::RelrDyn);
+ In.RelrDyn);
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
- InX::RelrDyn->getParent());
+ In.RelrDyn->getParent());
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
sizeof(Elf_Relr));
}
@@ -1329,33 +1347,33 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// as RelaIplt have. And we still want to emit proper dynamic tags for that
// case, so here we always use RelaPlt as marker for the begining of
// .rel[a].plt section.
- if (InX::RelaPlt->getParent()->Live) {
- addInSec(DT_JMPREL, InX::RelaPlt);
- addSize(DT_PLTRELSZ, InX::RelaPlt->getParent());
+ if (In.RelaPlt->getParent()->Live) {
+ addInSec(DT_JMPREL, In.RelaPlt);
+ Entries.push_back({DT_PLTRELSZ, addPltRelSz});
switch (Config->EMachine) {
case EM_MIPS:
- addInSec(DT_MIPS_PLTGOT, InX::GotPlt);
+ addInSec(DT_MIPS_PLTGOT, In.GotPlt);
break;
case EM_SPARCV9:
- addInSec(DT_PLTGOT, InX::Plt);
+ addInSec(DT_PLTGOT, In.Plt);
break;
default:
- addInSec(DT_PLTGOT, InX::GotPlt);
+ addInSec(DT_PLTGOT, In.GotPlt);
break;
}
addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL);
}
- addInSec(DT_SYMTAB, InX::DynSymTab);
+ addInSec(DT_SYMTAB, In.DynSymTab);
addInt(DT_SYMENT, sizeof(Elf_Sym));
- addInSec(DT_STRTAB, InX::DynStrTab);
- addInt(DT_STRSZ, InX::DynStrTab->getSize());
+ addInSec(DT_STRTAB, In.DynStrTab);
+ addInt(DT_STRSZ, In.DynStrTab->getSize());
if (!Config->ZText)
addInt(DT_TEXTREL, 0);
- if (InX::GnuHashTab)
- addInSec(DT_GNU_HASH, InX::GnuHashTab);
- if (InX::HashTab)
- addInSec(DT_HASH, InX::HashTab);
+ if (In.GnuHashTab)
+ addInSec(DT_GNU_HASH, In.GnuHashTab);
+ if (In.HashTab)
+ addInSec(DT_HASH, In.HashTab);
if (Out::PreinitArray) {
addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray);
@@ -1377,47 +1395,47 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (B->isDefined())
addSym(DT_FINI, B);
- bool HasVerNeed = In<ELFT>::VerNeed->getNeedNum() != 0;
- if (HasVerNeed || In<ELFT>::VerDef)
- addInSec(DT_VERSYM, In<ELFT>::VerSym);
- if (In<ELFT>::VerDef) {
- addInSec(DT_VERDEF, In<ELFT>::VerDef);
+ bool HasVerNeed = InX<ELFT>::VerNeed->getNeedNum() != 0;
+ if (HasVerNeed || In.VerDef)
+ addInSec(DT_VERSYM, InX<ELFT>::VerSym);
+ if (In.VerDef) {
+ addInSec(DT_VERDEF, In.VerDef);
addInt(DT_VERDEFNUM, getVerDefNum());
}
if (HasVerNeed) {
- addInSec(DT_VERNEED, In<ELFT>::VerNeed);
- addInt(DT_VERNEEDNUM, In<ELFT>::VerNeed->getNeedNum());
+ addInSec(DT_VERNEED, InX<ELFT>::VerNeed);
+ addInt(DT_VERNEEDNUM, InX<ELFT>::VerNeed->getNeedNum());
}
if (Config->EMachine == EM_MIPS) {
addInt(DT_MIPS_RLD_VERSION, 1);
addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase());
- addInt(DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols());
+ addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols());
- add(DT_MIPS_LOCAL_GOTNO, [] { return InX::MipsGot->getLocalEntriesNum(); });
+ add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); });
- if (const Symbol *B = InX::MipsGot->getFirstGlobalEntry())
+ if (const Symbol *B = In.MipsGot->getFirstGlobalEntry())
addInt(DT_MIPS_GOTSYM, B->DynsymIndex);
else
- addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols());
- addInSec(DT_PLTGOT, InX::MipsGot);
- if (InX::MipsRldMap) {
+ addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols());
+ addInSec(DT_PLTGOT, In.MipsGot);
+ if (In.MipsRldMap) {
if (!Config->Pie)
- addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap);
// Store the offset to the .rld_map section
// relative to the address of the tag.
- addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap);
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap);
}
}
// Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
- if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) {
+ if (Config->EMachine == EM_PPC64 && !In.Plt->empty()) {
// The Glink tag points to 32 bytes before the first lazy symbol resolution
// stub, which starts directly after the header.
Entries.push_back({DT_PPC64_GLINK, [=] {
unsigned Offset = Target->PltHeaderSize - 32;
- return InX::Plt->getVA(0) + Offset;
+ return In.Plt->getVA(0) + Offset;
}});
}
@@ -1486,13 +1504,17 @@ void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
}
void RelocationBaseSection::finalizeContents() {
- // If all relocations are R_*_RELATIVE they don't refer to any
- // dynamic symbol and we don't need a dynamic symbol table. If that
- // is the case, just use 0 as the link.
- Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex : 0;
+ // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
+ // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that
+ // case.
+ InputSection *SymTab = Config->Relocatable ? In.SymTab : In.DynSymTab;
+ if (SymTab && SymTab->getParent())
+ getParent()->Link = SymTab->getParent()->SectionIndex;
+ else
+ getParent()->Link = 0;
- // Set required output section properties.
- getParent()->Link = Link;
+ if (In.RelaIplt == this || In.RelaPlt == this)
+ getParent()->Info = In.GotPlt->getParent()->SectionIndex;
}
RelrBaseSection::RelrBaseSection()
@@ -1621,10 +1643,9 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
NonRelatives.push_back(R);
}
- llvm::sort(Relatives.begin(), Relatives.end(),
- [](const Elf_Rel &A, const Elf_Rel &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) {
+ return A.r_offset < B.r_offset;
+ });
// Try to find groups of relative relocations which are spaced one word
// apart from one another. These generally correspond to vtable entries. The
@@ -1702,10 +1723,9 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
// Finally the non-relative relocations.
- llvm::sort(NonRelatives.begin(), NonRelatives.end(),
- [](const Elf_Rela &A, const Elf_Rela &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
@@ -1720,6 +1740,11 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
}
+ // Don't allow the section to shrink; otherwise the size of the section can
+ // oscillate infinitely.
+ if (RelocData.size() < OldSize)
+ RelocData.append(OldSize - RelocData.size(), 0);
+
// Returns whether the section size changed. We need to keep recomputing both
// section layout and the contents of this section until the size converges
// because changing this section's size can affect section layout, which in
@@ -1843,10 +1868,13 @@ static bool sortMipsSymbols(const SymbolTableEntry &L,
}
void SymbolTableBaseSection::finalizeContents() {
- getParent()->Link = StrTabSec.getParent()->SectionIndex;
+ if (OutputSection *Sec = StrTabSec.getParent())
+ getParent()->Link = Sec->SectionIndex;
- if (this->Type != SHT_DYNSYM)
+ if (this->Type != SHT_DYNSYM) {
+ sortSymTabSymbols();
return;
+ }
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
@@ -1855,9 +1883,9 @@ void SymbolTableBaseSection::finalizeContents() {
// Because the first symbol entry is a null entry, 1 is the first.
getParent()->Info = 1;
- if (InX::GnuHashTab) {
+ if (In.GnuHashTab) {
// NB: It also sorts Symbols to meet the GNU hash table requirements.
- InX::GnuHashTab->addSymbols(Symbols);
+ In.GnuHashTab->addSymbols(Symbols);
} else if (Config->EMachine == EM_MIPS) {
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
@@ -1874,9 +1902,7 @@ void SymbolTableBaseSection::finalizeContents() {
// Aside from above, we put local symbols in groups starting with the STT_FILE
// symbol. That is convenient for purpose of identifying where are local symbols
// coming from.
-void SymbolTableBaseSection::postThunkContents() {
- assert(this->Type == SHT_SYMTAB);
-
+void SymbolTableBaseSection::sortSymTabSymbols() {
// Move all local symbols before global symbols.
auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
@@ -1948,7 +1974,8 @@ static uint32_t getSymSectionIndex(Symbol *Sym) {
if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
return SHN_UNDEF;
if (const OutputSection *OS = Sym->getOutputSection())
- return OS->SectionIndex >= SHN_LORESERVE ? SHN_XINDEX : OS->SectionIndex;
+ return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX
+ : OS->SectionIndex;
return SHN_ABS;
}
@@ -2038,7 +2065,7 @@ void SymtabShndxSection::writeTo(uint8_t *Buf) {
// with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
// we need to write actual index, otherwise, we must write SHN_UNDEF(0).
Buf += 4; // Ignore .symtab[0] entry.
- for (const SymbolTableEntry &Entry : InX::SymTab->getSymbols()) {
+ for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) {
if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
Buf += 4;
@@ -2059,11 +2086,11 @@ bool SymtabShndxSection::empty() const {
}
void SymtabShndxSection::finalizeContents() {
- getParent()->Link = InX::SymTab->getParent()->SectionIndex;
+ getParent()->Link = In.SymTab->getParent()->SectionIndex;
}
size_t SymtabShndxSection::getSize() const {
- return InX::SymTab->getNumSymbols() * 4;
+ return In.SymTab->getNumSymbols() * 4;
}
// .hash and .gnu.hash sections contain on-disk hash tables that map
@@ -2102,7 +2129,8 @@ GnuHashTableSection::GnuHashTableSection()
}
void GnuHashTableSection::finalizeContents() {
- getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynSymTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
// Computes bloom filter size in word size. We want to allocate 12
// bits for each symbol. It must be a power of two.
@@ -2127,7 +2155,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
// Write a header.
write32(Buf, NBuckets);
- write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size());
+ write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size());
write32(Buf + 8, MaskWords);
write32(Buf + 12, Shift2);
Buf += 16;
@@ -2148,6 +2176,8 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
unsigned C = Config->Is64 ? 64 : 32;
for (const Entry &Sym : Symbols) {
+ // When C = 64, we choose a word with bits [6:...] and set 1 to two bits in
+ // the word using bits [0:5] and [26:31].
size_t I = (Sym.Hash / C) & (MaskWords - 1);
uint64_t Val = readUint(Buf + I * Config->Wordsize);
Val |= uint64_t(1) << (Sym.Hash % C);
@@ -2232,13 +2262,14 @@ HashTableSection::HashTableSection()
}
void HashTableSection::finalizeContents() {
- getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynSymTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries.
+ NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
- NumEntries += InX::DynSymTab->getNumSymbols();
+ NumEntries += In.DynSymTab->getNumSymbols();
this->Size = NumEntries * 4;
}
@@ -2246,7 +2277,7 @@ void HashTableSection::writeTo(uint8_t *Buf) {
// See comment in GnuHashTableSection::writeTo.
memset(Buf, 0, Size);
- unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
+ unsigned NumSymbols = In.DynSymTab->getNumSymbols();
uint32_t *P = reinterpret_cast<uint32_t *>(Buf);
write32(P++, NumSymbols); // nbucket
@@ -2255,7 +2286,7 @@ void HashTableSection::writeTo(uint8_t *Buf) {
uint32_t *Buckets = P;
uint32_t *Chains = P + NumSymbols;
- for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
Symbol *Sym = S.Sym;
StringRef Name = Sym->getName();
unsigned I = Sym->DynsymIndex;
@@ -2270,7 +2301,8 @@ void HashTableSection::writeTo(uint8_t *Buf) {
PltSection::PltSection(bool IsIplt)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
- HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) {
+ HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0),
+ IsIplt(IsIplt) {
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
if (Config->EMachine == EM_SPARCV9)
@@ -2278,9 +2310,9 @@ PltSection::PltSection(bool IsIplt)
}
void PltSection::writeTo(uint8_t *Buf) {
- // At beginning of PLT but not the IPLT, we have code to call the dynamic
+ // At beginning of PLT or retpoline IPLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
- if (!IsIplt)
+ if (HeaderSize > 0)
Target->writePltHeader(Buf);
size_t Off = HeaderSize;
// The IPlt is immediately after the Plt, account for this in RelOff
@@ -2298,9 +2330,9 @@ void PltSection::writeTo(uint8_t *Buf) {
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
- RelocationBaseSection *PltRelocSection = InX::RelaPlt;
+ RelocationBaseSection *PltRelocSection = In.RelaPlt;
if (IsIplt) {
- PltRelocSection = InX::RelaIplt;
+ PltRelocSection = In.RelaIplt;
Sym.IsInIplt = true;
}
unsigned RelOff =
@@ -2326,14 +2358,14 @@ void PltSection::addSymbols() {
}
unsigned PltSection::getPltRelocOff() const {
- return IsIplt ? InX::Plt->getSize() : 0;
+ return IsIplt ? In.Plt->getSize() : 0;
}
// The string hash function for .gdb_index.
static uint32_t computeGdbHash(StringRef S) {
uint32_t H = 0;
for (uint8_t C : S)
- H = H * 67 + tolower(C) - 113;
+ H = H * 67 + toLower(C) - 113;
return H;
}
@@ -2371,7 +2403,7 @@ static std::vector<InputSection *> getDebugInfoSections() {
static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
std::vector<GdbIndexSection::CuEntry> Ret;
- for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units())
+ for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units())
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
@@ -2381,12 +2413,15 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
std::vector<GdbIndexSection::AddressEntry> Ret;
uint32_t CuIdx = 0;
- for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) {
- DWARFAddressRangesVector Ranges;
- Cu->collectAddressRanges(Ranges);
+ for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) {
+ Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges();
+ if (!Ranges) {
+ error(toString(Sec) + ": " + toString(Ranges.takeError()));
+ return {};
+ }
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
- for (DWARFAddressRange &R : Ranges) {
+ for (DWARFAddressRange &R : *Ranges) {
InputSectionBase *S = Sections[R.SectionIndex];
if (!S || S == &InputSection::Discarded || !S->Live)
continue;
@@ -2399,21 +2434,35 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
}
++CuIdx;
}
+
return Ret;
}
-static std::vector<GdbIndexSection::NameTypeEntry>
-readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
- StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection();
- StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection();
-
- std::vector<GdbIndexSection::NameTypeEntry> Ret;
- for (StringRef Sec : {Sec1, Sec2}) {
- DWARFDebugPubTable Table(Sec, Config->IsLE, true);
- for (const DWARFDebugPubTable::Set &Set : Table.getData())
+template <class ELFT>
+static std::vector<GdbIndexSection::NameAttrEntry>
+readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj,
+ const std::vector<GdbIndexSection::CuEntry> &CUs) {
+ const DWARFSection &PubNames = Obj.getGnuPubNamesSection();
+ const DWARFSection &PubTypes = Obj.getGnuPubTypesSection();
+
+ std::vector<GdbIndexSection::NameAttrEntry> Ret;
+ for (const DWARFSection *Pub : {&PubNames, &PubTypes}) {
+ DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true);
+ for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
+ // The value written into the constant pool is Kind << 24 | CuIndex. As we
+ // don't know how many compilation units precede this object to compute
+ // CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add
+ // the number of preceding compilation units later.
+ uint32_t I =
+ lower_bound(CUs, Set.Offset,
+ [](GdbIndexSection::CuEntry CU, uint32_t Offset) {
+ return CU.CuOffset < Offset;
+ }) -
+ CUs.begin();
for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
- (Ent.Descriptor.toBits() << 24) | Idx});
+ (Ent.Descriptor.toBits() << 24) | I});
+ }
}
return Ret;
}
@@ -2421,9 +2470,18 @@ readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
// Create a list of symbols from a given list of symbol names and types
// by uniquifying them by name.
static std::vector<GdbIndexSection::GdbSymbol>
-createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) {
+createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs,
+ const std::vector<GdbIndexSection::GdbChunk> &Chunks) {
typedef GdbIndexSection::GdbSymbol GdbSymbol;
- typedef GdbIndexSection::NameTypeEntry NameTypeEntry;
+ typedef GdbIndexSection::NameAttrEntry NameAttrEntry;
+
+ // For each chunk, compute the number of compilation units preceding it.
+ uint32_t CuIdx = 0;
+ std::vector<uint32_t> CuIdxs(Chunks.size());
+ for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) {
+ CuIdxs[I] = CuIdx;
+ CuIdx += Chunks[I].CompilationUnits.size();
+ }
// The number of symbols we will handle in this function is of the order
// of millions for very large executables, so we use multi-threading to
@@ -2441,21 +2499,24 @@ createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) {
// Instantiate GdbSymbols while uniqufying them by name.
std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
- for (ArrayRef<NameTypeEntry> Entries : NameTypes) {
- for (const NameTypeEntry &Ent : Entries) {
+ uint32_t I = 0;
+ for (ArrayRef<NameAttrEntry> Entries : NameAttrs) {
+ for (const NameAttrEntry &Ent : Entries) {
size_t ShardId = Ent.Name.hash() >> Shift;
if ((ShardId & (Concurrency - 1)) != ThreadId)
continue;
+ uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I];
size_t &Idx = Map[ShardId][Ent.Name];
if (Idx) {
- Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type);
+ Symbols[ShardId][Idx - 1].CuVector.push_back(V);
continue;
}
Idx = Symbols[ShardId].size() + 1;
- Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0});
+ Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0});
}
+ ++I;
}
});
@@ -2498,7 +2559,7 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
S->Live = false;
std::vector<GdbChunk> Chunks(Sections.size());
- std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size());
+ std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size());
parallelForEachN(0, Sections.size(), [&](size_t I) {
ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
@@ -2507,12 +2568,14 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
Chunks[I].Sec = Sections[I];
Chunks[I].CompilationUnits = readCuList(Dwarf);
Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
- NameTypes[I] = readPubNamesAndTypes(Dwarf, I);
+ NameAttrs[I] = readPubNamesAndTypes<ELFT>(
+ static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()),
+ Chunks[I].CompilationUnits);
});
auto *Ret = make<GdbIndexSection>();
Ret->Chunks = std::move(Chunks);
- Ret->Symbols = createSymbols(NameTypes);
+ Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks);
Ret->initOutputSize();
return Ret;
}
@@ -2570,8 +2633,9 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
// Write the string pool.
Hdr->ConstantPoolOff = Buf - Start;
- for (GdbSymbol &Sym : Symbols)
+ parallelForEach(Symbols, [&](GdbSymbol &Sym) {
memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
+ });
// Write the CU vectors.
for (GdbSymbol &Sym : Symbols) {
@@ -2584,7 +2648,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
}
}
-bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
+bool GdbIndexSection::empty() const { return Chunks.empty(); }
EhFrameHeader::EhFrameHeader()
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
@@ -2596,13 +2660,13 @@ EhFrameHeader::EhFrameHeader()
void EhFrameHeader::writeTo(uint8_t *Buf) {
typedef EhFrameSection::FdeData FdeData;
- std::vector<FdeData> Fdes = InX::EhFrame->getFdeData();
+ std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
Buf[0] = 1;
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
- write32(Buf + 4, InX::EhFrame->getParent()->Addr - this->getVA() - 4);
+ write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4);
write32(Buf + 8, Fdes.size());
Buf += 12;
@@ -2615,13 +2679,12 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
size_t EhFrameHeader::getSize() const {
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
- return 12 + InX::EhFrame->NumFdes * 8;
+ return 12 + In.EhFrame->NumFdes * 8;
}
-bool EhFrameHeader::empty() const { return InX::EhFrame->empty(); }
+bool EhFrameHeader::empty() const { return In.EhFrame->empty(); }
-template <class ELFT>
-VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+VersionDefinitionSection::VersionDefinitionSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
".gnu.version_d") {}
@@ -2631,12 +2694,13 @@ static StringRef getFileDefName() {
return Config->OutputFile;
}
-template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
- FileDefNameOff = InX::DynStrTab->addString(getFileDefName());
+void VersionDefinitionSection::finalizeContents() {
+ FileDefNameOff = In.DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
- V.NameOff = InX::DynStrTab->addString(V.Name);
+ V.NameOff = In.DynStrTab->addString(V.Name);
- getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
@@ -2644,68 +2708,68 @@ template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
getParent()->Info = getVerDefNum();
}
-template <class ELFT>
-void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index,
- StringRef Name, size_t NameOff) {
- auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
- Verdef->vd_version = 1;
- Verdef->vd_cnt = 1;
- Verdef->vd_aux = sizeof(Elf_Verdef);
- Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
- Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0);
- Verdef->vd_ndx = Index;
- Verdef->vd_hash = hashSysV(Name);
-
- auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef));
- Verdaux->vda_name = NameOff;
- Verdaux->vda_next = 0;
+void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index,
+ StringRef Name, size_t NameOff) {
+ uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0;
+
+ // Write a verdef.
+ write16(Buf, 1); // vd_version
+ write16(Buf + 2, Flags); // vd_flags
+ write16(Buf + 4, Index); // vd_ndx
+ write16(Buf + 6, 1); // vd_cnt
+ write32(Buf + 8, hashSysV(Name)); // vd_hash
+ write32(Buf + 12, 20); // vd_aux
+ write32(Buf + 16, 28); // vd_next
+
+ // Write a veraux.
+ write32(Buf + 20, NameOff); // vda_name
+ write32(Buf + 24, 0); // vda_next
}
-template <class ELFT>
-void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
+void VersionDefinitionSection::writeTo(uint8_t *Buf) {
writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
for (VersionDefinition &V : Config->VersionDefinitions) {
- Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+ Buf += EntrySize;
writeOne(Buf, V.Id, V.Name, V.NameOff);
}
// Need to terminate the last version definition.
- Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
- Verdef->vd_next = 0;
+ write32(Buf + 16, 0); // vd_next
}
-template <class ELFT> size_t VersionDefinitionSection<ELFT>::getSize() const {
- return (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+size_t VersionDefinitionSection::getSize() const {
+ return EntrySize * getVerDefNum();
}
+// .gnu.version is a table where each entry is 2 byte long.
template <class ELFT>
VersionTableSection<ELFT>::VersionTableSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
".gnu.version") {
- this->Entsize = sizeof(Elf_Versym);
+ this->Entsize = 2;
}
template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
// At the moment of june 2016 GNU docs does not mention that sh_link field
// should be set, but Sun docs do. Also readelf relies on this field.
- getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+ getParent()->Link = In.DynSymTab->getParent()->SectionIndex;
}
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
- return sizeof(Elf_Versym) * (InX::DynSymTab->getSymbols().size() + 1);
+ return (In.DynSymTab->getSymbols().size() + 1) * 2;
}
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
- auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
- for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
- OutVersym->vs_index = S.Sym->VersionId;
- ++OutVersym;
+ Buf += 2;
+ for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
+ write16(Buf, S.Sym->VersionId);
+ Buf += 2;
}
}
template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
- return !In<ELFT>::VerDef && In<ELFT>::VerNeed->empty();
+ return !In.VerDef && InX<ELFT>::VerNeed->empty();
}
template <class ELFT>
@@ -2729,7 +2793,7 @@ template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
if (File.VerdefMap.empty())
- Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)});
+ Needed.push_back({&File, In.DynStrTab->addString(File.SoName)});
const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
@@ -2737,8 +2801,8 @@ template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
if (NV.Index == 0) {
- NV.StrTab = InX::DynStrTab->addString(File.getStringTable().data() +
- Ver->getAux()->vda_name);
+ NV.StrTab = In.DynStrTab->addString(File.getStringTable().data() +
+ Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->VersionId = NV.Index;
@@ -2780,7 +2844,8 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
}
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
- getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
getParent()->Info = Needed.size();
}
@@ -2896,12 +2961,6 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
}
-// Debug sections may be compressed by zlib. Decompress if exists.
-void elf::decompressSections() {
- parallelForEach(InputSections,
- [](InputSectionBase *Sec) { Sec->maybeDecompress(); });
-}
-
template <class ELFT> void elf::splitSections() {
// splitIntoPieces needs to be called on each MergeInputSection
// before calling finalizeContents().
@@ -2929,8 +2988,10 @@ void elf::mergeSections() {
// We do not want to handle sections that are not alive, so just remove
// them instead of trying to merge.
- if (!MS->Live)
+ if (!MS->Live) {
+ S = nullptr;
continue;
+ }
StringRef OutsecName = getOutputSectionName(MS);
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
@@ -3038,34 +3099,54 @@ bool ThunkSection::assignOffsets() {
return Changed;
}
-InputSection *InX::ARMAttributes;
-BssSection *InX::Bss;
-BssSection *InX::BssRelRo;
-BuildIdSection *InX::BuildId;
-EhFrameHeader *InX::EhFrameHdr;
-EhFrameSection *InX::EhFrame;
-SyntheticSection *InX::Dynamic;
-StringTableSection *InX::DynStrTab;
-SymbolTableBaseSection *InX::DynSymTab;
-InputSection *InX::Interp;
-GdbIndexSection *InX::GdbIndex;
-GotSection *InX::Got;
-GotPltSection *InX::GotPlt;
-GnuHashTableSection *InX::GnuHashTab;
-HashTableSection *InX::HashTab;
-IgotPltSection *InX::IgotPlt;
-MipsGotSection *InX::MipsGot;
-MipsRldMapSection *InX::MipsRldMap;
-PltSection *InX::Plt;
-PltSection *InX::Iplt;
-RelocationBaseSection *InX::RelaDyn;
-RelrBaseSection *InX::RelrDyn;
-RelocationBaseSection *InX::RelaPlt;
-RelocationBaseSection *InX::RelaIplt;
-StringTableSection *InX::ShStrTab;
-StringTableSection *InX::StrTab;
-SymbolTableBaseSection *InX::SymTab;
-SymtabShndxSection *InX::SymTabShndx;
+// If linking position-dependent code then the table will store the addresses
+// directly in the binary so the section has type SHT_PROGBITS. If linking
+// position-independent code the section has type SHT_NOBITS since it will be
+// allocated and filled in by the dynamic linker.
+PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8,
+ ".branch_lt") {}
+
+void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) {
+ assert(Sym.PPC64BranchltIndex == 0xffff);
+ Sym.PPC64BranchltIndex = Entries.size();
+ Entries.push_back(&Sym);
+}
+
+size_t PPC64LongBranchTargetSection::getSize() const {
+ return Entries.size() * 8;
+}
+
+void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) {
+ assert(Target->GotPltEntrySize == 8);
+ // If linking non-pic we have the final addresses of the targets and they get
+ // written to the table directly. For pic the dynamic linker will allocate
+ // the section and fill it it.
+ if (Config->Pic)
+ return;
+
+ for (const Symbol *Sym : Entries) {
+ assert(Sym->getVA());
+ // Need calls to branch to the local entry-point since a long-branch
+ // must be a local-call.
+ write64(Buf,
+ Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther));
+ Buf += Target->GotPltEntrySize;
+ }
+}
+
+bool PPC64LongBranchTargetSection::empty() const {
+ // `removeUnusedSyntheticSections()` is called before thunk allocation which
+ // is too early to determine if this section will be empty or not. We need
+ // Finalized to keep the section alive until after thunk creation. Finalized
+ // only gets set to true once `finalizeSections()` is called after thunk
+ // creation. Becuase of this, if we don't create any long-branch thunks we end
+ // up with an empty .branch_lt section in the binary.
+ return Finalized && Entries.empty();
+}
+
+InStruct elf::In;
template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
@@ -3141,8 +3222,3 @@ template class elf::VersionNeedSection<ELF32LE>;
template class elf::VersionNeedSection<ELF32BE>;
template class elf::VersionNeedSection<ELF64LE>;
template class elf::VersionNeedSection<ELF64BE>;
-
-template class elf::VersionDefinitionSection<ELF32LE>;
-template class elf::VersionDefinitionSection<ELF32BE>;
-template class elf::VersionDefinitionSection<ELF64LE>;
-template class elf::VersionDefinitionSection<ELF64BE>;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index a780c6631374..6fc40d355d5e 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -21,8 +21,8 @@
#ifndef LLD_ELF_SYNTHETIC_SECTION_H
#define LLD_ELF_SYNTHETIC_SECTION_H
+#include "DWARF.h"
#include "EhFrame.h"
-#include "GdbIndex.h"
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
@@ -50,8 +50,6 @@ public:
// If the section has the SHF_ALLOC flag and the size may be changed if
// thunks are added, update the section size.
virtual bool updateAllocSize() { return false; }
- // If any additional finalization of contents are needed post thunk creation.
- virtual void postThunkContents() {}
virtual bool empty() const { return false; }
static bool classof(const SectionBase *D) {
@@ -137,6 +135,15 @@ protected:
uint64_t Size = 0;
};
+// .note.GNU-stack section.
+class GnuStackSection : public SyntheticSection {
+public:
+ GnuStackSection()
+ : SyntheticSection(0, llvm::ELF::SHT_PROGBITS, 1, ".note.GNU-stack") {}
+ void writeTo(uint8_t *Buf) override {}
+ size_t getSize() const override { return 0; }
+};
+
// .note.gnu.build-id section.
class BuildIdSection : public SyntheticSection {
// First 16 bytes are a header.
@@ -163,7 +170,9 @@ private:
class BssSection final : public SyntheticSection {
public:
BssSection(StringRef Name, uint64_t Size, uint32_t Alignment);
- void writeTo(uint8_t *) override {}
+ void writeTo(uint8_t *) override {
+ llvm_unreachable("unexpected writeTo() call for SHT_NOBITS section");
+ }
bool empty() const override { return getSize() == 0; }
size_t getSize() const override { return Size; }
@@ -300,8 +309,6 @@ private:
uint64_t Size = 0;
- size_t LocalEntriesNum = 0;
-
// Symbol and addend.
typedef std::pair<Symbol *, int64_t> GotEntry;
@@ -333,8 +340,6 @@ private:
size_t getPageEntriesNum() const;
// Number of entries require 16-bit index to access.
size_t getIndexedEntriesNum() const;
-
- bool isOverflow() const;
};
// Container of GOT created for each input file.
@@ -529,6 +534,7 @@ struct RelativeReloc {
class RelrBaseSection : public SyntheticSection {
public:
RelrBaseSection();
+ bool empty() const override { return Relocs.empty(); }
std::vector<RelativeReloc> Relocs;
};
@@ -561,7 +567,6 @@ class SymbolTableBaseSection : public SyntheticSection {
public:
SymbolTableBaseSection(StringTableSection &StrTabSec);
void finalizeContents() override;
- void postThunkContents() override;
size_t getSize() const override { return getNumSymbols() * Entsize; }
void addSymbol(Symbol *Sym);
unsigned getNumSymbols() const { return Symbols.size() + 1; }
@@ -569,6 +574,8 @@ public:
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
protected:
+ void sortSymTabSymbols();
+
// A vector of symbols and their string table offsets.
std::vector<SymbolTableEntry> Symbols;
@@ -612,7 +619,8 @@ public:
void addSymbols(std::vector<SymbolTableEntry> &Symbols);
private:
- enum { Shift2 = 6 };
+ // See the comment in writeBloomFilter.
+ enum { Shift2 = 26 };
void writeBloomFilter(uint8_t *Buf);
void writeHashTable(uint8_t *Buf);
@@ -652,13 +660,13 @@ public:
size_t getSize() const override;
bool empty() const override { return Entries.empty(); }
void addSymbols();
-
template <class ELFT> void addEntry(Symbol &Sym);
+ size_t HeaderSize;
+
private:
unsigned getPltRelocOff() const;
std::vector<std::pair<const Symbol *, unsigned>> Entries;
- size_t HeaderSize;
bool IsIplt;
};
@@ -676,9 +684,9 @@ public:
uint64_t CuLength;
};
- struct NameTypeEntry {
+ struct NameAttrEntry {
llvm::CachedHashStringRef Name;
- uint32_t Type;
+ uint32_t CuIndexAndAttrs;
};
struct GdbChunk {
@@ -748,11 +756,7 @@ public:
// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
// The section shall contain an array of Elf_Verdef structures, optionally
// followed by an array of Elf_Verdaux structures.
-template <class ELFT>
class VersionDefinitionSection final : public SyntheticSection {
- typedef typename ELFT::Verdef Elf_Verdef;
- typedef typename ELFT::Verdaux Elf_Verdaux;
-
public:
VersionDefinitionSection();
void finalizeContents() override;
@@ -760,6 +764,7 @@ public:
void writeTo(uint8_t *Buf) override;
private:
+ enum { EntrySize = 28 };
void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
unsigned FileDefNameOff;
@@ -773,8 +778,6 @@ private:
// the own object or in any of the dependencies.
template <class ELFT>
class VersionTableSection final : public SyntheticSection {
- typedef typename ELFT::Versym Elf_Versym;
-
public:
VersionTableSection();
void finalizeContents() override;
@@ -964,9 +967,27 @@ private:
size_t Size = 0;
};
+// This section is used to store the addresses of functions that are called
+// in range-extending thunks on PowerPC64. When producing position dependant
+// code the addresses are link-time constants and the table is written out to
+// the binary. When producing position-dependant code the table is allocated and
+// filled in by the dynamic linker.
+class PPC64LongBranchTargetSection final : public SyntheticSection {
+public:
+ PPC64LongBranchTargetSection();
+ void addEntry(Symbol &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override;
+ void finalizeContents() override { Finalized = true; }
+
+private:
+ std::vector<const Symbol *> Entries;
+ bool Finalized = false;
+};
+
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
-void decompressSections();
template <class ELFT> void splitSections();
void mergeSections();
@@ -974,46 +995,48 @@ Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
uint64_t Size, InputSectionBase &Section);
// Linker generated sections which can be used as inputs.
-struct InX {
- static InputSection *ARMAttributes;
- static BssSection *Bss;
- static BssSection *BssRelRo;
- static BuildIdSection *BuildId;
- static EhFrameHeader *EhFrameHdr;
- static EhFrameSection *EhFrame;
- static SyntheticSection *Dynamic;
- static StringTableSection *DynStrTab;
- static SymbolTableBaseSection *DynSymTab;
- static GnuHashTableSection *GnuHashTab;
- static HashTableSection *HashTab;
- static InputSection *Interp;
- static GdbIndexSection *GdbIndex;
- static GotSection *Got;
- static GotPltSection *GotPlt;
- static IgotPltSection *IgotPlt;
- static MipsGotSection *MipsGot;
- static MipsRldMapSection *MipsRldMap;
- static PltSection *Plt;
- static PltSection *Iplt;
- static RelocationBaseSection *RelaDyn;
- static RelrBaseSection *RelrDyn;
- static RelocationBaseSection *RelaPlt;
- static RelocationBaseSection *RelaIplt;
- static StringTableSection *ShStrTab;
- static StringTableSection *StrTab;
- static SymbolTableBaseSection *SymTab;
- static SymtabShndxSection* SymTabShndx;
-};
-
-template <class ELFT> struct In {
- static VersionDefinitionSection<ELFT> *VerDef;
+struct InStruct {
+ InputSection *ARMAttributes;
+ BssSection *Bss;
+ BssSection *BssRelRo;
+ BuildIdSection *BuildId;
+ EhFrameHeader *EhFrameHdr;
+ EhFrameSection *EhFrame;
+ SyntheticSection *Dynamic;
+ StringTableSection *DynStrTab;
+ SymbolTableBaseSection *DynSymTab;
+ GnuHashTableSection *GnuHashTab;
+ HashTableSection *HashTab;
+ InputSection *Interp;
+ GdbIndexSection *GdbIndex;
+ GotSection *Got;
+ GotPltSection *GotPlt;
+ IgotPltSection *IgotPlt;
+ PPC64LongBranchTargetSection *PPC64LongBranchTarget;
+ MipsGotSection *MipsGot;
+ MipsRldMapSection *MipsRldMap;
+ PltSection *Plt;
+ PltSection *Iplt;
+ RelocationBaseSection *RelaDyn;
+ RelrBaseSection *RelrDyn;
+ RelocationBaseSection *RelaPlt;
+ RelocationBaseSection *RelaIplt;
+ StringTableSection *ShStrTab;
+ StringTableSection *StrTab;
+ SymbolTableBaseSection *SymTab;
+ SymtabShndxSection *SymTabShndx;
+ VersionDefinitionSection *VerDef;
+};
+
+extern InStruct In;
+
+template <class ELFT> struct InX {
static VersionTableSection<ELFT> *VerSym;
static VersionNeedSection<ELFT> *VerNeed;
};
-template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
-template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym;
-template <class ELFT> VersionNeedSection<ELFT> *In<ELFT>::VerNeed;
+template <class ELFT> VersionTableSection<ELFT> *InX<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *InX<ELFT>::VerNeed;
} // namespace elf
} // namespace lld
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 815f3a045551..01073a62cfd6 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -73,12 +73,16 @@ TargetInfo *elf::getTarget() {
case ELF64BEKind:
return getMipsTargetInfo<ELF64BE>();
default:
- fatal("unsupported MIPS target");
+ llvm_unreachable("unsupported MIPS target");
}
+ case EM_MSP430:
+ return getMSP430TargetInfo();
case EM_PPC:
return getPPCTargetInfo();
case EM_PPC64:
return getPPC64TargetInfo();
+ case EM_RISCV:
+ return getRISCVTargetInfo();
case EM_SPARCV9:
return getSPARCV9TargetInfo();
case EM_X86_64:
@@ -86,7 +90,7 @@ TargetInfo *elf::getTarget() {
return getX32TargetInfo();
return getX86_64TargetInfo();
}
- fatal("unknown target machine");
+ llvm_unreachable("unknown target machine");
}
template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) {
@@ -130,12 +134,11 @@ bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return false;
}
-bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const {
+bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const {
llvm_unreachable("Target doesn't support split stacks.");
}
-
bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
return true;
}
diff --git a/ELF/Target.h b/ELF/Target.h
index 82c7b8f7b6c5..685ad05ecd66 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -13,6 +13,8 @@
#include "InputSection.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Support/MathExtras.h"
+#include <array>
namespace lld {
std::string toString(elf::RelType Type);
@@ -43,10 +45,6 @@ public:
virtual void addPltHeaderSymbols(InputSection &IS) const {}
virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {}
- unsigned getPltEntryOffset(unsigned Index) const {
- return Index * PltEntrySize + PltHeaderSize;
- }
-
// Returns true if a relocation only uses the low bits of a value such that
// all those bits are in the same page. For example, if the relocation
// only uses the low 12 bits in a system with 4k pages. If this is true, the
@@ -60,11 +58,18 @@ public:
const InputFile *File, uint64_t BranchAddr,
const Symbol &S) const;
+ // On systems with range extensions we place collections of Thunks at
+ // regular spacings that enable the majority of branches reach the Thunks.
+ // a value of 0 means range extension thunks are not supported.
+ virtual uint32_t getThunkSectionSpacing() const { return 0; }
+
// The function with a prologue starting at Loc was compiled with
// -fsplit-stack and it calls a function compiled without. Adjust the prologue
// to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks.
- virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const;
+ // The symbols st_other flags are needed on PowerPC64 for determining the
+ // offset to the split-stack prologue.
+ virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const;
// Return true if we can reach Dst from Src with Relocation RelocType
virtual bool inBranchRange(RelType Type, uint64_t Src,
@@ -87,12 +92,9 @@ public:
// True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got.
bool GotBaseSymInGotPlt = true;
- // On systems with range extensions we place collections of Thunks at
- // regular spacings that enable the majority of branches reach the Thunks.
- uint32_t ThunkSectionSpacing = 0;
-
RelType CopyRel;
RelType GotRel;
+ RelType NoneRel;
RelType PltRel;
RelType RelativeRel;
RelType IRelativeRel;
@@ -112,20 +114,16 @@ public:
// On PPC ELF V2 abi, the first entry in the .got is the .TOC.
unsigned GotHeaderEntriesNum = 0;
- // For TLS variant 1, the TCB is a fixed size specified by the Target.
- // For variant 2, the TCB is an unspecified size.
- // Set to 0 for variant 2.
- unsigned TcbSize = 0;
-
- // Set to the offset (in bytes) that the thread pointer is initialized to
- // point to, relative to the start of the thread local storage.
- unsigned TlsTpOffset = 0;
-
bool NeedsThunks = false;
// A 4-byte field corresponding to one or more trap instructions, used to pad
// executable OutputSections.
- uint32_t TrapInstr = 0;
+ std::array<uint8_t, 4> TrapInstr;
+
+ // If a target needs to rewrite calls to __morestack to instead call
+ // __morestack_non_split when a split-stack enabled caller calls a
+ // non-split-stack callee this will return true. Otherwise returns false.
+ bool NeedsMoreStackNonSplit = true;
virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const;
@@ -148,8 +146,10 @@ TargetInfo *getAMDGPUTargetInfo();
TargetInfo *getARMTargetInfo();
TargetInfo *getAVRTargetInfo();
TargetInfo *getHexagonTargetInfo();
+TargetInfo *getMSP430TargetInfo();
TargetInfo *getPPC64TargetInfo();
TargetInfo *getPPCTargetInfo();
+TargetInfo *getRISCVTargetInfo();
TargetInfo *getSPARCV9TargetInfo();
TargetInfo *getX32TargetInfo();
TargetInfo *getX86TargetInfo();
@@ -168,6 +168,15 @@ static inline std::string getErrorLocation(const uint8_t *Loc) {
return getErrorPlace(Loc).Loc;
}
+// In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first is
+// a global entry point (GEP) which typically is used to intiailzie the TOC
+// pointer in general purpose register 2. The second is a local entry
+// point (LEP) which bypasses the TOC pointer initialization code. The
+// offset between GEP and LEP is encoded in a function's st_other flags.
+// This function will return the offset (in bytes) from the global entry-point
+// to the local entry-point.
+unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther);
+
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
@@ -184,19 +193,18 @@ static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V,
Hint = "; consider recompiling with -fdebug-types-section to reduce size "
"of debug sections";
- error(ErrPlace.Loc + "relocation " + lld::toString(Type) +
- " out of range: " + V.str() + " is not in [" + Twine(Min).str() + ", " +
- Twine(Max).str() + "]" + Hint);
+ errorOrWarn(ErrPlace.Loc + "relocation " + lld::toString(Type) +
+ " out of range: " + V.str() + " is not in [" + Twine(Min).str() +
+ ", " + Twine(Max).str() + "]" + Hint);
}
-// Sign-extend Nth bit all the way to MSB.
-inline int64_t signExtend(uint64_t V, int N) {
- return int64_t(V << (64 - N)) >> (64 - N);
+inline unsigned getPltEntryOffset(unsigned Idx) {
+ return Target->PltHeaderSize + Target->PltEntrySize * Idx;
}
// Make sure that V can be represented as an N bit signed integer.
inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) {
- if (V != signExtend(V, N))
+ if (V != llvm::SignExtend64(V, N))
reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N));
}
@@ -210,7 +218,7 @@ inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
// For the error message we should cast V to a signed integer so that error
// messages show a small negative value rather than an extremely large one
- if (V != (uint64_t)signExtend(V, N) && (V >> N) != 0)
+ if (V != (uint64_t)llvm::SignExtend64(V, N) && (V >> N) != 0)
reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N),
llvm::maxIntN(N));
}
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index 2cd7e51ae357..95b57dc0db42 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -159,6 +159,50 @@ public:
void addSymbols(ThunkSection &IS) override;
};
+// Implementations of Thunks for older Arm architectures that do not support
+// the movt/movw instructions. These thunks require at least Architecture v5
+// as used on processors such as the Arm926ej-s. There are no Thumb entry
+// points as there is no Thumb branch instruction on these architecture that
+// can result in a thunk
+class ARMV5ABSLongThunk final : public ARMThunk {
+public:
+ ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 8; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+class ARMV5PILongThunk final : public ARMThunk {
+public:
+ ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
+class ThumbV6MABSLongThunk final : public ThumbThunk {
+public:
+ ThumbV6MABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class ThumbV6MPILongThunk final : public ThumbThunk {
+public:
+ ThumbV6MPILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
// MIPS LA25 thunk
class MipsThunk final : public Thunk {
public:
@@ -209,6 +253,46 @@ public:
void addSymbols(ThunkSection &IS) override;
};
+// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
+// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
+// larger then that we need to emit a long-branch thunk. The target address
+// of the callee is stored in a table to be accessed TOC-relative. Since the
+// call must be local (a non-local call will have a PltCallStub instead) the
+// table stores the address of the callee's local entry point. For
+// position-independent code a corresponding relative dynamic relocation is
+// used.
+class PPC64LongBranchThunk : public Thunk {
+public:
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+
+protected:
+ PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {}
+};
+
+class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
+public:
+ PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+ assert(!Dest.IsPreemptible);
+ if (Dest.isInPPC64Branchlt())
+ return;
+
+ In.PPC64LongBranchTarget->addEntry(Dest);
+ In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget,
+ Dest.getPPC64LongBranchOffset(), true, &Dest,
+ getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)});
+ }
+};
+
+class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
+public:
+ PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+ if (!Dest.isInPPC64Branchlt())
+ In.PPC64LongBranchTarget->addEntry(Dest);
+ }
+};
+
} // end anonymous namespace
Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
@@ -395,12 +479,12 @@ void ARMV7PILongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
- 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
- 0x1c, 0xff, 0x2f, 0xe1, // bx r12
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
};
uint64_t S = getARMThunkDestVA(Destination);
uint64_t P = getThunkTargetSym()->getVA();
- uint64_t Offset = S - P - 16;
+ int64_t Offset = S - P - 16;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset);
@@ -416,12 +500,12 @@ void ThumbV7PILongThunk::writeLong(uint8_t *Buf) {
const uint8_t Data[] = {
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
- 0xfc, 0x44, // L1: add r12, pc
- 0x60, 0x47, // bx r12
+ 0xfc, 0x44, // L1: add ip, pc
+ 0x60, 0x47, // bx ip
};
uint64_t S = getARMThunkDestVA(Destination);
uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
- uint64_t Offset = S - P - 12;
+ int64_t Offset = S - P - 12;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset);
@@ -433,6 +517,102 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
addSymbol("$t", STT_NOTYPE, 0, IS);
}
+void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
+ 0x00, 0x00, 0x00, 0x00, // L1: .word S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination));
+}
+
+void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 4, IS);
+}
+
+bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ARMV5PILongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
+ 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
+}
+
+void ARMV5PILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 12, IS);
+}
+
+bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is r12 we must instead spill a low register
+ // to the stack to use as a scratch register. We push r1 even though we
+ // don't need to get some space to use for the return address.
+ const uint8_t Data[] = {
+ 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
+ 0x01, 0x48, // ldr r0, [pc, #4] ; L1
+ 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
+ 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
+ 0x00, 0x00, 0x00, 0x00 // L1: .word S
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 8, R_ARM_ABS32, S);
+}
+
+void ThumbV6MABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 8, IS);
+}
+
+void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is ip (r12) we must instead spill a low
+ // register to the stack to use as a scratch register.
+ const uint8_t Data[] = {
+ 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
+ 0x02, 0x48, // ldr r0, [pc, #8] ; L2
+ 0x84, 0x46, // mov ip, r0 ; high to low register
+ 0x01, 0xbc, // pop {r0} ; restore scratch register
+ 0xe7, 0x44, // L1: add pc, ip ; transfer control
+ 0xc0, 0x46, // nop ; pad to 4-byte boundary
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
+}
+
+void ThumbV6MPILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv6MPILongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 12, IS);
+}
+
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
void MipsThunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA();
@@ -502,17 +682,21 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
return dyn_cast<InputSection>(DR.Section);
}
-void PPC64PltCallStub::writeTo(uint8_t *Buf) {
- int64_t Off = Destination.getGotPltVA() - getPPC64TocBase();
- // Need to add 0x8000 to offset to account for the low bits being signed.
- uint16_t OffHa = (Off + 0x8000) >> 16;
- uint16_t OffLo = Off;
+static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) {
+ uint16_t OffHa = (Offset + 0x8000) >> 16;
+ uint16_t OffLo = Offset & 0xffff;
- write32(Buf + 0, 0xf8410018); // std r2,24(r1)
- write32(Buf + 4, 0x3d820000 | OffHa); // addis r12,r2, X@plt@to@ha
- write32(Buf + 8, 0xe98c0000 | OffLo); // ld r12,X@plt@toc@l(r12)
- write32(Buf + 12, 0x7d8903a6); // mtctr r12
- write32(Buf + 16, 0x4e800420); // bctr
+ write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa
+ write32(Buf + 4, 0xe98c0000 | OffLo); // ld r12, OffLo(r12)
+ write32(Buf + 8, 0x7d8903a6); // mtctr r12
+ write32(Buf + 12, 0x4e800420); // bctr
+}
+
+void PPC64PltCallStub::writeTo(uint8_t *Buf) {
+ int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase();
+ // Save the TOC pointer to the save-slot reserved in the call frame.
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ writePPCLoadAndBranch(Buf + 4, Offset);
}
void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
@@ -521,6 +705,16 @@ void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
S->NeedsTocRestore = true;
}
+void PPC64LongBranchThunk::writeTo(uint8_t *Buf) {
+ int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase();
+ writePPCLoadAndBranch(Buf, Offset);
+}
+
+void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0,
+ IS);
+}
+
Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
@@ -534,10 +728,67 @@ static Thunk *addThunkAArch64(RelType Type, Symbol &S) {
}
// Creates a thunk for Thumb-ARM interworking.
+// Arm Architectures v5 and v6 do not support Thumb2 technology. This means
+// - MOVT and MOVW instructions cannot be used
+// - Only Thumb relocation that can generate a Thunk is a BL, this can always
+// be transformed into a BLX
+static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) {
+ switch (Reloc) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ case R_ARM_THM_CALL:
+ if (Config->Pic)
+ return make<ARMV5PILongThunk>(S);
+ return make<ARMV5ABSLongThunk>(S);
+ }
+ fatal("relocation " + toString(Reloc) + " to " + toString(S) +
+ " not supported for Armv5 or Armv6 targets");
+}
+
+// Create a thunk for Thumb long branch on V6-M.
+// Arm Architecture v6-M only supports Thumb instructions. This means
+// - MOVT and MOVW instructions cannot be used.
+// - Only a limited number of instructions can access registers r8 and above
+// - No interworking support is needed (all Thumb).
+static Thunk *addThunkV6M(RelType Reloc, Symbol &S) {
+ switch (Reloc) {
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ if (Config->Pic)
+ return make<ThumbV6MPILongThunk>(S);
+ return make<ThumbV6MABSLongThunk>(S);
+ }
+ fatal("relocation " + toString(Reloc) + " to " + toString(S) +
+ " not supported for Armv6-M targets");
+}
+
+// Creates a thunk for Thumb-ARM interworking or branch range extension.
static Thunk *addThunkArm(RelType Reloc, Symbol &S) {
- // ARM relocations need ARM to Thumb interworking Thunks.
- // Thumb relocations need Thumb to ARM relocations.
- // Use position independent Thunks if we require position independent code.
+ // Decide which Thunk is needed based on:
+ // Available instruction set
+ // - An Arm Thunk can only be used if Arm state is available.
+ // - A Thumb Thunk can only be used if Thumb state is available.
+ // - Can only use a Thunk if it uses instructions that the Target supports.
+ // Relocation is branch or branch and link
+ // - Branch instructions cannot change state, can only select Thunk that
+ // starts in the same state as the caller.
+ // - Branch and link relocations can change state, can select Thunks from
+ // either Arm or Thumb.
+ // Position independent Thunks if we require position independent code.
+
+ // Handle architectures that have restrictions on the instructions that they
+ // can use in Thunks. The flags below are set by reading the BuildAttributes
+ // of the input objects. InputFiles.cpp contains the mapping from ARM
+ // architecture to flag.
+ if (!Config->ARMHasMovtMovw) {
+ if (!Config->ARMJ1J2BranchEncoding)
+ return addThunkPreArmv7(Reloc, S);
+ return addThunkV6M(Reloc, S);
+ }
+
switch (Reloc) {
case R_ARM_PC24:
case R_ARM_PLT32:
@@ -565,9 +816,14 @@ static Thunk *addThunkMips(RelType Type, Symbol &S) {
}
static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
- if (Type == R_PPC64_REL24)
+ assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk");
+ if (S.isInPlt())
return make<PPC64PltCallStub>(S);
- fatal("unexpected relocation type");
+
+ if (Config->Pic)
+ return make<PPC64PILongBranchThunk>(S);
+
+ return make<PPC64PDLongBranchThunk>(S);
}
Thunk *addThunk(RelType Type, Symbol &S) {
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 73a97380b54b..17f4c7961d30 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -53,8 +53,10 @@ private:
void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
void sortSections();
void resolveShfLinkOrder();
+ void maybeAddThunks();
void sortInputSections();
void finalizeSections();
+ void checkExecuteOnly();
void setReservedSymbolSections();
std::vector<PhdrEntry *> createPhdrs();
@@ -77,7 +79,6 @@ private:
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSection *Sec);
- uint64_t getEntryAddr();
std::vector<PhdrEntry *> Phdrs;
@@ -114,18 +115,16 @@ StringRef elf::getOutputSectionName(const InputSectionBase *S) {
// for instance.
if (Config->ZKeepTextSectionPrefix)
for (StringRef V :
- {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) {
+ {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."})
if (isSectionPrefix(V, S->Name))
return V.drop_back();
- }
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
- ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
+ ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."})
if (isSectionPrefix(V, S->Name))
return V.drop_back();
- }
// CommonSection is identified as "COMMON" in linker scripts.
// By default, it should go to .bss section.
@@ -159,7 +158,7 @@ template <class ELFT> static void combineEhFrameSections() {
if (!ES || !ES->Live)
continue;
- InX::EhFrame->addSection<ELFT>(ES);
+ In.EhFrame->addSection<ELFT>(ES);
S = nullptr;
}
@@ -173,10 +172,14 @@ static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec,
Symbol *S = Symtab->find(Name);
if (!S || S->isDefined())
return nullptr;
- Symbol *Sym = Symtab->addRegular(Name, StOther, STT_NOTYPE, Val,
- /*Size=*/0, Binding, Sec,
- /*File=*/nullptr);
- return cast<Defined>(Sym);
+ return Symtab->addDefined(Name, StOther, STT_NOTYPE, Val,
+ /*Size=*/0, Binding, Sec,
+ /*File=*/nullptr);
+}
+
+static Defined *addAbsolute(StringRef Name) {
+ return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL,
+ nullptr, nullptr);
}
// The linker is expected to define some symbols depending on
@@ -188,21 +191,19 @@ void elf::addReservedSymbols() {
// to GOT. Default offset is 0x7ff0.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- ElfSym::MipsGp = Symtab->addAbsolute("_gp", STV_HIDDEN, STB_GLOBAL);
+ ElfSym::MipsGp = addAbsolute("_gp");
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
// start of function and 'gp' pointer into GOT.
if (Symtab->find("_gp_disp"))
- ElfSym::MipsGpDisp =
- Symtab->addAbsolute("_gp_disp", STV_HIDDEN, STB_GLOBAL);
+ ElfSym::MipsGpDisp = addAbsolute("_gp_disp");
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// pointer. This symbol is used in the code generated by .cpload pseudo-op
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
if (Symtab->find("__gnu_local_gp"))
- ElfSym::MipsLocalGp =
- Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL);
+ ElfSym::MipsLocalGp = addAbsolute("__gnu_local_gp");
}
// The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
@@ -211,9 +212,20 @@ void elf::addReservedSymbols() {
// _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
// represent the TOC base which is offset by 0x8000 bytes from the start of
// the .got section.
- ElfSym::GlobalOffsetTable = addOptionalRegular(
- (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_",
- Out::ElfHeader, Target->GotBaseSymOff);
+ // We do not allow _GLOBAL_OFFSET_TABLE_ to be defined by input objects as the
+ // correctness of some relocations depends on its value.
+ StringRef GotTableSymName =
+ (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_";
+ if (Symbol *S = Symtab->find(GotTableSymName)) {
+ if (S->isDefined())
+ error(toString(S->File) + " cannot redefine linker defined symbol '" +
+ GotTableSymName + "'");
+ else
+ ElfSym::GlobalOffsetTable = Symtab->addDefined(
+ GotTableSymName, STV_HIDDEN, STT_NOTYPE, Target->GotBaseSymOff,
+ /*Size=*/0, STB_GLOBAL, Out::ElfHeader,
+ /*File=*/nullptr);
+ }
// __ehdr_start is the location of ELF file headers. Note that we define
// this symbol unconditionally even when using a linker script, which
@@ -263,54 +275,52 @@ template <class ELFT> static void createSyntheticSections() {
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
- InX::DynStrTab = make<StringTableSection>(".dynstr", true);
- InX::Dynamic = make<DynamicSection<ELFT>>();
+ In.DynStrTab = make<StringTableSection>(".dynstr", true);
+ In.Dynamic = make<DynamicSection<ELFT>>();
if (Config->AndroidPackDynRelocs) {
- InX::RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
+ In.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn");
} else {
- InX::RelaDyn = make<RelocationSection<ELFT>>(
+ In.RelaDyn = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
}
- InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
+ In.ShStrTab = make<StringTableSection>(".shstrtab", false);
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
Out::ProgramHeaders->Alignment = Config->Wordsize;
if (needsInterpSection()) {
- InX::Interp = createInterpSection();
- Add(InX::Interp);
- } else {
- InX::Interp = nullptr;
+ In.Interp = createInterpSection();
+ Add(In.Interp);
}
if (Config->Strip != StripPolicy::All) {
- InX::StrTab = make<StringTableSection>(".strtab", false);
- InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
- InX::SymTabShndx = make<SymtabShndxSection>();
+ In.StrTab = make<StringTableSection>(".strtab", false);
+ In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab);
+ In.SymTabShndx = make<SymtabShndxSection>();
}
if (Config->BuildId != BuildIdKind::None) {
- InX::BuildId = make<BuildIdSection>();
- Add(InX::BuildId);
+ In.BuildId = make<BuildIdSection>();
+ Add(In.BuildId);
}
- InX::Bss = make<BssSection>(".bss", 0, 1);
- Add(InX::Bss);
+ In.Bss = make<BssSection>(".bss", 0, 1);
+ Add(In.Bss);
// If there is a SECTIONS command and a .data.rel.ro section name use name
// .data.rel.ro.bss so that we match in the .data.rel.ro output section.
// This makes sure our relro is contiguous.
bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro");
- InX::BssRelRo =
+ In.BssRelRo =
make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
- Add(InX::BssRelRo);
+ Add(In.BssRelRo);
// Add MIPS-specific sections.
if (Config->EMachine == EM_MIPS) {
if (!Config->Shared && Config->HasDynSymTab) {
- InX::MipsRldMap = make<MipsRldMapSection>();
- Add(InX::MipsRldMap);
+ In.MipsRldMap = make<MipsRldMapSection>();
+ Add(In.MipsRldMap);
}
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
Add(Sec);
@@ -321,65 +331,70 @@ template <class ELFT> static void createSyntheticSections() {
}
if (Config->HasDynSymTab) {
- InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
- Add(InX::DynSymTab);
+ In.DynSymTab = make<SymbolTableSection<ELFT>>(*In.DynStrTab);
+ Add(In.DynSymTab);
- In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
- Add(In<ELFT>::VerSym);
+ InX<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
+ Add(InX<ELFT>::VerSym);
if (!Config->VersionDefinitions.empty()) {
- In<ELFT>::VerDef = make<VersionDefinitionSection<ELFT>>();
- Add(In<ELFT>::VerDef);
+ In.VerDef = make<VersionDefinitionSection>();
+ Add(In.VerDef);
}
- In<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
- Add(In<ELFT>::VerNeed);
+ InX<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
+ Add(InX<ELFT>::VerNeed);
if (Config->GnuHash) {
- InX::GnuHashTab = make<GnuHashTableSection>();
- Add(InX::GnuHashTab);
+ In.GnuHashTab = make<GnuHashTableSection>();
+ Add(In.GnuHashTab);
}
if (Config->SysvHash) {
- InX::HashTab = make<HashTableSection>();
- Add(InX::HashTab);
+ In.HashTab = make<HashTableSection>();
+ Add(In.HashTab);
}
- Add(InX::Dynamic);
- Add(InX::DynStrTab);
- Add(InX::RelaDyn);
+ Add(In.Dynamic);
+ Add(In.DynStrTab);
+ Add(In.RelaDyn);
}
if (Config->RelrPackDynRelocs) {
- InX::RelrDyn = make<RelrSection<ELFT>>();
- Add(InX::RelrDyn);
+ In.RelrDyn = make<RelrSection<ELFT>>();
+ Add(In.RelrDyn);
}
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
- InX::MipsGot = make<MipsGotSection>();
- Add(InX::MipsGot);
+ In.MipsGot = make<MipsGotSection>();
+ Add(In.MipsGot);
} else {
- InX::Got = make<GotSection>();
- Add(InX::Got);
+ In.Got = make<GotSection>();
+ Add(In.Got);
}
- InX::GotPlt = make<GotPltSection>();
- Add(InX::GotPlt);
- InX::IgotPlt = make<IgotPltSection>();
- Add(InX::IgotPlt);
+ if (Config->EMachine == EM_PPC64) {
+ In.PPC64LongBranchTarget = make<PPC64LongBranchTargetSection>();
+ Add(In.PPC64LongBranchTarget);
+ }
+
+ In.GotPlt = make<GotPltSection>();
+ Add(In.GotPlt);
+ In.IgotPlt = make<IgotPltSection>();
+ Add(In.IgotPlt);
if (Config->GdbIndex) {
- InX::GdbIndex = GdbIndexSection::create<ELFT>();
- Add(InX::GdbIndex);
+ In.GdbIndex = GdbIndexSection::create<ELFT>();
+ Add(In.GdbIndex);
}
// We always need to add rel[a].plt to output if it has entries.
// Even for static linking it can contain R_[*]_IRELATIVE relocations.
- InX::RelaPlt = make<RelocationSection<ELFT>>(
+ In.RelaPlt = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
- Add(InX::RelaPlt);
+ Add(In.RelaPlt);
// The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
// that the IRelative relocations are processed last by the dynamic loader.
@@ -387,34 +402,42 @@ template <class ELFT> static void createSyntheticSections() {
// packing is enabled because that would cause a section type mismatch.
// However, because the Android dynamic loader reads .rel.plt after .rel.dyn,
// we can get the desired behaviour by placing the iplt section in .rel.plt.
- InX::RelaIplt = make<RelocationSection<ELFT>>(
+ In.RelaIplt = make<RelocationSection<ELFT>>(
(Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs)
? ".rel.dyn"
- : InX::RelaPlt->Name,
+ : In.RelaPlt->Name,
false /*Sort*/);
- Add(InX::RelaIplt);
-
- InX::Plt = make<PltSection>(false);
- Add(InX::Plt);
- InX::Iplt = make<PltSection>(true);
- Add(InX::Iplt);
+ Add(In.RelaIplt);
+
+ In.Plt = make<PltSection>(false);
+ Add(In.Plt);
+ In.Iplt = make<PltSection>(true);
+ Add(In.Iplt);
+
+ // .note.GNU-stack is always added when we are creating a re-linkable
+ // object file. Other linkers are using the presence of this marker
+ // section to control the executable-ness of the stack area, but that
+ // is irrelevant these days. Stack area should always be non-executable
+ // by default. So we emit this section unconditionally.
+ if (Config->Relocatable)
+ Add(make<GnuStackSection>());
if (!Config->Relocatable) {
if (Config->EhFrameHdr) {
- InX::EhFrameHdr = make<EhFrameHeader>();
- Add(InX::EhFrameHdr);
+ In.EhFrameHdr = make<EhFrameHeader>();
+ Add(In.EhFrameHdr);
}
- InX::EhFrame = make<EhFrameSection>();
- Add(InX::EhFrame);
+ In.EhFrame = make<EhFrameSection>();
+ Add(In.EhFrame);
}
- if (InX::SymTab)
- Add(InX::SymTab);
- if (InX::SymTabShndx)
- Add(InX::SymTabShndx);
- Add(InX::ShStrTab);
- if (InX::StrTab)
- Add(InX::StrTab);
+ if (In.SymTab)
+ Add(In.SymTab);
+ if (In.SymTabShndx)
+ Add(In.SymTabShndx);
+ Add(In.ShStrTab);
+ if (In.StrTab)
+ Add(In.StrTab);
if (Config->EMachine == EM_ARM && !Config->Relocatable)
// Add a sentinel to terminate .ARM.exidx. It helps an unwinder
@@ -451,6 +474,7 @@ template <class ELFT> void Writer<ELFT>::run() {
// to the string table, and add entries to .got and .plt.
// finalizeSections does that.
finalizeSections();
+ checkExecuteOnly();
if (errorCount())
return;
@@ -476,10 +500,9 @@ template <class ELFT> void Writer<ELFT>::run() {
setPhdrs();
- if (Config->Relocatable) {
+ if (Config->Relocatable)
for (OutputSection *Sec : OutputSections)
Sec->Addr = 0;
- }
if (Config->CheckSections)
checkSections();
@@ -548,9 +571,11 @@ static bool includeInSymtab(const Symbol &B) {
if (!Sec)
return true;
Sec = Sec->Repl;
+
// Exclude symbols pointing to garbage-collected sections.
if (isa<InputSectionBase>(Sec) && !Sec->Live)
return false;
+
if (auto *S = dyn_cast<MergeInputSection>(Sec))
if (!S->getSectionPiece(D->Value)->Live)
return false;
@@ -562,7 +587,7 @@ static bool includeInSymtab(const Symbol &B) {
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
- if (!InX::SymTab)
+ if (!In.SymTab)
return;
for (InputFile *File : ObjectFiles) {
ObjFile<ELFT> *F = cast<ObjFile<ELFT>>(File);
@@ -581,16 +606,16 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
SectionBase *Sec = DR->Section;
if (!shouldKeepInSymtab(Sec, B->getName(), *B))
continue;
- InX::SymTab->addSymbol(B);
+ In.SymTab->addSymbol(B);
}
}
}
+// Create a section symbol for each output section so that we can represent
+// relocations that point to the section. If we know that no relocation is
+// referring to a section (that happens if the section is a synthetic one), we
+// don't create a section symbol for that section.
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
- // Create a section symbol for each output section so that we can represent
- // relocations that point to the section. If we know that no relocation is
- // referring to a section (that happens if the section is a synthetic one), we
- // don't create a section symbol for that section.
for (BaseCommand *Base : Script->SectionCommands) {
auto *Sec = dyn_cast<OutputSection>(Base);
if (!Sec)
@@ -617,7 +642,7 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
auto *Sym =
make<Defined>(IS->File, "", STB_LOCAL, /*StOther=*/0, STT_SECTION,
/*Value=*/0, /*Size=*/0, IS);
- InX::SymTab->addSymbol(Sym);
+ In.SymTab->addSymbol(Sym);
}
}
@@ -662,9 +687,14 @@ static bool isRelroSection(const OutputSection *Sec) {
// .got contains pointers to external symbols. They are resolved by
// the dynamic linker when a module is loaded into memory, and after
// that they are not expected to change. So, it can be in RELRO.
- if (InX::Got && Sec == InX::Got->getParent())
+ if (In.Got && Sec == In.Got->getParent())
return true;
+ // .toc is a GOT-ish section for PowerPC64. Their contents are accessed
+ // through r2 register, which is reserved for that purpose. Since r2 is used
+ // for accessing .got as well, .got and .toc need to be close enough in the
+ // virtual address space. Usually, .toc comes just after .got. Since we place
+ // .got into RELRO, .toc needs to be placed into RELRO too.
if (Sec->Name.equals(".toc"))
return true;
@@ -672,13 +702,13 @@ static bool isRelroSection(const OutputSection *Sec) {
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
// disabled, which enables us to put it into RELRO.
- if (Sec == InX::GotPlt->getParent())
+ if (Sec == In.GotPlt->getParent())
return Config->ZNow;
// .dynamic section contains data for the dynamic linker, and
// there's no need to write to it at runtime, so it's better to put
// it into RELRO.
- if (Sec == InX::Dynamic->getParent())
+ if (Sec == In.Dynamic->getParent())
return true;
// Sections with some special names are put into RELRO. This is a
@@ -700,17 +730,17 @@ static bool isRelroSection(const OutputSection *Sec) {
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
RF_NOT_ADDR_SET = 1 << 18,
- RF_NOT_INTERP = 1 << 17,
- RF_NOT_ALLOC = 1 << 16,
- RF_WRITE = 1 << 15,
- RF_EXEC_WRITE = 1 << 14,
- RF_EXEC = 1 << 13,
- RF_RODATA = 1 << 12,
- RF_NON_TLS_BSS = 1 << 11,
- RF_NON_TLS_BSS_RO = 1 << 10,
- RF_NOT_TLS = 1 << 9,
- RF_BSS = 1 << 8,
- RF_NOTE = 1 << 7,
+ RF_NOT_ALLOC = 1 << 17,
+ RF_NOT_INTERP = 1 << 16,
+ RF_NOT_NOTE = 1 << 15,
+ RF_WRITE = 1 << 14,
+ RF_EXEC_WRITE = 1 << 13,
+ RF_EXEC = 1 << 12,
+ RF_RODATA = 1 << 11,
+ RF_NON_TLS_BSS = 1 << 10,
+ RF_NON_TLS_BSS_RO = 1 << 9,
+ RF_NOT_TLS = 1 << 8,
+ RF_BSS = 1 << 7,
RF_PPC_NOT_TOCBSS = 1 << 6,
RF_PPC_TOCL = 1 << 5,
RF_PPC_TOC = 1 << 4,
@@ -729,16 +759,24 @@ static unsigned getSectionRank(const OutputSection *Sec) {
return Rank;
Rank |= RF_NOT_ADDR_SET;
+ // Allocatable sections go first to reduce the total PT_LOAD size and
+ // so debug info doesn't change addresses in actual code.
+ if (!(Sec->Flags & SHF_ALLOC))
+ return Rank | RF_NOT_ALLOC;
+
// Put .interp first because some loaders want to see that section
// on the first page of the executable file when loaded into memory.
if (Sec->Name == ".interp")
return Rank;
Rank |= RF_NOT_INTERP;
- // Allocatable sections go first to reduce the total PT_LOAD size and
- // so debug info doesn't change addresses in actual code.
- if (!(Sec->Flags & SHF_ALLOC))
- return Rank | RF_NOT_ALLOC;
+ // Put .note sections (which make up one PT_NOTE) at the beginning so that
+ // they are likely to be included in a core file even if core file size is
+ // limited. In particular, we want a .note.gnu.build-id and a .note.tag to be
+ // included in a core to match core files with executables.
+ if (Sec->Type == SHT_NOTE)
+ return Rank;
+ Rank |= RF_NOT_NOTE;
// Sort sections based on their access permission in the following
// order: R, RX, RWX, RW. This order is based on the following
@@ -802,12 +840,6 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (IsNoBits)
Rank |= RF_BSS;
- // We create a NOTE segment for contiguous .note sections, so make
- // them contigous if there are more than one .note section with the
- // same attributes.
- if (Sec->Type == SHT_NOTE)
- Rank |= RF_NOTE;
-
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64) {
@@ -850,8 +882,10 @@ static unsigned getSectionRank(const OutputSection *Sec) {
static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
const OutputSection *A = cast<OutputSection>(ACmd);
const OutputSection *B = cast<OutputSection>(BCmd);
+
if (A->SortRank != B->SortRank)
return A->SortRank < B->SortRank;
+
if (!(A->SortRank & RF_NOT_ADDR_SET))
return Config->SectionStartMap.lookup(A->Name) <
Config->SectionStartMap.lookup(B->Name);
@@ -874,14 +908,20 @@ void PhdrEntry::add(OutputSection *Sec) {
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
- if (needsInterpSection())
+ if (Config->Relocatable || needsInterpSection())
return;
- StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
- addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
- S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
- ElfSym::RelaIpltEnd =
- addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
+ // By default, __rela_iplt_{start,end} belong to a dummy section 0
+ // because .rela.plt might be empty and thus removed from output.
+ // We'll override Out::ElfHeader with In.RelaIplt later when we are
+ // sure that .rela.plt exists in output.
+ ElfSym::RelaIpltStart = addOptionalRegular(
+ Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start",
+ Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
+
+ ElfSym::RelaIpltEnd = addOptionalRegular(
+ Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end",
+ Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
@@ -895,7 +935,7 @@ void Writer<ELFT>::forEachRelSec(
for (InputSectionBase *IS : InputSections)
if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC))
Fn(*IS);
- for (EhInputSection *ES : InX::EhFrame->Sections)
+ for (EhInputSection *ES : In.EhFrame->Sections)
Fn(*ES);
}
@@ -908,15 +948,19 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
if (ElfSym::GlobalOffsetTable) {
// The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
// to the start of the .got or .got.plt section.
- InputSection *GotSection = InX::GotPlt;
+ InputSection *GotSection = In.GotPlt;
if (!Target->GotBaseSymInGotPlt)
- GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
- : cast<InputSection>(InX::Got);
+ GotSection = In.MipsGot ? cast<InputSection>(In.MipsGot)
+ : cast<InputSection>(In.Got);
ElfSym::GlobalOffsetTable->Section = GotSection;
}
- if (ElfSym::RelaIpltEnd)
- ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize();
+ // .rela_iplt_{start,end} mark the start and the end of .rela.plt section.
+ if (ElfSym::RelaIpltStart && !In.RelaIplt->empty()) {
+ ElfSym::RelaIpltStart->Section = In.RelaIplt;
+ ElfSym::RelaIpltEnd->Section = In.RelaIplt;
+ ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize();
+ }
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
@@ -1088,7 +1132,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
SymbolOrderEntry &Ent = It->second;
Ent.Present = true;
- warnUnorderableSymbol(&Sym);
+ maybeWarnUnorderableSymbol(&Sym);
if (auto *D = dyn_cast<Defined>(&Sym)) {
if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
@@ -1097,6 +1141,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
}
}
};
+
// We want both global and local symbols. We get the global ones from the
// symbol table and iterate the object files for the local ones.
for (Symbol *Sym : Symtab->getSymbols())
@@ -1132,11 +1177,10 @@ sortISDBySectionOrder(InputSectionDescription *ISD,
}
OrderedSections.push_back({IS, I->second});
}
- llvm::sort(
- OrderedSections.begin(), OrderedSections.end(),
- [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) {
- return A.second < B.second;
- });
+ llvm::sort(OrderedSections, [&](std::pair<InputSection *, int> A,
+ std::pair<InputSection *, int> B) {
+ return A.second < B.second;
+ });
// Find an insertion point for the ordered section list in the unordered
// section list. On targets with limited-range branches, this is the mid-point
@@ -1166,7 +1210,7 @@ sortISDBySectionOrder(InputSectionDescription *ISD,
// we effectively double the amount of code that could potentially call into
// the hot code without a thunk.
size_t InsPt = 0;
- if (Target->ThunkSectionSpacing && !OrderedSections.empty()) {
+ if (Target->getThunkSectionSpacing() && !OrderedSections.empty()) {
uint64_t UnorderedPos = 0;
for (; InsPt != UnorderedSections.size(); ++InsPt) {
UnorderedPos += UnorderedSections[InsPt]->getSize();
@@ -1342,10 +1386,12 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) {
if (A->kind() == InputSectionBase::Synthetic ||
B->kind() == InputSectionBase::Synthetic)
return A->kind() != InputSectionBase::Synthetic;
+
InputSection *LA = A->getLinkOrderDep();
InputSection *LB = B->getLinkOrderDep();
OutputSection *AOut = LA->getParent();
OutputSection *BOut = LB->getParent();
+
if (AOut != BOut)
return AOut->SectionIndex < BOut->SectionIndex;
return LA->OutSecOff < LB->OutSecOff;
@@ -1392,6 +1438,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
return false;
+
// All table entries in this .ARM.exidx Section can be merged into the
// previous Section.
return true;
@@ -1423,18 +1470,19 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
assert(Sections.size() >= 2 &&
"We should create a sentinel section only if there are "
"alive regular exidx sections.");
+
// The last executable section is required to fill the sentinel.
// Remember it here so that we don't have to find it again.
Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
}
+ // The EHABI for the Arm Architecture permits consecutive identical
+ // table entries to be merged. We use a simple implementation that
+ // removes a .ARM.exidx Input Section if it can be merged into the
+ // previous one. This does not require any rewriting of InputSection
+ // contents but misses opportunities for fine grained deduplication
+ // where only a subset of the InputSection contents can be merged.
if (Config->MergeArmExidx) {
- // The EHABI for the Arm Architecture permits consecutive identical
- // table entries to be merged. We use a simple implementation that
- // removes a .ARM.exidx Input Section if it can be merged into the
- // previous one. This does not require any rewriting of InputSection
- // contents but misses opportunities for fine grained deduplication
- // where only a subset of the InputSection contents can be merged.
size_t Prev = 0;
// The last one is a sentinel entry which should not be removed.
for (size_t I = 1; I < Sections.size() - 1; ++I) {
@@ -1456,11 +1504,49 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
}
}
-static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
- llvm::function_ref<void(SyntheticSection *)> Fn) {
- for (SyntheticSection *SS : Sections)
- if (SS && SS->getParent() && !SS->empty())
- Fn(SS);
+// For most RISC ISAs, we need to generate content that depends on the address
+// of InputSections. For example some architectures such as AArch64 use small
+// displacements for jump instructions that is the linker's responsibility for
+// creating range extension thunks for. As the generation of the content may
+// also alter InputSection addresses we must converge to a fixed point.
+template <class ELFT> void Writer<ELFT>::maybeAddThunks() {
+ if (!Target->NeedsThunks && !Config->AndroidPackDynRelocs &&
+ !Config->RelrPackDynRelocs)
+ return;
+
+ ThunkCreator TC;
+ AArch64Err843419Patcher A64P;
+
+ for (;;) {
+ bool Changed = false;
+
+ Script->assignAddresses();
+
+ if (Target->NeedsThunks)
+ Changed |= TC.createThunks(OutputSections);
+
+ if (Config->FixCortexA53Errata843419) {
+ if (Changed)
+ Script->assignAddresses();
+ Changed |= A64P.createFixes();
+ }
+
+ if (In.MipsGot)
+ In.MipsGot->updateAllocSize();
+
+ Changed |= In.RelaDyn->updateAllocSize();
+
+ if (In.RelrDyn)
+ Changed |= In.RelrDyn->updateAllocSize();
+
+ if (!Changed)
+ return;
+ }
+}
+
+static void finalizeSynthetic(SyntheticSection *Sec) {
+ if (Sec && !Sec->empty() && Sec->getParent())
+ Sec->finalizeContents();
}
// In order to allow users to manipulate linker-synthesized sections,
@@ -1500,6 +1586,7 @@ static void removeUnusedSyntheticSections() {
// with the same name defined in other ELF executable or DSO.
static bool computeIsPreemptible(const Symbol &B) {
assert(!B.isLocal());
+
// Only symbols that appear in dynsym can be preempted.
if (!B.includeInDynsym())
return false;
@@ -1528,7 +1615,6 @@ static bool computeIsPreemptible(const Symbol &B) {
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
- Out::DebugInfo = findSection(".debug_info");
Out::PreinitArray = findSection(".preinit_array");
Out::InitArray = findSection(".init_array");
Out::FiniArray = findSection(".fini_array");
@@ -1547,46 +1633,51 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// It should be okay as no one seems to care about the type.
// Even the author of gold doesn't remember why gold behaves that way.
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
- if (InX::DynSymTab)
- Symtab->addRegular("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/,
- /*Size=*/0, STB_WEAK, InX::Dynamic,
+ if (In.Dynamic->Parent)
+ Symtab->addDefined("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/,
+ /*Size=*/0, STB_WEAK, In.Dynamic,
/*File=*/nullptr);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
+ // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined.
+ if (Config->EMachine == EM_RISCV)
+ if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
+ addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
+
// This responsible for splitting up .eh_frame section into
// pieces. The relocation scan uses those pieces, so this has to be
// earlier.
- applySynthetic({InX::EhFrame},
- [](SyntheticSection *SS) { SS->finalizeContents(); });
+ finalizeSynthetic(In.EhFrame);
for (Symbol *S : Symtab->getSymbols())
- S->IsPreemptible |= computeIsPreemptible(*S);
+ if (!S->IsPreemptible)
+ S->IsPreemptible = computeIsPreemptible(*S);
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
if (!Config->Relocatable)
forEachRelSec(scanRelocations<ELFT>);
- if (InX::Plt && !InX::Plt->empty())
- InX::Plt->addSymbols();
- if (InX::Iplt && !InX::Iplt->empty())
- InX::Iplt->addSymbols();
+ if (In.Plt && !In.Plt->empty())
+ In.Plt->addSymbols();
+ if (In.Iplt && !In.Iplt->empty())
+ In.Iplt->addSymbols();
// Now that we have defined all possible global symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
for (Symbol *Sym : Symtab->getSymbols()) {
if (!includeInSymtab(*Sym))
continue;
- if (InX::SymTab)
- InX::SymTab->addSymbol(Sym);
+ if (In.SymTab)
+ In.SymTab->addSymbol(Sym);
- if (InX::DynSymTab && Sym->includeInDynsym()) {
- InX::DynSymTab->addSymbol(Sym);
+ if (Sym->includeInDynsym()) {
+ In.DynSymTab->addSymbol(Sym);
if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
if (File->IsNeeded && !Sym->isUndefined())
- In<ELFT>::VerNeed->addSymbol(Sym);
+ InX<ELFT>::VerNeed->addSymbol(Sym);
}
}
@@ -1594,8 +1685,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
- if (InX::MipsGot)
- InX::MipsGot->build<ELFT>();
+ if (In.MipsGot)
+ In.MipsGot->build<ELFT>();
removeUnusedSyntheticSections();
@@ -1607,15 +1698,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
- // Ensure data sections are not mixed with executable sections when
- // -execute-only is used.
- if (Config->ExecuteOnly)
- for (OutputSection *OS : OutputSections)
- if (OS->Flags & SHF_EXECINSTR)
- for (InputSection *IS : getInputSections(OS))
- if (!(IS->Flags & SHF_EXECINSTR))
- error("-execute-only does not support intermingling data and code");
-
// Prefer command line supplied address over other constraints.
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
@@ -1628,10 +1710,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
- unsigned I = 1;
- for (OutputSection *Sec : OutputSections) {
- Sec->SectionIndex = I++;
- Sec->ShName = InX::ShStrTab->addString(Sec->Name);
+ for (size_t I = 0, E = OutputSections.size(); I != E; ++I) {
+ OutputSection *Sec = OutputSections[I];
+ Sec->SectionIndex = I + 1;
+ Sec->ShName = In.ShStrTab->addString(Sec->Name);
}
// Binary and relocatable output does not have PHDRS.
@@ -1641,6 +1723,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs();
addPtArmExid(Phdrs);
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
+
+ // Find the TLS segment. This happens before the section layout loop so that
+ // Android relocation packing can look up TLS symbol addresses.
+ for (PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_TLS)
+ Out::TlsPhdr = P;
}
// Some symbols are defined in term of program headers. Now that we
@@ -1649,15 +1737,30 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
- applySynthetic(
- {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab,
- InX::HashTab, InX::SymTab, InX::SymTabShndx, InX::ShStrTab,
- InX::StrTab, In<ELFT>::VerDef, InX::DynStrTab, InX::Got,
- InX::MipsGot, InX::IgotPlt, InX::GotPlt, InX::RelaDyn,
- InX::RelrDyn, InX::RelaIplt, InX::RelaPlt, InX::Plt,
- InX::Iplt, InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed,
- InX::Dynamic},
- [](SyntheticSection *SS) { SS->finalizeContents(); });
+ finalizeSynthetic(In.DynSymTab);
+ finalizeSynthetic(In.Bss);
+ finalizeSynthetic(In.BssRelRo);
+ finalizeSynthetic(In.GnuHashTab);
+ finalizeSynthetic(In.HashTab);
+ finalizeSynthetic(In.SymTabShndx);
+ finalizeSynthetic(In.ShStrTab);
+ finalizeSynthetic(In.StrTab);
+ finalizeSynthetic(In.VerDef);
+ finalizeSynthetic(In.DynStrTab);
+ finalizeSynthetic(In.Got);
+ finalizeSynthetic(In.MipsGot);
+ finalizeSynthetic(In.IgotPlt);
+ finalizeSynthetic(In.GotPlt);
+ finalizeSynthetic(In.RelaDyn);
+ finalizeSynthetic(In.RelrDyn);
+ finalizeSynthetic(In.RelaIplt);
+ finalizeSynthetic(In.RelaPlt);
+ finalizeSynthetic(In.Plt);
+ finalizeSynthetic(In.Iplt);
+ finalizeSynthetic(In.EhFrameHdr);
+ finalizeSynthetic(InX<ELFT>::VerSym);
+ finalizeSynthetic(InX<ELFT>::VerNeed);
+ finalizeSynthetic(In.Dynamic);
if (!Script->HasSectionsCommand && !Config->Relocatable)
fixSectionAlignments();
@@ -1666,37 +1769,21 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// needs to be resolved before any other address dependent operation.
resolveShfLinkOrder();
- // Some architectures need to generate content that depends on the address
- // of InputSections. For example some architectures use small displacements
- // for jump instructions that is the linker's responsibility for creating
- // range extension thunks for. As the generation of the content may also
- // alter InputSection addresses we must converge to a fixed point.
- if (Target->NeedsThunks || Config->AndroidPackDynRelocs ||
- Config->RelrPackDynRelocs) {
- ThunkCreator TC;
- AArch64Err843419Patcher A64P;
- bool Changed;
- do {
- Script->assignAddresses();
- Changed = false;
- if (Target->NeedsThunks)
- Changed |= TC.createThunks(OutputSections);
- if (Config->FixCortexA53Errata843419) {
- if (Changed)
- Script->assignAddresses();
- Changed |= A64P.createFixes();
- }
- if (InX::MipsGot)
- InX::MipsGot->updateAllocSize();
- Changed |= InX::RelaDyn->updateAllocSize();
- if (InX::RelrDyn)
- Changed |= InX::RelrDyn->updateAllocSize();
- } while (Changed);
- }
+ // Jump instructions in many ISAs have small displacements, and therefore they
+ // cannot jump to arbitrary addresses in memory. For example, RISC-V JAL
+ // instruction can target only +-1 MiB from PC. It is a linker's
+ // responsibility to create and insert small pieces of code between sections
+ // to extend the ranges if jump targets are out of range. Such code pieces are
+ // called "thunks".
+ //
+ // We add thunks at this stage. We couldn't do this before this point because
+ // this is the earliest point where we know sizes of sections and their
+ // layouts (that are needed to determine if jump targets are in range).
+ maybeAddThunks();
- // createThunks may have added local symbols to the static symbol table
- applySynthetic({InX::SymTab},
- [](SyntheticSection *SS) { SS->postThunkContents(); });
+ // maybeAddThunks may have added local symbols to the static symbol table.
+ finalizeSynthetic(In.SymTab);
+ finalizeSynthetic(In.PPC64LongBranchTarget);
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
@@ -1705,6 +1792,21 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Sec->finalize<ELFT>();
}
+// Ensure data sections are not mixed with executable sections when
+// -execute-only is used. -execute-only is a feature to make pages executable
+// but not readable, and the feature is currently supported only on AArch64.
+template <class ELFT> void Writer<ELFT>::checkExecuteOnly() {
+ if (!Config->ExecuteOnly)
+ return;
+
+ for (OutputSection *OS : OutputSections)
+ if (OS->Flags & SHF_EXECINSTR)
+ for (InputSection *IS : getInputSections(OS))
+ if (!(IS->Flags & SHF_EXECINSTR))
+ error("cannot place " + toString(IS) + " into " + toString(OS->Name) +
+ ": -execute-only does not support intermingling data and code");
+}
+
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
@@ -1721,9 +1823,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
// program to fail to link due to relocation overflow, if their
// program text is above 2 GiB. We use the address of the .text
// section instead to prevent that failure.
+ //
+ // In a rare sitaution, .text section may not exist. If that's the
+ // case, use the image base address as a last resort.
OutputSection *Default = findSection(".text");
if (!Default)
Default = Out::ElfHeader;
+
auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
@@ -1763,7 +1869,7 @@ static bool needsPtLoad(OutputSection *Sec) {
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
// responsible for allocating space for them, not the PT_LOAD that
// contains the TLS initialization image.
- if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS)
+ if ((Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS)
return false;
return true;
}
@@ -1815,12 +1921,14 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Segments are contiguous memory regions that has the same attributes
// (e.g. executable or writable). There is one phdr for each segment.
// Therefore, we need to create a new phdr when the next section has
- // different flags or is loaded at a discontiguous address using AT linker
- // script command. At the same time, we don't want to create a separate
- // load segment for the headers, even if the first output section has
- // an AT attribute.
+ // different flags or is loaded at a discontiguous address or memory
+ // region using AT or AT> linker script command, respectively. At the same
+ // time, we don't want to create a separate load segment for the headers,
+ // even if the first output section has an AT or AT> attribute.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if ((Sec->LMAExpr && Load->LastSec != Out::ProgramHeaders) ||
+ if (((Sec->LMAExpr ||
+ (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) &&
+ Load->LastSec != Out::ProgramHeaders) ||
Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
@@ -1839,9 +1947,8 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
Ret.push_back(TlsHdr);
// Add an entry for .dynamic.
- if (InX::DynSymTab)
- AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags())
- ->add(InX::Dynamic->getParent());
+ if (OutputSection *Sec = In.Dynamic->getParent())
+ AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec);
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
@@ -1869,10 +1976,10 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
Ret.push_back(RelRo);
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
- if (!InX::EhFrame->empty() && InX::EhFrameHdr && InX::EhFrame->getParent() &&
- InX::EhFrameHdr->getParent())
- AddHdr(PT_GNU_EH_FRAME, InX::EhFrameHdr->getParent()->getPhdrFlags())
- ->add(InX::EhFrameHdr->getParent());
+ if (!In.EhFrame->empty() && In.EhFrameHdr && In.EhFrame->getParent() &&
+ In.EhFrameHdr->getParent())
+ AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags())
+ ->add(In.EhFrameHdr->getParent());
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
// the dynamic linker fill the segment with random data.
@@ -1943,77 +2050,77 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
for (const PhdrEntry *P : Phdrs) {
if (P->p_type != PT_GNU_RELRO)
continue;
+
if (P->FirstSec)
PageAlign(P->FirstSec);
+
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto End = OutputSections.end();
auto I = std::find(OutputSections.begin(), End, P->LastSec);
if (I == End || (I + 1) == End)
continue;
+
OutputSection *Cmd = (*(I + 1));
if (needsPtLoad(Cmd))
PageAlign(Cmd);
}
}
-// Adjusts the file alignment for a given output section and returns
-// its new file offset. The file offset must be the same with its
-// virtual address (modulo the page size) so that the loader can load
-// executables without any address adjustment.
-static uint64_t getFileAlignment(uint64_t Off, OutputSection *Cmd) {
- OutputSection *First = Cmd->PtLoad ? Cmd->PtLoad->FirstSec : nullptr;
- // The first section in a PT_LOAD has to have congruent offset and address
- // module the page size.
- if (Cmd == First)
- return alignTo(Off, std::max<uint64_t>(Cmd->Alignment, Config->MaxPageSize),
- Cmd->Addr);
-
- // For SHT_NOBITS we don't want the alignment of the section to impact the
- // offset of the sections that follow. Since nothing seems to care about the
- // sh_offset of the SHT_NOBITS section itself, just ignore it.
- if (Cmd->Type == SHT_NOBITS)
+// Compute an in-file position for a given section. The file offset must be the
+// same with its virtual address modulo the page size, so that the loader can
+// load executables without any address adjustment.
+static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) {
+ // File offsets are not significant for .bss sections. By convention, we keep
+ // section offsets monotonically increasing rather than setting to zero.
+ if (OS->Type == SHT_NOBITS)
return Off;
// If the section is not in a PT_LOAD, we just have to align it.
- if (!Cmd->PtLoad)
- return alignTo(Off, Cmd->Alignment);
+ if (!OS->PtLoad)
+ return alignTo(Off, OS->Alignment);
+
+ // The first section in a PT_LOAD has to have congruent offset and address
+ // module the page size.
+ OutputSection *First = OS->PtLoad->FirstSec;
+ if (OS == First) {
+ uint64_t Alignment = std::max<uint64_t>(OS->Alignment, Config->MaxPageSize);
+ return alignTo(Off, Alignment, OS->Addr);
+ }
// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
- return First->Offset + Cmd->Addr - First->Addr;
+ return First->Offset + OS->Addr - First->Addr;
}
-static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) {
- Off = getFileAlignment(Off, Cmd);
- Cmd->Offset = Off;
+// Set an in-file position to a given section and returns the end position of
+// the section.
+static uint64_t setFileOffset(OutputSection *OS, uint64_t Off) {
+ Off = computeFileOffset(OS, Off);
+ OS->Offset = Off;
- // For SHT_NOBITS we should not count the size.
- if (Cmd->Type == SHT_NOBITS)
+ if (OS->Type == SHT_NOBITS)
return Off;
-
- return Off + Cmd->Size;
+ return Off + OS->Size;
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
uint64_t Off = 0;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
- Off = setOffset(Sec, Off);
+ Off = setFileOffset(Sec, Off);
FileSize = alignTo(Off, Config->Wordsize);
}
static std::string rangeToString(uint64_t Addr, uint64_t Len) {
- if (Len == 0)
- return "<empty range at 0x" + utohexstr(Addr) + ">";
return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
}
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uint64_t Off = 0;
- Off = setOffset(Out::ElfHeader, Off);
- Off = setOffset(Out::ProgramHeaders, Off);
+ Off = setFileOffset(Out::ElfHeader, Off);
+ Off = setFileOffset(Out::ProgramHeaders, Off);
PhdrEntry *LastRX = nullptr;
for (PhdrEntry *P : Phdrs)
@@ -2021,9 +2128,10 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
LastRX = P;
for (OutputSection *Sec : OutputSections) {
- Off = setOffset(Sec, Off);
+ Off = setFileOffset(Sec, Off);
if (Script->HasSectionsCommand)
continue;
+
// If this is a last section of the last executable segment and that
// segment is the last loadable segment, align the offset of the
// following section to avoid loading non-segments parts of the file.
@@ -2048,7 +2156,7 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
continue;
if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
error("unable to place section " + Sec->Name + " at file offset " +
- rangeToString(Sec->Offset, Sec->Offset + Sec->Size) +
+ rangeToString(Sec->Offset, Sec->Size) +
"; check your linker script for overflows");
}
}
@@ -2059,19 +2167,23 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
for (PhdrEntry *P : Phdrs) {
OutputSection *First = P->FirstSec;
OutputSection *Last = P->LastSec;
+
if (First) {
P->p_filesz = Last->Offset - First->Offset;
if (Last->Type != SHT_NOBITS)
P->p_filesz += Last->Size;
+
P->p_memsz = Last->Addr + Last->Size - First->Addr;
P->p_offset = First->Offset;
P->p_vaddr = First->Addr;
+
if (!P->HasLMA)
P->p_paddr = First->getLMA();
}
- if (P->p_type == PT_LOAD)
+
+ if (P->p_type == PT_LOAD) {
P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize);
- else if (P->p_type == PT_GNU_RELRO) {
+ } else if (P->p_type == PT_GNU_RELRO) {
P->p_align = 1;
// The glibc dynamic loader rounds the size down, so we need to round up
// to protect the last page. This is a no-op on FreeBSD which always
@@ -2079,12 +2191,22 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
P->p_memsz = alignTo(P->p_memsz, Target->PageSize);
}
- // The TLS pointer goes after PT_TLS. At least glibc will align it,
- // so round up the size to make sure the offsets are correct.
- if (P->p_type == PT_TLS) {
- Out::TlsPhdr = P;
- if (P->p_memsz)
- P->p_memsz = alignTo(P->p_memsz, P->p_align);
+ if (P->p_type == PT_TLS && P->p_memsz) {
+ if (!Config->Shared &&
+ (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) {
+ // On ARM/AArch64, reserve extra space (8 words) between the thread
+ // pointer and an executable's TLS segment by overaligning the segment.
+ // This reservation is needed for backwards compatibility with Android's
+ // TCB, which allocates several slots after the thread pointer (e.g.
+ // TLS_SLOT_STACK_GUARD==5). For simplicity, this overalignment is also
+ // done on other operating systems.
+ P->p_align = std::max<uint64_t>(P->p_align, Config->Wordsize * 8);
+ }
+
+ // The TLS pointer goes after PT_TLS for variant 2 targets. At least glibc
+ // will align it, so round up the size to make sure the offsets are
+ // correct.
+ P->p_memsz = alignTo(P->p_memsz, P->p_align);
}
}
}
@@ -2101,10 +2223,9 @@ struct SectionOffset {
// load and virtual adresses).
static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections,
bool IsVirtualAddr) {
- llvm::sort(Sections.begin(), Sections.end(),
- [=](const SectionOffset &A, const SectionOffset &B) {
- return A.Offset < B.Offset;
- });
+ llvm::sort(Sections, [=](const SectionOffset &A, const SectionOffset &B) {
+ return A.Offset < B.Offset;
+ });
// Finding overlap is easy given a vector is sorted by start position.
// If an element starts before the end of the previous element, they overlap.
@@ -2148,7 +2269,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// file so we skip any non-allocated sections in that case.
std::vector<SectionOffset> FileOffs;
for (OutputSection *Sec : OutputSections)
- if (0 < Sec->Size && Sec->Type != SHT_NOBITS &&
+ if (Sec->Size > 0 && Sec->Type != SHT_NOBITS &&
(!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
FileOffs.push_back({Sec, Sec->Offset});
checkOverlap("file", FileOffs, false);
@@ -2166,7 +2287,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// ranges in the file.
std::vector<SectionOffset> VMAs;
for (OutputSection *Sec : OutputSections)
- if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
VMAs.push_back({Sec, Sec->Addr});
checkOverlap("virtual address", VMAs, true);
@@ -2175,7 +2296,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// script with AT().
std::vector<SectionOffset> LMAs;
for (OutputSection *Sec : OutputSections)
- if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
LMAs.push_back({Sec, Sec->getLMA()});
checkOverlap("load address", LMAs, false);
}
@@ -2188,7 +2309,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// 4. the number represented by the entry symbol, if it is a number;
// 5. the address of the first byte of the .text section, if present;
// 6. the address 0.
-template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
+static uint64_t getEntryAddr() {
// Case 1, 2 or 3
if (Symbol *B = Symtab->find(Config->Entry))
return B->getVA();
@@ -2231,6 +2352,7 @@ static uint8_t getAbiVersion() {
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
+
// For executable segments, the trap instructions are written before writing
// the header. Setting Elf header bytes to zero ensures that any unused bytes
// in header are zero-cleared, instead of having trap instructions.
@@ -2289,7 +2411,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
else
EHdr->e_shnum = Num;
- uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex;
+ uint32_t StrTabIndex = In.ShStrTab->getParent()->SectionIndex;
if (StrTabIndex >= SHN_LORESERVE) {
SHdrs->sh_link = StrTabIndex;
EHdr->e_shstrndx = SHN_XINDEX;
@@ -2303,7 +2425,8 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// Open a result file.
template <class ELFT> void Writer<ELFT>::openFile() {
- if (!Config->Is64 && FileSize > UINT32_MAX) {
+ uint64_t MaxSize = Config->Is64 ? INT64_MAX : UINT32_MAX;
+ if (MaxSize < FileSize) {
error("output file too large: " + Twine(FileSize) + " bytes");
return;
}
@@ -2368,8 +2491,8 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
OutputSection *EhFrameHdr = nullptr;
- if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
- EhFrameHdr = InX::EhFrameHdr->getParent();
+ if (In.EhFrameHdr && !In.EhFrameHdr->empty())
+ EhFrameHdr = In.EhFrameHdr->getParent();
// In -r or -emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
@@ -2389,13 +2512,13 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
- if (!InX::BuildId || !InX::BuildId->getParent())
+ if (!In.BuildId || !In.BuildId->getParent())
return;
// Compute a hash of all sections of the output file.
uint8_t *Start = Buffer->getBufferStart();
uint8_t *End = Start + FileSize;
- InX::BuildId->writeBuildId({Start, End});
+ In.BuildId->writeBuildId({Start, End});
}
template void elf::writeResult<ELF32LE>();