[lld] r306565 - Add basic 64-bit SPARC support

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 28 10:05:39 PDT 2017


Author: ruiu
Date: Wed Jun 28 10:05:39 2017
New Revision: 306565

URL: http://llvm.org/viewvc/llvm-project?rev=306565&view=rev
Log:
Add basic 64-bit SPARC support

Add support for the most common SPARC relocations.
Make DT_PLTGOT point to the PLT on SPARC.
Mark the PLT as executable on SPARC.

This adds a basic test that creates a SPARV9 executable
that invokes the exit system call on OpenBSD.

Patch by Mark Kettenis.

Differential Revision: https://reviews.llvm.org/D34618

Added:
    lld/trunk/ELF/Arch/SPARCV9.cpp
    lld/trunk/test/ELF/basic-sparcv9.s
Modified:
    lld/trunk/ELF/CMakeLists.txt
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h
    lld/trunk/test/lit.cfg

Added: lld/trunk/ELF/Arch/SPARCV9.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/SPARCV9.cpp?rev=306565&view=auto
==============================================================================
--- lld/trunk/ELF/Arch/SPARCV9.cpp (added)
+++ lld/trunk/ELF/Arch/SPARCV9.cpp Wed Jun 28 10:05:39 2017
@@ -0,0 +1,152 @@
+//===- SPARCV9.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class SPARCV9 final : public TargetInfo {
+public:
+  SPARCV9();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+SPARCV9::SPARCV9() {
+  CopyRel = R_SPARC_COPY;
+  GotRel = R_SPARC_GLOB_DAT;
+  PltRel = R_SPARC_JMP_SLOT;
+  RelativeRel = R_SPARC_RELATIVE;
+  GotEntrySize = 8;
+  PltEntrySize = 32;
+  PltHeaderSize = 4 * PltEntrySize;
+
+  PageSize = 8192;
+  DefaultMaxPageSize = 0x100000;
+  DefaultImageBase = 0x100000;
+}
+
+RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S,
+                            const uint8_t *Loc) const {
+  switch (Type) {
+  case R_SPARC_32:
+  case R_SPARC_UA32:
+  case R_SPARC_64:
+  case R_SPARC_UA64:
+    return R_ABS;
+  case R_SPARC_PC10:
+  case R_SPARC_PC22:
+    if (&S == ElfSym::GlobalOffsetTable)
+      return R_GOTONLY_PC;
+    LLVM_FALLTHROUGH;
+  case R_SPARC_DISP32:
+  case R_SPARC_WDISP30:
+    return R_PC;
+  case R_SPARC_GOT10:
+    return R_GOT_OFF;
+  case R_SPARC_GOT22:
+    return R_GOT_OFF;
+  case R_SPARC_WPLT30:
+    return R_PLT_PC;
+  case R_SPARC_NONE:
+    return R_NONE;
+  default:
+    error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+    return R_HINT;
+  }
+}
+
+void SPARCV9::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_SPARC_32:
+  case R_SPARC_UA32:
+    // V-word32
+    checkUInt<32>(Loc, Val, Type);
+    write32be(Loc, Val);
+    break;
+  case R_SPARC_DISP32:
+    // V-disp32
+    checkInt<32>(Loc, Val, Type);
+    write32be(Loc, Val);
+    break;
+  case R_SPARC_WDISP30:
+  case R_SPARC_WPLT30:
+    // V-disp30
+    checkInt<32>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
+    break;
+  case R_SPARC_22:
+    // V-imm22
+    checkUInt<22>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
+    break;
+  case R_SPARC_GOT22:
+  case R_SPARC_PC22:
+    // T-imm22
+    write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff));
+    break;
+  case R_SPARC_WDISP19:
+    // V-disp19
+    checkInt<21>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
+    break;
+  case R_SPARC_GOT10:
+  case R_SPARC_PC10:
+    // T-simm10
+    write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff));
+    break;
+  case R_SPARC_64:
+  case R_SPARC_UA64:
+  case R_SPARC_GLOB_DAT:
+    // V-xword64
+    write64be(Loc, Val);
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                       uint64_t PltEntryAddr, int32_t Index,
+                       unsigned RelOff) const {
+  const uint8_t PltData[] = {
+      0x03, 0x00, 0x00, 0x00, // sethi   (. - .PLT0), %g1
+      0x30, 0x68, 0x00, 0x00, // ba,a    %xcc, .PLT1
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00  // nop
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+
+  uint64_t Off = PltHeaderSize + Index * PltEntrySize;
+  relocateOne(Buf, R_SPARC_22, Off);
+  relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
+}
+
+TargetInfo *elf::getSPARCV9TargetInfo() {
+  static SPARCV9 Target;
+  return &Target;
+}

Modified: lld/trunk/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/CMakeLists.txt?rev=306565&r1=306564&r2=306565&view=diff
==============================================================================
--- lld/trunk/ELF/CMakeLists.txt (original)
+++ lld/trunk/ELF/CMakeLists.txt Wed Jun 28 10:05:39 2017
@@ -15,6 +15,7 @@ add_lld_library(lldELF
   Arch/MipsArchTree.cpp
   Arch/PPC.cpp
   Arch/PPC64.cpp
+  Arch/SPARCV9.cpp
   Arch/X86.cpp
   Arch/X86_64.cpp
   Driver.cpp

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=306565&r1=306564&r2=306565&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Wed Jun 28 10:05:39 2017
@@ -1090,8 +1090,17 @@ template <class ELFT> void DynamicSectio
   if (In<ELFT>::RelaPlt->getParent()->Size > 0) {
     add({DT_JMPREL, In<ELFT>::RelaPlt});
     add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size});
-    add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
-         InX::GotPlt});
+    switch (Config->EMachine) {
+    case EM_MIPS:
+      add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt});
+      break;
+    case EM_SPARCV9:
+      add({DT_PLTGOT, In<ELFT>::Plt});
+      break;
+    default:
+      add({DT_PLTGOT, In<ELFT>::GotPlt});
+      break;
+    }
     add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)});
   }
 
@@ -1632,7 +1641,12 @@ template <class ELFT> void HashTableSect
 
 PltSection::PltSection(size_t S)
     : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
-      HeaderSize(S) {}
+      HeaderSize(S) {
+  // 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)
+    this->Flags |= SHF_WRITE;
+}
 
 void PltSection::writeTo(uint8_t *Buf) {
   // At beginning of PLT but not the IPLT, we have code to call the dynamic

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=306565&r1=306564&r2=306565&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Wed Jun 28 10:05:39 2017
@@ -77,6 +77,8 @@ TargetInfo *elf::getTarget() {
     return getPPCTargetInfo();
   case EM_PPC64:
     return getPPC64TargetInfo();
+  case EM_SPARCV9:
+    return getSPARCV9TargetInfo();
   case EM_X86_64:
     if (Config->EKind == ELF32LEKind)
       return getX32TargetInfo();

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=306565&r1=306564&r2=306565&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Wed Jun 28 10:05:39 2017
@@ -112,6 +112,7 @@ TargetInfo *getARMTargetInfo();
 TargetInfo *getAVRTargetInfo();
 TargetInfo *getPPC64TargetInfo();
 TargetInfo *getPPCTargetInfo();
+TargetInfo *getSPARCV9TargetInfo();
 TargetInfo *getX32TargetInfo();
 TargetInfo *getX86TargetInfo();
 TargetInfo *getX86_64TargetInfo();

Added: lld/trunk/test/ELF/basic-sparcv9.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/basic-sparcv9.s?rev=306565&view=auto
==============================================================================
--- lld/trunk/test/ELF/basic-sparcv9.s (added)
+++ lld/trunk/test/ELF/basic-sparcv9.s Wed Jun 28 10:05:39 2017
@@ -0,0 +1,200 @@
+# RUN: llvm-mc -filetype=obj -triple=sparc64-unknown-openbsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+# REQUIRES: sparc
+
+# exits with return code 42 on OpenBSD/sparc64
+.global _start
+_start:
+  mov	42, %o0
+  mov	1, %g1
+  ta	0
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: BigEndian (0x2)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_SPARCV9 (0x2B)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: [[ENTRY:0x[0-9A-F]+]]
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x100080
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 6
+# CHECK-NEXT:   StringTableSectionIndex: 4
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x200000
+# CHECK-NEXT:     Offset: 0x100000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x10000C
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100018
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 5
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100048
+# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100072
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _start
+# CHECK-NEXT:     Value: [[ENTRY]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x100040
+# CHECK-NEXT:     PhysicalAddress: 0x100040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x100000
+# CHECK-NEXT:     PhysicalAddress: 0x100000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 1048576
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x100000
+# CHECK-NEXT:     VirtualAddress: 0x200000
+# CHECK-NEXT:     PhysicalAddress: 0x200000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 1048576
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]

Modified: lld/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/lit.cfg?rev=306565&r1=306564&r2=306565&view=diff
==============================================================================
--- lld/trunk/test/lit.cfg (original)
+++ lld/trunk/test/lit.cfg Wed Jun 28 10:05:39 2017
@@ -255,6 +255,8 @@ if re.search(r'Mips', archs):
     config.available_features.add('mips')
 if re.search(r'PowerPC', archs):
     config.available_features.add('ppc')
+if re.search(r'Sparc', archs):
+    config.available_features.add('sparc')
 if re.search(r'X86', archs):
     config.available_features.add('x86')
 llvm_config_cmd.wait()




More information about the llvm-commits mailing list