[lld] r314675 - [MIPS] Fix PLT entries generation in case of linking regular and microMIPS code

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 2 07:56:41 PDT 2017


Author: atanasyan
Date: Mon Oct  2 07:56:41 2017
New Revision: 314675

URL: http://llvm.org/viewvc/llvm-project?rev=314675&view=rev
Log:
[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

Modified:
    lld/trunk/ELF/Arch/Mips.cpp
    lld/trunk/ELF/Arch/MipsArchTree.cpp
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/Writer.cpp
    lld/trunk/ELF/Writer.h
    lld/trunk/test/ELF/mips-elf-flags.s
    lld/trunk/test/ELF/mips-micro-jal.s

Modified: lld/trunk/ELF/Arch/Mips.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/Mips.cpp?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/Mips.cpp (original)
+++ lld/trunk/ELF/Arch/Mips.cpp Mon Oct  2 07:56:41 2017
@@ -238,37 +238,29 @@ static void writeMicroRelocation16(uint8
   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 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,
 
   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);

Modified: lld/trunk/ELF/Arch/MipsArchTree.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/MipsArchTree.cpp?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/MipsArchTree.cpp (original)
+++ lld/trunk/ELF/Arch/MipsArchTree.cpp Mon Oct  2 07:56:41 2017
@@ -281,7 +281,7 @@ static uint32_t getArchFlags(ArrayRef<Fi
   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 *
   }
 }
 
-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>();

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Mon Oct  2 07:56:41 2017
@@ -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

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Mon Oct  2 07:56:41 2017
@@ -1080,6 +1080,9 @@ template <class ELFT> void LinkerDriver:
     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.

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Mon Oct  2 07:56:41 2017
@@ -151,7 +151,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsS
       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);

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Oct  2 07:56:41 2017
@@ -1798,7 +1798,7 @@ template <class ELFT> void Writer<ELFT>:
     // 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);

Modified: lld/trunk/ELF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.h?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.h (original)
+++ lld/trunk/ELF/Writer.h Mon Oct  2 07:56:41 2017
@@ -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);

Modified: lld/trunk/test/ELF/mips-elf-flags.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-elf-flags.s?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-elf-flags.s (original)
+++ lld/trunk/test/ELF/mips-elf-flags.s Mon Oct  2 07:56:41 2017
@@ -35,6 +35,12 @@
 # RUN: llvm-readobj -h -mips-abi-flags %t.exe \
 # RUN:   | FileCheck -check-prefix=OCTEON %s
 
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %S/Inputs/mips-fpic.s -o %t-mm.o
+# RUN: ld.lld %t.o %t-mm.o -o %t.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=MICRO %s
+
 # REQUIRES: mips
 
   .text
@@ -170,3 +176,26 @@ __start:
 # OCTEON-NEXT:   ]
 # OCTEON-NEXT:   Flags 2: 0x0
 # OCTEON-NEXT: }
+
+# MICRO:      Flags [
+# MICRO-NEXT:   EF_MIPS_ABI_O32
+# MICRO-NEXT:   EF_MIPS_ARCH_32
+# MICRO-NEXT:   EF_MIPS_CPIC
+# MICRO-NEXT:   EF_MIPS_MICROMIPS
+# MICRO-NEXT: ]
+# MICRO:      MIPS ABI Flags {
+# MICRO-NEXT:   Version: 0
+# MICRO-NEXT:   ISA: MIPS32
+# MICRO-NEXT:   ISA Extension: None
+# MICRO-NEXT:   ASEs [
+# MICRO-NEXT:     microMIPS
+# MICRO-NEXT:   ]
+# MICRO-NEXT:   FP ABI: Hard float (double precision)
+# MICRO-NEXT:   GPR size: 32
+# MICRO-NEXT:   CPR1 size: 32
+# MICRO-NEXT:   CPR2 size: 0
+# MICRO-NEXT:   Flags 1 [
+# MICRO-NEXT:     ODDSPREG
+# MICRO-NEXT:   ]
+# MICRO-NEXT:   Flags 2: 0x0
+# MICRO-NEXT: }

Modified: lld/trunk/test/ELF/mips-micro-jal.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-micro-jal.s?rev=314675&r1=314674&r2=314675&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-micro-jal.s (original)
+++ lld/trunk/test/ELF/mips-micro-jal.s Mon Oct  2 07:56:41 2017
@@ -34,6 +34,17 @@
 # RUN: ld.lld -o %tel.exe %t2el.o %tel.so
 # RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=ELR6 %s
 
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
+# RUN: ld.lld -shared -o %teb.so %t1eb.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-fpic.s -o %t-reg.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=micromips %s -o %t2eb.o
+# RUN: ld.lld --no-threads -o %teb.exe %t-reg.o %t2eb.o %teb.so
+# RUN: llvm-objdump -d -mattr=micromips %teb.exe \
+# RUN:   | FileCheck --check-prefix=MIXED %s
+
 # REQUIRES: mips
 
 # EB:      Disassembly of section .plt:
@@ -106,6 +117,25 @@
 # ELR6-NEXT:    20038:       02 0f           move16  $24, $2
 # ELR6-NEXT:    2003a:       23 47           jrc16   $25
 
+# MIXED:      Disassembly of section .plt:
+# MIXED-NEXT: .plt:
+# MIXED-NEXT:    20020:       79 80 3f f9     addiupc $3, 65508
+# MIXED-NEXT:    20024:       ff 23 00 00     lw      $25, 0($3)
+# MIXED-NEXT:    20028:       05 35           subu16  $2, $2, $3
+# MIXED-NEXT:    2002a:       25 25           srl16   $2, $2, 2
+# MIXED-NEXT:    2002c:       33 02 ff fe     addiu   $24, $2, -2
+# MIXED-NEXT:    20030:       0d ff           move    $15, $ra
+# MIXED-NEXT:    20032:       45 f9           jalrs16 $25
+# MIXED-NEXT:    20034:       0f 83           move    $gp, $3
+# MIXED-NEXT:    20036:       0c 00           nop
+# MIXED-NEXT:    20038:       00 00 00 00     nop
+# MIXED-NEXT:    2003c:       00 00 00 00     nop
+
+# MIXED-NEXT:    20040:       79 00 3f f3     addiupc $2, 65484
+# MIXED-NEXT:    20044:       ff 22 00 00     lw      $25, 0($2)
+# MIXED-NEXT:    20048:       45 99           jr16    $25
+# MIXED-NEXT:    2004a:       0f 02           move    $24, $2
+
 # PLT:      Entries [
 # PLT-NEXT:   Entry {
 # PLT-NEXT:     Address: 0x3000C




More information about the llvm-commits mailing list