const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const { if (!Symbol.isVariable()) return &Symbol; const MCExpr *Expr = Symbol.getVariableValue(); MCValue Value; if (!Expr->evaluateAsValue(Value, *this)) llvm_unreachable("Invalid Expression"); const MCSymbolRefExpr *RefB = Value.getSymB(); if (RefB) Assembler.getContext().reportFatalError( SMLoc(), Twine("symbol '") + RefB->getSymbol().getName() + "' could not be evaluated in a subtraction expression"); const MCSymbolRefExpr *A = Value.getSymA(); if (!A) return nullptr; const MCSymbol &ASym = A->getSymbol(); const MCAssembler &Asm = getAssembler(); if (ASym.isCommon()) { // FIXME: we should probably add a SMLoc to MCExpr. Asm.getContext().reportFatalError(SMLoc(), "Common symbol " + ASym.getName() + " cannot be used in assignment expr"); } return &ASym; }
void AMDGPUAsmBackend::processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, const MCValue &Target, uint64_t &Value, bool &IsResolved) { MCValue Res; // When we have complex expressions like: BB0_1 + (BB0_2 - 4), which are // used for long branches, this function will be called with // IsResolved = false and Value set to some pre-computed value. In // the example above, the value would be: // (BB0_1 + (BB0_2 - 4)) - CurrentOffsetFromStartOfFunction. // This is not what we want. We just want the expression computation // only. The reason the MC layer subtracts the current offset from the // expression is because the fixup is of kind FK_PCRel_4. // For these scenarios, evaluateAsValue gives us the computation that we // want. if (!IsResolved && Fixup.getValue()->evaluateAsValue(Res, Layout) && Res.isAbsolute()) { Value = Res.getConstant(); IsResolved = true; } if (IsResolved) Value = adjustFixupValue(Fixup, Value, &Asm.getContext()); }
bool WinCOFFObjectWriter::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; return !SectionB && BaseSection == SectionA; }
const MCFixup *RISCVMCExpr::getPCRelHiFixup() const { MCValue AUIPCLoc; if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr)) return nullptr; const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); if (!AUIPCSRE) return nullptr; const auto *DF = dyn_cast_or_null<MCDataFragment>(AUIPCSRE->findAssociatedFragment()); if (!DF) return nullptr; const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); for (const MCFixup &F : DF->getFixups()) { if (F.getOffset() != AUIPCSymbol->getOffset()) continue; switch ((unsigned)F.getKind()) { default: continue; case RISCV::fixup_riscv_pcrel_hi20: return &F; } } return nullptr; }
static bool getSymbolOffsetImpl(const MCAsmLayout &Layout, const MCSymbol &S, bool ReportError, uint64_t &Val) { if (!S.isVariable()) return getLabelOffset(Layout, S, ReportError, Val); // If SD is a variable, evaluate it. MCValue Target; if (!S.getVariableValue()->evaluateAsValue(Target, Layout)) report_fatal_error("unable to evaluate offset for variable '" + S.getName() + "'"); uint64_t Offset = Target.getConstant(); const MCSymbolRefExpr *A = Target.getSymA(); if (A) { uint64_t ValA; if (!getLabelOffset(Layout, A->getSymbol(), ReportError, ValA)) return false; Offset += ValA; } const MCSymbolRefExpr *B = Target.getSymB(); if (B) { uint64_t ValB; if (!getLabelOffset(Layout, B->getSymbol(), ReportError, ValB)) return false; Offset -= ValB; } Val = Offset; return true; }
bool MCAssembler::isThumbFunc(const MCSymbol *Symbol) const { if (ThumbFuncs.count(Symbol)) return true; if (!Symbol->isVariable()) return false; const MCExpr *Expr = Symbol->getVariableValue(); MCValue V; if (!Expr->evaluateAsRelocatable(V, nullptr, nullptr)) return false; if (V.getSymB() || V.getRefKind() != MCSymbolRefExpr::VK_None) return false; const MCSymbolRefExpr *Ref = V.getSymA(); if (!Ref) return false; if (Ref->getKind() != MCSymbolRefExpr::VK_None) return false; const MCSymbol &Sym = Ref->getSymbol(); if (!isThumbFunc(&Sym)) return false; ThumbFuncs.insert(Symbol); // Cache it. return true; }
unsigned X86WinCOFFObjectWriter::getRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const { unsigned FixupKind = IsCrossSection ? FK_PCRel_4 : Fixup.getKind(); MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); if (getMachine() == COFF::IMAGE_FILE_MACHINE_AMD64) { switch (FixupKind) { case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: case X86::reloc_riprel_4byte_relax: case X86::reloc_riprel_4byte_relax_rex: return COFF::IMAGE_REL_AMD64_REL32; case FK_Data_4: case X86::reloc_signed_4byte: case X86::reloc_signed_4byte_relax: if (Modifier == MCSymbolRefExpr::VK_COFF_IMGREL32) return COFF::IMAGE_REL_AMD64_ADDR32NB; if (Modifier == MCSymbolRefExpr::VK_SECREL) return COFF::IMAGE_REL_AMD64_SECREL; return COFF::IMAGE_REL_AMD64_ADDR32; case FK_Data_8: return COFF::IMAGE_REL_AMD64_ADDR64; case FK_SecRel_2: return COFF::IMAGE_REL_AMD64_SECTION; case FK_SecRel_4: return COFF::IMAGE_REL_AMD64_SECREL; default: llvm_unreachable("unsupported relocation type"); } } else if (getMachine() == COFF::IMAGE_FILE_MACHINE_I386) { switch (FixupKind) { case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: return COFF::IMAGE_REL_I386_REL32; case FK_Data_4: case X86::reloc_signed_4byte: case X86::reloc_signed_4byte_relax: if (Modifier == MCSymbolRefExpr::VK_COFF_IMGREL32) return COFF::IMAGE_REL_I386_DIR32NB; if (Modifier == MCSymbolRefExpr::VK_SECREL) return COFF::IMAGE_REL_AMD64_SECREL; return COFF::IMAGE_REL_I386_DIR32; case FK_SecRel_2: return COFF::IMAGE_REL_I386_SECTION; case FK_SecRel_4: return COFF::IMAGE_REL_I386_SECREL; default: llvm_unreachable("unsupported relocation type"); } } else llvm_unreachable("Unsupported COFF machine type."); }
/// NOTE: It is really important to have both the Asm and Layout arguments. /// They might look redundant, but this function can be used before layout /// is done (see the object streamer for example) and having the Asm argument /// lets us avoid relaxations early. static bool EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet, const MCValue &LHS,const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst, MCValue &Res) { // FIXME: This routine (and other evaluation parts) are *incredibly* sloppy // about dealing with modifiers. This will ultimately bite us, one day. const MCSymbolRefExpr *LHS_A = LHS.getSymA(); const MCSymbolRefExpr *LHS_B = LHS.getSymB(); int64_t LHS_Cst = LHS.getConstant(); // Fold the result constant immediately. int64_t Result_Cst = LHS_Cst + RHS_Cst; assert((!Layout || Asm) && "Must have an assembler object if layout is given!"); // If we have a layout, we can fold resolved differences. if (Asm) { // First, fold out any differences which are fully resolved. By // reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). // we have the four possible differences: // (LHS_A - LHS_B), // (LHS_A - RHS_B), // (RHS_A - LHS_B), // (RHS_A - RHS_B). // Since we are attempting to be as aggressive as possible about folding, we // attempt to evaluate each possible alternative. AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B, Result_Cst); AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B, Result_Cst); AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B, Result_Cst); AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B, Result_Cst); } // We can't represent the addition or subtraction of two symbols. if ((LHS_A && RHS_A) || (LHS_B && RHS_B)) return false; // At this point, we have at most one additive symbol and one subtractive // symbol -- find them. const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A; const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B; // If we have a negated symbol, then we must have also have a non-negated // symbol in order to encode the expression. if (B && !A) return false; Res = MCValue::get(A, B, Result_Cst); return true; }
bool AsmExpr::EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const { MCValue Value; if (!EvaluateAsRelocatable(Ctx, Value) || !Value.isAbsolute()) return false; Res = Value.getConstant(); return true; }
bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { MCValue Value; if (!EvaluateAsRelocatable(Value) || !Value.isAbsolute()) return false; Res = Value.getConstant(); return true; }
bool AArch64MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { if (!getSubExpr()->EvaluateAsRelocatable(Res, Layout, Fixup)) return false; Res = MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind()); return true; }
bool PPCMCExpr::evaluateAsConstant(int64_t &Res) const { MCValue Value; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) return false; if (!Value.isAbsolute()) return false; Res = evaluateAsInt64(Value.getConstant()); return true; }
static MCSymbolRefExpr::VariantKind getAccessVariant(const MCValue &Target, const MCFixup &Fixup) { const MCExpr *Expr = Fixup.getValue(); if (Expr->getKind() != MCExpr::Target) return Target.getAccessVariant(); switch (cast<PPCMCExpr>(Expr)->getKind()) { case PPCMCExpr::VK_PPC_None: return MCSymbolRefExpr::VK_None; case PPCMCExpr::VK_PPC_LO: return MCSymbolRefExpr::VK_PPC_LO; case PPCMCExpr::VK_PPC_HI: return MCSymbolRefExpr::VK_PPC_HI; case PPCMCExpr::VK_PPC_HA: return MCSymbolRefExpr::VK_PPC_HA; case PPCMCExpr::VK_PPC_HIGHERA: return MCSymbolRefExpr::VK_PPC_HIGHERA; case PPCMCExpr::VK_PPC_HIGHER: return MCSymbolRefExpr::VK_PPC_HIGHER; case PPCMCExpr::VK_PPC_HIGHEST: return MCSymbolRefExpr::VK_PPC_HIGHEST; case PPCMCExpr::VK_PPC_HIGHESTA: return MCSymbolRefExpr::VK_PPC_HIGHESTA; } llvm_unreachable("unknown PPCMCExpr kind"); }
bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { MCValue Value; if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || Kind == VK_RISCV_CALL) return false; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) return false; if (!Value.isAbsolute()) return false; Res = evaluateAsInt64(Value.getConstant()); return true; }
void MachObjectWriter::markAbsoluteVariableSymbols(MCAssembler &Asm, const MCAsmLayout &Layout) { for (MCSymbolData &SD : Asm.symbols()) { if (!SD.getSymbol().isVariable()) continue; // Is the variable is a symbol difference (SA - SB + C) expression, // and neither symbol is external, mark the variable as absolute. const MCExpr *Expr = SD.getSymbol().getVariableValue(); MCValue Value; if (Expr->EvaluateAsRelocatable(Value, &Layout, nullptr)) { if (Value.getSymA() && Value.getSymB()) const_cast<MCSymbol*>(&SD.getSymbol())->setAbsolute(); } } }
void X86MachObjectWriter::RecordTLVPRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && !is64Bit() && "Should only be called with a 32-bit TLVP relocation!"); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); unsigned IsPCRel = 0; // Get the symbol data. const MCSymbolData *SD_A = &Asm.getSymbolData(Target.getSymA()->getSymbol()); unsigned Index = SD_A->getIndex(); // We're only going to have a second symbol in pic mode and it'll be a // subtraction from the picbase. For 32-bit pic the addend is the difference // between the picbase and the next address. For 32-bit static the addend is // zero. if (Target.getSymB()) { // If this is a subtraction then we're pcrel. uint32_t FixupAddress = Writer->getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); const MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); IsPCRel = 1; FixedValue = (FixupAddress - Writer->getSymbolAddress(SD_B, Layout) + Target.getConstant()); FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } // struct relocation_info (8 bytes) MachO::any_relocation_info MRE; MRE.r_word0 = Value; MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (1 << 27) | // r_extern (MachO::GENERIC_RELOC_TLV << 28)); // r_type Writer->addRelocation(Fragment->getParent(), MRE); }
SVMSymbolInfo SVMMemoryLayout::getSymbol(const MCAssembler &Asm, const MCAsmLayout &Layout, MCValue Value, bool useCodeAddresses) const { /* * Convert an MCValue into a resolved SVMSymbolInfo, * by evaluating (SymA - SymB + Constant). */ int64_t CValue = Value.getConstant(); const MCSymbolRefExpr *SA = Value.getSymA(); const MCSymbolRefExpr *SB = Value.getSymB(); SVMSymbolInfo SIA, SIB; if (SA) SIA = getSymbol(Asm, Layout, &SA->getSymbol(), useCodeAddresses); if (SB) SIB = getSymbol(Asm, Layout, &SB->getSymbol(), useCodeAddresses); if ((SIA.Kind == SVMSymbolInfo::NONE || SIA.Kind == SVMSymbolInfo::LOCAL) && (SIB.Kind == SVMSymbolInfo::NONE || SIB.Kind == SVMSymbolInfo::LOCAL)) { // Arithmetic is allowed. SIA.Kind = SVMSymbolInfo::LOCAL; SIA.Value = CValue + SIA.Value - SIB.Value; return SIA; } if (SIA.Kind == SIB.Kind && SIA.Value == SIB.Value) { // Two special symbols cancel out, yield a normal constant SIA.Kind = SVMSymbolInfo::LOCAL; SIA.Value = CValue; return SIA; } if (SIA.Kind != SVMSymbolInfo::NONE && SIB.Kind != SVMSymbolInfo::NONE) report_fatal_error("Can't take the difference of special symbols '" + Twine(SA->getSymbol().getName()) + "' and '" + Twine(SB->getSymbol().getName()) + "'"); if (SIB.Kind != SVMSymbolInfo::NONE) report_fatal_error("Can't negate special symbol '" + Twine(SB->getSymbol().getName()) + "'"); if (CValue != 0) report_fatal_error("Can't add constant to special symbol '" + Twine(SA->getSymbol().getName()) + "'"); return SIA; }
// Try to fully compute Expr to an absolute value and if that fails produce // a relocatable expr. // FIXME: Should this be the behavior of EvaluateAsRelocatable itself? static bool evaluate(const MCExpr &Expr, const MCAsmLayout &Layout, const MCFixup &Fixup, MCValue &Target) { if (Expr.EvaluateAsValue(Target, &Layout, &Fixup)) { if (Target.isAbsolute()) return true; } return Expr.EvaluateAsRelocatable(Target, &Layout, &Fixup); }
static bool isScatteredFixupFullyResolved(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup, const MCValue Target, const MCSymbolData *BaseSymbol) { // The effective fixup address is // addr(atom(A)) + offset(A) // - addr(atom(B)) - offset(B) // - addr(BaseSymbol) + <fixup offset from base symbol> // and the offsets are not relocatable, so the fixup is fully resolved when // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0. // // Note that "false" is almost always conservatively correct (it means we emit // a relocation which is unnecessary), except when it would force us to emit a // relocation which the target cannot encode. const MCSymbolData *A_Base = 0, *B_Base = 0; if (const MCSymbolRefExpr *A = Target.getSymA()) { // Modified symbol references cannot be resolved. if (A->getKind() != MCSymbolRefExpr::VK_None) return false; A_Base = Asm.getAtom(Layout, &Asm.getSymbolData(A->getSymbol())); if (!A_Base) return false; } if (const MCSymbolRefExpr *B = Target.getSymB()) { // Modified symbol references cannot be resolved. if (B->getKind() != MCSymbolRefExpr::VK_None) return false; B_Base = Asm.getAtom(Layout, &Asm.getSymbolData(B->getSymbol())); if (!B_Base) return false; } // If there is no base, A and B have to be the same atom for this fixup to be // fully resolved. if (!BaseSymbol) return A_Base == B_Base; // Otherwise, B must be missing and A must be the base. return !B_Base && BaseSymbol == A_Base; }
unsigned AMDGPUELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { // SCRATCH_RSRC_DWORD[01] is a special global variable that represents // the scratch buffer. if (Target.getSymA()->getSymbol().getName() == "SCRATCH_RSRC_DWORD0") return ELF::R_AMDGPU_ABS32_LO; if (Target.getSymA()->getSymbol().getName() == "SCRATCH_RSRC_DWORD1") return ELF::R_AMDGPU_ABS32_HI; switch (Fixup.getKind()) { default: break; case FK_PCRel_4: return ELF::R_AMDGPU_REL32; } llvm_unreachable("unhandled relocation type"); }
unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel); if (getEMachine() == ELF::EM_X86_64) return getRelocType64(Modifier, Type, IsPCRel); assert(getEMachine() == ELF::EM_386 && "Unsupported ELF machine type."); return getRelocType32(Modifier, getType32(Type), IsPCRel); }
unsigned ARMWinCOFFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const { assert(getMachine() == COFF::IMAGE_FILE_MACHINE_ARMNT && "AArch64 support not yet implemented"); MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); switch (static_cast<unsigned>(Fixup.getKind())) { default: { const MCFixupKindInfo &Info = MAB.getFixupKindInfo(Fixup.getKind()); report_fatal_error(Twine("unsupported relocation type: ") + Info.Name); } case FK_Data_4: switch (Modifier) { case MCSymbolRefExpr::VK_COFF_IMGREL32: return COFF::IMAGE_REL_ARM_ADDR32NB; case MCSymbolRefExpr::VK_SECREL: return COFF::IMAGE_REL_ARM_SECREL; default: return COFF::IMAGE_REL_ARM_ADDR32; } case FK_SecRel_2: return COFF::IMAGE_REL_ARM_SECTION; case FK_SecRel_4: return COFF::IMAGE_REL_ARM_SECREL; case ARM::fixup_t2_condbranch: return COFF::IMAGE_REL_ARM_BRANCH20T; case ARM::fixup_t2_uncondbranch: case ARM::fixup_arm_thumb_bl: return COFF::IMAGE_REL_ARM_BRANCH24T; case ARM::fixup_arm_thumb_blx: return COFF::IMAGE_REL_ARM_BLX23T; case ARM::fixup_t2_movw_lo16: case ARM::fixup_t2_movt_hi16: return COFF::IMAGE_REL_ARM_MOV32T; } }
const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const { if (!Symbol.isVariable()) return &Symbol; const MCExpr *Expr = Symbol.getVariableValue(); MCValue Value; if (!Expr->EvaluateAsValue(Value, this, nullptr)) llvm_unreachable("Invalid Expression"); const MCSymbolRefExpr *RefB = Value.getSymB(); if (RefB) Assembler.getContext().FatalError( SMLoc(), Twine("symbol '") + RefB->getSymbol().getName() + "' could not be evaluated in a subtraction expression"); const MCSymbolRefExpr *A = Value.getSymA(); if (!A) return nullptr; return &A->getSymbol(); }
bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs) const { MCValue Value; // Fast path constants. if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(this)) { Res = CE->getValue(); return true; } // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us // absolutize differences across sections and that is what the MachO writer // uses Addrs for. bool IsRelocatable = EvaluateAsRelocatableImpl(Value, Asm, Layout, Addrs, /*InSet*/ Addrs); // Record the current value. Res = Value.getConstant(); return IsRelocatable && Value.isAbsolute(); }
bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { // VK_RISCV_PCREL_LO has to be handled specially. The MCExpr inside is // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup // pointing to the real target. We need to generate an MCValue in the form of // (<real target> + <offset from this fixup to the auipc fixup>). The Fixup // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct. MCValue AUIPCLoc; if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout)) return false; const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment // boundries. if (!AUIPCSRE || findAssociatedFragment() != AUIPCSRE->findAssociatedFragment()) return false; const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); if (!AUIPCSymbol) return false; const MCFixup *TargetFixup = getPCRelHiFixup(); if (!TargetFixup) return false; if ((unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20) return false; MCValue Target; if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout)) return false; if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection()) return false; if (&Target.getSymA()->getSymbol().getSection() != findAssociatedFragment()->getParent()) return false; uint64_t AUIPCOffset = AUIPCSymbol->getOffset(); Res = MCValue::get(Target.getSymA(), nullptr, Target.getConstant() + (Fixup->getOffset() - AUIPCOffset)); return true; }
static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue Target, const MCSection *BaseSection) { // The effective fixup address is // addr(atom(A)) + offset(A) // - addr(atom(B)) - offset(B) // - addr(<base symbol>) + <fixup offset from base symbol> // and the offsets are not relocatable, so the fixup is fully resolved when // addr(atom(A)) - addr(atom(B)) - addr(<base symbol>)) == 0. // // The simple (Darwin, except on x86_64) way of dealing with this was to // assume that any reference to a temporary symbol *must* be a temporary // symbol in the same atom, unless the sections differ. Therefore, any PCrel // relocation to a temporary symbol (in the same section) is fully // resolved. This also works in conjunction with absolutized .set, which // requires the compiler to use .set to absolutize the differences between // symbols which the compiler knows to be assembly time constants, so we don't // need to worry about considering symbol differences fully resolved. // Non-relative fixups are only resolved if constant. if (!BaseSection) return Target.isAbsolute(); // Otherwise, relative fixups are only resolved if not a difference and the // target is a temporary in the same section. if (Target.isAbsolute() || Target.getSymB()) return false; const MCSymbol *A = &Target.getSymA()->getSymbol(); if (!A->isTemporary() || !A->isInSection() || &A->getSection() != BaseSection) return false; return true; }
bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup)) return true; if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup)) return false; // Some custom fixup types are not valid with symbol difference expressions if (Res.getSymA() && Res.getSymB()) { switch (getKind()) { default: return true; case VK_RISCV_LO: case VK_RISCV_HI: case VK_RISCV_PCREL_LO: case VK_RISCV_PCREL_HI: return false; } } return true; }
bool PPCMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { MCValue Value; if (!getSubExpr()->evaluateAsRelocatable(Value, Layout, Fixup)) return false; if (Value.isAbsolute()) { int64_t Result = evaluateAsInt64(Value.getConstant()); if ((Fixup == nullptr || (unsigned)Fixup->getKind() != PPC::fixup_ppc_half16) && (Result >= 0x8000)) return false; Res = MCValue::get(Result); } else { if (!Layout) return false; MCContext &Context = Layout->getAssembler().getContext(); const MCSymbolRefExpr *Sym = Value.getSymA(); MCSymbolRefExpr::VariantKind Modifier = Sym->getKind(); if (Modifier != MCSymbolRefExpr::VK_None) return false; switch (Kind) { default: llvm_unreachable("Invalid kind!"); case VK_PPC_LO: Modifier = MCSymbolRefExpr::VK_PPC_LO; break; case VK_PPC_HI: Modifier = MCSymbolRefExpr::VK_PPC_HI; break; case VK_PPC_HA: Modifier = MCSymbolRefExpr::VK_PPC_HA; break; case VK_PPC_HIGHERA: Modifier = MCSymbolRefExpr::VK_PPC_HIGHERA; break; case VK_PPC_HIGHER: Modifier = MCSymbolRefExpr::VK_PPC_HIGHER; break; case VK_PPC_HIGHEST: Modifier = MCSymbolRefExpr::VK_PPC_HIGHEST; break; case VK_PPC_HIGHESTA: Modifier = MCSymbolRefExpr::VK_PPC_HIGHESTA; break; } Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context); Res = MCValue::get(Sym, Value.getSymB(), Value.getConstant()); } return true; }
unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); unsigned Kind = Fixup.getKind(); switch (Modifier) { case MCSymbolRefExpr::VK_None: if (IsPCRel) return getPCRelReloc(Kind); return getAbsoluteReloc(Kind); case MCSymbolRefExpr::VK_NTPOFF: assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); return getTLSLEReloc(Kind); case MCSymbolRefExpr::VK_INDNTPOFF: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_TLS_IEENT; llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); case MCSymbolRefExpr::VK_DTPOFF: assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); return getTLSLDOReloc(Kind); case MCSymbolRefExpr::VK_TLSLDM: assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); return getTLSLDMReloc(Kind); case MCSymbolRefExpr::VK_TLSGD: assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); return getTLSGDReloc(Kind); case MCSymbolRefExpr::VK_GOT: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_GOTENT; llvm_unreachable("Only PC-relative GOT accesses are supported for now"); case MCSymbolRefExpr::VK_PLT: assert(IsPCRel && "@PLT shouldt be PC-relative"); return getPLTReloc(Kind); default: llvm_unreachable("Modifier not supported"); } }
static bool EvaluateSymbolicAdd(const MCValue &LHS, const MCSymbol *RHS_A, const MCSymbol *RHS_B, int64_t RHS_Cst, MCValue &Res) { // We can't add or subtract two symbols. if ((LHS.getSymA() && RHS_A) || (LHS.getSymB() && RHS_B)) return false; const MCSymbol *A = LHS.getSymA() ? LHS.getSymA() : RHS_A; const MCSymbol *B = LHS.getSymB() ? LHS.getSymB() : RHS_B; if (B) { // If we have a negated symbol, then we must have also have a non-negated // symbol in order to encode the expression. We can do this check later to // permit expressions which eventually fold to a representable form -- such // as (a + (0 - b)) -- if necessary. if (!A) return false; } Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst); return true; }