aboutsummaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2017-10-02 14:56:41 +0000
committerSimon Atanasyan <simon@atanasyan.com>2017-10-02 14:56:41 +0000
commitfd9cccecf42e4e8c7d55c19eedc6f44d4075a3d5 (patch)
tree36e44af83e4ff3229928e83a7c5a1f5c85f796c1 /ELF
parent74be062570b01a28f8637444e70405771d738053 (diff)
[MIPS] Fix PLT entries generation in case of linking regular and microMIPS code
Currently LLD calls the `isMicroMips` routine to determine type of PLT entries needs to be generated: regular or microMIPS. This routine checks ELF header flags in the `FirstObj` to retrieve type of linked object files. So if the first file does not contain microMIPS code, LLD will generate PLT entries with regular (non-microMIPS) code only. Ideally, if a PLT entry is referenced by microMIPS code only this entry should contain microMIPS code, if a PLT entry is referenced by regular code this entry should contain regular code. In a "mixed" case the PLT entry can be either microMIPS or regular, but each "cross-mode-call" has additional cost. It's rather difficult to implement this ideal solution. But we can assume that if there is an input object file with microMIPS code, the most part of the code is microMIPS too. So we need to deduce type of PLT entries based on finally calculated ELF header flags and do not check only the first input object file. This change implements this. - The `getMipsEFlags` renamed to the `calcMipsEFlags`. The function called from the `LinkerDriver::link`. Result is stored in the Configuration::MipsEFlags field. - The `isMicroMips` and `isMipsR6` routines access the `MipsEFlags` field to get and check calculated ELF flags. - New types of PLT records created when necessary. Differential revision: https://reviews.llvm.org/D37747 git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@314675 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Arch/Mips.cpp27
-rw-r--r--ELF/Arch/MipsArchTree.cpp10
-rw-r--r--ELF/Config.h6
-rw-r--r--ELF/Driver.cpp3
-rw-r--r--ELF/SyntheticSections.cpp2
-rw-r--r--ELF/Writer.cpp2
-rw-r--r--ELF/Writer.h2
7 files changed, 26 insertions, 26 deletions
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index 06618ec3f..4665ca110 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -238,37 +238,29 @@ static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
write16<E>(Loc, Data);
}
-template <class ELFT> static bool isMicroMips() {
- // FIXME (simon): This code does not support the case when both
- // microMIPS and MIPS object files are linked together.
- const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
- uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH_ASE;
- return Arch == EF_MIPS_MICROMIPS;
-}
+static bool isMicroMips() { return Config->MipsEFlags & EF_MIPS_MICROMIPS; }
-template <class ELFT> static bool isMipsR6() {
- const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
- uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
+static bool isMipsR6() {
+ uint32_t Arch = Config->MipsEFlags & EF_MIPS_ARCH;
return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
}
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
- if (isMicroMips<ELFT>()) {
+ if (isMicroMips()) {
uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
uint64_t Plt = In<ELFT>::Plt->getVA();
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(Buf, 0, PltHeaderSize);
- write16<E>(Buf, isMipsR6<ELFT>() ? 0x7860 : 0x7980);
- // addiupc v1, (GOTPLT) - .
+ write16<E>(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - .
write16<E>(Buf + 4, 0xff23); // lw $25, 0($3)
write16<E>(Buf + 8, 0x0535); // subu16 $2, $2, $3
write16<E>(Buf + 10, 0x2525); // srl16 $2, $2, 2
write16<E>(Buf + 12, 0x3302); // addiu $24, $2, -2
write16<E>(Buf + 14, 0xfffe);
write16<E>(Buf + 16, 0x0dff); // move $15, $31
- if (isMipsR6<ELFT>()) {
+ if (isMipsR6()) {
write16<E>(Buf + 18, 0x0f83); // move $28, $3
write16<E>(Buf + 20, 0x472b); // jalrc $25
write16<E>(Buf + 22, 0x0c00); // nop
@@ -310,11 +302,11 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const endianness E = ELFT::TargetEndianness;
- if (isMicroMips<ELFT>()) {
+ if (isMicroMips()) {
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(Buf, 0, PltEntrySize);
- if (isMipsR6<ELFT>()) {
+ if (isMipsR6()) {
write16<E>(Buf, 0x7840); // addiupc $2, (GOTPLT) - .
write16<E>(Buf + 4, 0xff22); // lw $25, 0($2)
write16<E>(Buf + 8, 0x0f02); // move $24, $2
@@ -332,8 +324,7 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
- // jr $25
- write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
+ write32<E>(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0);
diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp
index ff3aa9d40..f78b6ba86 100644
--- a/ELF/Arch/MipsArchTree.cpp
+++ b/ELF/Arch/MipsArchTree.cpp
@@ -281,7 +281,7 @@ static uint32_t getArchFlags(ArrayRef<FileFlags> Files) {
return Ret;
}
-template <class ELFT> uint32_t elf::getMipsEFlags() {
+template <class ELFT> uint32_t elf::calcMipsEFlags() {
std::vector<FileFlags> V;
for (InputFile *F : ObjectFiles)
V.push_back(
@@ -364,7 +364,7 @@ bool elf::isMipsN32Abi(const InputFile *F) {
}
}
-template uint32_t elf::getMipsEFlags<ELF32LE>();
-template uint32_t elf::getMipsEFlags<ELF32BE>();
-template uint32_t elf::getMipsEFlags<ELF64LE>();
-template uint32_t elf::getMipsEFlags<ELF64BE>();
+template uint32_t elf::calcMipsEFlags<ELF32LE>();
+template uint32_t elf::calcMipsEFlags<ELF32BE>();
+template uint32_t elf::calcMipsEFlags<ELF64LE>();
+template uint32_t elf::calcMipsEFlags<ELF64BE>();
diff --git a/ELF/Config.h b/ELF/Config.h
index ecc339972..83afb8489 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -211,6 +211,12 @@ struct Configuration {
// if that's true.)
bool IsMips64EL;
+ // Holds set of ELF header flags for MIPS targets. The set calculated
+ // by the `elf::calcMipsEFlags` function and cached in this field. For
+ // the calculation we iterate over all input object files and combine
+ // their ELF flags.
+ uint32_t MipsEFlags = 0;
+
// The ELF spec defines two types of relocation table entries, RELA and
// REL. RELA is a triplet of (offset, info, addend) while REL is a
// tuple of (offset, info). Addends for REL are implicit and read from
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index e272f00fd..b53d88ba3 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -1080,6 +1080,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (InputSectionBase *S : F->getSections())
InputSections.push_back(cast<InputSection>(S));
+ if (Config->EMachine == EM_MIPS)
+ Config->MipsEFlags = calcMipsEFlags<ELFT>();
+
// This adds a .comment section containing a version string. We have to add it
// before decompressAndMergeSections because the .comment section is a
// mergeable section.
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 835b4ca87..591039549 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -151,7 +151,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
return nullptr;
}
- // LLD checks ISA compatibility in getMipsEFlags(). Here we just
+ // LLD checks ISA compatibility in calcMipsEFlags(). Here we just
// select the highest number of ISA/Rev/Ext.
Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 62748082f..aee315e33 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -1798,7 +1798,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// kernels (as of 2016) require an EABI version to be set.
EHdr->e_flags = EF_ARM_EABI_VER5;
else if (Config->EMachine == EM_MIPS)
- EHdr->e_flags = getMipsEFlags<ELFT>();
+ EHdr->e_flags = Config->MipsEFlags;
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
diff --git a/ELF/Writer.h b/ELF/Writer.h
index 83070005f..4db5fe824 100644
--- a/ELF/Writer.h
+++ b/ELF/Writer.h
@@ -48,7 +48,7 @@ struct PhdrEntry {
llvm::StringRef getOutputSectionName(llvm::StringRef Name);
-template <class ELFT> uint32_t getMipsEFlags();
+template <class ELFT> uint32_t calcMipsEFlags();
uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
llvm::StringRef FileName);