COFF: ARM: Implement MOV32T relocation.

llvm-svn: 243201
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index b7d0dd1..55a3646 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -48,6 +48,7 @@
 static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
 static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
 static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
+static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
 
 void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, uint64_t S,
                                uint64_t P) {
@@ -82,6 +83,26 @@
   }
 }
 
+static void applyMOV32T(uint8_t *Off, uint32_t V) {
+  uint16_t X = V;
+  or16(Off, ((X & 0x800) >> 1) | ((X >> 12) & 0xf));
+  or16(Off + 2, ((X & 0x700) << 4) | (X & 0xff));
+  X = V >> 16;
+  or16(Off + 4, ((X & 0x800) >> 1) | ((X >> 12) & 0xf));
+  or16(Off + 6, ((X & 0x700) << 4) | (X & 0xff));
+}
+
+void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, uint64_t S,
+                               uint64_t P) {
+  switch (Type) {
+  case IMAGE_REL_ARM_ADDR32:   add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break;
+  case IMAGE_REL_ARM_MOV32T:   applyMOV32T(Off, S + Config->ImageBase); break;
+  default:
+    llvm::report_fatal_error("Unsupported relocation type");
+  }
+}
+
 void SectionChunk::writeTo(uint8_t *Buf) {
   if (!hasData())
     return;
@@ -102,6 +123,9 @@
     case IMAGE_FILE_MACHINE_I386:
       applyRelX86(Off, Rel.Type, S, P);
       break;
+    case IMAGE_FILE_MACHINE_ARMNT:
+      applyRelARM(Off, Rel.Type, S, P);
+      break;
     default:
       llvm_unreachable("unknown machine type");
     }
@@ -125,6 +149,12 @@
     if (Rel.Type == IMAGE_REL_I386_DIR32)
       return IMAGE_REL_BASED_HIGHLOW;
     return IMAGE_REL_BASED_ABSOLUTE;
+  case IMAGE_FILE_MACHINE_ARMNT:
+    if (Rel.Type == IMAGE_REL_ARM_ADDR32)
+      return IMAGE_REL_BASED_HIGHLOW;
+    if (Rel.Type == IMAGE_REL_ARM_MOV32T)
+      return IMAGE_REL_BASED_ARM_MOV32T;
+    return IMAGE_REL_BASED_ABSOLUTE;
   default:
     llvm_unreachable("unknown machine type");
   }