Index: ELF/Driver.cpp
===================================================================
--- ELF/Driver.cpp
+++ ELF/Driver.cpp
@@ -251,6 +251,13 @@
     Symtab.addIgnoredSym("_GLOBAL_OFFSET_TABLE_");
   }
 
+  // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
+  // so that it points to an absolute address which is relative to GOT.
+  // See "Global Data Symbols" in Chapter 6 in the following document:
+  // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (Config->EMachine == EM_MIPS)
+    Symtab.addAbsoluteSym("_gp", DefinedAbsolute<ELFT>::MipsGp);
+
   for (std::unique_ptr<InputFile> &F : Files)
     Symtab.addFile(std::move(F));
 
Index: ELF/OutputSections.h
===================================================================
--- ELF/OutputSections.h
+++ ELF/OutputSections.h
@@ -113,9 +113,7 @@
 
 public:
   GotSection();
-  void finalize() override {
-    this->Header.sh_size = Entries.size() * sizeof(uintX_t);
-  }
+  void finalize() override;
   void writeTo(uint8_t *Buf) override;
   void addEntry(SymbolBody *Sym);
   bool empty() const { return Entries.empty(); }
Index: ELF/OutputSections.cpp
===================================================================
--- ELF/OutputSections.cpp
+++ ELF/OutputSections.cpp
@@ -72,11 +72,13 @@
 GotSection<ELFT>::GotSection()
     : OutputSectionBase<ELFT>(".got", llvm::ELF::SHT_PROGBITS,
                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE) {
+  if (Config->EMachine == EM_MIPS)
+    this->Header.sh_flags |= llvm::ELF::SHF_MIPS_GPREL;
   this->Header.sh_addralign = sizeof(uintX_t);
 }
 
 template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
-  Sym->GotIndex = Entries.size();
+  Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size();
   Entries.push_back(Sym);
 }
 
@@ -86,11 +88,21 @@
   return this->getVA() + B.GotIndex * sizeof(uintX_t);
 }
 
+template <class ELFT> void GotSection<ELFT>::finalize() {
+  this->Header.sh_size =
+      (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t);
+}
+
 template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+  Target->writeGotHeaderEntries(Buf);
+  Buf += Target->getGotHeaderEntriesNum() * sizeof(uintX_t);
   for (const SymbolBody *B : Entries) {
     uint8_t *Entry = Buf;
     Buf += sizeof(uintX_t);
-    if (canBePreempted(B, false))
+    // MIPS has special rules to fill up GOT entries.
+    // As the first approach, we can store addresses for symbols
+    // which have them.
+    if (Config->EMachine != EM_MIPS && canBePreempted(B, false))
       continue; // The dynamic linker will take care of it.
     uintX_t VA = getSymVA<ELFT>(*B);
     write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
Index: ELF/SymbolTable.h
===================================================================
--- ELF/SymbolTable.h
+++ ELF/SymbolTable.h
@@ -50,6 +50,8 @@
 
   SymbolBody *addUndefined(StringRef Name);
   SymbolBody *addUndefinedOpt(StringRef Name);
+  void addAbsoluteSym(StringRef Name,
+                      typename llvm::object::ELFFile<ELFT>::Elf_Sym &ESym);
   void addSyntheticSym(StringRef Name, OutputSectionBase<ELFT> &Section,
                        typename llvm::object::ELFFile<ELFT>::uintX_t Value);
   void addIgnoredSym(StringRef Name);
Index: ELF/SymbolTable.cpp
===================================================================
--- ELF/SymbolTable.cpp
+++ ELF/SymbolTable.cpp
@@ -71,6 +71,12 @@
 }
 
 template <class ELFT>
+void SymbolTable<ELFT>::addAbsoluteSym(StringRef Name,
+                                       typename ELFFile<ELFT>::Elf_Sym &ESym) {
+  resolve(new (Alloc) DefinedAbsolute<ELFT>(Name, ESym));
+}
+
+template <class ELFT>
 void SymbolTable<ELFT>::addSyntheticSym(StringRef Name,
                                         OutputSectionBase<ELFT> &Section,
                                         typename ELFFile<ELFT>::uintX_t Value) {
Index: ELF/Symbols.h
===================================================================
--- ELF/Symbols.h
+++ ELF/Symbols.h
@@ -177,6 +177,11 @@
 public:
   static Elf_Sym IgnoreUndef;
 
+  // The content for _gp symbol for MIPS target.
+  // The symbol has to be added early to reserve a place in symbol tables.
+  // The value of the symbol is computed later by Writer.
+  static Elf_Sym MipsGp;
+
   DefinedAbsolute(StringRef N, const Elf_Sym &Sym)
       : Defined<ELFT>(Base::DefinedAbsoluteKind, N, Sym) {}
 
@@ -188,6 +193,9 @@
 template <class ELFT>
 typename DefinedAbsolute<ELFT>::Elf_Sym DefinedAbsolute<ELFT>::IgnoreUndef;
 
+template <class ELFT>
+typename DefinedAbsolute<ELFT>::Elf_Sym DefinedAbsolute<ELFT>::MipsGp;
+
 template <class ELFT> class DefinedCommon : public Defined<ELFT> {
   typedef ELFSymbolBody<ELFT> Base;
   typedef typename Base::Elf_Sym Elf_Sym;
Index: ELF/Target.h
===================================================================
--- ELF/Target.h
+++ ELF/Target.h
@@ -11,6 +11,7 @@
 #define LLD_ELF_TARGET_H
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
 
 #include <memory>
 
@@ -31,7 +32,9 @@
   unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; }
   unsigned getPltEntrySize() const { return PltEntrySize; }
   bool supportsLazyRelocations() const { return LazyRelocations; }
+  unsigned getGotHeaderEntriesNum() const { return GotHeaderEntriesNum; }
   virtual unsigned getPLTRefReloc(unsigned Type) const;
+  virtual void writeGotHeaderEntries(uint8_t *Buf) const;
   virtual void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const = 0;
   virtual void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
                                  uint64_t PltEntryAddr) const = 0;
@@ -66,11 +69,15 @@
   unsigned RelativeReloc;
   unsigned PltEntrySize = 8;
   unsigned PltZeroEntrySize = 0;
+  unsigned GotHeaderEntriesNum = 0;
   bool LazyRelocations = false;
 };
 
 uint64_t getPPC64TocBase();
 
+template <class ELFT>
+typename llvm::object::ELFFile<ELFT>::uintX_t getMipsGpAddr();
+
 extern std::unique_ptr<TargetInfo> Target;
 TargetInfo *createTarget();
 }
Index: ELF/Target.cpp
===================================================================
--- ELF/Target.cpp
+++ ELF/Target.cpp
@@ -35,6 +35,14 @@
 
 std::unique_ptr<TargetInfo> Target;
 
+template <bool IsLE> static uint32_t read32(const uint8_t *L);
+template <> uint32_t read32<true>(const uint8_t *L) { return read32le(L); }
+template <> uint32_t read32<false>(const uint8_t *L) { return read32be(L); }
+
+template <bool IsLE> static void write32(uint8_t *L, uint32_t V);
+template <> void write32<true>(uint8_t *L, uint32_t V) { write32le(L, V); }
+template <> void write32<false>(uint8_t *L, uint32_t V) { write32be(L, V); }
+
 static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); }
 static void add32be(uint8_t *L, int32_t V) { write32be(L, read32be(L) + V); }
 static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); }
@@ -108,6 +116,7 @@
 template <class ELFT> class MipsTargetInfo final : public TargetInfo {
 public:
   MipsTargetInfo();
+  void writeGotHeaderEntries(uint8_t *Buf) const override;
   void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
   void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
                          uint64_t PltEntryAddr) const override;
@@ -155,6 +164,8 @@
 
 bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
 
+void TargetInfo::writeGotHeaderEntries(uint8_t *Buf) const {}
+
 X86TargetInfo::X86TargetInfo() {
   PCRelReloc = R_386_PC32;
   GotReloc = R_386_GLOB_DAT;
@@ -670,6 +681,16 @@
 
 template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
   PageSize = 65536;
+  GotRefReloc = R_MIPS_GOT16;
+  GotHeaderEntriesNum = 2;
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::writeGotHeaderEntries(uint8_t *Buf) const {
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Off Elf_Off;
+  auto *P = reinterpret_cast<Elf_Off *>(Buf);
+  // Module pointer
+  P[1] = ELFT::Is64Bits ? 0x8000000000000000 : 0x80000000;
 }
 
 template <class ELFT>
@@ -684,7 +705,7 @@
 template <class ELFT>
 bool MipsTargetInfo<ELFT>::relocNeedsGot(uint32_t Type,
                                          const SymbolBody &S) const {
-  return false;
+  return Type == R_MIPS_GOT16;
 }
 
 template <class ELFT>
@@ -702,9 +723,27 @@
   case R_MIPS_32:
     add32<IsLE>(Loc, SA);
     break;
+  case R_MIPS_GOT16: {
+    int64_t V = SA - getMipsGpAddr<ELFT>();
+    if (!isInt<16>(V))
+      error("Relocation R_MIPS_GOT16 out of range");
+    write32<IsLE>(Loc, (read32<IsLE>(Loc) & 0xffff0000) | (V & 0xffff));
+    break;
+  }
   default:
     error("unrecognized reloc " + Twine(Type));
   }
 }
+
+template <class ELFT>
+typename llvm::object::ELFFile<ELFT>::uintX_t getMipsGpAddr() {
+  const unsigned GPOffset = 0x7ff0;
+  return Out<ELFT>::Got->getVA() ? (Out<ELFT>::Got->getVA() + GPOffset) : 0;
+}
+
+template uint32_t getMipsGpAddr<ELF32LE>();
+template uint32_t getMipsGpAddr<ELF32BE>();
+template uint64_t getMipsGpAddr<ELF64LE>();
+template uint64_t getMipsGpAddr<ELF64BE>();
 }
 }
Index: ELF/Writer.cpp
===================================================================
--- ELF/Writer.cpp
+++ ELF/Writer.cpp
@@ -225,6 +225,12 @@
       }
     }
 
+    if (Config->EMachine == EM_MIPS && NeedsGot) {
+      // MIPS ABI has special rules to process GOT entries
+      // and doesn't require relocation entries for them.
+      Body->setUsedInDynamicReloc();
+      continue;
+    }
     bool CBP = canBePreempted(Body, NeedsGot);
     if (!CBP && (!Config->Shared || Target->isRelRelative(Type)))
       continue;
@@ -762,6 +768,10 @@
   // Add space for section headers.
   SectionHeaderOff = RoundUpToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
   FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr);
+
+  // Update MIPS _gp absolute symbol so that it points to the static data.
+  if (Config->EMachine == EM_MIPS)
+    DefinedAbsolute<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>();
 }
 
 // Returns the number of PHDR entries.
Index: test/elf2/basic-mips.s
===================================================================
--- test/elf2/basic-mips.s
+++ test/elf2/basic-mips.s
@@ -27,7 +27,7 @@
 # CHECK-NEXT:   Version: 1
 # CHECK-NEXT:   Entry: 0x20000
 # CHECK-NEXT:   ProgramHeaderOffset: 0x34
-# CHECK-NEXT:   SectionHeaderOffset: 0x20070
+# CHECK-NEXT:   SectionHeaderOffset: 0x20084
 # CHECK-NEXT:   Flags [ (0x0)
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   HeaderSize: 52
@@ -138,7 +138,7 @@
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
 # CHECK-NEXT:     Offset: 0x20000
-# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Size: 48
 # CHECK-NEXT:     Link: 8
 # CHECK-NEXT:     Info: 1
 # CHECK-NEXT:     AddressAlignment: 4
@@ -151,7 +151,7 @@
 # CHECK-NEXT:     Flags [ (0x0)
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
-# CHECK-NEXT:     Offset: 0x20020
+# CHECK-NEXT:     Offset: 0x20030
 # CHECK-NEXT:     Size: 68
 # CHECK-NEXT:     Link: 0
 # CHECK-NEXT:     Info: 0
@@ -165,8 +165,8 @@
 # CHECK-NEXT:     Flags [ (0x0)
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
-# CHECK-NEXT:     Offset: 0x20064
-# CHECK-NEXT:     Size: 9
+# CHECK-NEXT:     Offset: 0x20074
+# CHECK-NEXT:     Size: 13
 # CHECK-NEXT:     Link: 0
 # CHECK-NEXT:     Info: 0
 # CHECK-NEXT:     AddressAlignment: 1
@@ -184,6 +184,15 @@
 # CHECK-NEXT:     Section: Undefined (0x0)
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _gp
+# 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: Absolute (0xFFF1)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
 # CHECK-NEXT:     Name: __start
 # CHECK-NEXT:     Value: 0x20000
 # CHECK-NEXT:     Size: 0
Index: test/elf2/mips-got-relocs.s
===================================================================
--- /dev/null
+++ test/elf2/mips-got-relocs.s
@@ -0,0 +1,99 @@
+# Check R_MIPS_GOT16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld2 %t-be.o -o %t-be.exe
+# RUN: llvm-objdump -section-headers -t %t-be.exe | FileCheck -check-prefix=EXE_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-be.exe | FileCheck -check-prefix=EXE_GOT_BE %s
+# RUN: llvm-objdump -d %t-be.exe | FileCheck -check-prefix=EXE_DIS_BE %s
+# RUN: llvm-readobj -relocations %t-be.exe | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-be.exe | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld2 %t-el.o -o %t-el.exe
+# RUN: llvm-objdump -section-headers -t %t-el.exe | FileCheck -check-prefix=EXE_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-el.exe | FileCheck -check-prefix=EXE_GOT_EL %s
+# RUN: llvm-objdump -d %t-el.exe | FileCheck -check-prefix=EXE_DIS_EL %s
+# RUN: llvm-readobj -relocations %t-el.exe | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-el.exe | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: ld.lld2 -shared %t-be.o -o %t-be.so
+# RUN: llvm-objdump -section-headers -t %t-be.so | FileCheck -check-prefix=DSO_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-be.so | FileCheck -check-prefix=DSO_GOT_BE %s
+# RUN: llvm-objdump -d %t-be.so | FileCheck -check-prefix=DSO_DIS_BE %s
+# RUN: llvm-readobj -relocations %t-be.so | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-be.so | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: ld.lld2 -shared %t-el.o -o %t-el.so
+# RUN: llvm-objdump -section-headers -t %t-el.so | FileCheck -check-prefix=DSO_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-el.so | FileCheck -check-prefix=DSO_GOT_EL %s
+# RUN: llvm-objdump -d %t-el.so | FileCheck -check-prefix=DSO_DIS_EL %s
+# RUN: llvm-readobj -relocations %t-el.so | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-el.so | FileCheck -check-prefix=SHFLAGS %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui $2, %got(v1)
+
+  .data
+  .globl v1
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .word 0
+
+# EXE_SYM: Sections:
+# EXE_SYM: .got 0000000c 0000000000030004 DATA
+# EXE_SYM: SYMBOL TABLE:
+# EXE_SYM: 00037ff4         *ABS*		 00000000 _gp
+#          ^-- .got + GP offset (0x7ff0)
+# EXE_SYM: 00030000 g       .data		 00000004 v1
+
+# EXE_GOT_BE: Contents of section .got:
+# EXE_GOT_BE:  30004 00000000 80000000 00030000
+#                    ^        ^        ^-- v1 (0x30000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# EXE_GOT_EL: Contents of section .got:
+# EXE_GOT_EL:  30004 00000000 00000080 00000300
+#                    ^        ^        ^-- v1 (0x30000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# v1GotAddr (0x3000c) - _gp (0x37ff4) = -0x7fe8 => 0x8018 = 32792
+# EXE_DIS_BE:  20000:  3c 02 80 18  lui $2, 32792
+# EXE_DIS_EL:  20000:  18 80 02 3c  lui $2, 32792
+
+# DSO_SYM: Sections:
+# DSO_SYM: .got 0000000c 0000000000020034 DATA
+# DSO_SYM: SYMBOL TABLE:
+# DSO_SYM: 00028024         *ABS*		 00000000 _gp
+#          ^-- .got + GP offset (0x7ff0)
+# DSO_SYM: 00020000 g       .data		 00000004 v1
+
+# DSO_GOT_BE: Contents of section .got:
+# DSO_GOT_BE:  20034 00000000 80000000 00020000
+#                    ^        ^        ^-- v1 (0x20000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# DSO_GOT_EL: Contents of section .got:
+# DSO_GOT_EL:  20034 00000000 00000080 00000200
+#                    ^        ^        ^-- v1 (0x20000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# v1GotAddr (0x2003c) - _gp (0x28024) = -0x7fe8 => 0x8018 = 32792
+# DSO_DIS_BE:  10000:  3c 02 80 18  lui $2, 32792
+# DSO_DIS_EL:  10000:  18 80 02 3c  lui $2, 32792
+
+# NORELOC:      Relocations [
+# NORELOC-NEXT: ]
+
+# SHFLAGS:      Name: .got
+# SHFLAGS-NEXT: Type: SHT_PROGBITS
+# SHFLAGS-NEXT: Flags [ (0x10000003)
+#                        ^-- SHF_MIPS_GPREL | SHF_ALLOC | SHF_WRITE