ARM Fixups relative to thumb functions need to have the low bit of the value
[oota-llvm.git] / lib / MC / MCAssembler.cpp
index 323352ff8b790ed6959b3524f27cff7f524ff819..5bc477d7bccf73c30c196f699ef4169025a90475 100644 (file)
@@ -235,12 +235,15 @@ bool MCAssembler::EvaluateFixup(const MCObjectWriter &Writer,
   bool IsPCRel = Emitter.getFixupKindInfo(
     Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel;
   bool IsResolved = true;
+  bool IsThumb = false;
   if (const MCSymbolRefExpr *A = Target.getSymA()) {
     const MCSymbol &Sym = A->getSymbol().AliasedSymbol();
     if (Sym.isDefined())
       Value += Layout.getSymbolOffset(&getSymbolData(Sym));
     else
       IsResolved = false;
+    if (isThumbFunc(&Sym))
+      IsThumb = true;
   }
   if (const MCSymbolRefExpr *B = Target.getSymB()) {
     const MCSymbol &Sym = B->getSymbol().AliasedSymbol();
@@ -253,8 +256,22 @@ bool MCAssembler::EvaluateFixup(const MCObjectWriter &Writer,
   if (IsResolved)
     IsResolved = Writer.IsFixupFullyResolved(*this, Target, IsPCRel, DF);
 
-  if (IsPCRel)
-    Value -= Layout.getFragmentOffset(DF) + Fixup.getOffset();
+  if (IsPCRel) {
+    bool ShouldAlignPC = Emitter.getFixupKindInfo(
+                        Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsAligned;
+    // PC should be aligned to a 4-byte value.
+    if (ShouldAlignPC)
+      Value -= Layout.getFragmentOffset(DF) + (Fixup.getOffset() & ~0x3);
+    else
+      Value -= Layout.getFragmentOffset(DF) + Fixup.getOffset();
+  }
+
+  // ARM fixups based from a thumb function address need to have the low
+  // bit set. The actual value is always at least 16-bit aligned, so the
+  // low bit is normally clear and available for use as an ISA flag for
+  // interworking.
+  if (IsThumb)
+    Value |= 1;
 
   return IsResolved;
 }