// 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_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_pcrel_hi20: ShouldForce = T->getValue()->findAssociatedFragment() != Fixup.getValue()->findAssociatedFragment(); break; } break; } return ShouldForce || STI.getFeatureBits()[RISCV::FeatureRelax] || ForceRelocs; }
unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, 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(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Fixup.getKind()); assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && "Unsupported ELF machine type."); return getRelocType32(Modifier, getType32(Type), IsPCRel); }
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"); } }
unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { AArch64MCExpr::VariantKind RefKind = static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); AArch64MCExpr::VariantKind SymLoc = AArch64MCExpr::getSymbolLoc(RefKind); bool IsNC = AArch64MCExpr::isNotChecked(RefKind); assert((!Target.getSymA() || Target.getSymA()->getKind() == MCSymbolRefExpr::VK_None) && "Should only be expression-level modifiers here"); assert((!Target.getSymB() || Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None) && "Should only be expression-level modifiers here"); if (IsPCRel) { switch ((unsigned)Fixup.getKind()) { case FK_Data_1: Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported"); return ELF::R_AARCH64_NONE; case FK_Data_2: return R_CLS(PREL16); case FK_Data_4: return R_CLS(PREL32); case FK_Data_8: if (IsILP32) { Ctx.reportError(Fixup.getLoc(), "ILP32 8 byte PC relative data " "relocation not supported (LP64 eqv: PREL64)"); return ELF::R_AARCH64_NONE; } else return ELF::R_AARCH64_PREL64; case AArch64::fixup_aarch64_pcrel_adr_imm21: assert(SymLoc == AArch64MCExpr::VK_NONE && "unexpected ADR relocation"); return R_CLS(ADR_PREL_LO21); case AArch64::fixup_aarch64_pcrel_adrp_imm21: if (SymLoc == AArch64MCExpr::VK_ABS && !IsNC) return R_CLS(ADR_PREL_PG_HI21); if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) { if (IsILP32) { Ctx.reportError(Fixup.getLoc(), "invalid fixup for 32-bit pcrel ADRP instruction " "VK_ABS VK_NC"); return ELF::R_AARCH64_NONE; } else { return ELF::R_AARCH64_ADR_PREL_PG_HI21_NC; } } if (SymLoc == AArch64MCExpr::VK_GOT && !IsNC) return R_CLS(ADR_GOT_PAGE); if (SymLoc == AArch64MCExpr::VK_GOTTPREL && !IsNC) return R_CLS(TLSIE_ADR_GOTTPREL_PAGE21); if (SymLoc == AArch64MCExpr::VK_TLSDESC && !IsNC) return R_CLS(TLSDESC_ADR_PAGE21); Ctx.reportError(Fixup.getLoc(), "invalid symbol kind for ADRP relocation"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_pcrel_branch26: return R_CLS(JUMP26); case AArch64::fixup_aarch64_pcrel_call26: return R_CLS(CALL26); case AArch64::fixup_aarch64_ldr_pcrel_imm19: if (SymLoc == AArch64MCExpr::VK_GOTTPREL) return R_CLS(TLSIE_LD_GOTTPREL_PREL19); return R_CLS(LD_PREL_LO19); case AArch64::fixup_aarch64_pcrel_branch14: return R_CLS(TSTBR14); case AArch64::fixup_aarch64_pcrel_branch19: return R_CLS(CONDBR19); default: Ctx.reportError(Fixup.getLoc(), "Unsupported pc-relative fixup kind"); return ELF::R_AARCH64_NONE; } } else { if (IsILP32 && isNonILP32reloc(Fixup, RefKind, Ctx)) return ELF::R_AARCH64_NONE; switch ((unsigned)Fixup.getKind()) { case FK_Data_1: Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported"); return ELF::R_AARCH64_NONE; case FK_Data_2: return R_CLS(ABS16); case FK_Data_4: return R_CLS(ABS32); case FK_Data_8: if (IsILP32) { Ctx.reportError(Fixup.getLoc(), "ILP32 8 byte absolute data " "relocation not supported (LP64 eqv: ABS64)"); return ELF::R_AARCH64_NONE; } else return ELF::R_AARCH64_ABS64; case AArch64::fixup_aarch64_add_imm12: if (RefKind == AArch64MCExpr::VK_DTPREL_HI12) return R_CLS(TLSLD_ADD_DTPREL_HI12); if (RefKind == AArch64MCExpr::VK_TPREL_HI12) return R_CLS(TLSLE_ADD_TPREL_HI12); if (RefKind == AArch64MCExpr::VK_DTPREL_LO12_NC) return R_CLS(TLSLD_ADD_DTPREL_LO12_NC); if (RefKind == AArch64MCExpr::VK_DTPREL_LO12) return R_CLS(TLSLD_ADD_DTPREL_LO12); if (RefKind == AArch64MCExpr::VK_TPREL_LO12_NC) return R_CLS(TLSLE_ADD_TPREL_LO12_NC); if (RefKind == AArch64MCExpr::VK_TPREL_LO12) return R_CLS(TLSLE_ADD_TPREL_LO12); if (RefKind == AArch64MCExpr::VK_TLSDESC_LO12) return R_CLS(TLSDESC_ADD_LO12); if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(ADD_ABS_LO12_NC); Ctx.reportError(Fixup.getLoc(), "invalid fixup for add (uimm12) instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale1: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST8_ABS_LO12_NC); if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return R_CLS(TLSLD_LDST8_DTPREL_LO12); if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return R_CLS(TLSLD_LDST8_DTPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return R_CLS(TLSLE_LDST8_TPREL_LO12); if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return R_CLS(TLSLE_LDST8_TPREL_LO12_NC); Ctx.reportError(Fixup.getLoc(), "invalid fixup for 8-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale2: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST16_ABS_LO12_NC); if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return R_CLS(TLSLD_LDST16_DTPREL_LO12); if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return R_CLS(TLSLD_LDST16_DTPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return R_CLS(TLSLE_LDST16_TPREL_LO12); if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return R_CLS(TLSLE_LDST16_TPREL_LO12_NC); Ctx.reportError(Fixup.getLoc(), "invalid fixup for 16-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale4: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST32_ABS_LO12_NC); if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return R_CLS(TLSLD_LDST32_DTPREL_LO12); if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return R_CLS(TLSLD_LDST32_DTPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return R_CLS(TLSLE_LDST32_TPREL_LO12); if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return R_CLS(TLSLE_LDST32_TPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_GOT && IsNC) { if (IsILP32) { return ELF::R_AARCH64_P32_LD32_GOT_LO12_NC; } else { Ctx.reportError(Fixup.getLoc(), "LP64 4 byte unchecked GOT load/store relocation " "not supported (ILP32 eqv: LD32_GOT_LO12_NC"); return ELF::R_AARCH64_NONE; } } if (SymLoc == AArch64MCExpr::VK_GOT && !IsNC) { if (IsILP32) { Ctx.reportError(Fixup.getLoc(), "ILP32 4 byte checked GOT load/store relocation " "not supported (unchecked eqv: LD32_GOT_LO12_NC)"); } else { Ctx.reportError(Fixup.getLoc(), "LP64 4 byte checked GOT load/store relocation " "not supported (unchecked/ILP32 eqv: " "LD32_GOT_LO12_NC)"); } return ELF::R_AARCH64_NONE; } if (SymLoc == AArch64MCExpr::VK_GOTTPREL && IsNC) { if (IsILP32) { return ELF::R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC; } else { Ctx.reportError(Fixup.getLoc(), "LP64 32-bit load/store " "relocation not supported (ILP32 eqv: " "TLSIE_LD32_GOTTPREL_LO12_NC)"); return ELF::R_AARCH64_NONE; } } if (SymLoc == AArch64MCExpr::VK_TLSDESC && !IsNC) { if (IsILP32) { return ELF::R_AARCH64_P32_TLSDESC_LD32_LO12; } else { Ctx.reportError(Fixup.getLoc(), "LP64 4 byte TLSDESC load/store relocation " "not supported (ILP32 eqv: TLSDESC_LD64_LO12)"); return ELF::R_AARCH64_NONE; } } Ctx.reportError(Fixup.getLoc(), "invalid fixup for 32-bit load/store instruction " "fixup_aarch64_ldst_imm12_scale4"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale8: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST64_ABS_LO12_NC); if (SymLoc == AArch64MCExpr::VK_GOT && IsNC) { if (!IsILP32) { return ELF::R_AARCH64_LD64_GOT_LO12_NC; } else { Ctx.reportError(Fixup.getLoc(), "ILP32 64-bit load/store " "relocation not supported (LP64 eqv: " "LD64_GOT_LO12_NC)"); return ELF::R_AARCH64_NONE; } } if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return R_CLS(TLSLD_LDST64_DTPREL_LO12); if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return R_CLS(TLSLD_LDST64_DTPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return R_CLS(TLSLE_LDST64_TPREL_LO12); if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return R_CLS(TLSLE_LDST64_TPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_GOTTPREL && IsNC) { if (!IsILP32) { return ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; } else { Ctx.reportError(Fixup.getLoc(), "ILP32 64-bit load/store " "relocation not supported (LP64 eqv: " "TLSIE_LD64_GOTTPREL_LO12_NC)"); return ELF::R_AARCH64_NONE; } } if (SymLoc == AArch64MCExpr::VK_TLSDESC) { if (!IsILP32) { return ELF::R_AARCH64_TLSDESC_LD64_LO12; } else { Ctx.reportError(Fixup.getLoc(), "ILP32 64-bit load/store " "relocation not supported (LP64 eqv: " "TLSDESC_LD64_LO12)"); return ELF::R_AARCH64_NONE; } } Ctx.reportError(Fixup.getLoc(), "invalid fixup for 64-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale16: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST128_ABS_LO12_NC); if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return R_CLS(TLSLD_LDST128_DTPREL_LO12); if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return R_CLS(TLSLD_LDST128_DTPREL_LO12_NC); if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return R_CLS(TLSLE_LDST128_TPREL_LO12); if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return R_CLS(TLSLE_LDST128_TPREL_LO12_NC); Ctx.reportError(Fixup.getLoc(), "invalid fixup for 128-bit load/store instruction"); return ELF::R_AARCH64_NONE; // ILP32 case not reached here, tested with isNonILP32reloc case AArch64::fixup_aarch64_movw: if (RefKind == AArch64MCExpr::VK_ABS_G3) return ELF::R_AARCH64_MOVW_UABS_G3; if (RefKind == AArch64MCExpr::VK_ABS_G2) return ELF::R_AARCH64_MOVW_UABS_G2; if (RefKind == AArch64MCExpr::VK_ABS_G2_S) return ELF::R_AARCH64_MOVW_SABS_G2; if (RefKind == AArch64MCExpr::VK_ABS_G2_NC) return ELF::R_AARCH64_MOVW_UABS_G2_NC; if (RefKind == AArch64MCExpr::VK_ABS_G1) return R_CLS(MOVW_UABS_G1); if (RefKind == AArch64MCExpr::VK_ABS_G1_S) return ELF::R_AARCH64_MOVW_SABS_G1; if (RefKind == AArch64MCExpr::VK_ABS_G1_NC) return ELF::R_AARCH64_MOVW_UABS_G1_NC; if (RefKind == AArch64MCExpr::VK_ABS_G0) return R_CLS(MOVW_UABS_G0); if (RefKind == AArch64MCExpr::VK_ABS_G0_S) return R_CLS(MOVW_SABS_G0); if (RefKind == AArch64MCExpr::VK_ABS_G0_NC) return R_CLS(MOVW_UABS_G0_NC); if (RefKind == AArch64MCExpr::VK_DTPREL_G2) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G2; if (RefKind == AArch64MCExpr::VK_DTPREL_G1) return R_CLS(TLSLD_MOVW_DTPREL_G1); if (RefKind == AArch64MCExpr::VK_DTPREL_G1_NC) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC; if (RefKind == AArch64MCExpr::VK_DTPREL_G0) return R_CLS(TLSLD_MOVW_DTPREL_G0); if (RefKind == AArch64MCExpr::VK_DTPREL_G0_NC) return R_CLS(TLSLD_MOVW_DTPREL_G0_NC); if (RefKind == AArch64MCExpr::VK_TPREL_G2) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G2; if (RefKind == AArch64MCExpr::VK_TPREL_G1) return R_CLS(TLSLE_MOVW_TPREL_G1); if (RefKind == AArch64MCExpr::VK_TPREL_G1_NC) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC; if (RefKind == AArch64MCExpr::VK_TPREL_G0) return R_CLS(TLSLE_MOVW_TPREL_G0); if (RefKind == AArch64MCExpr::VK_TPREL_G0_NC) return R_CLS(TLSLE_MOVW_TPREL_G0_NC); if (RefKind == AArch64MCExpr::VK_GOTTPREL_G1) return ELF::R_AARCH64_TLSIE_MOVW_GOTTPREL_G1; if (RefKind == AArch64MCExpr::VK_GOTTPREL_G0_NC) return ELF::R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for movz/movk instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_tlsdesc_call: return R_CLS(TLSDESC_CALL); default: Ctx.reportError(Fixup.getLoc(), "Unknown ELF relocation type"); return ELF::R_AARCH64_NONE; } } llvm_unreachable("Unimplemented fixup -> relocation"); }
unsigned X86WinCOFFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const { unsigned FixupKind = Fixup.getKind(); if (IsCrossSection) { if (FixupKind != FK_Data_4 && FixupKind != llvm::X86::reloc_signed_4byte) { Ctx.reportError(Fixup.getLoc(), "Cannot represent this expression"); return COFF::IMAGE_REL_AMD64_ADDR32; } FixupKind = FK_PCRel_4; } 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: case X86::reloc_branch_4byte_pcrel: 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: Ctx.reportError(Fixup.getLoc(), "unsupported relocation type"); return COFF::IMAGE_REL_AMD64_ADDR32; } } 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: Ctx.reportError(Fixup.getLoc(), "unsupported relocation type"); return COFF::IMAGE_REL_I386_DIR32; } } else llvm_unreachable("Unsupported COFF machine type."); }
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; }
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); }
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); }
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; } }
static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, MCContext &Ctx) { unsigned Kind = Fixup.getKind(); switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); case RISCV::fixup_riscv_got_hi20: llvm_unreachable("Relocation should be unconditionally forced\n"); case FK_Data_1: case FK_Data_2: case FK_Data_4: case FK_Data_8: return Value; case RISCV::fixup_riscv_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_tprel_lo12_i: return Value & 0xfff; case RISCV::fixup_riscv_lo12_s: case RISCV::fixup_riscv_pcrel_lo12_s: case RISCV::fixup_riscv_tprel_lo12_s: return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); case RISCV::fixup_riscv_hi20: case RISCV::fixup_riscv_pcrel_hi20: case RISCV::fixup_riscv_tprel_hi20: // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. return ((Value + 0x800) >> 12) & 0xfffff; case RISCV::fixup_riscv_jal: { if (!isInt<21>(Value)) Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); if (Value & 0x1) Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); // Need to produce imm[19|10:1|11|19:12] from the 21-bit Value. unsigned Sbit = (Value >> 20) & 0x1; unsigned Hi8 = (Value >> 12) & 0xff; unsigned Mid1 = (Value >> 11) & 0x1; unsigned Lo10 = (Value >> 1) & 0x3ff; // Inst{31} = Sbit; // Inst{30-21} = Lo10; // Inst{20} = Mid1; // Inst{19-12} = Hi8; Value = (Sbit << 19) | (Lo10 << 9) | (Mid1 << 8) | Hi8; return Value; } case RISCV::fixup_riscv_branch: { if (!isInt<13>(Value)) Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); if (Value & 0x1) Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); // Need to extract imm[12], imm[10:5], imm[4:1], imm[11] from the 13-bit // Value. unsigned Sbit = (Value >> 12) & 0x1; unsigned Hi1 = (Value >> 11) & 0x1; unsigned Mid6 = (Value >> 5) & 0x3f; unsigned Lo4 = (Value >> 1) & 0xf; // Inst{31} = Sbit; // Inst{30-25} = Mid6; // Inst{11-8} = Lo4; // Inst{7} = Hi1; Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); return Value; } case RISCV::fixup_riscv_call: case RISCV::fixup_riscv_call_plt: { // Jalr will add UpperImm with the sign-extended 12-bit LowerImm, // we need to add 0x800ULL before extract upper bits to reflect the // effect of the sign extension. uint64_t UpperImm = (Value + 0x800ULL) & 0xfffff000ULL; uint64_t LowerImm = Value & 0xfffULL; return UpperImm | ((LowerImm << 20) << 32); } case RISCV::fixup_riscv_rvc_jump: { // Need to produce offset[11|4|9:8|10|6|7|3:1|5] from the 11-bit Value. unsigned Bit11 = (Value >> 11) & 0x1; unsigned Bit4 = (Value >> 4) & 0x1; unsigned Bit9_8 = (Value >> 8) & 0x3; unsigned Bit10 = (Value >> 10) & 0x1; unsigned Bit6 = (Value >> 6) & 0x1; unsigned Bit7 = (Value >> 7) & 0x1; unsigned Bit3_1 = (Value >> 1) & 0x7; unsigned Bit5 = (Value >> 5) & 0x1; Value = (Bit11 << 10) | (Bit4 << 9) | (Bit9_8 << 7) | (Bit10 << 6) | (Bit6 << 5) | (Bit7 << 4) | (Bit3_1 << 1) | Bit5; return Value; } case RISCV::fixup_riscv_rvc_branch: { // Need to produce offset[8|4:3], [reg 3 bit], offset[7:6|2:1|5] unsigned Bit8 = (Value >> 8) & 0x1; unsigned Bit7_6 = (Value >> 6) & 0x3; unsigned Bit5 = (Value >> 5) & 0x1; unsigned Bit4_3 = (Value >> 3) & 0x3; unsigned Bit2_1 = (Value >> 1) & 0x3; Value = (Bit8 << 12) | (Bit4_3 << 10) | (Bit7_6 << 5) | (Bit2_1 << 3) | (Bit5 << 2); return Value; } } }
void ELFObjectWriter::recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { MCAsmBackend &Backend = Asm.getBackend(); bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { // Let A, B and C being the components of Target and R be the location of // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). // If it is pcrel, we want to compute (A - B + C - R). // In general, ELF has no relocations for -B. It can only represent (A + C) // or (A + C - R). If B = R + K and the relocation is not pcrel, we can // replace B to implement it: (A - R - K + C) if (IsPCRel) { Ctx.reportError( Fixup.getLoc(), "No relocation available to represent this relative expression"); return; } const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); if (SymB.isUndefined()) { Ctx.reportError(Fixup.getLoc(), Twine("symbol '") + SymB.getName() + "' can not be undefined in a subtraction expression"); return; } assert(!SymB.isAbsolute() && "Should have been folded"); const MCSection &SecB = SymB.getSection(); if (&SecB != &FixupSection) { Ctx.reportError(Fixup.getLoc(), "Cannot represent a difference across sections"); return; } uint64_t SymBOffset = Layout.getSymbolOffset(SymB); uint64_t K = SymBOffset - FixupOffset; IsPCRel = true; C -= K; } // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr; bool ViaWeakRef = false; if (SymA && SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { SymA = cast<MCSymbolELF>(&Inner->getSymbol()); ViaWeakRef = true; } } } unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); uint64_t OriginalC = C; bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) C += Layout.getSymbolOffset(*SymA); uint64_t Addend = 0; if (hasRelocationAddend()) { Addend = C; C = 0; } FixedValue = C; if (!RelocateWithSymbol) { const MCSection *SecA = (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr; auto *ELFSec = cast_or_null<MCSectionELF>(SecA); const auto *SectionSymbol = ELFSec ? cast<MCSymbolELF>(ELFSec->getBeginSymbol()) : nullptr; if (SectionSymbol) SectionSymbol->setUsedInReloc(); ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, OriginalC); Relocations[&FixupSection].push_back(Rec); return; } const auto *RenamedSymA = SymA; if (SymA) { if (const MCSymbolELF *R = Renames.lookup(SymA)) RenamedSymA = R; if (ViaWeakRef) RenamedSymA->setIsWeakrefUsedInReloc(); else RenamedSymA->setUsedInReloc(); } ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, OriginalC); Relocations[&FixupSection].push_back(Rec); }
bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, uint64_t &Value) const { ++stats::evaluateFixup; // FIXME: This code has some duplication with recordRelocation. We should // probably merge the two into a single callback that tries to evaluate a // fixup and records a relocation if one is needed. const MCExpr *Expr = Fixup.getValue(); if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) getContext().reportFatalError(Fixup.getLoc(), "expected relocatable expression"); bool IsPCRel = Backend.getFixupKindInfo( Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; bool IsResolved; if (IsPCRel) { if (Target.getSymB()) { IsResolved = false; } else if (!Target.getSymA()) { IsResolved = false; } else { const MCSymbolRefExpr *A = Target.getSymA(); const MCSymbol &SA = A->getSymbol(); if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) { IsResolved = false; } else { IsResolved = getWriter().isSymbolRefDifferenceFullyResolvedImpl( *this, SA, *DF, false, true); } } } else { IsResolved = Target.isAbsolute(); } Value = Target.getConstant(); if (const MCSymbolRefExpr *A = Target.getSymA()) { const MCSymbol &Sym = A->getSymbol(); if (Sym.isDefined()) Value += Layout.getSymbolOffset(Sym); } if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbol &Sym = B->getSymbol(); if (Sym.isDefined()) Value -= Layout.getSymbolOffset(Sym); } bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; assert((ShouldAlignPC ? IsPCRel : true) && "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); if (IsPCRel) { uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset(); // A number of ARM fixups in Thumb mode require that the effective PC // address be determined as the 32-bit aligned version of the actual offset. if (ShouldAlignPC) Offset &= ~0x3; Value -= Offset; } // Let the backend adjust the fixup value if necessary, including whether // we need a relocation. Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value, IsResolved); return IsResolved; }
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 ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, MCContext &Ctx) const { MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); if (IsPCRel) { switch ((unsigned)Fixup.getKind()) { default: Ctx.reportFatalError(Fixup.getLoc(), "unsupported relocation on symbol"); return ELF::R_ARM_NONE; case FK_Data_4: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_REL32; case MCSymbolRefExpr::VK_GOTTPOFF: return ELF::R_ARM_TLS_IE32; case MCSymbolRefExpr::VK_ARM_GOT_PREL: return ELF::R_ARM_GOT_PREL; case MCSymbolRefExpr::VK_ARM_PREL31: return ELF::R_ARM_PREL31; } case ARM::fixup_arm_blx: case ARM::fixup_arm_uncondbl: switch (Modifier) { case MCSymbolRefExpr::VK_PLT: return ELF::R_ARM_CALL; case MCSymbolRefExpr::VK_TLSCALL: return ELF::R_ARM_TLS_CALL; default: return ELF::R_ARM_CALL; } case ARM::fixup_arm_condbl: case ARM::fixup_arm_condbranch: case ARM::fixup_arm_uncondbranch: return ELF::R_ARM_JUMP24; case ARM::fixup_t2_condbranch: return ELF::R_ARM_THM_JUMP19; case ARM::fixup_t2_uncondbranch: return ELF::R_ARM_THM_JUMP24; case ARM::fixup_arm_movt_hi16: return ELF::R_ARM_MOVT_PREL; case ARM::fixup_arm_movw_lo16: return ELF::R_ARM_MOVW_PREL_NC; case ARM::fixup_t2_movt_hi16: return ELF::R_ARM_THM_MOVT_PREL; case ARM::fixup_t2_movw_lo16: return ELF::R_ARM_THM_MOVW_PREL_NC; case ARM::fixup_arm_thumb_br: return ELF::R_ARM_THM_JUMP11; case ARM::fixup_arm_thumb_bcc: return ELF::R_ARM_THM_JUMP8; case ARM::fixup_arm_thumb_bl: case ARM::fixup_arm_thumb_blx: switch (Modifier) { case MCSymbolRefExpr::VK_TLSCALL: return ELF::R_ARM_THM_TLS_CALL; default: return ELF::R_ARM_THM_CALL; } } } switch ((unsigned)Fixup.getKind()) { default: Ctx.reportFatalError(Fixup.getLoc(), "unsupported relocation on symbol"); return ELF::R_ARM_NONE; case FK_Data_1: switch (Modifier) { default: llvm_unreachable("unsupported Modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_ABS8; } case FK_Data_2: switch (Modifier) { default: llvm_unreachable("unsupported modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_ABS16; } case FK_Data_4: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_ARM_NONE: return ELF::R_ARM_NONE; case MCSymbolRefExpr::VK_GOT: return ELF::R_ARM_GOT_BREL; case MCSymbolRefExpr::VK_TLSGD: return ELF::R_ARM_TLS_GD32; case MCSymbolRefExpr::VK_TPOFF: return ELF::R_ARM_TLS_LE32; case MCSymbolRefExpr::VK_GOTTPOFF: return ELF::R_ARM_TLS_IE32; case MCSymbolRefExpr::VK_None: return ELF::R_ARM_ABS32; case MCSymbolRefExpr::VK_GOTOFF: return ELF::R_ARM_GOTOFF32; case MCSymbolRefExpr::VK_ARM_GOT_PREL: return ELF::R_ARM_GOT_PREL; case MCSymbolRefExpr::VK_ARM_TARGET1: return ELF::R_ARM_TARGET1; case MCSymbolRefExpr::VK_ARM_TARGET2: return ELF::R_ARM_TARGET2; case MCSymbolRefExpr::VK_ARM_PREL31: return ELF::R_ARM_PREL31; case MCSymbolRefExpr::VK_ARM_SBREL: return ELF::R_ARM_SBREL32; case MCSymbolRefExpr::VK_ARM_TLSLDO: return ELF::R_ARM_TLS_LDO32; case MCSymbolRefExpr::VK_TLSCALL: return ELF::R_ARM_TLS_CALL; case MCSymbolRefExpr::VK_TLSDESC: return ELF::R_ARM_TLS_GOTDESC; case MCSymbolRefExpr::VK_TLSLDM: return ELF::R_ARM_TLS_LDM32; case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ: return ELF::R_ARM_TLS_DESCSEQ; } case ARM::fixup_arm_condbranch: case ARM::fixup_arm_uncondbranch: return ELF::R_ARM_JUMP24; case ARM::fixup_arm_movt_hi16: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_MOVT_ABS; case MCSymbolRefExpr::VK_ARM_SBREL: return ELF::R_ARM_MOVT_BREL; } case ARM::fixup_arm_movw_lo16: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_MOVW_ABS_NC; case MCSymbolRefExpr::VK_ARM_SBREL: return ELF::R_ARM_MOVW_BREL_NC; } case ARM::fixup_t2_movt_hi16: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_THM_MOVT_ABS; case MCSymbolRefExpr::VK_ARM_SBREL: return ELF::R_ARM_THM_MOVT_BREL; } case ARM::fixup_t2_movw_lo16: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: return ELF::R_ARM_THM_MOVW_ABS_NC; case MCSymbolRefExpr::VK_ARM_SBREL: return ELF::R_ARM_THM_MOVW_BREL_NC; } } }
unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { AArch64MCExpr::VariantKind RefKind = static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); AArch64MCExpr::VariantKind SymLoc = AArch64MCExpr::getSymbolLoc(RefKind); bool IsNC = AArch64MCExpr::isNotChecked(RefKind); assert((!Target.getSymA() || Target.getSymA()->getKind() == MCSymbolRefExpr::VK_None) && "Should only be expression-level modifiers here"); assert((!Target.getSymB() || Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None) && "Should only be expression-level modifiers here"); if (IsPCRel) { switch ((unsigned)Fixup.getKind()) { case FK_Data_1: Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported"); return ELF::R_AARCH64_NONE; case FK_Data_2: return ELF::R_AARCH64_PREL16; case FK_Data_4: return ELF::R_AARCH64_PREL32; case FK_Data_8: return ELF::R_AARCH64_PREL64; case AArch64::fixup_aarch64_pcrel_adr_imm21: assert(SymLoc == AArch64MCExpr::VK_NONE && "unexpected ADR relocation"); return ELF::R_AARCH64_ADR_PREL_LO21; case AArch64::fixup_aarch64_pcrel_adrp_imm21: if (SymLoc == AArch64MCExpr::VK_ABS && !IsNC) return ELF::R_AARCH64_ADR_PREL_PG_HI21; if (SymLoc == AArch64MCExpr::VK_GOT && !IsNC) return ELF::R_AARCH64_ADR_GOT_PAGE; if (SymLoc == AArch64MCExpr::VK_GOTTPREL && !IsNC) return ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21; if (SymLoc == AArch64MCExpr::VK_TLSDESC && !IsNC) return ELF::R_AARCH64_TLSDESC_ADR_PAGE21; Ctx.reportError(Fixup.getLoc(), "invalid symbol kind for ADRP relocation"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_pcrel_branch26: return ELF::R_AARCH64_JUMP26; case AArch64::fixup_aarch64_pcrel_call26: return ELF::R_AARCH64_CALL26; case AArch64::fixup_aarch64_ldr_pcrel_imm19: if (SymLoc == AArch64MCExpr::VK_GOTTPREL) return ELF::R_AARCH64_TLSIE_LD_GOTTPREL_PREL19; return ELF::R_AARCH64_LD_PREL_LO19; case AArch64::fixup_aarch64_pcrel_branch14: return ELF::R_AARCH64_TSTBR14; case AArch64::fixup_aarch64_pcrel_branch19: return ELF::R_AARCH64_CONDBR19; default: Ctx.reportError(Fixup.getLoc(), "Unsupported pc-relative fixup kind"); return ELF::R_AARCH64_NONE; } } else { switch ((unsigned)Fixup.getKind()) { case FK_Data_1: Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported"); return ELF::R_AARCH64_NONE; case FK_Data_2: return ELF::R_AARCH64_ABS16; case FK_Data_4: return ELF::R_AARCH64_ABS32; case FK_Data_8: return ELF::R_AARCH64_ABS64; case AArch64::fixup_aarch64_add_imm12: if (RefKind == AArch64MCExpr::VK_DTPREL_HI12) return ELF::R_AARCH64_TLSLD_ADD_DTPREL_HI12; if (RefKind == AArch64MCExpr::VK_TPREL_HI12) return ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12; if (RefKind == AArch64MCExpr::VK_DTPREL_LO12_NC) return ELF::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC; if (RefKind == AArch64MCExpr::VK_DTPREL_LO12) return ELF::R_AARCH64_TLSLD_ADD_DTPREL_LO12; if (RefKind == AArch64MCExpr::VK_TPREL_LO12_NC) return ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC; if (RefKind == AArch64MCExpr::VK_TPREL_LO12) return ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12; if (RefKind == AArch64MCExpr::VK_TLSDESC_LO12) return ELF::R_AARCH64_TLSDESC_ADD_LO12_NC; if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return ELF::R_AARCH64_ADD_ABS_LO12_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for add (uimm12) instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale1: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return ELF::R_AARCH64_LDST8_ABS_LO12_NC; if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return ELF::R_AARCH64_TLSLD_LDST8_DTPREL_LO12; if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return ELF::R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC; if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return ELF::R_AARCH64_TLSLE_LDST8_TPREL_LO12; if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return ELF::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for 8-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale2: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return ELF::R_AARCH64_LDST16_ABS_LO12_NC; if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return ELF::R_AARCH64_TLSLD_LDST16_DTPREL_LO12; if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return ELF::R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC; if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return ELF::R_AARCH64_TLSLE_LDST16_TPREL_LO12; if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return ELF::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for 16-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale4: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return ELF::R_AARCH64_LDST32_ABS_LO12_NC; if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return ELF::R_AARCH64_TLSLD_LDST32_DTPREL_LO12; if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return ELF::R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC; if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return ELF::R_AARCH64_TLSLE_LDST32_TPREL_LO12; if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return ELF::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for 32-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale8: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return ELF::R_AARCH64_LDST64_ABS_LO12_NC; if (SymLoc == AArch64MCExpr::VK_GOT && IsNC) return ELF::R_AARCH64_LD64_GOT_LO12_NC; if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return ELF::R_AARCH64_TLSLD_LDST64_DTPREL_LO12; if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC) return ELF::R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC; if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC) return ELF::R_AARCH64_TLSLE_LDST64_TPREL_LO12; if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC) return ELF::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC; if (SymLoc == AArch64MCExpr::VK_GOTTPREL && IsNC) return ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; if (SymLoc == AArch64MCExpr::VK_TLSDESC && IsNC) return ELF::R_AARCH64_TLSDESC_LD64_LO12_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for 64-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_ldst_imm12_scale16: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return ELF::R_AARCH64_LDST128_ABS_LO12_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for 128-bit load/store instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_movw: if (RefKind == AArch64MCExpr::VK_ABS_G3) return ELF::R_AARCH64_MOVW_UABS_G3; if (RefKind == AArch64MCExpr::VK_ABS_G2) return ELF::R_AARCH64_MOVW_UABS_G2; if (RefKind == AArch64MCExpr::VK_ABS_G2_S) return ELF::R_AARCH64_MOVW_SABS_G2; if (RefKind == AArch64MCExpr::VK_ABS_G2_NC) return ELF::R_AARCH64_MOVW_UABS_G2_NC; if (RefKind == AArch64MCExpr::VK_ABS_G1) return ELF::R_AARCH64_MOVW_UABS_G1; if (RefKind == AArch64MCExpr::VK_ABS_G1_S) return ELF::R_AARCH64_MOVW_SABS_G1; if (RefKind == AArch64MCExpr::VK_ABS_G1_NC) return ELF::R_AARCH64_MOVW_UABS_G1_NC; if (RefKind == AArch64MCExpr::VK_ABS_G0) return ELF::R_AARCH64_MOVW_UABS_G0; if (RefKind == AArch64MCExpr::VK_ABS_G0_S) return ELF::R_AARCH64_MOVW_SABS_G0; if (RefKind == AArch64MCExpr::VK_ABS_G0_NC) return ELF::R_AARCH64_MOVW_UABS_G0_NC; if (RefKind == AArch64MCExpr::VK_DTPREL_G2) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G2; if (RefKind == AArch64MCExpr::VK_DTPREL_G1) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G1; if (RefKind == AArch64MCExpr::VK_DTPREL_G1_NC) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC; if (RefKind == AArch64MCExpr::VK_DTPREL_G0) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G0; if (RefKind == AArch64MCExpr::VK_DTPREL_G0_NC) return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC; if (RefKind == AArch64MCExpr::VK_TPREL_G2) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G2; if (RefKind == AArch64MCExpr::VK_TPREL_G1) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G1; if (RefKind == AArch64MCExpr::VK_TPREL_G1_NC) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC; if (RefKind == AArch64MCExpr::VK_TPREL_G0) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0; if (RefKind == AArch64MCExpr::VK_TPREL_G0_NC) return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC; if (RefKind == AArch64MCExpr::VK_GOTTPREL_G1) return ELF::R_AARCH64_TLSIE_MOVW_GOTTPREL_G1; if (RefKind == AArch64MCExpr::VK_GOTTPREL_G0_NC) return ELF::R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC; Ctx.reportError(Fixup.getLoc(), "invalid fixup for movz/movk instruction"); return ELF::R_AARCH64_NONE; case AArch64::fixup_aarch64_tlsdesc_call: return ELF::R_AARCH64_TLSDESC_CALL; default: Ctx.reportError(Fixup.getLoc(), "Unknown ELF relocation type"); return ELF::R_AARCH64_NONE; } } llvm_unreachable("Unimplemented fixup -> relocation"); }
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); const MCSymbol &Symbol = Target.getSymA()->getSymbol(); const MCSymbol &A = Symbol.AliasedSymbol(); if (!Asm.hasSymbolData(A)) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + A.getName() + "' can not be undefined"); MCSymbolData &A_SD = Asm.getSymbolData(A); MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); COFFSection *coff_section = SectionMap[&SectionData->getSection()]; COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; const MCSymbolRefExpr *SymB = Target.getSymB(); bool CrossSection = false; if (SymB) { const MCSymbol *B = &SymB->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); if (!B_SD.getFragment()) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + B->getName() + "' can not be undefined in a subtraction expression"); if (!A_SD.getFragment()) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + Symbol.getName() + "' can not be undefined in a subtraction expression"); CrossSection = &Symbol.getSection() != &B->getSection(); // Offset of the symbol in the section int64_t a = Layout.getSymbolOffset(&B_SD); // Ofeset of the relocation in the section int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); FixedValue = b - a; // In the case where we have SymbA and SymB, we just need to store the delta // between the two symbols. Update FixedValue to account for the delta, and // skip recording the relocation. if (!CrossSection) return; } else { FixedValue = Target.getConstant(); } COFFRelocation Reloc; Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); // Turn relocations for temporary symbols into section relocations. if (coff_symbol->MCData->getSymbol().isTemporary() || CrossSection) { Reloc.Symb = coff_symbol->Section->Symbol; FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + coff_symbol->MCData->getOffset(); } else Reloc.Symb = coff_symbol; ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup, CrossSection); // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? if (Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32 || Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32) FixedValue += 4; coff_section->Relocations.push_back(Reloc); }
void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, bool &IsPCRel, uint64_t &FixedValue) { assert(Target.getSymA() && "Relocation must reference a symbol!"); const MCSymbol &Symbol = Target.getSymA()->getSymbol(); const MCSymbol &A = Symbol.AliasedSymbol(); if (!Asm.hasSymbolData(A)) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + A.getName() + "' can not be undefined"); const MCSymbolData &A_SD = Asm.getSymbolData(A); MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); COFFSection *coff_section = SectionMap[&SectionData->getSection()]; COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; const MCSymbolRefExpr *SymB = Target.getSymB(); bool CrossSection = false; if (SymB) { const MCSymbol *B = &SymB->getSymbol(); const MCSymbolData &B_SD = Asm.getSymbolData(*B); if (!B_SD.getFragment()) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + B->getName() + "' can not be undefined in a subtraction expression"); if (!A_SD.getFragment()) Asm.getContext().FatalError( Fixup.getLoc(), Twine("symbol '") + Symbol.getName() + "' can not be undefined in a subtraction expression"); CrossSection = &Symbol.getSection() != &B->getSection(); // Offset of the symbol in the section int64_t a = Layout.getSymbolOffset(&B_SD); // Ofeset of the relocation in the section int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); FixedValue = b - a; // In the case where we have SymbA and SymB, we just need to store the delta // between the two symbols. Update FixedValue to account for the delta, and // skip recording the relocation. if (!CrossSection) return; } else { FixedValue = Target.getConstant(); } COFFRelocation Reloc; Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); // Turn relocations for temporary symbols into section relocations. if (coff_symbol->MCData->getSymbol().isTemporary() || CrossSection) { Reloc.Symb = coff_symbol->Section->Symbol; FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + coff_symbol->MCData->getOffset(); } else Reloc.Symb = coff_symbol; ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup, CrossSection); // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? if ((Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 && Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32) || (Header.Machine == COFF::IMAGE_FILE_MACHINE_I386 && Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32)) FixedValue += 4; if (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) { switch (Reloc.Data.Type) { case COFF::IMAGE_REL_ARM_ABSOLUTE: case COFF::IMAGE_REL_ARM_ADDR32: case COFF::IMAGE_REL_ARM_ADDR32NB: case COFF::IMAGE_REL_ARM_TOKEN: case COFF::IMAGE_REL_ARM_SECTION: case COFF::IMAGE_REL_ARM_SECREL: break; case COFF::IMAGE_REL_ARM_BRANCH11: case COFF::IMAGE_REL_ARM_BLX11: // IMAGE_REL_ARM_BRANCH11 and IMAGE_REL_ARM_BLX11 are only used for // pre-ARMv7, which implicitly rules it out of ARMNT (it would be valid // for Windows CE). case COFF::IMAGE_REL_ARM_BRANCH24: case COFF::IMAGE_REL_ARM_BLX24: case COFF::IMAGE_REL_ARM_MOV32A: // IMAGE_REL_ARM_BRANCH24, IMAGE_REL_ARM_BLX24, IMAGE_REL_ARM_MOV32A are // only used for ARM mode code, which is documented as being unsupported // by Windows on ARM. Emperical proof indicates that masm is able to // generate the relocations however the rest of the MSVC toolchain is // unable to handle it. llvm_unreachable("unsupported relocation"); break; case COFF::IMAGE_REL_ARM_MOV32T: break; case COFF::IMAGE_REL_ARM_BRANCH20T: case COFF::IMAGE_REL_ARM_BRANCH24T: case COFF::IMAGE_REL_ARM_BLX23T: // IMAGE_REL_BRANCH20T, IMAGE_REL_ARM_BRANCH24T, IMAGE_REL_ARM_BLX23T all // perform a 4 byte adjustment to the relocation. Relative branches are // offset by 4 on ARM, however, because there is no RELA relocations, all // branches are offset by 4. FixedValue = FixedValue + 4; break; } } coff_section->Relocations.push_back(Reloc); }
// assumes IsILP32 is true static 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 true; case AArch64MCExpr::VK_ABS_G2_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G2_NC)); return true; case AArch64MCExpr::VK_ABS_G1_S: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_SABS_G1)); return true; case AArch64MCExpr::VK_ABS_G1_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G1_NC)); return true; case AArch64MCExpr::VK_DTPREL_G2: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLD_MOVW_DTPREL_G2)); return true; case AArch64MCExpr::VK_DTPREL_G1_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLD_MOVW_DTPREL_G1_NC)); return true; case AArch64MCExpr::VK_TPREL_G2: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLE_MOVW_TPREL_G2)); return true; case AArch64MCExpr::VK_TPREL_G1_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLE_MOVW_TPREL_G1_NC)); return true; case AArch64MCExpr::VK_GOTTPREL_G1: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSIE_MOVW_GOTTPREL_G1)); return true; case AArch64MCExpr::VK_GOTTPREL_G0_NC: Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSIE_MOVW_GOTTPREL_G0_NC)); return true; default: return false; } return false; }
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); }
static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, MCContext *Ctx) { unsigned Kind = Fixup.getKind(); int64_t SignedValue = static_cast<int64_t>(Value); switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); case AArch64::fixup_aarch64_pcrel_adr_imm21: if (Ctx && (SignedValue > 2097151 || SignedValue < -2097152)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); return AdrImmBits(Value & 0x1fffffULL); case AArch64::fixup_aarch64_pcrel_adrp_imm21: return AdrImmBits((Value & 0x1fffff000ULL) >> 12); case AArch64::fixup_aarch64_ldr_pcrel_imm19: case AArch64::fixup_aarch64_pcrel_branch19: // Signed 21-bit immediate if (SignedValue > 2097151 || SignedValue < -2097152) if (Ctx) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); if (Ctx && (Value & 0x3)) Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); // Low two bits are not encoded. return (Value >> 2) & 0x7ffff; case AArch64::fixup_aarch64_add_imm12: case AArch64::fixup_aarch64_ldst_imm12_scale1: // Unsigned 12-bit immediate if (Ctx && Value >= 0x1000) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); return Value; case AArch64::fixup_aarch64_ldst_imm12_scale2: // Unsigned 12-bit immediate which gets multiplied by 2 if (Ctx && (Value >= 0x2000)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); if (Ctx && (Value & 0x1)) Ctx->reportError(Fixup.getLoc(), "fixup must be 2-byte aligned"); return Value >> 1; case AArch64::fixup_aarch64_ldst_imm12_scale4: // Unsigned 12-bit immediate which gets multiplied by 4 if (Ctx && (Value >= 0x4000)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); if (Ctx && (Value & 0x3)) Ctx->reportError(Fixup.getLoc(), "fixup must be 4-byte aligned"); return Value >> 2; case AArch64::fixup_aarch64_ldst_imm12_scale8: // Unsigned 12-bit immediate which gets multiplied by 8 if (Ctx && (Value >= 0x8000)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); if (Ctx && (Value & 0x7)) Ctx->reportError(Fixup.getLoc(), "fixup must be 8-byte aligned"); return Value >> 3; case AArch64::fixup_aarch64_ldst_imm12_scale16: // Unsigned 12-bit immediate which gets multiplied by 16 if (Ctx && (Value >= 0x10000)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); if (Ctx && (Value & 0xf)) Ctx->reportError(Fixup.getLoc(), "fixup must be 16-byte aligned"); return Value >> 4; case AArch64::fixup_aarch64_movw: if (Ctx) Ctx->reportError(Fixup.getLoc(), "no resolvable MOVZ/MOVK fixups supported yet"); return Value; case AArch64::fixup_aarch64_pcrel_branch14: // Signed 16-bit immediate if (Ctx && (SignedValue > 32767 || SignedValue < -32768)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); // Low two bits are not encoded (4-byte alignment assumed). if (Ctx && (Value & 0x3)) Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); return (Value >> 2) & 0x3fff; case AArch64::fixup_aarch64_pcrel_branch26: case AArch64::fixup_aarch64_pcrel_call26: // Signed 28-bit immediate if (Ctx && (SignedValue > 134217727 || SignedValue < -134217728)) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); // Low two bits are not encoded (4-byte alignment assumed). if (Ctx && (Value & 0x3)) Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); return (Value >> 2) & 0x3ffffff; case FK_Data_1: case FK_Data_2: case FK_Data_4: case FK_Data_8: return Value; } }