Index: llvm/lib/MC/WinCOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/WinCOFFObjectWriter.cpp +++ llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -906,29 +906,67 @@ COFFRelocation Reloc; Reloc.Data.SymbolTableIndex = 0; - Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); + Reloc.Data.VirtualAddress = + Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + Reloc.Data.Type = OWriter.TargetObjectWriter->getRelocType( + Asm.getContext(), Target, Fixup, SymB, Asm.getBackend()); - // Turn relocations for temporary symbols into section relocations. if (A.isTemporary()) { - MCSection *TargetSection = &A.getSection(); - assert( - SectionMap.contains(TargetSection) && - "Section must already have been defined in executePostLayoutBinding!"); - COFFSection *Section = SectionMap[TargetSection]; - Reloc.Symb = Section->Symbol; - FixedValue += Layout.getSymbolOffset(A); - // Technically, we should do the final adjustments of FixedValue (below) - // before picking an offset symbol, otherwise we might choose one which - // is slightly too far away. The relocations where it really matters - // (arm64 adrp relocations) don't get any offset though. - if (UseOffsetLabels && !Section->OffsetSymbols.empty()) { - uint64_t LabelIndex = FixedValue >> OffsetLabelIntervalBits; - if (LabelIndex > 0) { - if (LabelIndex <= Section->OffsetSymbols.size()) - Reloc.Symb = Section->OffsetSymbols[LabelIndex - 1]; - else - Reloc.Symb = Section->OffsetSymbols.back(); - FixedValue -= Reloc.Symb->Data.Value; + if (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64 && + Reloc.Data.Type == COFF::IMAGE_REL_ARM64_BRANCH26) { + // For a b/bl instruction that branches a temporary symbol, an + // IMAGE_REL_ARM64_BRANCH26 relocation to another symbol + a + // non-zero offset could be emitted but the linkers (link.exe + // and lld) don't currently support this type of relocation and + // cause incorrect relocations and crashes. Avoid this by adding + // the temporary symbol to the symbol table and use a relocation + // to that symbol without an offset. Note that we cannot drop + // the relocation here either because this is a cross-section + // branch or there's a reason that a relocation is used even if + // it's within the same section (eg. link.exe depends on the + // relocations between functions present even in the same + // section, as in the comment in + // isSymbolRefDifferenceFullyResolvedImpl() above). + COFFSymbol *S = SymbolMap[&A]; + if (!S) { + uint64_t Offset = FixedValue + Layout.getSymbolOffset(A); + if (!(A.isInSection() && + Offset < Layout.getSectionAddressSize(&A.getSection()))) { + Asm.getContext().reportError( + Fixup.getLoc(), + Twine("symbol '") + A.getName() + + "' can not be outside of the section"); + return; + } + S = createSymbol(A.getName()); + S->Section = SectionMap[&A.getSection()]; + S->Data.StorageClass = COFF::IMAGE_SYM_CLASS_LABEL; + S->Data.Value = Offset; + } + Reloc.Symb = S; + FixedValue = 0; // Zero offset + } else { + // Turn relocations for temporary symbols into section relocations. + MCSection *TargetSection = &A.getSection(); + assert( + SectionMap.contains(TargetSection) && + "Section must already have been defined in executePostLayoutBinding!"); + COFFSection *Section = SectionMap[TargetSection]; + Reloc.Symb = Section->Symbol; + FixedValue += Layout.getSymbolOffset(A); + // Technically, we should do the final adjustments of FixedValue (below) + // before picking an offset symbol, otherwise we might choose one which + // is slightly too far away. The relocations where it really matters + // (arm64 adrp relocations) don't get any offset though. + if (UseOffsetLabels && !Section->OffsetSymbols.empty()) { + uint64_t LabelIndex = FixedValue >> OffsetLabelIntervalBits; + if (LabelIndex > 0) { + if (LabelIndex <= Section->OffsetSymbols.size()) + Reloc.Symb = Section->OffsetSymbols[LabelIndex - 1]; + else + Reloc.Symb = Section->OffsetSymbols.back(); + FixedValue -= Reloc.Symb->Data.Value; + } } } } else { @@ -940,10 +978,6 @@ ++Reloc.Symb->Relocations; - Reloc.Data.VirtualAddress += Fixup.getOffset(); - Reloc.Data.Type = OWriter.TargetObjectWriter->getRelocType( - Asm.getContext(), Target, Fixup, SymB, Asm.getBackend()); - // The *_REL32 relocations are relative to the end of the relocation, // not to the start. if ((Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 && Index: llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -314,6 +314,11 @@ return (Value >> 2) & 0x3fff; case AArch64::fixup_aarch64_pcrel_branch26: case AArch64::fixup_aarch64_pcrel_call26: + if (TheTriple.isOSBinFormatCOFF() && !IsResolved && SignedValue != 0) { + // MSVC link.exe and lld do not support this relocation type + // with a non-zero offset + Ctx.reportError(Fixup.getLoc(), "fixup value unsupported by linkers"); + } // Signed 28-bit immediate if (SignedValue > 134217727 || SignedValue < -134217728) Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); Index: llvm/test/MC/AArch64/coff-relocations-branch26.s =================================================================== --- /dev/null +++ llvm/test/MC/AArch64/coff-relocations-branch26.s @@ -0,0 +1,57 @@ +// RUN: llvm-mc -triple aarch64-unknown-windows-msvc -filetype obj %s -o - | \ +// RUN: llvm-objdump -D -r - | FileCheck %s + + .text +main: + nop + b .Ltarget + b .Lother_target + +// A privte label target in the same section + .def .Ltarget + .scl 2 + .type 32 + .endef + .p2align 2 +.Ltarget: + ret + +// A privte label target in another section + .section "other" + nop + nop + nop + nop + nop + nop + nop + nop + .def .Lother_target + .scl 2 + .type 32 + .endef + .p2align 2 +.Lother_target: + ret + +// Check that both branches have a relocation with a zero offset. +// +// CHECK: 0000000000000000
: +// CHECK: 0: d503201f nop +// CHECK: 4: 14000000 b 0x4 +// CHECK: 0000000000000004: IMAGE_REL_ARM64_BRANCH26 .Ltarget +// CHECK: 8: 14000000 b 0x8 +// CHECK: 0000000000000008: IMAGE_REL_ARM64_BRANCH26 .Lother_target +// CHECK: 000000000000000c <.Ltarget>: +// CHECK: c: d65f03c0 ret +// CHECK: 0000000000000000 : +// CHECK: 0: d503201f nop +// CHECK: 4: d503201f nop +// CHECK: 8: d503201f nop +// CHECK: c: d503201f nop +// CHECK: 10: d503201f nop +// CHECK: 14: d503201f nop +// CHECK: 18: d503201f nop +// CHECK: 1c: d503201f nop +// CHECK: 0000000000000020 <.Lother_target>: +// CHECK: 20: d65f03c0 ret