unsigned Cpu0ELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { // determine the type of the relocation unsigned Type = (unsigned)ELF::R_CPU0_NONE; unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case FK_Data_4: Type = ELF::R_CPU0_32; break; case FK_GPRel_4: Type = ELF::R_CPU0_GPREL32; break; case Cpu0::fixup_Cpu0_24: Type = ELF::R_CPU0_24; break; case Cpu0::fixup_Cpu0_32: Type = ELF::R_CPU0_32; break; case Cpu0::fixup_Cpu0_HI16: Type = ELF::R_CPU0_HI16; break; case Cpu0::fixup_Cpu0_LO16: Type = ELF::R_CPU0_LO16; break; case Cpu0::fixup_Cpu0_GPREL16: Type = ELF::R_CPU0_GPREL16; break; case Cpu0::fixup_Cpu0_GOT_Global: case Cpu0::fixup_Cpu0_GOT_Local: Type = ELF::R_CPU0_GOT16; break; case Cpu0::fixup_Cpu0_PC16: Type = ELF::R_CPU0_PC16; break; case Cpu0::fixup_Cpu0_PC24: Type = ELF::R_CPU0_PC24; break; case Cpu0::fixup_Cpu0_GOT_HI16: Type = ELF::R_CPU0_GOT_HI16; break; case Cpu0::fixup_Cpu0_GOT_LO16: Type = ELF::R_CPU0_GOT_LO16; break; } return Type; }
void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef<char> Data, uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const { Value = adjustFixupValue(Fixup, Value, &Asm.getContext()); if (!Value) return; // Doesn't change encoding. MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); // Shift the value into position. Value <<= Info.TargetOffset; unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); uint32_t Offset = Fixup.getOffset(); assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); // For each byte of the fragment that the fixup touches, mask in the bits from // the fixup value. for (unsigned i = 0; i != NumBytes; ++i) Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff); }
void AArch64AsmBackend::processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, uint64_t &Value, bool &IsResolved) { // The ADRP instruction adds some multiple of 0x1000 to the current PC & // ~0xfff. This means that the required offset to reach a symbol can vary by // up to one step depending on where the ADRP is in memory. For example: // // ADRP x0, there // there: // // If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and // we'll need that as an offset. At any other address "there" will be in the // same page as the ADRP and the instruction should encode 0x0. Assuming the // section isn't 0x1000-aligned, we therefore need to delegate this decision // to the linker -- a relocation! if ((uint32_t)Fixup.getKind() == AArch64::fixup_a64_adr_prel_page || (uint32_t)Fixup.getKind() == AArch64::fixup_a64_adr_prel_got_page || (uint32_t)Fixup.getKind() == AArch64::fixup_a64_adr_gottprel_page || (uint32_t)Fixup.getKind() == AArch64::fixup_a64_tlsdesc_adr_page) IsResolved = false; }
void SystemZMCAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value) const { MCFixupKind Kind = Fixup.getKind(); unsigned Offset = Fixup.getOffset(); unsigned Size = (getFixupKindInfo(Kind).TargetSize + 7) / 8; assert(Offset + Size <= DataSize && "Invalid fixup offset!"); // Big-endian insertion of Size bytes. Value = extractBitsForFixup(Kind, Value); unsigned ShiftValue = (Size * 8) - 8; for (unsigned I = 0; I != Size; ++I) { Data[Offset + I] |= uint8_t(Value >> ShiftValue); ShiftValue -= 8; } }
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); }
// assumes IsILP32 is true bool isNonILP32reloc(const MCFixup &Fixup, AArch64MCExpr::VariantKind RefKind, MCContext &Ctx) { if ((unsigned)Fixup.getKind() != AArch64::fixup_aarch64_movw) return false; switch(RefKind) { case AArch64MCExpr::VK_ABS_G3: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G3)); return true; case AArch64MCExpr::VK_ABS_G2: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G2)); return true; case AArch64MCExpr::VK_ABS_G2_S: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_SABS_G2)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_ABS_G2_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G2_NC)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_ABS_G1_S: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_SABS_G1)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_ABS_G1_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G1_NC)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_DTPREL_G2: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLD_MOVW_DTPREL_G2)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_DTPREL_G1_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLD_MOVW_DTPREL_G1_NC)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_TPREL_G2: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLE_MOVW_TPREL_G2)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_TPREL_G1_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLE_MOVW_TPREL_G1_NC)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_GOTTPREL_G1: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSIE_MOVW_GOTTPREL_G1)); return ELF::R_AARCH64_NONE; case AArch64MCExpr::VK_GOTTPREL_G0_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSIE_MOVW_GOTTPREL_G0_NC)); return ELF::R_AARCH64_NONE; default: return false; } return false; }
unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { // determine the type of the relocation switch ((unsigned)Fixup.getKind()) { default: llvm_unreachable("invalid fixup kind!"); case FK_SecRel_8: return ELF::R_X86_64_64; case FK_SecRel_4: return ELF::R_X86_64_PC32; case FK_Data_8: return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; case FK_Data_4: return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; } }
std::pair<uint64_t, bool> MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F, const MCFixup &Fixup) { // Evaluate the fixup. MCValue Target; uint64_t FixedValue; bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; if (!evaluateFixup(Layout, Fixup, &F, Target, FixedValue)) { // The fixup was unresolved, we need a relocation. Inform the object // writer of the relocation, and give it an opportunity to adjust the // fixup value if need be. getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, IsPCRel, FixedValue); } return std::make_pair(FixedValue, IsPCRel); }
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"); } }
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 SampleELFObjectWriter:: GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend) const { // determine the type of the relocation unsigned Type = (unsigned)ELF::R_MIPS_NONE; unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case Sample::fixup_Sample_24: Type = ELF::R_MIPS_26; break; } return Type; }
unsigned LEGELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { if (!IsPCRel) { llvm_unreachable("Only dealying with PC-relative fixups for now"); } unsigned Type = 0; switch ((unsigned)Fixup.getKind()) { default: llvm_unreachable("Unimplemented"); case LEG::fixup_leg_mov_hi16_pcrel: Type = ELF::R_ARM_MOVT_PREL; break; case LEG::fixup_leg_mov_lo16_pcrel: Type = ELF::R_ARM_MOVW_PREL_NC; break; } return Type; }
bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { switch ((unsigned)Fixup.getKind()) { case ARM::fixup_arm_thumb_br: { // Relaxing tB to t2B. tB has a signed 12-bit displacement with the // low bit being an implied zero. There's an implied +4 offset for the // branch, so we adjust the other way here to determine what's // encodable. // // Relax if the value is too big for a (signed) i8. int64_t Offset = int64_t(Value) - 4; return Offset > 2046 || Offset < -2048; } case ARM::fixup_arm_thumb_bcc: { // Relaxing tBcc to t2Bcc. tBcc has a signed 9-bit displacement with the // low bit being an implied zero. There's an implied +4 offset for the // branch, so we adjust the other way here to determine what's // encodable. // // Relax if the value is too big for a (signed) i8. int64_t Offset = int64_t(Value) - 4; return Offset > 254 || Offset < -256; } case ARM::fixup_thumb_adr_pcrel_10: case ARM::fixup_arm_thumb_cp: { // If the immediate is negative, greater than 1020, or not a multiple // of four, the wide version of the instruction must be used. int64_t Offset = int64_t(Value) - 4; return Offset > 1020 || Offset < 0 || Offset & 3; } case ARM::fixup_arm_thumb_cb: // If we have a Thumb CBZ or CBNZ instruction and its target is the next // instruction it is is actually out of range for the instruction. // It will be changed to a NOP. int64_t Offset = (Value & ~1); return Offset == 2; } llvm_unreachable("Unexpected fixup kind in fixupNeedsRelaxation()!"); }
// If linker relaxation is enabled, or the relax option had previously been // enabled, always emit relocations even if the fixup can be resolved. This is // necessary for correctness as offsets may change during relaxation. bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target) { bool ShouldForce = false; switch ((unsigned)Fixup.getKind()) { default: break; case RISCV::fixup_riscv_got_hi20: return true; case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_s: // For pcrel_lo12, force a relocation if the target of the corresponding // pcrel_hi20 is not in the same fragment. const MCFixup *T = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(); if (!T) { Asm.getContext().reportError(Fixup.getLoc(), "could not find corresponding %pcrel_hi"); return false; } switch ((unsigned)T->getKind()) { default: llvm_unreachable("Unexpected fixup kind for pcrel_lo12"); break; case RISCV::fixup_riscv_got_hi20: ShouldForce = true; break; case RISCV::fixup_riscv_pcrel_hi20: ShouldForce = T->getValue()->findAssociatedFragment() != Fixup.getValue()->findAssociatedFragment(); break; } break; } return ShouldForce || STI.getFeatureBits()[RISCV::FeatureRelax] || ForceRelocs; }
void SVMMemoryLayout::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { SVM::Fixups kind = (SVM::Fixups) Fixup.getKind(); switch (kind) { case SVM::fixup_fnstack: { /* * Function stack adjustment annotation. The adjustment amount is * stored in the first argument of a binary op. * (See SVMMCCodeEmitter::EncodeInstruction) * * We store this offset for later, in our FNStackMap, indexed * by the address of the FNStack pseudo-op itself. */ FNStackMap[std::make_pair(Fragment->getParent(), Layout.getFragmentOffset(Fragment))] = (int)Target.getConstant(); break; } default: { /* * All other fixups are applied later, in ApplyLateFixups(). * This is necessary because other fixup types can depend on * the FNStack values collected above. */ SVMLateFixup LF((MCFragment *) Fragment, Fixup, Target); LateFixupList.push_back(LF); // This gets OR'ed with the fixup later. Zero it. FixedValue = 0; break; } } }
static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, MCContext *Ctx) { int64_t SignedValue = static_cast<int64_t>(Value); switch (Fixup.getKind()) { case AMDGPU::fixup_si_sopp_br: { int64_t BrImm = (SignedValue - 4) / 4; if (Ctx && !isInt<16>(BrImm)) Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16"); return BrImm; } case FK_Data_1: case FK_Data_2: case FK_Data_4: case FK_Data_8: case FK_PCRel_4: case FK_SecRel_4: return Value; default: llvm_unreachable("unhandled fixup kind"); } }
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); }
static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, MCContext *Ctx = NULL) { unsigned Kind = Fixup.getKind(); switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); case FK_Data_1: case FK_Data_2: case FK_Data_4: return Value; case ARM::fixup_arm_movt_hi16: Value >>= 16; // Fallthrough case ARM::fixup_arm_movw_lo16: case ARM::fixup_arm_movt_hi16_pcrel: case ARM::fixup_arm_movw_lo16_pcrel: { unsigned Hi4 = (Value & 0xF000) >> 12; unsigned Lo12 = Value & 0x0FFF; // inst{19-16} = Hi4; // inst{11-0} = Lo12; Value = (Hi4 << 16) | (Lo12); return Value; } case ARM::fixup_t2_movt_hi16: Value >>= 16; // Fallthrough case ARM::fixup_t2_movw_lo16: case ARM::fixup_t2_movt_hi16_pcrel: //FIXME: Shouldn't this be shifted like // the other hi16 fixup? case ARM::fixup_t2_movw_lo16_pcrel: { unsigned Hi4 = (Value & 0xF000) >> 12; unsigned i = (Value & 0x800) >> 11; unsigned Mid3 = (Value & 0x700) >> 8; unsigned Lo8 = Value & 0x0FF; // inst{19-16} = Hi4; // inst{26} = i; // inst{14-12} = Mid3; // inst{7-0} = Lo8; Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8); uint64_t swapped = (Value & 0xFFFF0000) >> 16; swapped |= (Value & 0x0000FFFF) << 16; return swapped; } case ARM::fixup_arm_ldst_pcrel_12: // ARM PC-relative values are offset by 8. Value -= 4; // FALLTHROUGH case ARM::fixup_t2_ldst_pcrel_12: { // Offset by 4, adjusted by two due to the half-word ordering of thumb. Value -= 4; bool isAdd = true; if ((int64_t)Value < 0) { Value = -Value; isAdd = false; } if (Ctx && Value >= 4096) Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); Value |= isAdd << 23; // Same addressing mode as fixup_arm_pcrel_10, // but with 16-bit halfwords swapped. if (Kind == ARM::fixup_t2_ldst_pcrel_12) { uint64_t swapped = (Value & 0xFFFF0000) >> 16; swapped |= (Value & 0x0000FFFF) << 16; return swapped; } return Value; } case ARM::fixup_thumb_adr_pcrel_10: return ((Value - 4) >> 2) & 0xff; case ARM::fixup_arm_adr_pcrel_12: { // ARM PC-relative values are offset by 8. Value -= 8; unsigned opc = 4; // bits {24-21}. Default to add: 0b0100 if ((int64_t)Value < 0) { Value = -Value; opc = 2; // 0b0010 } if (Ctx && ARM_AM::getSOImmVal(Value) == -1) Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); // Encode the immediate and shift the opcode into place. return ARM_AM::getSOImmVal(Value) | (opc << 21); } case ARM::fixup_t2_adr_pcrel_12: { Value -= 4; unsigned opc = 0; if ((int64_t)Value < 0) { Value = -Value; opc = 5; } uint32_t out = (opc << 21); out |= (Value & 0x800) << 15; out |= (Value & 0x700) << 4; out |= (Value & 0x0FF); uint64_t swapped = (out & 0xFFFF0000) >> 16; swapped |= (out & 0x0000FFFF) << 16; return swapped; } case ARM::fixup_arm_condbranch: case ARM::fixup_arm_uncondbranch: case ARM::fixup_arm_uncondbl: case ARM::fixup_arm_condbl: case ARM::fixup_arm_blx: // These values don't encode the low two bits since they're always zero. // Offset by 8 just as above. return 0xffffff & ((Value - 8) >> 2); case ARM::fixup_t2_uncondbranch: { Value = Value - 4; Value >>= 1; // Low bit is not encoded. uint32_t out = 0; bool I = Value & 0x800000; bool J1 = Value & 0x400000; bool J2 = Value & 0x200000; J1 ^= I; J2 ^= I; out |= I << 26; // S bit out |= !J1 << 13; // J1 bit out |= !J2 << 11; // J2 bit out |= (Value & 0x1FF800) << 5; // imm6 field out |= (Value & 0x0007FF); // imm11 field uint64_t swapped = (out & 0xFFFF0000) >> 16; swapped |= (out & 0x0000FFFF) << 16; return swapped; } case ARM::fixup_t2_condbranch: { Value = Value - 4; Value >>= 1; // Low bit is not encoded. uint64_t out = 0; out |= (Value & 0x80000) << 7; // S bit out |= (Value & 0x40000) >> 7; // J2 bit out |= (Value & 0x20000) >> 4; // J1 bit out |= (Value & 0x1F800) << 5; // imm6 field out |= (Value & 0x007FF); // imm11 field uint32_t swapped = (out & 0xFFFF0000) >> 16; swapped |= (out & 0x0000FFFF) << 16; return swapped; } case ARM::fixup_arm_thumb_bl: { // The value doesn't encode the low bit (always zero) and is offset by // four. The 32-bit immediate value is encoded as // imm32 = SignExtend(S:I1:I2:imm10:imm11:0) // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S). // The value is encoded into disjoint bit positions in the destination // opcode. x = unchanged, I = immediate value bit, S = sign extension bit, // J = either J1 or J2 bit // // BL: xxxxxSIIIIIIIIII xxJxJIIIIIIIIIII // // Note that the halfwords are stored high first, low second; so we need // to transpose the fixup value here to map properly. uint32_t offset = (Value - 4) >> 1; uint32_t signBit = (offset & 0x800000) >> 23; uint32_t I1Bit = (offset & 0x400000) >> 22; uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit; uint32_t I2Bit = (offset & 0x200000) >> 21; uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit; uint32_t imm10Bits = (offset & 0x1FF800) >> 11; uint32_t imm11Bits = (offset & 0x000007FF); uint32_t Binary = 0; uint32_t firstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10Bits); uint32_t secondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) | (uint16_t)imm11Bits); Binary |= secondHalf << 16; Binary |= firstHalf; return Binary; } case ARM::fixup_arm_thumb_blx: { // The value doesn't encode the low two bits (always zero) and is offset by // four (see fixup_arm_thumb_cp). The 32-bit immediate value is encoded as // imm32 = SignExtend(S:I1:I2:imm10H:imm10L:00) // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S). // The value is encoded into disjoint bit positions in the destination // opcode. x = unchanged, I = immediate value bit, S = sign extension bit, // J = either J1 or J2 bit, 0 = zero. // // BLX: xxxxxSIIIIIIIIII xxJxJIIIIIIIIII0 // // Note that the halfwords are stored high first, low second; so we need // to transpose the fixup value here to map properly. uint32_t offset = (Value - 2) >> 2; uint32_t signBit = (offset & 0x400000) >> 22; uint32_t I1Bit = (offset & 0x200000) >> 21; uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit; uint32_t I2Bit = (offset & 0x100000) >> 20; uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit; uint32_t imm10HBits = (offset & 0xFFC00) >> 10; uint32_t imm10LBits = (offset & 0x3FF); uint32_t Binary = 0; uint32_t firstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10HBits); uint32_t secondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) | ((uint16_t)imm10LBits) << 1); Binary |= secondHalf << 16; Binary |= firstHalf; return Binary; } case ARM::fixup_arm_thumb_cp: // Offset by 4, and don't encode the low two bits. Two bytes of that // 'off by 4' is implicitly handled by the half-word ordering of the // Thumb encoding, so we only need to adjust by 2 here. return ((Value - 2) >> 2) & 0xff; case ARM::fixup_arm_thumb_cb: { // Offset by 4 and don't encode the lower bit, which is always 0. uint32_t Binary = (Value - 4) >> 1; return ((Binary & 0x20) << 4) | ((Binary & 0x1f) << 3); } case ARM::fixup_arm_thumb_br: // Offset by 4 and don't encode the lower bit, which is always 0. return ((Value - 4) >> 1) & 0x7ff; case ARM::fixup_arm_thumb_bcc: // Offset by 4 and don't encode the lower bit, which is always 0. return ((Value - 4) >> 1) & 0xff; case ARM::fixup_arm_pcrel_10_unscaled: { Value = Value - 8; // ARM fixups offset by an additional word and don't // need to adjust for the half-word ordering. bool isAdd = true; if ((int64_t)Value < 0) { Value = -Value; isAdd = false; } // The value has the low 4 bits encoded in [3:0] and the high 4 in [11:8]. if (Ctx && Value >= 256) Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); Value = (Value & 0xf) | ((Value & 0xf0) << 4); return Value | (isAdd << 23); } case ARM::fixup_arm_pcrel_10: Value = Value - 4; // ARM fixups offset by an additional word and don't // need to adjust for the half-word ordering. // Fall through. case ARM::fixup_t2_pcrel_10: { // Offset by 4, adjusted by two due to the half-word ordering of thumb. Value = Value - 4; bool isAdd = true; if ((int64_t)Value < 0) { Value = -Value; isAdd = false; } // These values don't encode the low two bits since they're always zero. Value >>= 2; if (Ctx && Value >= 256) Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); Value |= isAdd << 23; // Same addressing mode as fixup_arm_pcrel_10, but with 16-bit halfwords // swapped. if (Kind == ARM::fixup_t2_pcrel_10) { uint32_t swapped = (Value & 0xFFFF0000) >> 16; swapped |= (Value & 0x0000FFFF) << 16; return swapped; } return Value; }
unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { // Determine the type of the relocation. unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { case Mips::fixup_Mips_NONE: return ELF::R_MIPS_NONE; case Mips::fixup_Mips_16: case FK_Data_2: return IsPCRel ? ELF::R_MIPS_PC16 : ELF::R_MIPS_16; case Mips::fixup_Mips_32: case FK_Data_4: return IsPCRel ? ELF::R_MIPS_PC32 : ELF::R_MIPS_32; } if (IsPCRel) { switch (Kind) { case Mips::fixup_Mips_Branch_PCRel: case Mips::fixup_Mips_PC16: return ELF::R_MIPS_PC16; case Mips::fixup_MICROMIPS_PC7_S1: return ELF::R_MICROMIPS_PC7_S1; case Mips::fixup_MICROMIPS_PC10_S1: return ELF::R_MICROMIPS_PC10_S1; case Mips::fixup_MICROMIPS_PC16_S1: return ELF::R_MICROMIPS_PC16_S1; case Mips::fixup_MIPS_PC19_S2: return ELF::R_MIPS_PC19_S2; case Mips::fixup_MIPS_PC18_S3: return ELF::R_MIPS_PC18_S3; case Mips::fixup_MIPS_PC21_S2: return ELF::R_MIPS_PC21_S2; case Mips::fixup_MIPS_PC26_S2: return ELF::R_MIPS_PC26_S2; case Mips::fixup_MIPS_PCHI16: return ELF::R_MIPS_PCHI16; case Mips::fixup_MIPS_PCLO16: return ELF::R_MIPS_PCLO16; } llvm_unreachable("invalid PC-relative fixup kind!"); } switch (Kind) { case Mips::fixup_Mips_64: case FK_Data_8: return ELF::R_MIPS_64; case FK_GPRel_4: if (isN64()) { unsigned Type = (unsigned)ELF::R_MIPS_NONE; Type = setRType((unsigned)ELF::R_MIPS_GPREL32, Type); Type = setRType2((unsigned)ELF::R_MIPS_64, Type); Type = setRType3((unsigned)ELF::R_MIPS_NONE, Type); return Type; } return ELF::R_MIPS_GPREL32; case Mips::fixup_Mips_GPREL16: return ELF::R_MIPS_GPREL16; case Mips::fixup_Mips_26: return ELF::R_MIPS_26; case Mips::fixup_Mips_CALL16: return ELF::R_MIPS_CALL16; case Mips::fixup_Mips_GOT_Global: case Mips::fixup_Mips_GOT_Local: return ELF::R_MIPS_GOT16; case Mips::fixup_Mips_HI16: return ELF::R_MIPS_HI16; case Mips::fixup_Mips_LO16: return ELF::R_MIPS_LO16; case Mips::fixup_Mips_TLSGD: return ELF::R_MIPS_TLS_GD; case Mips::fixup_Mips_GOTTPREL: return ELF::R_MIPS_TLS_GOTTPREL; case Mips::fixup_Mips_TPREL_HI: return ELF::R_MIPS_TLS_TPREL_HI16; case Mips::fixup_Mips_TPREL_LO: return ELF::R_MIPS_TLS_TPREL_LO16; case Mips::fixup_Mips_TLSLDM: return ELF::R_MIPS_TLS_LDM; case Mips::fixup_Mips_DTPREL_HI: return ELF::R_MIPS_TLS_DTPREL_HI16; case Mips::fixup_Mips_DTPREL_LO: return ELF::R_MIPS_TLS_DTPREL_LO16; case Mips::fixup_Mips_GOT_PAGE: return ELF::R_MIPS_GOT_PAGE; case Mips::fixup_Mips_GOT_OFST: return ELF::R_MIPS_GOT_OFST; case Mips::fixup_Mips_GOT_DISP: return ELF::R_MIPS_GOT_DISP; case Mips::fixup_Mips_GPOFF_HI: { unsigned Type = (unsigned)ELF::R_MIPS_NONE; Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type); Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type); Type = setRType3((unsigned)ELF::R_MIPS_HI16, Type); return Type; } case Mips::fixup_Mips_GPOFF_LO: { unsigned Type = (unsigned)ELF::R_MIPS_NONE; Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type); Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type); Type = setRType3((unsigned)ELF::R_MIPS_LO16, Type); return Type; } case Mips::fixup_Mips_HIGHER: return ELF::R_MIPS_HIGHER; case Mips::fixup_Mips_HIGHEST: return ELF::R_MIPS_HIGHEST; case Mips::fixup_Mips_GOT_HI16: return ELF::R_MIPS_GOT_HI16; case Mips::fixup_Mips_GOT_LO16: return ELF::R_MIPS_GOT_LO16; case Mips::fixup_Mips_CALL_HI16: return ELF::R_MIPS_CALL_HI16; case Mips::fixup_Mips_CALL_LO16: return ELF::R_MIPS_CALL_LO16; case Mips::fixup_MICROMIPS_26_S1: return ELF::R_MICROMIPS_26_S1; case Mips::fixup_MICROMIPS_HI16: return ELF::R_MICROMIPS_HI16; case Mips::fixup_MICROMIPS_LO16: return ELF::R_MICROMIPS_LO16; case Mips::fixup_MICROMIPS_GOT16: return ELF::R_MICROMIPS_GOT16; case Mips::fixup_MICROMIPS_CALL16: return ELF::R_MICROMIPS_CALL16; case Mips::fixup_MICROMIPS_GOT_DISP: return ELF::R_MICROMIPS_GOT_DISP; case Mips::fixup_MICROMIPS_GOT_PAGE: return ELF::R_MICROMIPS_GOT_PAGE; case Mips::fixup_MICROMIPS_GOT_OFST: return ELF::R_MICROMIPS_GOT_OFST; case Mips::fixup_MICROMIPS_TLS_GD: return ELF::R_MICROMIPS_TLS_GD; case Mips::fixup_MICROMIPS_TLS_LDM: return ELF::R_MICROMIPS_TLS_LDM; case Mips::fixup_MICROMIPS_TLS_DTPREL_HI16: return ELF::R_MICROMIPS_TLS_DTPREL_HI16; case Mips::fixup_MICROMIPS_TLS_DTPREL_LO16: return ELF::R_MICROMIPS_TLS_DTPREL_LO16; case Mips::fixup_MICROMIPS_TLS_TPREL_HI16: return ELF::R_MICROMIPS_TLS_TPREL_HI16; case Mips::fixup_MICROMIPS_TLS_TPREL_LO16: return ELF::R_MICROMIPS_TLS_TPREL_LO16; } llvm_unreachable("invalid fixup kind!"); }
bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo( const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym, unsigned &Log2Size, const MCAssembler &Asm) { RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED); Log2Size = ~0U; switch ((unsigned)Fixup.getKind()) { default: return false; case FK_Data_1: Log2Size = llvm::Log2_32(1); return true; case FK_Data_2: Log2Size = llvm::Log2_32(2); return true; case FK_Data_4: Log2Size = llvm::Log2_32(4); if (Sym->getKind() == MCSymbolRefExpr::VK_GOT) RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); return true; case FK_Data_8: Log2Size = llvm::Log2_32(8); if (Sym->getKind() == MCSymbolRefExpr::VK_GOT) RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT); return true; case AArch64::fixup_aarch64_add_imm12: case AArch64::fixup_aarch64_ldst_imm12_scale1: case AArch64::fixup_aarch64_ldst_imm12_scale2: case AArch64::fixup_aarch64_ldst_imm12_scale4: case AArch64::fixup_aarch64_ldst_imm12_scale8: case AArch64::fixup_aarch64_ldst_imm12_scale16: Log2Size = llvm::Log2_32(4); switch (Sym->getKind()) { default: llvm_unreachable("Unexpected symbol reference variant kind!"); case MCSymbolRefExpr::VK_PAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12); return true; case MCSymbolRefExpr::VK_GOTPAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12); return true; case MCSymbolRefExpr::VK_TLVPPAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12); return true; } case AArch64::fixup_aarch64_pcrel_adrp_imm21: Log2Size = llvm::Log2_32(4); // This encompasses the relocation for the whole 21-bit value. switch (Sym->getKind()) { default: Asm.getContext().FatalError(Fixup.getLoc(), "ADR/ADRP relocations must be GOT relative"); case MCSymbolRefExpr::VK_PAGE: RelocType = unsigned(MachO::ARM64_RELOC_PAGE21); return true; case MCSymbolRefExpr::VK_GOTPAGE: RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21); return true; case MCSymbolRefExpr::VK_TLVPPAGE: RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21); return true; } return true; case AArch64::fixup_aarch64_pcrel_branch26: case AArch64::fixup_aarch64_pcrel_call26: Log2Size = llvm::Log2_32(4); RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26); return true; } }
void AArch64MachObjectWriter::RecordRelocation( 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()); // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment); unsigned Log2Size = 0; int64_t Value = 0; unsigned Index = 0; unsigned Type = 0; unsigned Kind = Fixup.getKind(); const MCSymbolData *RelSymbol = nullptr; 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; if (IsPCRel) { 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. Type = MachO::ARM64_RELOC_POINTER_TO_GOT; IsPCRel = 1; MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(A_Base, 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)); Type = MachO::ARM64_RELOC_UNSIGNED; MachO::any_relocation_info MRE; MRE.r_word0 = FixupOffset; MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28); Writer->addRelocation(A_Base, Fragment->getParent(), MRE); RelSymbol = B_Base; Type = MachO::ARM64_RELOC_SUBTRACTOR; } else { // A + constant const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); const MCSectionMachO &Section = static_cast<const MCSectionMachO &>( Fragment->getParent()->getSection()); bool CanUseLocalRelocation = canUseLocalRelocation(Section, *Symbol, Log2Size); if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) { const MCSection &Sec = Symbol->getSection(); if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec)) Asm.addLocalUsedInReloc(*Symbol); } const MCSymbolData &SD = Asm.getSymbolData(*Symbol); const MCSymbolData *Base = Asm.getAtom(&SD); // 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, &Fixup)) 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) { RelSymbol = Base; // Add the local offset, if needed. if (Base != &SD) Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); } else if (Symbol->isInSection()) { if (!CanUseLocalRelocation) 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; 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) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); // Now set up the Addend relocation. Type = MachO::ARM64_RELOC_ADDEND; Index = Value; RelSymbol = nullptr; IsPCRel = 0; Log2Size = 2; // 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) | (Type << 28); Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); }
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 MCSymbolData &A_SD = Asm.getSymbolData(*A); const MCSymbol *A_Base = Asm.getAtom(&A_SD); const MCSymbol *B = &Target.getSymB()->getSymbol(); if (B->isTemporary()) B = &Writer->findAliasedSymbol(*B); const MCSymbolData &B_SD = Asm.getSymbolData(*B); const MCSymbol *B_Base = Asm.getAtom(&B_SD); // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported relocation of modified symbol", false); // We don't support PCrel relocations of differences. Darwin 'as' doesn't // implement most of these correctly. if (IsPCRel) report_fatal_error("unsupported pc-relative relocation of difference", false); // 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) report_fatal_error("unsupported relocation with identical base", false); // 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().FatalError(Fixup.getLoc(), "unsupported relocation with subtraction expression, symbol '" + Name + "' can not be undefined in a subtraction expression"); } Value += Writer->getSymbolAddress(&A_SD, Layout) - (!A_Base ? 0 : Writer->getSymbolAddress(&A_Base->getData(), Layout)); Value -= Writer->getSymbolAddress(&B_SD, Layout) - (!B_Base ? 0 : Writer->getSymbolAddress(&B_Base->getData(), Layout)); if (!A_Base) Index = A_SD.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_SD.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)) Asm.addLocalUsedInReloc(*Symbol); } const MCSymbolData &SD = Asm.getSymbolData(*Symbol); RelSymbol = Asm.getAtom(&SD); // 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()->getSection()); 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->getData() != &SD) Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(&RelSymbol->getData()); } else if (Symbol->isInSection() && !Symbol->isVariable()) { // The index is the section ordinal (1-based). Index = SD.getFragment()->getParent()->getOrdinal() + 1; Value += Writer->getSymbolAddress(&SD, 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 { report_fatal_error("unsupported relocation of variable '" + Symbol->getName() + "'", false); } } else { report_fatal_error("unsupported relocation of undefined symbol '" + Symbol->getName() + "'", false); } 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) { report_fatal_error("unsupported symbol modifier in relocation", false); } 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) report_fatal_error("unsupported symbol modifier in branch " "relocation", false); 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) { report_fatal_error("TLVP symbol modifier should have been rip-rel", false); } else if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in relocation", false); else { Type = MachO::X86_64_RELOC_UNSIGNED; unsigned Kind = Fixup.getKind(); if (Kind == X86::reloc_signed_4byte) report_fatal_error("32-bit absolute addressing is not supported in " "64-bit mode", false); } } } // 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); }
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(); const MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) report_fatal_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression", false); uint32_t Value = Writer->getSymbolAddress(A_SD, Layout); uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent()); FixedValue += SecAddr; uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); if (!B_SD->getFragment()) report_fatal_error("symbol '" + B->getSymbol().getName() + "' can not be undefined in a subtraction expression", 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_SD->isExternal() ? (unsigned)MachO::GENERIC_RELOC_SECTDIFF : (unsigned)MachO::GENERIC_RELOC_LOCAL_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. 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().FatalError(Fixup.getLoc(), Twine("Section too large, can't encode " "r_address (") + Buffer + ") into 24 bits of scattered " "relocation entry."); llvm_unreachable("fatal error returned?!"); } 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; }
unsigned OR1KELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend) const { unsigned Type; unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { default: llvm_unreachable("Invalid fixup kind!"); case FK_Data_4: if(IsPCRel) Type = ELF::R_OR1K_32_PCREL; else Type = ELF::R_OR1K_32; break; case FK_Data_2: if(IsPCRel) Type = ELF::R_OR1K_16_PCREL; else Type = ELF::R_OR1K_16; break; case FK_Data_1: if(IsPCRel) Type = ELF::R_OR1K_8_PCREL; else Type = ELF::R_OR1K_8; break; case OR1K::fixup_OR1K_PCREL32: case FK_PCRel_4: Type = ELF::R_OR1K_32_PCREL; break; case OR1K::fixup_OR1K_PCREL16: case FK_PCRel_2: Type = ELF::R_OR1K_16_PCREL; break; case OR1K::fixup_OR1K_PCREL8: case FK_PCRel_1: Type = ELF::R_OR1K_8_PCREL; break; case OR1K::fixup_OR1K_32: Type = ELF::R_OR1K_32; break; case OR1K::fixup_OR1K_16: Type = ELF::R_OR1K_16; break; case OR1K::fixup_OR1K_8: Type = ELF::R_OR1K_8; break; case OR1K::fixup_OR1K_NONE: Type = ELF::R_OR1K_NONE; break; case OR1K::fixup_OR1K_LO16_INSN: Type = ELF::R_OR1K_LO_16_IN_INSN; break; case OR1K::fixup_OR1K_HI16_INSN: Type = ELF::R_OR1K_HI_16_IN_INSN; break; case OR1K::fixup_OR1K_REL26: Type = ELF::R_OR1K_INSN_REL_26; break; case OR1K::fixup_OR1K_GOTPC_HI16: Type = ELF::R_OR1K_GOTPC_HI16; break; case OR1K::fixup_OR1K_GOTPC_LO16: Type = ELF::R_OR1K_GOTPC_LO16; break; case OR1K::fixup_OR1K_GOT16: Type = ELF::R_OR1K_GOT16; break; case OR1K::fixup_OR1K_PLT26: Type = ELF::R_OR1K_PLT26; break; case OR1K::fixup_OR1K_GOTOFF_HI16: Type = ELF::R_OR1K_GOTOFF_HI16; break; case OR1K::fixup_OR1K_GOTOFF_LO16: Type = ELF::R_OR1K_GOTOFF_LO16; break; case OR1K::fixup_OR1K_COPY: Type = ELF::R_OR1K_COPY; break; case OR1K::fixup_OR1K_GLOB_DAT: Type = ELF::R_OR1K_GLOB_DAT; break; case OR1K::fixup_OR1K_JMP_SLOT: Type = ELF::R_OR1K_JMP_SLOT; break; case OR1K::fixup_OR1K_RELATIVE: Type = ELF::R_OR1K_RELATIVE; break; } return Type; }
unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); unsigned Type = 0; if (IsPCRel) { switch ((unsigned)Fixup.getKind()) { default: report_fatal_error("unsupported relocation on symbol"); return ELF::R_ARM_NONE; case FK_Data_4: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_ARM_REL32; break; case MCSymbolRefExpr::VK_TLSGD: llvm_unreachable("unimplemented"); case MCSymbolRefExpr::VK_GOTTPOFF: Type = ELF::R_ARM_TLS_IE32; break; case MCSymbolRefExpr::VK_ARM_GOT_PREL: Type = ELF::R_ARM_GOT_PREL; break; case MCSymbolRefExpr::VK_ARM_PREL31: Type = ELF::R_ARM_PREL31; break; } break; case ARM::fixup_arm_blx: case ARM::fixup_arm_uncondbl: switch (Modifier) { case MCSymbolRefExpr::VK_PLT: Type = ELF::R_ARM_CALL; break; case MCSymbolRefExpr::VK_TLSCALL: Type = ELF::R_ARM_TLS_CALL; break; default: Type = ELF::R_ARM_CALL; break; } break; case ARM::fixup_arm_condbl: case ARM::fixup_arm_condbranch: case ARM::fixup_arm_uncondbranch: Type = ELF::R_ARM_JUMP24; break; case ARM::fixup_t2_condbranch: Type = ELF::R_ARM_THM_JUMP19; break; case ARM::fixup_t2_uncondbranch: Type = ELF::R_ARM_THM_JUMP24; break; case ARM::fixup_arm_movt_hi16: Type = ELF::R_ARM_MOVT_PREL; break; case ARM::fixup_arm_movw_lo16: Type = ELF::R_ARM_MOVW_PREL_NC; break; case ARM::fixup_t2_movt_hi16: Type = ELF::R_ARM_THM_MOVT_PREL; break; case ARM::fixup_t2_movw_lo16: Type = ELF::R_ARM_THM_MOVW_PREL_NC; break; case ARM::fixup_arm_thumb_bl: case ARM::fixup_arm_thumb_blx: switch (Modifier) { case MCSymbolRefExpr::VK_TLSCALL: Type = ELF::R_ARM_THM_TLS_CALL; break; default: Type = ELF::R_ARM_THM_CALL; break; } break; } } else { switch ((unsigned)Fixup.getKind()) { default: report_fatal_error("unsupported relocation on symbol"); return ELF::R_ARM_NONE; case FK_Data_1: switch (Modifier) { default: llvm_unreachable("unsupported Modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_ARM_ABS8; break; } break; case FK_Data_2: switch (Modifier) { default: llvm_unreachable("unsupported modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_ARM_ABS16; break; } break; case FK_Data_4: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_ARM_NONE: Type = ELF::R_ARM_NONE; break; case MCSymbolRefExpr::VK_GOT: Type = ELF::R_ARM_GOT_BREL; break; case MCSymbolRefExpr::VK_TLSGD: Type = ELF::R_ARM_TLS_GD32; break; case MCSymbolRefExpr::VK_TPOFF: Type = ELF::R_ARM_TLS_LE32; break; case MCSymbolRefExpr::VK_GOTTPOFF: Type = ELF::R_ARM_TLS_IE32; break; case MCSymbolRefExpr::VK_None: Type = ELF::R_ARM_ABS32; break; case MCSymbolRefExpr::VK_GOTOFF: Type = ELF::R_ARM_GOTOFF32; break; case MCSymbolRefExpr::VK_ARM_GOT_PREL: Type = ELF::R_ARM_GOT_PREL; break; case MCSymbolRefExpr::VK_ARM_TARGET1: Type = ELF::R_ARM_TARGET1; break; case MCSymbolRefExpr::VK_ARM_TARGET2: Type = ELF::R_ARM_TARGET2; break; case MCSymbolRefExpr::VK_ARM_PREL31: Type = ELF::R_ARM_PREL31; break; case MCSymbolRefExpr::VK_ARM_SBREL: Type = ELF::R_ARM_SBREL32; break; case MCSymbolRefExpr::VK_ARM_TLSLDO: Type = ELF::R_ARM_TLS_LDO32; break; case MCSymbolRefExpr::VK_TLSCALL: Type = ELF::R_ARM_TLS_CALL; break; case MCSymbolRefExpr::VK_TLSDESC: Type = ELF::R_ARM_TLS_GOTDESC; break; case MCSymbolRefExpr::VK_TLSLDM: Type = ELF::R_ARM_TLS_LDM32; break; case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ: Type = ELF::R_ARM_TLS_DESCSEQ; break; } break; case ARM::fixup_arm_ldst_pcrel_12: case ARM::fixup_arm_pcrel_10: case ARM::fixup_arm_adr_pcrel_12: case ARM::fixup_arm_thumb_bl: case ARM::fixup_arm_thumb_cb: case ARM::fixup_arm_thumb_cp: case ARM::fixup_arm_thumb_br: llvm_unreachable("Unimplemented"); case ARM::fixup_arm_condbranch: case ARM::fixup_arm_uncondbranch: Type = ELF::R_ARM_JUMP24; break; case ARM::fixup_arm_movt_hi16: Type = ELF::R_ARM_MOVT_ABS; break; case ARM::fixup_arm_movw_lo16: Type = ELF::R_ARM_MOVW_ABS_NC; break; case ARM::fixup_t2_movt_hi16: Type = ELF::R_ARM_THM_MOVT_ABS; break; case ARM::fixup_t2_movw_lo16: Type = ELF::R_ARM_THM_MOVW_ABS_NC; break; } } return Type; }
unsigned HexagonELFObjectWriter::GetRelocType(MCValue const & /*Target*/, MCFixup const &Fixup, bool IsPCRel) const { switch ((unsigned)Fixup.getKind()) { default: DEBUG(dbgs() << "unrecognized relocation " << Fixup.getKind() << "\n"); llvm_unreachable("Unimplemented Fixup kind!"); return ELF::R_HEX_NONE; case FK_Data_4: return (IsPCRel) ? ELF::R_HEX_32_PCREL : ELF::R_HEX_32; case FK_PCRel_4: return ELF::R_HEX_32_PCREL; case FK_Data_2: return ELF::R_HEX_16; case FK_Data_1: return ELF::R_HEX_8; case fixup_Hexagon_B22_PCREL: return ELF::R_HEX_B22_PCREL; case fixup_Hexagon_B15_PCREL: return ELF::R_HEX_B15_PCREL; case fixup_Hexagon_B7_PCREL: return ELF::R_HEX_B7_PCREL; case fixup_Hexagon_LO16: return ELF::R_HEX_LO16; case fixup_Hexagon_HI16: return ELF::R_HEX_HI16; case fixup_Hexagon_32: return ELF::R_HEX_32; case fixup_Hexagon_16: return ELF::R_HEX_16; case fixup_Hexagon_8: return ELF::R_HEX_8; case fixup_Hexagon_GPREL16_0: return ELF::R_HEX_GPREL16_0; case fixup_Hexagon_GPREL16_1: return ELF::R_HEX_GPREL16_1; case fixup_Hexagon_GPREL16_2: return ELF::R_HEX_GPREL16_2; case fixup_Hexagon_GPREL16_3: return ELF::R_HEX_GPREL16_3; case fixup_Hexagon_HL16: return ELF::R_HEX_HL16; case fixup_Hexagon_B13_PCREL: return ELF::R_HEX_B13_PCREL; case fixup_Hexagon_B9_PCREL: return ELF::R_HEX_B9_PCREL; case fixup_Hexagon_B32_PCREL_X: return ELF::R_HEX_B32_PCREL_X; case fixup_Hexagon_32_6_X: return ELF::R_HEX_32_6_X; case fixup_Hexagon_B22_PCREL_X: return ELF::R_HEX_B22_PCREL_X; case fixup_Hexagon_B15_PCREL_X: return ELF::R_HEX_B15_PCREL_X; case fixup_Hexagon_B13_PCREL_X: return ELF::R_HEX_B13_PCREL_X; case fixup_Hexagon_B9_PCREL_X: return ELF::R_HEX_B9_PCREL_X; case fixup_Hexagon_B7_PCREL_X: return ELF::R_HEX_B7_PCREL_X; case fixup_Hexagon_16_X: return ELF::R_HEX_16_X; case fixup_Hexagon_12_X: return ELF::R_HEX_12_X; case fixup_Hexagon_11_X: return ELF::R_HEX_11_X; case fixup_Hexagon_10_X: return ELF::R_HEX_10_X; case fixup_Hexagon_9_X: return ELF::R_HEX_9_X; case fixup_Hexagon_8_X: return ELF::R_HEX_8_X; case fixup_Hexagon_7_X: return ELF::R_HEX_7_X; case fixup_Hexagon_6_X: return ELF::R_HEX_6_X; case fixup_Hexagon_32_PCREL: return ELF::R_HEX_32_PCREL; case fixup_Hexagon_COPY: return ELF::R_HEX_COPY; case fixup_Hexagon_GLOB_DAT: return ELF::R_HEX_GLOB_DAT; case fixup_Hexagon_JMP_SLOT: return ELF::R_HEX_JMP_SLOT; case fixup_Hexagon_RELATIVE: return ELF::R_HEX_RELATIVE; case fixup_Hexagon_PLT_B22_PCREL: return ELF::R_HEX_PLT_B22_PCREL; case fixup_Hexagon_GOTREL_LO16: return ELF::R_HEX_GOTREL_LO16; case fixup_Hexagon_GOTREL_HI16: return ELF::R_HEX_GOTREL_HI16; case fixup_Hexagon_GOTREL_32: return ELF::R_HEX_GOTREL_32; case fixup_Hexagon_GOT_LO16: return ELF::R_HEX_GOT_LO16; case fixup_Hexagon_GOT_HI16: return ELF::R_HEX_GOT_HI16; case fixup_Hexagon_GOT_32: return ELF::R_HEX_GOT_32; case fixup_Hexagon_GOT_16: return ELF::R_HEX_GOT_16; case fixup_Hexagon_DTPMOD_32: return ELF::R_HEX_DTPMOD_32; case fixup_Hexagon_DTPREL_LO16: return ELF::R_HEX_DTPREL_LO16; case fixup_Hexagon_DTPREL_HI16: return ELF::R_HEX_DTPREL_HI16; case fixup_Hexagon_DTPREL_32: return ELF::R_HEX_DTPREL_32; case fixup_Hexagon_DTPREL_16: return ELF::R_HEX_DTPREL_16; case fixup_Hexagon_GD_PLT_B22_PCREL: return ELF::R_HEX_GD_PLT_B22_PCREL; case fixup_Hexagon_LD_PLT_B22_PCREL: return ELF::R_HEX_LD_PLT_B22_PCREL; case fixup_Hexagon_GD_GOT_LO16: return ELF::R_HEX_GD_GOT_LO16; case fixup_Hexagon_GD_GOT_HI16: return ELF::R_HEX_GD_GOT_HI16; case fixup_Hexagon_GD_GOT_32: return ELF::R_HEX_GD_GOT_32; case fixup_Hexagon_GD_GOT_16: return ELF::R_HEX_GD_GOT_16; case fixup_Hexagon_LD_GOT_LO16: return ELF::R_HEX_LD_GOT_LO16; case fixup_Hexagon_LD_GOT_HI16: return ELF::R_HEX_LD_GOT_HI16; case fixup_Hexagon_LD_GOT_32: return ELF::R_HEX_LD_GOT_32; case fixup_Hexagon_LD_GOT_16: return ELF::R_HEX_LD_GOT_16; case fixup_Hexagon_IE_LO16: return ELF::R_HEX_IE_LO16; case fixup_Hexagon_IE_HI16: return ELF::R_HEX_IE_HI16; case fixup_Hexagon_IE_32: return ELF::R_HEX_IE_32; case fixup_Hexagon_IE_GOT_LO16: return ELF::R_HEX_IE_GOT_LO16; case fixup_Hexagon_IE_GOT_HI16: return ELF::R_HEX_IE_GOT_HI16; case fixup_Hexagon_IE_GOT_32: return ELF::R_HEX_IE_GOT_32; case fixup_Hexagon_IE_GOT_16: return ELF::R_HEX_IE_GOT_16; case fixup_Hexagon_TPREL_LO16: return ELF::R_HEX_TPREL_LO16; case fixup_Hexagon_TPREL_HI16: return ELF::R_HEX_TPREL_HI16; case fixup_Hexagon_TPREL_32: return ELF::R_HEX_TPREL_32; case fixup_Hexagon_TPREL_16: return ELF::R_HEX_TPREL_16; case fixup_Hexagon_6_PCREL_X: return ELF::R_HEX_6_PCREL_X; case fixup_Hexagon_GOTREL_32_6_X: return ELF::R_HEX_GOTREL_32_6_X; case fixup_Hexagon_GOTREL_16_X: return ELF::R_HEX_GOTREL_16_X; case fixup_Hexagon_GOTREL_11_X: return ELF::R_HEX_GOTREL_11_X; case fixup_Hexagon_GOT_32_6_X: return ELF::R_HEX_GOT_32_6_X; case fixup_Hexagon_GOT_16_X: return ELF::R_HEX_GOT_16_X; case fixup_Hexagon_GOT_11_X: return ELF::R_HEX_GOT_11_X; case fixup_Hexagon_DTPREL_32_6_X: return ELF::R_HEX_DTPREL_32_6_X; case fixup_Hexagon_DTPREL_16_X: return ELF::R_HEX_DTPREL_16_X; case fixup_Hexagon_DTPREL_11_X: return ELF::R_HEX_DTPREL_11_X; case fixup_Hexagon_GD_GOT_32_6_X: return ELF::R_HEX_GD_GOT_32_6_X; case fixup_Hexagon_GD_GOT_16_X: return ELF::R_HEX_GD_GOT_16_X; case fixup_Hexagon_GD_GOT_11_X: return ELF::R_HEX_GD_GOT_11_X; case fixup_Hexagon_LD_GOT_32_6_X: return ELF::R_HEX_LD_GOT_32_6_X; case fixup_Hexagon_LD_GOT_16_X: return ELF::R_HEX_LD_GOT_16_X; case fixup_Hexagon_LD_GOT_11_X: return ELF::R_HEX_LD_GOT_11_X; case fixup_Hexagon_IE_32_6_X: return ELF::R_HEX_IE_32_6_X; case fixup_Hexagon_IE_16_X: return ELF::R_HEX_IE_16_X; case fixup_Hexagon_IE_GOT_32_6_X: return ELF::R_HEX_IE_GOT_32_6_X; case fixup_Hexagon_IE_GOT_16_X: return ELF::R_HEX_IE_GOT_16_X; case fixup_Hexagon_IE_GOT_11_X: return ELF::R_HEX_IE_GOT_11_X; case fixup_Hexagon_TPREL_32_6_X: return ELF::R_HEX_TPREL_32_6_X; case fixup_Hexagon_TPREL_16_X: return ELF::R_HEX_TPREL_16_X; case fixup_Hexagon_TPREL_11_X: return ELF::R_HEX_TPREL_11_X; } }
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 MCSymbolData *SD = nullptr; if (Target.getSymA()) SD = &Asm.getSymbolData(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 && SD && !Writer->doesSymbolRequireExternRelocation(SD) && 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 (SD->getSymbol().isVariable()) { int64_t Res; if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( Res, Layout, Writer->getSectionAddressMap())) { FixedValue = Res; return; } } // Check whether we need an external or internal relocation. if (Writer->doesSymbolRequireExternRelocation(SD)) { RelSymbol = &SD->getSymbol(); // 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 (!SD->getSymbol().isUndefined()) FixedValue -= Layout.getSymbolOffset(SD); } else { // The index is the section ordinal (1-based). const MCSectionData &SymSD = Asm.getSectionData( SD->getSymbol().getSection()); Index = SymSD.getOrdinal() + 1; FixedValue += Writer->getSectionAddress(&SymSD); } 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); }
unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { MCSymbolRefExpr::VariantKind Modifier = getAccessVariant(Target, Fixup); // determine the type of the relocation unsigned Type; if (IsPCRel) { switch ((unsigned)Fixup.getKind()) { default: llvm_unreachable("Unimplemented"); case PPC::fixup_ppc_br24: case PPC::fixup_ppc_br24abs: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC_REL24; break; case MCSymbolRefExpr::VK_PLT: Type = ELF::R_PPC_PLTREL24; break; case MCSymbolRefExpr::VK_PPC_LOCAL: Type = ELF::R_PPC_LOCAL24PC; break; } break; case PPC::fixup_ppc_brcond14: case PPC::fixup_ppc_brcond14abs: Type = ELF::R_PPC_REL14; break; case PPC::fixup_ppc_half16: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC_REL16; break; case MCSymbolRefExpr::VK_PPC_LO: Type = ELF::R_PPC_REL16_LO; break; case MCSymbolRefExpr::VK_PPC_HI: Type = ELF::R_PPC_REL16_HI; break; case MCSymbolRefExpr::VK_PPC_HA: Type = ELF::R_PPC_REL16_HA; break; } break; case FK_Data_4: case FK_PCRel_4: Type = ELF::R_PPC_REL32; break; case FK_Data_8: case FK_PCRel_8: Type = ELF::R_PPC64_REL64; break; } } else { switch ((unsigned)Fixup.getKind()) { default: llvm_unreachable("invalid fixup kind!"); case PPC::fixup_ppc_br24abs: Type = ELF::R_PPC_ADDR24; break; case PPC::fixup_ppc_brcond14abs: Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ break; case PPC::fixup_ppc_half16: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC_ADDR16; break; case MCSymbolRefExpr::VK_PPC_LO: Type = ELF::R_PPC_ADDR16_LO; break; case MCSymbolRefExpr::VK_PPC_HI: Type = ELF::R_PPC_ADDR16_HI; break; case MCSymbolRefExpr::VK_PPC_HA: Type = ELF::R_PPC_ADDR16_HA; break; case MCSymbolRefExpr::VK_PPC_HIGHER: Type = ELF::R_PPC64_ADDR16_HIGHER; break; case MCSymbolRefExpr::VK_PPC_HIGHERA: Type = ELF::R_PPC64_ADDR16_HIGHERA; break; case MCSymbolRefExpr::VK_PPC_HIGHEST: Type = ELF::R_PPC64_ADDR16_HIGHEST; break; case MCSymbolRefExpr::VK_PPC_HIGHESTA: Type = ELF::R_PPC64_ADDR16_HIGHESTA; break; case MCSymbolRefExpr::VK_GOT: Type = ELF::R_PPC_GOT16; break; case MCSymbolRefExpr::VK_PPC_GOT_LO: Type = ELF::R_PPC_GOT16_LO; break; case MCSymbolRefExpr::VK_PPC_GOT_HI: Type = ELF::R_PPC_GOT16_HI; break; case MCSymbolRefExpr::VK_PPC_GOT_HA: Type = ELF::R_PPC_GOT16_HA; break; case MCSymbolRefExpr::VK_PPC_TOC: Type = ELF::R_PPC64_TOC16; break; case MCSymbolRefExpr::VK_PPC_TOC_LO: Type = ELF::R_PPC64_TOC16_LO; break; case MCSymbolRefExpr::VK_PPC_TOC_HI: Type = ELF::R_PPC64_TOC16_HI; break; case MCSymbolRefExpr::VK_PPC_TOC_HA: Type = ELF::R_PPC64_TOC16_HA; break; case MCSymbolRefExpr::VK_PPC_TPREL: Type = ELF::R_PPC_TPREL16; break; case MCSymbolRefExpr::VK_PPC_TPREL_LO: Type = ELF::R_PPC_TPREL16_LO; break; case MCSymbolRefExpr::VK_PPC_TPREL_HI: Type = ELF::R_PPC_TPREL16_HI; break; case MCSymbolRefExpr::VK_PPC_TPREL_HA: Type = ELF::R_PPC_TPREL16_HA; break; case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER: Type = ELF::R_PPC64_TPREL16_HIGHER; break; case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA: Type = ELF::R_PPC64_TPREL16_HIGHERA; break; case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST: Type = ELF::R_PPC64_TPREL16_HIGHEST; break; case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA: Type = ELF::R_PPC64_TPREL16_HIGHESTA; break; case MCSymbolRefExpr::VK_PPC_DTPREL: Type = ELF::R_PPC64_DTPREL16; break; case MCSymbolRefExpr::VK_PPC_DTPREL_LO: Type = ELF::R_PPC64_DTPREL16_LO; break; case MCSymbolRefExpr::VK_PPC_DTPREL_HI: Type = ELF::R_PPC64_DTPREL16_HI; break; case MCSymbolRefExpr::VK_PPC_DTPREL_HA: Type = ELF::R_PPC64_DTPREL16_HA; break; case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER: Type = ELF::R_PPC64_DTPREL16_HIGHER; break; case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA: Type = ELF::R_PPC64_DTPREL16_HIGHERA; break; case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST: Type = ELF::R_PPC64_DTPREL16_HIGHEST; break; case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA: Type = ELF::R_PPC64_DTPREL16_HIGHESTA; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSGD: if (is64Bit()) Type = ELF::R_PPC64_GOT_TLSGD16; else Type = ELF::R_PPC_GOT_TLSGD16; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO: Type = ELF::R_PPC64_GOT_TLSGD16_LO; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI: Type = ELF::R_PPC64_GOT_TLSGD16_HI; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA: Type = ELF::R_PPC64_GOT_TLSGD16_HA; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSLD: if (is64Bit()) Type = ELF::R_PPC64_GOT_TLSLD16; else Type = ELF::R_PPC_GOT_TLSLD16; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO: Type = ELF::R_PPC64_GOT_TLSLD16_LO; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI: Type = ELF::R_PPC64_GOT_TLSLD16_HI; break; case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA: Type = ELF::R_PPC64_GOT_TLSLD16_HA; break; case MCSymbolRefExpr::VK_PPC_GOT_TPREL: /* We don't have R_PPC64_GOT_TPREL16, but since GOT offsets are always 4-aligned, we can use R_PPC64_GOT_TPREL16_DS. */ Type = ELF::R_PPC64_GOT_TPREL16_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: /* We don't have R_PPC64_GOT_TPREL16_LO, but since GOT offsets are always 4-aligned, we can use R_PPC64_GOT_TPREL16_LO_DS. */ Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI: Type = ELF::R_PPC64_GOT_TPREL16_HI; break; case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: /* We don't have R_PPC64_GOT_DTPREL16, but since GOT offsets are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_DS. */ Type = ELF::R_PPC64_GOT_DTPREL16_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: /* We don't have R_PPC64_GOT_DTPREL16_LO, but since GOT offsets are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_LO_DS. */ Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA: Type = ELF::R_PPC64_GOT_TPREL16_HA; break; case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI: Type = ELF::R_PPC64_GOT_DTPREL16_HI; break; case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA: Type = ELF::R_PPC64_GOT_DTPREL16_HA; break; } break; case PPC::fixup_ppc_half16ds: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC64_ADDR16_DS; break; case MCSymbolRefExpr::VK_PPC_LO: Type = ELF::R_PPC64_ADDR16_LO_DS; break; case MCSymbolRefExpr::VK_GOT: Type = ELF::R_PPC64_GOT16_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_LO: Type = ELF::R_PPC64_GOT16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_TOC: Type = ELF::R_PPC64_TOC16_DS; break; case MCSymbolRefExpr::VK_PPC_TOC_LO: Type = ELF::R_PPC64_TOC16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_TPREL: Type = ELF::R_PPC64_TPREL16_DS; break; case MCSymbolRefExpr::VK_PPC_TPREL_LO: Type = ELF::R_PPC64_TPREL16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_DTPREL: Type = ELF::R_PPC64_DTPREL16_DS; break; case MCSymbolRefExpr::VK_PPC_DTPREL_LO: Type = ELF::R_PPC64_DTPREL16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_TPREL: Type = ELF::R_PPC64_GOT_TPREL16_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: Type = ELF::R_PPC64_GOT_DTPREL16_DS; break; case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS; break; } break; case PPC::fixup_ppc_nofixup: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_PPC_TLSGD: if (is64Bit()) Type = ELF::R_PPC64_TLSGD; else Type = ELF::R_PPC_TLSGD; break; case MCSymbolRefExpr::VK_PPC_TLSLD: if (is64Bit()) Type = ELF::R_PPC64_TLSLD; else Type = ELF::R_PPC_TLSLD; break; case MCSymbolRefExpr::VK_PPC_TLS: if (is64Bit()) Type = ELF::R_PPC64_TLS; else Type = ELF::R_PPC_TLS; break; } break; case FK_Data_8: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_PPC_TOCBASE: Type = ELF::R_PPC64_TOC; break; case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC64_ADDR64; break; case MCSymbolRefExpr::VK_PPC_DTPMOD: Type = ELF::R_PPC64_DTPMOD64; break; case MCSymbolRefExpr::VK_PPC_TPREL: Type = ELF::R_PPC64_TPREL64; break; case MCSymbolRefExpr::VK_PPC_DTPREL: Type = ELF::R_PPC64_DTPREL64; break; } break; case FK_Data_4: Type = ELF::R_PPC_ADDR32; break; case FK_Data_2: Type = ELF::R_PPC_ADDR16; break; } } return Type; }
//@GetRelocType { unsigned Cpu0ELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { // determine the type of the relocation unsigned Type = (unsigned)ELF::R_CPU0_NONE; unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case FK_Data_4: Type = ELF::R_CPU0_32; break; #if CH >= CH8_1 //1 case FK_GPRel_4: Type = ELF::R_CPU0_GPREL32; break; #endif case Cpu0::fixup_Cpu0_32: Type = ELF::R_CPU0_32; break; case Cpu0::fixup_Cpu0_GPREL16: Type = ELF::R_CPU0_GPREL16; break; #if CH >= CH9_1 case Cpu0::fixup_Cpu0_CALL16: Type = ELF::R_CPU0_CALL16; break; #endif case Cpu0::fixup_Cpu0_GOT_Global: case Cpu0::fixup_Cpu0_GOT_Local: Type = ELF::R_CPU0_GOT16; break; case Cpu0::fixup_Cpu0_HI16: Type = ELF::R_CPU0_HI16; break; case Cpu0::fixup_Cpu0_LO16: Type = ELF::R_CPU0_LO16; break; #if CH >= CH12_1 case Cpu0::fixup_Cpu0_TLSGD: Type = ELF::R_CPU0_TLS_GD; break; case Cpu0::fixup_Cpu0_GOTTPREL: Type = ELF::R_CPU0_TLS_GOTTPREL; break; #endif #if CH >= CH8_1 //2 case Cpu0::fixup_Cpu0_PC16: Type = ELF::R_CPU0_PC16; break; case Cpu0::fixup_Cpu0_PC24: Type = ELF::R_CPU0_PC24; break; #endif #if CH >= CH12_1 case Cpu0::fixup_Cpu0_TP_HI: Type = ELF::R_CPU0_TLS_TP_HI16; break; case Cpu0::fixup_Cpu0_TP_LO: Type = ELF::R_CPU0_TLS_TP_LO16; break; case Cpu0::fixup_Cpu0_TLSLDM: Type = ELF::R_CPU0_TLS_LDM; break; case Cpu0::fixup_Cpu0_DTP_HI: Type = ELF::R_CPU0_TLS_DTP_HI16; break; case Cpu0::fixup_Cpu0_DTP_LO: Type = ELF::R_CPU0_TLS_DTP_LO16; break; #endif case Cpu0::fixup_Cpu0_GOT_HI16: Type = ELF::R_CPU0_GOT_HI16; break; case Cpu0::fixup_Cpu0_GOT_LO16: Type = ELF::R_CPU0_GOT_LO16; break; } return Type; }
unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Fixup.getValue())) { if (SExpr->getKind() == SparcMCExpr::VK_Sparc_R_DISP32) return ELF::R_SPARC_DISP32; } if (IsPCRel) { switch((unsigned)Fixup.getKind()) { default: llvm_unreachable("Unimplemented fixup -> relocation"); case FK_Data_1: return ELF::R_SPARC_DISP8; case FK_Data_2: return ELF::R_SPARC_DISP16; case FK_Data_4: return ELF::R_SPARC_DISP32; case FK_Data_8: return ELF::R_SPARC_DISP64; case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30; case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22; case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19; case Sparc::fixup_sparc_pc22: return ELF::R_SPARC_PC22; case Sparc::fixup_sparc_pc10: return ELF::R_SPARC_PC10; case Sparc::fixup_sparc_wplt30: return ELF::R_SPARC_WPLT30; } } switch((unsigned)Fixup.getKind()) { default: llvm_unreachable("Unimplemented fixup -> relocation"); case FK_Data_1: return ELF::R_SPARC_8; case FK_Data_2: return ((Fixup.getOffset() % 2) ? ELF::R_SPARC_UA16 : ELF::R_SPARC_16); case FK_Data_4: return ((Fixup.getOffset() % 4) ? ELF::R_SPARC_UA32 : ELF::R_SPARC_32); case FK_Data_8: return ((Fixup.getOffset() % 8) ? ELF::R_SPARC_UA64 : ELF::R_SPARC_64); case Sparc::fixup_sparc_hi22: return ELF::R_SPARC_HI22; case Sparc::fixup_sparc_lo10: return ELF::R_SPARC_LO10; case Sparc::fixup_sparc_h44: return ELF::R_SPARC_H44; case Sparc::fixup_sparc_m44: return ELF::R_SPARC_M44; case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44; case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22; case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10; case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22; case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10; case Sparc::fixup_sparc_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22; case Sparc::fixup_sparc_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10; case Sparc::fixup_sparc_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD; case Sparc::fixup_sparc_tls_gd_call: return ELF::R_SPARC_TLS_GD_CALL; case Sparc::fixup_sparc_tls_ldm_hi22: return ELF::R_SPARC_TLS_LDM_HI22; case Sparc::fixup_sparc_tls_ldm_lo10: return ELF::R_SPARC_TLS_LDM_LO10; case Sparc::fixup_sparc_tls_ldm_add: return ELF::R_SPARC_TLS_LDM_ADD; case Sparc::fixup_sparc_tls_ldm_call: return ELF::R_SPARC_TLS_LDM_CALL; case Sparc::fixup_sparc_tls_ldo_hix22: return ELF::R_SPARC_TLS_LDO_HIX22; case Sparc::fixup_sparc_tls_ldo_lox10: return ELF::R_SPARC_TLS_LDO_LOX10; case Sparc::fixup_sparc_tls_ldo_add: return ELF::R_SPARC_TLS_LDO_ADD; case Sparc::fixup_sparc_tls_ie_hi22: return ELF::R_SPARC_TLS_IE_HI22; case Sparc::fixup_sparc_tls_ie_lo10: return ELF::R_SPARC_TLS_IE_LO10; case Sparc::fixup_sparc_tls_ie_ld: return ELF::R_SPARC_TLS_IE_LD; case Sparc::fixup_sparc_tls_ie_ldx: return ELF::R_SPARC_TLS_IE_LDX; case Sparc::fixup_sparc_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD; case Sparc::fixup_sparc_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22; case Sparc::fixup_sparc_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10; } return ELF::R_SPARC_NONE; }