コード例 #1
0
ファイル: WinCOFFObjectWriter.cpp プロジェクト: arsenm/llvm
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm,
                                           const MCAsmLayout &Layout,
                                           const MCFragment *Fragment,
                                           const MCFixup &Fixup,
                                           MCValue Target,
                                           bool &IsPCRel,
                                           uint64_t &FixedValue) {
  assert(Target.getSymA() && "Relocation must reference a symbol!");

  const MCSymbol &Symbol = Target.getSymA()->getSymbol();
  const MCSymbol &A = Symbol.AliasedSymbol();
  if (!Asm.hasSymbolData(A))
    Asm.getContext().FatalError(
        Fixup.getLoc(),
        Twine("symbol '") + A.getName() + "' can not be undefined");

  MCSymbolData &A_SD = Asm.getSymbolData(A);

  MCSectionData const *SectionData = Fragment->getParent();

  // Mark this symbol as requiring an entry in the symbol table.
  assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() &&
         "Section must already have been defined in ExecutePostLayoutBinding!");
  assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() &&
         "Symbol must already have been defined in ExecutePostLayoutBinding!");

  COFFSection *coff_section = SectionMap[&SectionData->getSection()];
  COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()];
  const MCSymbolRefExpr *SymB = Target.getSymB();
  bool CrossSection = false;

  if (SymB) {
    const MCSymbol *B = &SymB->getSymbol();
    MCSymbolData &B_SD = Asm.getSymbolData(*B);
    if (!B_SD.getFragment())
      Asm.getContext().FatalError(
          Fixup.getLoc(),
          Twine("symbol '") + B->getName() +
              "' can not be undefined in a subtraction expression");

    if (!A_SD.getFragment())
      Asm.getContext().FatalError(
          Fixup.getLoc(),
          Twine("symbol '") + Symbol.getName() +
              "' can not be undefined in a subtraction expression");

    CrossSection = &Symbol.getSection() != &B->getSection();

    // Offset of the symbol in the section
    int64_t a = Layout.getSymbolOffset(&B_SD);

    // Ofeset of the relocation in the section
    int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();

    FixedValue = b - a;
    // In the case where we have SymbA and SymB, we just need to store the delta
    // between the two symbols.  Update FixedValue to account for the delta, and
    // skip recording the relocation.
    if (!CrossSection)
      return;
  } else {
    FixedValue = Target.getConstant();
  }

  COFFRelocation Reloc;

  Reloc.Data.SymbolTableIndex = 0;
  Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment);

  // Turn relocations for temporary symbols into section relocations.
  if (coff_symbol->MCData->getSymbol().isTemporary() || CrossSection) {
    Reloc.Symb = coff_symbol->Section->Symbol;
    FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment)
                + coff_symbol->MCData->getOffset();
  } else
    Reloc.Symb = coff_symbol;

  ++Reloc.Symb->Relocations;

  Reloc.Data.VirtualAddress += Fixup.getOffset();
  Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup,
                                                     CrossSection);

  // FIXME: Can anyone explain what this does other than adjust for the size
  // of the offset?
  if ((Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 &&
       Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32) ||
      (Header.Machine == COFF::IMAGE_FILE_MACHINE_I386 &&
       Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32))
    FixedValue += 4;

  coff_section->Relocations.push_back(Reloc);
}
コード例 #2
0
bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout,
                                const MCFixup &Fixup, const MCFragment *DF,
                                MCValue &Target, uint64_t &Value) const {
  ++stats::evaluateFixup;

  if (!Fixup.getValue()->EvaluateAsRelocatable(Target, Layout))
    getContext().FatalError(Fixup.getLoc(), "expected relocatable expression");

  bool IsPCRel = Backend.getFixupKindInfo(
    Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel;

  bool IsResolved;
  if (IsPCRel) {
    if (Target.getSymB()) {
      IsResolved = false;
    } else if (!Target.getSymA()) {
      IsResolved = false;
    } else {
      const MCSymbolRefExpr *A = Target.getSymA();
      const MCSymbol &SA = A->getSymbol();
      if (A->getKind() != MCSymbolRefExpr::VK_None ||
          SA.AliasedSymbol().isUndefined()) {
        IsResolved = false;
      } else {
        const MCSymbolData &DataA = getSymbolData(SA);
        IsResolved =
          getWriter().IsSymbolRefDifferenceFullyResolvedImpl(*this, DataA,
                                                             *DF, false, true);
      }
    }
  } else {
    IsResolved = Target.isAbsolute();
  }

  Value = Target.getConstant();

  if (const MCSymbolRefExpr *A = Target.getSymA()) {
    const MCSymbol &Sym = A->getSymbol().AliasedSymbol();
    if (Sym.isDefined())
      Value += Layout.getSymbolOffset(&getSymbolData(Sym));
  }
  if (const MCSymbolRefExpr *B = Target.getSymB()) {
    const MCSymbol &Sym = B->getSymbol().AliasedSymbol();
    if (Sym.isDefined())
      Value -= Layout.getSymbolOffset(&getSymbolData(Sym));
  }


  bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
                         MCFixupKindInfo::FKF_IsAlignedDownTo32Bits;
  assert((ShouldAlignPC ? IsPCRel : true) &&
    "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!");

  if (IsPCRel) {
    uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset();

    // A number of ARM fixups in Thumb mode require that the effective PC
    // address be determined as the 32-bit aligned version of the actual offset.
    if (ShouldAlignPC) Offset &= ~0x3;
    Value -= Offset;
  }

  // Let the backend adjust the fixup value if necessary, including whether
  // we need a relocation.
  Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value,
                            IsResolved);

  return IsResolved;
}
コード例 #3
0
ファイル: MCAssembler.cpp プロジェクト: davidlt/root
bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout,
                                const MCFixup &Fixup, const MCFragment *DF,
                                MCValue &Target, uint64_t &Value) const {
  ++stats::evaluateFixup;

  // FIXME: This code has some duplication with recordRelocation. We should
  // probably merge the two into a single callback that tries to evaluate a
  // fixup and records a relocation if one is needed.
  const MCExpr *Expr = Fixup.getValue();
  if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) {
    getContext().reportError(Fixup.getLoc(), "expected relocatable expression");
    // Claim to have completely evaluated the fixup, to prevent any further
    // processing from being done.
    Value = 0;
    return true;
  }

  bool IsPCRel = Backend.getFixupKindInfo(
    Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel;

  bool IsResolved;
  if (IsPCRel) {
    if (Target.getSymB()) {
      IsResolved = false;
    } else if (!Target.getSymA()) {
      IsResolved = false;
    } else {
      const MCSymbolRefExpr *A = Target.getSymA();
      const MCSymbol &SA = A->getSymbol();
      if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) {
        IsResolved = false;
      } else {
        IsResolved = getWriter().isSymbolRefDifferenceFullyResolvedImpl(
            *this, SA, *DF, false, true);
      }
    }
  } else {
    IsResolved = Target.isAbsolute();
  }

  Value = Target.getConstant();

  if (const MCSymbolRefExpr *A = Target.getSymA()) {
    const MCSymbol &Sym = A->getSymbol();
    if (Sym.isDefined())
      Value += Layout.getSymbolOffset(Sym);
  }
  if (const MCSymbolRefExpr *B = Target.getSymB()) {
    const MCSymbol &Sym = B->getSymbol();
    if (Sym.isDefined())
      Value -= Layout.getSymbolOffset(Sym);
  }

  bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
                         MCFixupKindInfo::FKF_IsAlignedDownTo32Bits;
  assert((ShouldAlignPC ? IsPCRel : true) &&
    "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!");

  if (IsPCRel) {
    uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset();

    // A number of ARM fixups in Thumb mode require that the effective PC
    // address be determined as the 32-bit aligned version of the actual offset.
    if (ShouldAlignPC) Offset &= ~0x3;
    Value -= Offset;
  }

  // Let the backend adjust the fixup value if necessary, including whether
  // we need a relocation.
  Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value,
                            IsResolved);

  return IsResolved;
}
コード例 #4
0
bool X86MachObjectWriter::recordScatteredRelocation(MachObjectWriter *Writer,
                                                    const MCAssembler &Asm,
                                                    const MCAsmLayout &Layout,
                                                    const MCFragment *Fragment,
                                                    const MCFixup &Fixup,
                                                    MCValue Target,
                                                    unsigned Log2Size,
                                                    uint64_t &FixedValue) {
  uint64_t OriginalFixedValue = FixedValue;
  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  unsigned Type = MachO::GENERIC_RELOC_VANILLA;

  // See <reloc.h>.
  const MCSymbol *A = &Target.getSymA()->getSymbol();

  if (!A->getFragment()) {
    Asm.getContext().reportError(
        Fixup.getLoc(),
        "symbol '" + A->getName() +
            "' can not be undefined in a subtraction expression");
    return false;
  }

  uint32_t Value = Writer->getSymbolAddress(*A, Layout);
  uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
  FixedValue += SecAddr;
  uint32_t Value2 = 0;

  if (const MCSymbolRefExpr *B = Target.getSymB()) {
    const MCSymbol *SB = &B->getSymbol();

    if (!SB->getFragment()) {
      Asm.getContext().reportError(
          Fixup.getLoc(),
          "symbol '" + SB->getName() +
              "' can not be undefined in a subtraction expression");
      return false;
    }

    // Select the appropriate difference relocation type.
    //
    // Note that there is no longer any semantic difference between these two
    // relocation types from the linkers point of view, this is done solely for
    // pedantic compatibility with 'as'.
    Type = A->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF
                           : (unsigned)MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
    Value2 = Writer->getSymbolAddress(*SB, Layout);
    FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
  }

  // Relocations are written out in reverse order, so the PAIR comes first.
  if (Type == MachO::GENERIC_RELOC_SECTDIFF ||
      Type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
    // If the offset is too large to fit in a scattered relocation,
    // we're hosed. It's an unfortunate limitation of the MachO format.
    if (FixupOffset > 0xffffff) {
      char Buffer[32];
      format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
      Asm.getContext().reportError(Fixup.getLoc(),
                         Twine("Section too large, can't encode "
                                "r_address (") + Buffer +
                         ") into 24 bits of scattered "
                         "relocation entry.");
      return false;
    }

    MachO::any_relocation_info MRE;
    MRE.r_word0 = ((0                         <<  0) | // r_address
                   (MachO::GENERIC_RELOC_PAIR << 24) | // r_type
                   (Log2Size                  << 28) |
                   (IsPCRel                   << 30) |
                   MachO::R_SCATTERED);
    MRE.r_word1 = Value2;
    Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  } else {
    // If the offset is more than 24-bits, it won't fit in a scattered
    // relocation offset field, so we fall back to using a non-scattered
    // relocation. This is a bit risky, as if the offset reaches out of
    // the block and the linker is doing scattered loading on this
    // symbol, things can go badly.
    //
    // Required for 'as' compatibility.
    if (FixupOffset > 0xffffff) {
      FixedValue = OriginalFixedValue;
      return false;
    }
  }

  MachO::any_relocation_info MRE;
  MRE.r_word0 = ((FixupOffset <<  0) |
                 (Type        << 24) |
                 (Log2Size    << 28) |
                 (IsPCRel     << 30) |
                 MachO::R_SCATTERED);
  MRE.r_word1 = Value;
  Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  return true;
}
コード例 #5
0
void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer,
                                              const MCAssembler &Asm,
                                              const MCAsmLayout &Layout,
                                              const MCFragment *Fragment,
                                              const MCFixup &Fixup,
                                              MCValue Target,
                                              uint64_t &FixedValue) {
  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());

  // If this is a 32-bit TLVP reloc it's handled a bit differently.
  if (Target.getSymA() &&
      Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) {
    recordTLVPRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
                         FixedValue);
    return;
  }

  // If this is a difference or a defined symbol plus an offset, then we need a
  // scattered relocation entry. Differences always require scattered
  // relocations.
  if (Target.getSymB()) {
    recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
                              Target, Log2Size, FixedValue);
    return;
  }

  // Get the symbol data, if any.
  const MCSymbol *A = nullptr;
  if (Target.getSymA())
    A = &Target.getSymA()->getSymbol();

  // If this is an internal relocation with an offset, it also needs a scattered
  // relocation entry.
  uint32_t Offset = Target.getConstant();
  if (IsPCRel)
    Offset += 1 << Log2Size;
  // Try to record the scattered relocation if needed. Fall back to non
  // scattered if necessary (see comments in recordScatteredRelocation()
  // for details).
  if (Offset && A && !Writer->doesSymbolRequireExternRelocation(*A) &&
      recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
                                Log2Size, FixedValue))
    return;

  // See <reloc.h>.
  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  unsigned Index = 0;
  unsigned Type = 0;
  const MCSymbol *RelSymbol = nullptr;

  if (Target.isAbsolute()) { // constant
    // SymbolNum of 0 indicates the absolute section.
    //
    // FIXME: Currently, these are never generated (see code below). I cannot
    // find a case where they are actually emitted.
    Type = MachO::GENERIC_RELOC_VANILLA;
  } else {
    // Resolve constant variables.
    if (A->isVariable()) {
      int64_t Res;
      if (A->getVariableValue()->evaluateAsAbsolute(
              Res, Layout, Writer->getSectionAddressMap())) {
        FixedValue = Res;
        return;
      }
    }

    // Check whether we need an external or internal relocation.
    if (Writer->doesSymbolRequireExternRelocation(*A)) {
      RelSymbol = A;
      // For external relocations, make sure to offset the fixup value to
      // compensate for the addend of the symbol address, if it was
      // undefined. This occurs with weak definitions, for example.
      if (!A->isUndefined())
        FixedValue -= Layout.getSymbolOffset(*A);
    } else {
      // The index is the section ordinal (1-based).
      const MCSection &Sec = A->getSection();
      Index = Sec.getOrdinal() + 1;
      FixedValue += Writer->getSectionAddress(&Sec);
    }
    if (IsPCRel)
      FixedValue -= Writer->getSectionAddress(Fragment->getParent());

    Type = MachO::GENERIC_RELOC_VANILLA;
  }

  // struct relocation_info (8 bytes)
  MachO::any_relocation_info MRE;
  MRE.r_word0 = FixupOffset;
  MRE.r_word1 =
      (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
}
コード例 #6
0
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm,
                                           const MCAsmLayout &Layout,
                                           const MCFragment *Fragment,
                                           const MCFixup &Fixup,
                                           MCValue Target,
                                           uint64_t &FixedValue) {
  assert(Target.getSymA() != NULL && "Relocation must reference a symbol!");

  const MCSymbol *A = &Target.getSymA()->getSymbol();
  MCSymbolData &A_SD = Asm.getSymbolData(*A);

  MCSectionData const *SectionData = Fragment->getParent();

  // Mark this symbol as requiring an entry in the symbol table.
  assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() &&
         "Section must already have been defined in ExecutePostLayoutBinding!");
  assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() &&
         "Symbol must already have been defined in ExecutePostLayoutBinding!");

  COFFSection *coff_section = SectionMap[&SectionData->getSection()];
  COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()];

  if (Target.getSymB()) {
    if (&Target.getSymA()->getSymbol().getSection()
     != &Target.getSymB()->getSymbol().getSection()) {
      llvm_unreachable("Symbol relative relocations are only allowed between "
                       "symbols in the same section");
    }
    const MCSymbol *B = &Target.getSymB()->getSymbol();
    MCSymbolData &B_SD = Asm.getSymbolData(*B);

    FixedValue = Layout.getSymbolOffset(&A_SD) - Layout.getSymbolOffset(&B_SD);

    // In the case where we have SymbA and SymB, we just need to store the delta
    // between the two symbols.  Update FixedValue to account for the delta, and
    // skip recording the relocation.
    return;
  } else {
    FixedValue = Target.getConstant();
  }

  COFFRelocation Reloc;

  Reloc.Data.SymbolTableIndex = 0;
  Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment);

  // Turn relocations for temporary symbols into section relocations.
  if (coff_symbol->MCData->getSymbol().isTemporary()) {
    Reloc.Symb = coff_symbol->Section->Symbol;
    FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment)
                + coff_symbol->MCData->getOffset();
  } else
    Reloc.Symb = coff_symbol;

  ++Reloc.Symb->Relocations;

  Reloc.Data.VirtualAddress += Fixup.getOffset();

  switch ((unsigned)Fixup.getKind()) {
  case FK_PCRel_4:
  case X86::reloc_riprel_4byte:
  case X86::reloc_riprel_4byte_movq_load:
    Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32
                              : COFF::IMAGE_REL_I386_REL32;
    // FIXME: Can anyone explain what this does other than adjust for the size
    // of the offset?
    FixedValue += 4;
    break;
  case FK_Data_4:
  case X86::reloc_signed_4byte:
    Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32
                              : COFF::IMAGE_REL_I386_DIR32;
    break;
  case FK_Data_8:
    if (Is64Bit)
      Reloc.Data.Type = COFF::IMAGE_REL_AMD64_ADDR64;
    else
      llvm_unreachable("unsupported relocation type");
    break;
  default:
    llvm_unreachable("unsupported relocation type");
  }

  coff_section->Relocations.push_back(Reloc);
}
コード例 #7
0
void X86MachObjectWriter::RecordX86_64Relocation(
    MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
    const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
    uint64_t &FixedValue) {
  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
  unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());

  // See <reloc.h>.
  uint32_t FixupOffset =
    Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
  uint32_t FixupAddress =
    Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
  int64_t Value = 0;
  unsigned Index = 0;
  unsigned IsExtern = 0;
  unsigned Type = 0;
  const MCSymbol *RelSymbol = nullptr;

  Value = Target.getConstant();

  if (IsPCRel) {
    // Compensate for the relocation offset, Darwin x86_64 relocations only have
    // the addend and appear to have attempted to define it to be the actual
    // expression addend without the PCrel bias. However, instructions with data
    // following the relocation are not accommodated for (see comment below
    // regarding SIGNED{1,2,4}), so it isn't exactly that either.
    Value += 1LL << Log2Size;
  }

  if (Target.isAbsolute()) { // constant
    // SymbolNum of 0 indicates the absolute section.
    Type = MachO::X86_64_RELOC_UNSIGNED;

    // FIXME: I believe this is broken, I don't think the linker can understand
    // it. I think it would require a local relocation, but I'm not sure if that
    // would work either. The official way to get an absolute PCrel relocation
    // is to use an absolute symbol (which we don't support yet).
    if (IsPCRel) {
      IsExtern = 1;
      Type = MachO::X86_64_RELOC_BRANCH;
    }
  } else if (Target.getSymB()) { // A - B + constant
    const MCSymbol *A = &Target.getSymA()->getSymbol();
    if (A->isTemporary())
      A = &Writer->findAliasedSymbol(*A);
    const MCSymbol *A_Base = Asm.getAtom(*A);

    const MCSymbol *B = &Target.getSymB()->getSymbol();
    if (B->isTemporary())
      B = &Writer->findAliasedSymbol(*B);
    const MCSymbol *B_Base = Asm.getAtom(*B);

    // Neither symbol can be modified.
    if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None) {
      Asm.getContext().reportError(Fixup.getLoc(),
                                   "unsupported relocation of modified symbol");
      return;
    }

    // We don't support PCrel relocations of differences. Darwin 'as' doesn't
    // implement most of these correctly.
    if (IsPCRel) {
      Asm.getContext().reportError(
          Fixup.getLoc(), "unsupported pc-relative relocation of difference");
      return;
    }

    // The support for the situation where one or both of the symbols would
    // require a local relocation is handled just like if the symbols were
    // external.  This is certainly used in the case of debug sections where the
    // section has only temporary symbols and thus the symbols don't have base
    // symbols.  This is encoded using the section ordinal and non-extern
    // relocation entries.

    // Darwin 'as' doesn't emit correct relocations for this (it ends up with a
    // single SIGNED relocation); reject it for now.  Except the case where both
    // symbols don't have a base, equal but both NULL.
    if (A_Base == B_Base && A_Base) {
      Asm.getContext().reportError(
          Fixup.getLoc(), "unsupported relocation with identical base");
      return;
    }

    // A subtraction expression where either symbol is undefined is a
    // non-relocatable expression.
    if (A->isUndefined() || B->isUndefined()) {
      StringRef Name = A->isUndefined() ? A->getName() : B->getName();
      Asm.getContext().reportError(Fixup.getLoc(),
        "unsupported relocation with subtraction expression, symbol '" +
        Name + "' can not be undefined in a subtraction expression");
      return;
    }

    Value += Writer->getSymbolAddress(*A, Layout) -
             (!A_Base ? 0 : Writer->getSymbolAddress(*A_Base, Layout));
    Value -= Writer->getSymbolAddress(*B, Layout) -
             (!B_Base ? 0 : Writer->getSymbolAddress(*B_Base, Layout));

    if (!A_Base)
      Index = A->getFragment()->getParent()->getOrdinal() + 1;
    Type = MachO::X86_64_RELOC_UNSIGNED;

    MachO::any_relocation_info MRE;
    MRE.r_word0 = FixupOffset;
    MRE.r_word1 =
        (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
    Writer->addRelocation(A_Base, Fragment->getParent(), MRE);

    if (B_Base)
      RelSymbol = B_Base;
    else
      Index = B->getFragment()->getParent()->getOrdinal() + 1;
    Type = MachO::X86_64_RELOC_SUBTRACTOR;
  } else {
    const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
    if (Symbol->isTemporary() && Value) {
      const MCSection &Sec = Symbol->getSection();
      if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec))
        Symbol->setUsedInReloc();
    }
    RelSymbol = Asm.getAtom(*Symbol);

    // Relocations inside debug sections always use local relocations when
    // possible. This seems to be done because the debugger doesn't fully
    // understand x86_64 relocation entries, and expects to find values that
    // have already been fixed up.
    if (Symbol->isInSection()) {
      const MCSectionMachO &Section =
          static_cast<const MCSectionMachO &>(*Fragment->getParent());
      if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
        RelSymbol = nullptr;
    }

    // x86_64 almost always uses external relocations, except when there is no
    // symbol to use as a base address (a local symbol with no preceding
    // non-local symbol).
    if (RelSymbol) {
      // Add the local offset, if needed.
      if (RelSymbol != Symbol)
        Value += Layout.getSymbolOffset(*Symbol) -
                 Layout.getSymbolOffset(*RelSymbol);
    } else if (Symbol->isInSection() && !Symbol->isVariable()) {
      // The index is the section ordinal (1-based).
      Index = Symbol->getFragment()->getParent()->getOrdinal() + 1;
      Value += Writer->getSymbolAddress(*Symbol, Layout);

      if (IsPCRel)
        Value -= FixupAddress + (1 << Log2Size);
    } else if (Symbol->isVariable()) {
      const MCExpr *Value = Symbol->getVariableValue();
      int64_t Res;
      bool isAbs = Value->evaluateAsAbsolute(Res, Layout,
                                             Writer->getSectionAddressMap());
      if (isAbs) {
        FixedValue = Res;
        return;
      } else {
        Asm.getContext().reportError(Fixup.getLoc(),
                                     "unsupported relocation of variable '" +
                                         Symbol->getName() + "'");
        return;
      }
    } else {
      Asm.getContext().reportError(
          Fixup.getLoc(), "unsupported relocation of undefined symbol '" +
                              Symbol->getName() + "'");
      return;
    }

    MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
    if (IsPCRel) {
      if (IsRIPRel) {
        if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
          // x86_64 distinguishes movq foo@GOTPCREL so that the linker can
          // rewrite the movq to an leaq at link time if the symbol ends up in
          // the same linkage unit.
          if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load)
            Type = MachO::X86_64_RELOC_GOT_LOAD;
          else
            Type = MachO::X86_64_RELOC_GOT;
        }  else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
          Type = MachO::X86_64_RELOC_TLV;
        }  else if (Modifier != MCSymbolRefExpr::VK_None) {
          Asm.getContext().reportError(
              Fixup.getLoc(), "unsupported symbol modifier in relocation");
          return;
        } else {
          Type = MachO::X86_64_RELOC_SIGNED;

          // The Darwin x86_64 relocation format has a problem where it cannot
          // encode an address (L<foo> + <constant>) which is outside the atom
          // containing L<foo>. Generally, this shouldn't occur but it does
          // happen when we have a RIPrel instruction with data following the
          // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel
          // adjustment Darwin x86_64 uses, the offset is still negative and the
          // linker has no way to recognize this.
          //
          // To work around this, Darwin uses several special relocation types
          // to indicate the offsets. However, the specification or
          // implementation of these seems to also be incomplete; they should
          // adjust the addend as well based on the actual encoded instruction
          // (the additional bias), but instead appear to just look at the final
          // offset.
          switch (-(Target.getConstant() + (1LL << Log2Size))) {
          case 1: Type = MachO::X86_64_RELOC_SIGNED_1; break;
          case 2: Type = MachO::X86_64_RELOC_SIGNED_2; break;
          case 4: Type = MachO::X86_64_RELOC_SIGNED_4; break;
          }
        }
      } else {
        if (Modifier != MCSymbolRefExpr::VK_None) {
          Asm.getContext().reportError(
              Fixup.getLoc(),
              "unsupported symbol modifier in branch relocation");
          return;
        }

        Type = MachO::X86_64_RELOC_BRANCH;
      }
    } else {
      if (Modifier == MCSymbolRefExpr::VK_GOT) {
        Type = MachO::X86_64_RELOC_GOT;
      } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
        // GOTPCREL is allowed as a modifier on non-PCrel instructions, in which
        // case all we do is set the PCrel bit in the relocation entry; this is
        // used with exception handling, for example. The source is required to
        // include any necessary offset directly.
        Type = MachO::X86_64_RELOC_GOT;
        IsPCRel = 1;
      } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
        Asm.getContext().reportError(
            Fixup.getLoc(), "TLVP symbol modifier should have been rip-rel");
        return;
      } else if (Modifier != MCSymbolRefExpr::VK_None) {
        Asm.getContext().reportError(
            Fixup.getLoc(), "unsupported symbol modifier in relocation");
        return;
      } else {
        Type = MachO::X86_64_RELOC_UNSIGNED;
        unsigned Kind = Fixup.getKind();
        if (Kind == X86::reloc_signed_4byte) {
          Asm.getContext().reportError(
              Fixup.getLoc(),
              "32-bit absolute addressing is not supported in 64-bit mode");
          return;
        }
      }
    }
  }

  // x86_64 always writes custom values into the fixups.
  FixedValue = Value;

  // struct relocation_info (8 bytes)
  MachO::any_relocation_info MRE;
  MRE.r_word0 = FixupOffset;
  MRE.r_word1 = (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
                (IsExtern << 27) | (Type << 28);
  Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
}
コード例 #8
0
ファイル: ELFObjectWriter.cpp プロジェクト: Y--/root
void ELFObjectWriter::recordRelocation(MCAssembler &Asm,
                                       const MCAsmLayout &Layout,
                                       const MCFragment *Fragment,
                                       const MCFixup &Fixup, MCValue Target,
                                       bool &IsPCRel, uint64_t &FixedValue) {
  const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent());
  uint64_t C = Target.getConstant();
  uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
  MCContext &Ctx = Asm.getContext();

  if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
    assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
           "Should not have constructed this");

    // Let A, B and C being the components of Target and R be the location of
    // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
    // If it is pcrel, we want to compute (A - B + C - R).

    // In general, ELF has no relocations for -B. It can only represent (A + C)
    // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
    // replace B to implement it: (A - R - K + C)
    if (IsPCRel) {
      Ctx.reportError(
          Fixup.getLoc(),
          "No relocation available to represent this relative expression");
      return;
    }

    const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol());

    if (SymB.isUndefined()) {
      Ctx.reportError(Fixup.getLoc(),
                      Twine("symbol '") + SymB.getName() +
                          "' can not be undefined in a subtraction expression");
      return;
    }

    assert(!SymB.isAbsolute() && "Should have been folded");
    const MCSection &SecB = SymB.getSection();
    if (&SecB != &FixupSection) {
      Ctx.reportError(Fixup.getLoc(),
                      "Cannot represent a difference across sections");
      return;
    }

    uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
    uint64_t K = SymBOffset - FixupOffset;
    IsPCRel = true;
    C -= K;
  }

  // We either rejected the fixup or folded B into C at this point.
  const MCSymbolRefExpr *RefA = Target.getSymA();
  const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr;

  bool ViaWeakRef = false;
  if (SymA && SymA->isVariable()) {
    const MCExpr *Expr = SymA->getVariableValue();
    if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
      if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
        SymA = cast<MCSymbolELF>(&Inner->getSymbol());
        ViaWeakRef = true;
      }
    }
  }

  unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel);
  uint64_t OriginalC = C;
  bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type);
  if (!RelocateWithSymbol && SymA && !SymA->isUndefined())
    C += Layout.getSymbolOffset(*SymA);

  uint64_t Addend = 0;
  if (hasRelocationAddend()) {
    Addend = C;
    C = 0;
  }

  FixedValue = C;

  if (!RelocateWithSymbol) {
    const MCSection *SecA =
        (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr;
    auto *ELFSec = cast_or_null<MCSectionELF>(SecA);
    const auto *SectionSymbol =
        ELFSec ? cast<MCSymbolELF>(ELFSec->getBeginSymbol()) : nullptr;
    if (SectionSymbol)
      SectionSymbol->setUsedInReloc();
    ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA,
                           OriginalC);
    Relocations[&FixupSection].push_back(Rec);
    return;
  }

  const auto *RenamedSymA = SymA;
  if (SymA) {
    if (const MCSymbolELF *R = Renames.lookup(SymA))
      RenamedSymA = R;

    if (ViaWeakRef)
      RenamedSymA->setIsWeakrefUsedInReloc();
    else
      RenamedSymA->setUsedInReloc();
  }
  ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA,
                         OriginalC);
  Relocations[&FixupSection].push_back(Rec);
}
コード例 #9
0
void ARMMachObjectWriter::
RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
                                 const MCAssembler &Asm,
                                 const MCAsmLayout &Layout,
                                 const MCFragment *Fragment,
                                 const MCFixup &Fixup,
                                 MCValue Target,
                                 uint64_t &FixedValue) {
  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
  unsigned Type = MachO::ARM_RELOC_HALF;

  // See <reloc.h>.
  const MCSymbol *A = &Target.getSymA()->getSymbol();
  const MCSymbolData *A_SD = &Asm.getSymbolData(*A);

  if (!A_SD->getFragment())
    Asm.getContext().FatalError(Fixup.getLoc(),
                       "symbol '" + A->getName() +
                       "' can not be undefined in a subtraction expression");

  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
  uint32_t Value2 = 0;
  uint64_t SecAddr =
    Writer->getSectionAddress(A_SD->getFragment()->getParent());
  FixedValue += SecAddr;

  if (const MCSymbolRefExpr *B = Target.getSymB()) {
    const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());

    if (!B_SD->getFragment())
      Asm.getContext().FatalError(Fixup.getLoc(),
                         "symbol '" + B->getSymbol().getName() +
                         "' can not be undefined in a subtraction expression");

    // Select the appropriate difference relocation type.
    Type = MachO::ARM_RELOC_HALF_SECTDIFF;
    Value2 = Writer->getSymbolAddress(B_SD, Layout);
    FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
  }

  // Relocations are written out in reverse order, so the PAIR comes first.
  // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
  //
  // For these two r_type relocations they always have a pair following them and
  // the r_length bits are used differently.  The encoding of the r_length is as
  // follows:
  //   low bit of r_length:
  //      0 - :lower16: for movw instructions
  //      1 - :upper16: for movt instructions
  //   high bit of r_length:
  //      0 - arm instructions
  //      1 - thumb instructions
  // the other half of the relocated expression is in the following pair
  // relocation entry in the low 16 bits of r_address field.
  unsigned ThumbBit = 0;
  unsigned MovtBit = 0;
  switch ((unsigned)Fixup.getKind()) {
  default: break;
  case ARM::fixup_arm_movt_hi16:
    MovtBit = 1;
    // The thumb bit shouldn't be set in the 'other-half' bit of the
    // relocation, but it will be set in FixedValue if the base symbol
    // is a thumb function. Clear it out here.
    if (Asm.isThumbFunc(A))
      FixedValue &= 0xfffffffe;
    break;
  case ARM::fixup_t2_movt_hi16:
    if (Asm.isThumbFunc(A))
      FixedValue &= 0xfffffffe;
    MovtBit = 1;
    // Fallthrough
  case ARM::fixup_t2_movw_lo16:
    ThumbBit = 1;
    break;
  }

  if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
    uint32_t OtherHalf = MovtBit
      ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);

    MachO::any_relocation_info MRE;
    MRE.r_word0 = ((OtherHalf             <<  0) |
                   (MachO::ARM_RELOC_PAIR << 24) |
                   (MovtBit               << 28) |
                   (ThumbBit              << 29) |
                   (IsPCRel               << 30) |
                   MachO::R_SCATTERED);
    MRE.r_word1 = Value2;
    Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
  }
コード例 #10
0
void AArch64MachObjectWriter::RecordRelocation(
    MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
    const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
    uint64_t &FixedValue) {
  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());

  // See <reloc.h>.
  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment);
  unsigned Log2Size = 0;
  int64_t Value = 0;
  unsigned Index = 0;
  unsigned IsExtern = 0;
  unsigned Type = 0;
  unsigned Kind = Fixup.getKind();

  FixupOffset += Fixup.getOffset();

  // AArch64 pcrel relocation addends do not include the section offset.
  if (IsPCRel)
    FixedValue += FixupOffset;

  // ADRP fixups use relocations for the whole symbol value and only
  // put the addend in the instruction itself. Clear out any value the
  // generic code figured out from the sybmol definition.
  if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
    FixedValue = 0;

  // imm19 relocations are for conditional branches, which require
  // assembler local symbols. If we got here, that's not what we have,
  // so complain loudly.
  if (Kind == AArch64::fixup_aarch64_pcrel_branch19) {
    Asm.getContext().FatalError(Fixup.getLoc(),
                                "conditional branch requires assembler-local"
                                " label. '" +
                                    Target.getSymA()->getSymbol().getName() +
                                    "' is external.");
    return;
  }

  // 14-bit branch relocations should only target internal labels, and so
  // should never get here.
  if (Kind == AArch64::fixup_aarch64_pcrel_branch14) {
    Asm.getContext().FatalError(Fixup.getLoc(),
                                "Invalid relocation on conditional branch!");
    return;
  }

  if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
                                  Asm)) {
    Asm.getContext().FatalError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
    return;
  }

  Value = Target.getConstant();

  if (Target.isAbsolute()) { // constant
    // FIXME: Should this always be extern?
    // SymbolNum of 0 indicates the absolute section.
    Type = MachO::ARM64_RELOC_UNSIGNED;
    Index = 0;

    if (IsPCRel) {
      IsExtern = 1;
      Asm.getContext().FatalError(Fixup.getLoc(),
                                  "PC relative absolute relocation!");

      // FIXME: x86_64 sets the type to a branch reloc here. Should we do
      // something similar?
    }
  } else if (Target.getSymB()) { // A - B + constant
    const MCSymbol *A = &Target.getSymA()->getSymbol();
    const MCSymbolData &A_SD = Asm.getSymbolData(*A);
    const MCSymbolData *A_Base = Asm.getAtom(&A_SD);

    const MCSymbol *B = &Target.getSymB()->getSymbol();
    const MCSymbolData &B_SD = Asm.getSymbolData(*B);
    const MCSymbolData *B_Base = Asm.getAtom(&B_SD);

    // Check for "_foo@got - .", which comes through here as:
    // Ltmp0:
    //    ... _foo@got - Ltmp0
    if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
        Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
        Layout.getSymbolOffset(&B_SD) ==
            Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) {
      // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
      Index = A_Base->getIndex();
      IsExtern = 1;
      Type = MachO::ARM64_RELOC_POINTER_TO_GOT;
      IsPCRel = 1;
      MachO::any_relocation_info MRE;
      MRE.r_word0 = FixupOffset;
      MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
                     (IsExtern << 27) | (Type << 28));
      Writer->addRelocation(Fragment->getParent(), MRE);
      return;
    } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
               Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None)
      // Otherwise, neither symbol can be modified.
      Asm.getContext().FatalError(Fixup.getLoc(),
                                  "unsupported relocation of modified symbol");

    // We don't support PCrel relocations of differences.
    if (IsPCRel)
      Asm.getContext().FatalError(Fixup.getLoc(),
                                  "unsupported pc-relative relocation of "
                                  "difference");

    // AArch64 always uses external relocations. If there is no symbol to use as
    // a base address (a local symbol with no preceding non-local symbol),
    // error out.
    //
    // FIXME: We should probably just synthesize an external symbol and use
    // that.
    if (!A_Base)
      Asm.getContext().FatalError(
          Fixup.getLoc(),
          "unsupported relocation of local symbol '" + A->getName() +
              "'. Must have non-local symbol earlier in section.");
    if (!B_Base)
      Asm.getContext().FatalError(
          Fixup.getLoc(),
          "unsupported relocation of local symbol '" + B->getName() +
              "'. Must have non-local symbol earlier in section.");

    if (A_Base == B_Base && A_Base)
      Asm.getContext().FatalError(Fixup.getLoc(),
                                  "unsupported relocation with identical base");

    Value += (!A_SD.getFragment() ? 0
                                  : Writer->getSymbolAddress(&A_SD, Layout)) -
             (!A_Base || !A_Base->getFragment()
                  ? 0
                  : Writer->getSymbolAddress(A_Base, Layout));
    Value -= (!B_SD.getFragment() ? 0
                                  : Writer->getSymbolAddress(&B_SD, Layout)) -
             (!B_Base || !B_Base->getFragment()
                  ? 0
                  : Writer->getSymbolAddress(B_Base, Layout));

    Index = A_Base->getIndex();
    IsExtern = 1;
    Type = MachO::ARM64_RELOC_UNSIGNED;

    MachO::any_relocation_info MRE;
    MRE.r_word0 = FixupOffset;
    MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
                   (IsExtern << 27) | (Type << 28));
    Writer->addRelocation(Fragment->getParent(), MRE);

    Index = B_Base->getIndex();
    IsExtern = 1;
    Type = MachO::ARM64_RELOC_SUBTRACTOR;
  } else { // A + constant
    const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
    const MCSymbolData &SD = Asm.getSymbolData(*Symbol);
    const MCSymbolData *Base = Asm.getAtom(&SD);
    const MCSectionMachO &Section = static_cast<const MCSectionMachO &>(
        Fragment->getParent()->getSection());

    // If the symbol is a variable and we weren't able to get a Base for it
    // (i.e., it's not in the symbol table associated with a section) resolve
    // the relocation based its expansion instead.
    if (Symbol->isVariable() && !Base) {
      // If the evaluation is an absolute value, just use that directly
      // to keep things easy.
      int64_t Res;
      if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute(
              Res, Layout, Writer->getSectionAddressMap())) {
        FixedValue = Res;
        return;
      }

      // FIXME: Will the Target we already have ever have any data in it
      // we need to preserve and merge with the new Target? How about
      // the FixedValue?
      if (!Symbol->getVariableValue()->EvaluateAsRelocatable(Target, &Layout))
        Asm.getContext().FatalError(Fixup.getLoc(),
                                    "unable to resolve variable '" +
                                        Symbol->getName() + "'");
      return RecordRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
                              FixedValue);
    }

    // Relocations inside debug sections always use local relocations when
    // possible. This seems to be done because the debugger doesn't fully
    // understand relocation entries and expects to find values that
    // have already been fixed up.
    if (Symbol->isInSection()) {
      if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
        Base = nullptr;
    }

    // AArch64 uses external relocations as much as possible. For debug
    // sections, and for pointer-sized relocations (.quad), we allow section
    // relocations.  It's code sections that run into trouble.
    if (Base) {
      Index = Base->getIndex();
      IsExtern = 1;

      // Add the local offset, if needed.
      if (Base != &SD)
        Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base);
    } else if (Symbol->isInSection()) {
      // Pointer-sized relocations can use a local relocation. Otherwise,
      // we have to be in a debug info section.
      if (!Section.hasAttribute(MachO::S_ATTR_DEBUG) && Log2Size != 3)
        Asm.getContext().FatalError(
            Fixup.getLoc(),
            "unsupported relocation of local symbol '" + Symbol->getName() +
                "'. Must have non-local symbol earlier in section.");
      // Adjust the relocation to be section-relative.
      // The index is the section ordinal (1-based).
      const MCSectionData &SymSD =
          Asm.getSectionData(SD.getSymbol().getSection());
      Index = SymSD.getOrdinal() + 1;
      IsExtern = 0;
      Value += Writer->getSymbolAddress(&SD, Layout);

      if (IsPCRel)
        Value -= Writer->getFragmentAddress(Fragment, Layout) +
                 Fixup.getOffset() + (1ULL << Log2Size);
    } else {
      // Resolve constant variables.
      if (SD.getSymbol().isVariable()) {
        int64_t Res;
        if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute(
                Res, Layout, Writer->getSectionAddressMap())) {
          FixedValue = Res;
          return;
        }
      }
      Asm.getContext().FatalError(Fixup.getLoc(),
                                  "unsupported relocation of variable '" +
                                      Symbol->getName() + "'");
    }
  }

  // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
  // is represented via an Addend relocation, not encoded directly into
  // the instruction.
  if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
       Type == MachO::ARM64_RELOC_PAGE21 ||
       Type == MachO::ARM64_RELOC_PAGEOFF12) &&
      Value) {
    assert((Value & 0xff000000) == 0 && "Added relocation out of range!");

    MachO::any_relocation_info MRE;
    MRE.r_word0 = FixupOffset;
    MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
                   (IsExtern << 27) | (Type << 28));
    Writer->addRelocation(Fragment->getParent(), MRE);

    // Now set up the Addend relocation.
    Type = MachO::ARM64_RELOC_ADDEND;
    Index = Value;
    IsPCRel = 0;
    Log2Size = 2;
    IsExtern = 0;

    // Put zero into the instruction itself. The addend is in the relocation.
    Value = 0;
  }

  // If there's any addend left to handle, encode it in the instruction.
  FixedValue = Value;

  // struct relocation_info (8 bytes)
  MachO::any_relocation_info MRE;
  MRE.r_word0 = FixupOffset;
  MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
                 (IsExtern << 27) | (Type << 28));
  Writer->addRelocation(Fragment->getParent(), MRE);
}
コード例 #11
0
ファイル: MCAssembler.cpp プロジェクト: CPFL/guc
bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
                                const MCFixup &Fixup, const MCFragment *DF,
                                MCValue &Target, uint64_t &Value) const {
  ++stats::EvaluateFixup;

  if (!Fixup.getValue()->EvaluateAsRelocatable(Target, &Layout))
    report_fatal_error("expected relocatable expression");

  // FIXME: How do non-scattered symbols work in ELF? I presume the linker
  // doesn't support small relocations, but then under what criteria does the
  // assembler allow symbol differences?

  Value = Target.getConstant();

  bool IsPCRel = Emitter.getFixupKindInfo(
    Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel;
  bool IsResolved = true;
  if (const MCSymbolRefExpr *A = Target.getSymA()) {
    if (A->getSymbol().isDefined())
      Value += Layout.getSymbolAddress(&getSymbolData(A->getSymbol()));
    else
      IsResolved = false;
  }
  if (const MCSymbolRefExpr *B = Target.getSymB()) {
    if (B->getSymbol().isDefined())
      Value -= Layout.getSymbolAddress(&getSymbolData(B->getSymbol()));
    else
      IsResolved = false;
  }

  // If we are using scattered symbols, determine whether this value is actually
  // resolved; scattering may cause atoms to move.
  if (IsResolved && getBackend().hasScatteredSymbols()) {
    if (getBackend().hasReliableSymbolDifference()) {
      // If this is a PCrel relocation, find the base atom (identified by its
      // symbol) that the fixup value is relative to.
      const MCSymbolData *BaseSymbol = 0;
      if (IsPCRel) {
        BaseSymbol = DF->getAtom();
        if (!BaseSymbol)
          IsResolved = false;
      }

      if (IsResolved)
        IsResolved = isScatteredFixupFullyResolved(*this, Layout, Fixup, Target,
                                                   BaseSymbol);
    } else {
      const MCSection *BaseSection = 0;
      if (IsPCRel)
        BaseSection = &DF->getParent()->getSection();

      IsResolved = isScatteredFixupFullyResolvedSimple(*this, Fixup, Target,
                                                       BaseSection);
    }
  }

  if (IsPCRel)
    Value -= Layout.getFragmentAddress(DF) + Fixup.getOffset();

  return IsResolved;
}
コード例 #12
0
void SVMAsmBackend::ApplyFixup(const MCFixup &Fixup, char *Data,
    unsigned DataSize, uint64_t Value) const
{
    ApplyStaticFixup(Fixup.getKind(), Data + Fixup.getOffset(), Value);
}