Make it possible for the MCObjectWriter to decide if a given fixup is fully
[oota-llvm.git] / lib / MC / ELFObjectWriter.cpp
index 7960a07499a7ad5a9b0389e11be9612d0fb5f68a..94251d76b285edf8cdfca8e08bc0b3810f89259b 100644 (file)
@@ -43,6 +43,20 @@ static unsigned GetType(const MCSymbolData &SD) {
   return Type;
 }
 
+static unsigned GetBinding(const MCSymbolData &SD) {
+  uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift;
+  assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL ||
+         Binding == ELF::STB_WEAK);
+  return Binding;
+}
+
+static void SetBinding(MCSymbolData &SD, unsigned Binding) {
+  assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL ||
+         Binding == ELF::STB_WEAK);
+  uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift);
+  SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift));
+}
+
 namespace {
 
   class ELFObjectWriterImpl {
@@ -260,6 +274,11 @@ namespace {
     void WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F,
                                   const MCSectionData *SD);
 
+    bool IsFixupFullyResolved(const MCAssembler &Asm,
+                              const MCValue Target,
+                              bool IsPCRel,
+                              const MCFragment *DF) const;
+
     void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout);
   };
 
@@ -374,25 +393,33 @@ void ELFObjectWriterImpl::WriteSymbolEntry(MCDataFragment *F, uint64_t name,
   }
 }
 
+static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout) {
+  if (Data.isCommon() && Data.isExternal())
+    return Data.getCommonAlignment();
+
+  const MCSymbol &Symbol = Data.getSymbol();
+  if (!Symbol.isInSection())
+    return 0;
+
+  if (!Data.isCommon() && !(Data.getFlags() & ELF_STB_Weak))
+    if (MCFragment *FF = Data.getFragment())
+      return Layout.getSymbolAddress(&Data) -
+             Layout.getSectionAddress(FF->getParent());
+
+  return 0;
+}
+
 void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD,
                                       const MCAsmLayout &Layout) {
   MCSymbolData &Data = *MSD.SymbolData;
   uint8_t Info = (Data.getFlags() & 0xff);
   uint8_t Other = ((Data.getFlags() & 0xf00) >> ELF_STV_Shift);
-  uint64_t Value = 0;
+  uint64_t Value = SymbolValue(Data, Layout);
   uint64_t Size = 0;
   const MCExpr *ESize;
 
-  if (Data.isCommon() && Data.isExternal())
-    Value = Data.getCommonAlignment();
-
   assert(!(Data.isCommon() && !Data.isExternal()));
 
-  if (!Data.isCommon() && !(Data.getFlags() & ELF_STB_Weak))
-    if (MCFragment *FF = Data.getFragment())
-      Value = Layout.getSymbolAddress(&Data) -
-              Layout.getSectionAddress(FF->getParent());
-
   ESize = Data.getSize();
   if (Data.getSize()) {
     MCValue Res;
@@ -460,20 +487,26 @@ void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F,
     assert((Data.getFlags() & ELF_STB_Global) &&
            "External symbol requires STB_GLOBAL flag");
     WriteSymbol(F, MSD, Layout);
-    if ((Data.getFlags() & (0xf << ELF_STB_Shift)) == ELF_STB_Local)
+    if (GetBinding(Data) == ELF::STB_LOCAL)
       LastLocalSymbolIndex++;
   }
 
   for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) {
     ELFSymbolData &MSD = UndefinedSymbolData[i];
     MCSymbolData &Data = *MSD.SymbolData;
-    Data.setFlags(Data.getFlags() | ELF_STB_Global);
     WriteSymbol(F, MSD, Layout);
-    if ((Data.getFlags() & (0xf << ELF_STB_Shift)) == ELF_STB_Local)
+    if (GetBinding(Data) == ELF::STB_LOCAL)
       LastLocalSymbolIndex++;
   }
 }
 
+static const MCSymbolData *getAtom(const MCSymbolData &SD) {
+  if (!SD.getFragment())
+    return 0;
+
+  return SD.getFragment()->getAtom();
+}
+
 // FIXME: this is currently X86/X86_64 only
 void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm,
                                            const MCAsmLayout &Layout,
@@ -489,7 +522,7 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm,
   if (!Target.isAbsolute()) {
     const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
     MCSymbolData &SD = Asm.getSymbolData(*Symbol);
-    const MCSymbolData *Base = Asm.getAtom(Layout, &SD);
+    const MCSymbolData *Base = getAtom(SD);
     MCFragment *F = SD.getFragment();
 
     // Avoid relocations for cases like jumps and calls in the same file.
@@ -502,13 +535,14 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm,
     }
 
     if (Base) {
-      if (F && !SD.isExternal()) {
+      if (Base != &SD) {
         Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1;
-        Value += Layout.getSymbolAddress(&SD);
+
+        MCSectionData *FSD = F->getParent();
+        // Offset of the symbol in the section
+        Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD);
       } else
         Index = getSymbolIndexInSymbolTable(Asm, Symbol);
-      if (Base != &SD)
-        Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base);
       Addend = Value;
       // Compensate for the addend on i386.
       if (Is64Bit)
@@ -521,11 +555,14 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm,
 
         MCSectionData *FSD = F->getParent();
         // Offset of the symbol in the section
-        Addend = Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD);
+        Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD);
       } else {
-        FixedValue = Value;
-        return;
+        Index = getSymbolIndexInSymbolTable(Asm, Symbol);
       }
+      Addend = Value;
+      // Compensate for the addend on i386.
+      if (Is64Bit)
+        Value = 0;
     }
   }
 
@@ -657,12 +694,15 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) {
     const MCSymbol &Symbol = it->getSymbol();
 
     // Ignore non-linker visible symbols.
-    if (!Asm.isSymbolLinkerVisible(Symbol))
+    if (!Asm.isSymbolLinkerVisible(Symbol) && !Symbol.isUndefined())
       continue;
 
     if (!it->isExternal() && !Symbol.isUndefined())
       continue;
 
+    if (Symbol.isVariable())
+      continue;
+
     uint64_t &Entry = StringIndexMap[Symbol.getName()];
     if (!Entry) {
       Entry = StringTable.size();
@@ -679,8 +719,10 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) {
       ExternalSymbolData.push_back(MSD);
     } else if (Symbol.isUndefined()) {
       MSD.SectionIndex = ELF::SHN_UNDEF;
-      // XXX: for some reason we dont Emit* this
-      it->setFlags(it->getFlags() | ELF_STB_Global);
+      // FIXME: Undefined symbols are global, but this is the first place we
+      // are able to set it.
+      if (GetBinding(*it) == ELF::STB_LOCAL)
+        SetBinding(*it, ELF::STB_GLOBAL);
       UndefinedSymbolData.push_back(MSD);
     } else if (Symbol.isAbsolute()) {
       MSD.SectionIndex = ELF::SHN_ABS;
@@ -738,7 +780,7 @@ void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout,
 
     WriteRelocationsFragment(Asm, F, &SD);
 
-    Asm.AddSectionToTheEnd(RelaSD, Layout);
+    Asm.AddSectionToTheEnd(*Writer, RelaSD, Layout);
   }
 }
 
@@ -805,8 +847,6 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm,
   MCContext &Ctx = Asm.getContext();
   MCDataFragment *F;
 
-  WriteRelocations(Asm, Layout);
-
   const MCSection *SymtabSection;
   unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32;
 
@@ -833,15 +873,16 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm,
   StrtabSD.setAlignment(1);
   StringTableIndex = Asm.size();
 
+  WriteRelocations(Asm, Layout);
 
   // Symbol table
   F = new MCDataFragment(&SymtabSD);
   WriteSymbolTable(F, Asm, Layout, NumRegularSections);
-  Asm.AddSectionToTheEnd(SymtabSD, Layout);
+  Asm.AddSectionToTheEnd(*Writer, SymtabSD, Layout);
 
   F = new MCDataFragment(&StrtabSD);
   F->getContents().append(StringTable.begin(), StringTable.end());
-  Asm.AddSectionToTheEnd(StrtabSD, Layout);
+  Asm.AddSectionToTheEnd(*Writer, StrtabSD, Layout);
 
   F = new MCDataFragment(&ShstrtabSD);
 
@@ -867,7 +908,41 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm,
     F->getContents() += '\x00';
   }
 
-  Asm.AddSectionToTheEnd(ShstrtabSD, Layout);
+  Asm.AddSectionToTheEnd(*Writer, ShstrtabSD, Layout);
+}
+
+bool ELFObjectWriterImpl::IsFixupFullyResolved(const MCAssembler &Asm,
+                                               const MCValue Target,
+                                               bool IsPCRel,
+                                               const MCFragment *DF) const {
+  // If this is a PCrel relocation, find the section this fixup value is
+  // relative to.
+  const MCSection *BaseSection = 0;
+  if (IsPCRel) {
+    BaseSection = &DF->getParent()->getSection();
+    assert(BaseSection);
+  }
+
+  const MCSection *SectionA = 0;
+  const MCSymbol *SymbolA = 0;
+  if (const MCSymbolRefExpr *A = Target.getSymA()) {
+    SymbolA = &A->getSymbol();
+    SectionA = &SymbolA->getSection();
+  }
+
+  const MCSection *SectionB = 0;
+  if (const MCSymbolRefExpr *B = Target.getSymB()) {
+    SectionB = &B->getSymbol().getSection();
+  }
+
+  if (!BaseSection)
+    return SectionA == SectionB;
+
+  const MCSymbolData &DataA = Asm.getSymbolData(*SymbolA);
+  if (DataA.isExternal())
+    return false;
+
+  return !SectionB && BaseSection == SectionA;
 }
 
 void ELFObjectWriterImpl::WriteObject(const MCAssembler &Asm,
@@ -1028,6 +1103,14 @@ void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm,
                                                   Target, FixedValue);
 }
 
+bool ELFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm,
+                                           const MCValue Target,
+                                           bool IsPCRel,
+                                           const MCFragment *DF) const {
+  return ((ELFObjectWriterImpl*) Impl)->IsFixupFullyResolved(Asm, Target,
+                                                             IsPCRel, DF);
+}
+
 void ELFObjectWriter::WriteObject(const MCAssembler &Asm,
                                   const MCAsmLayout &Layout) {
   ((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout);