Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -39,12 +39,18 @@ bool EmitEHFrame; bool EmitDebugFrame; SmallVector PendingLabels; + struct { + const MCSymbol *Sym; + MCFixup Fixup; + MCDataFragment *DF; + } PendingFixup; virtual void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo&) = 0; void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override; void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override; MCSymbol *EmitCFILabel() override; void EmitInstructionImpl(const MCInst &Inst, const MCSubtargetInfo &STI); + void resolvePendingFixup(); protected: MCObjectStreamer(MCContext &Context, std::unique_ptr TAB, Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -59,6 +59,30 @@ PendingLabels.clear(); } +// When fixup's offset is a forward declared label, e.g.: +// +// .reloc 1f, R_MIPS_JALR, foo +// 1: nop +// +// postpone adding it to Fixups vector until the label is defined and its offset +// is known. +// We support up to one pending fixup for now. +void MCObjectStreamer::resolvePendingFixup() { + if (!PendingFixup.Sym) + return; + + if (PendingFixup.Sym->isUndefined ()) { + getContext().reportError(PendingFixup.Fixup.getLoc(), + "unresolved relocation offset"); + return; + } + + flushPendingLabels(PendingFixup.DF, PendingFixup.DF->getContents().size()); + PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset()); + PendingFixup.DF->getFixups().push_back(PendingFixup.Fixup); + PendingFixup.Sym = nullptr; +} + // As a compile-time optimization, avoid allocating and evaluating an MCExpr // tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment. static Optional @@ -603,16 +627,6 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc, const MCSubtargetInfo &STI) { - int64_t OffsetValue; - if (!Offset.evaluateAsAbsolute(OffsetValue)) - llvm_unreachable("Offset is not absolute"); - - if (OffsetValue < 0) - llvm_unreachable("Offset is negative"); - - MCDataFragment *DF = getOrCreateDataFragment(&STI); - flushPendingLabels(DF, DF->getContents().size()); - Optional MaybeKind = Assembler->getBackend().getFixupKind(Name); if (!MaybeKind.hasValue()) return true; @@ -622,7 +636,33 @@ if (Expr == nullptr) Expr = MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext()); - DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); + + MCDataFragment *DF = getOrCreateDataFragment(&STI); + flushPendingLabels(DF, DF->getContents().size()); + + int64_t OffsetValue; + if (Offset.evaluateAsAbsolute(OffsetValue)) { + if (OffsetValue < 0) + llvm_unreachable(".reloc offset is negative"); + DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); + return false; + } + + if (Offset.getKind() != llvm::MCExpr::SymbolRef) + llvm_unreachable(".reloc offset is not absolute nor a label"); + + const MCSymbolRefExpr &SRE = cast(Offset); + if (SRE.getSymbol().isDefined()) { + DF->getFixups().push_back(MCFixup::create(SRE.getSymbol().getOffset(), + Expr, Kind, Loc)); + return false; + } + + resolvePendingFixup(); + + PendingFixup.Sym = &SRE.getSymbol(); + PendingFixup.DF = DF; + PendingFixup.Fixup = MCFixup::create(-1, Expr, Kind, Loc); return false; } @@ -689,5 +729,6 @@ MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams()); flushPendingLabels(); + resolvePendingFixup(); getAssembler().Finish(); } Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -2940,20 +2940,20 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { const MCExpr *Offset; const MCExpr *Expr = nullptr; - - SMLoc OffsetLoc = Lexer.getTok().getLoc(); int64_t OffsetValue; - // We can only deal with constant expressions at the moment. + SMLoc OffsetLoc = Lexer.getTok().getLoc(); if (parseExpression(Offset)) return true; - if (check(!Offset->evaluateAsAbsolute(OffsetValue, - getStreamer().getAssemblerPtr()), - OffsetLoc, "expression is not a constant value") || - check(OffsetValue < 0, OffsetLoc, "expression is negative") || - parseToken(AsmToken::Comma, "expected comma") || - check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) + if ((Offset->evaluateAsAbsolute(OffsetValue, + getStreamer().getAssemblerPtr()) && + check(OffsetValue < 0, OffsetLoc, "expression is negative")) || + (check(Offset->getKind() != llvm::MCExpr::Constant && + Offset->getKind() != llvm::MCExpr::SymbolRef, + OffsetLoc, "expected non-negative number or a label")) || + (parseToken(AsmToken::Comma, "expected comma") || + check(getTok().isNot(AsmToken::Identifier), "expected relocation name"))) return true; SMLoc NameLoc = Lexer.getTok().getLoc(); Index: test/MC/Mips/reloc-directive-bad-obj.s =================================================================== --- /dev/null +++ test/MC/Mips/reloc-directive-bad-obj.s @@ -0,0 +1,16 @@ +# RUN: not llvm-mc -triple mips-unknown-linux %s -show-encoding \ +# RUN: -target-abi=o32 -filetype=obj 2>&1 | FileCheck %s + .text + .reloc 0, R_NO_SUCH_RELOC, .text # CHECK: :[[@LINE]]:12: error: unknown relocation name + + .reloc 2f, R_MIPS_32, .text # CHECK: :[[@LINE]]:2: error: unresolved relocation offset + .reloc 1f, R_MIPS_32, .text +1: 2: + nop + + .reloc bar, R_MIPS_32, .text # CHECK: :[[@LINE]]:2: error: unresolved relocation offset + nop + + .reloc 1f, R_MIPS_32, .text +1: + nop Index: test/MC/Mips/reloc-directive-bad.s =================================================================== --- test/MC/Mips/reloc-directive-bad.s +++ test/MC/Mips/reloc-directive-bad.s @@ -1,6 +1,13 @@ -# RUN: not llvm-mc -triple mips-unknown-linux < %s -show-encoding -target-abi=o32 \ -# RUN: 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple mips-unknown-linux < %s -show-encoding \ +# RUN: -target-abi=o32 2>&1 | FileCheck %s .text foo: - .reloc 0, R_MIPS_32, .text+.text # CHECK: :[[@LINE]]:23: error: expression must be relocatable + .reloc foo+4, R_MIPS_32, .text # CHECK: :[[@LINE]]:9: error: expected non-negative number or a label + .reloc foo+foo, R_MIPS_32, .text # CHECK: :[[@LINE]]:9: error: expected non-negative number or a label + .reloc 0, R_MIPS_32, .text+.text # CHECK: :[[@LINE]]:23: error: expression must be relocatable + .reloc 0 R_MIPS_32, .text # CHECK: :[[@LINE]]:11: error: expected comma + .reloc 0, 0, R_MIPS_32, .text # CHECK: :[[@LINE]]:12: error: expected relocation name + .reloc -1, R_MIPS_32, .text # CHECK: :[[@LINE]]:9: error: expression is negative + .reloc 1b, R_MIPS_32, .text # CHECK: :[[@LINE]]:9: error: directional label undefined + .reloc 1f, R_MIPS_32, .text # CHECK: :[[@LINE]]:9: error: directional label undefined nop Index: test/MC/Mips/reloc-directive-label-offset.s =================================================================== --- /dev/null +++ test/MC/Mips/reloc-directive-label-offset.s @@ -0,0 +1,67 @@ +# RUN: llvm-mc -triple mips-unknown-linux %s -show-encoding -target-abi=o32 \ +# RUN: | FileCheck --check-prefixes=ASM,ASM-32 %s +# RUN: llvm-mc -triple mips64-unknown-linux %s -show-encoding -target-abi=n32 \ +# RUN: | FileCheck --check-prefixes=ASM,ASM-64 %s +# RUN: llvm-mc -triple mips64-unknown-linux %s -show-encoding -target-abi=n64 \ +# RUN: | FileCheck --check-prefixes=ASM,ASM-64 %s +# RUN: llvm-mc -triple mips-unknown-linux %s -show-encoding -target-abi=o32 \ +# RUN: -filetype=obj | llvm-readobj -r | FileCheck -check-prefix=OBJ-O32 %s +# RUN: llvm-mc -triple mips64-unknown-linux %s -show-encoding -target-abi=n32 \ +# RUN: -filetype=obj | llvm-readobj -r | FileCheck -check-prefix=OBJ-N32 %s +# RUN: llvm-mc -triple mips64-unknown-linux %s -show-encoding -target-abi=n64 \ +# RUN: -filetype=obj | llvm-readobj -r | FileCheck -check-prefix=OBJ-N64 %s + + .text +foo: # ASM-LABEL: foo: + nop +1: + nop + .reloc 1b, R_MIPS_NONE, foo # ASM-32: .reloc ($tmp0), R_MIPS_NONE, foo + # ASM-64: .reloc .Ltmp0, R_MIPS_NONE, foo + nop + .reloc 1f, R_MIPS_32, foo # ASM-32: .reloc ($tmp1), R_MIPS_32, foo + # ASM-64: .reloc .Ltmp1, R_MIPS_32, foo +1: + nop + .reloc 1f, R_MIPS_CALL16, foo # ASM-32: .reloc ($tmp2), R_MIPS_CALL16, foo + # ASM-64: .reloc .Ltmp2, R_MIPS_CALL16, foo +1: + nop + .reloc 2f, R_MIPS_GOT_DISP, foo # ASM-32: .reloc ($tmp3), R_MIPS_GOT_DISP, foo + # ASM-64: .reloc .Ltmp3, R_MIPS_GOT_DISP, foo + nop + nop +bar: +2: + nop + nop + .reloc bar, R_MIPS_GOT_PAGE, foo # ASM: .reloc bar, R_MIPS_GOT_PAGE, foo + nop + .reloc foo, R_MIPS_GOT_OFST, foo # ASM: .reloc foo, R_MIPS_GOT_OFST, foo + nop +1: + nop + +# OBJ-O32-LABEL: Relocations [ +# OBJ-O32: 0x0 R_MIPS_GOT_OFST .text 0x0 +# OBJ-O32-NEXT: 0x4 R_MIPS_NONE .text 0x0 +# OBJ-O32-NEXT: 0xC R_MIPS_32 .text 0x0 +# OBJ-O32-NEXT: 0x10 R_MIPS_CALL16 foo 0x0 +# OBJ-O32-NEXT: 0x1C R_MIPS_GOT_DISP foo 0x0 +# OBJ-O32-NEXT: 0x1C R_MIPS_GOT_PAGE .text 0x0 + +# OBJ-N32-LABEL: Relocations [ +# OBJ-N32: 0x4 R_MIPS_NONE .text 0x0 +# OBJ-N32-NEXT: 0xC R_MIPS_32 .text 0x0 +# OBJ-N32-NEXT: 0x10 R_MIPS_CALL16 foo 0x0 +# OBJ-N32-NEXT: 0x1C R_MIPS_GOT_PAGE .text 0x0 +# OBJ-N32-NEXT: 0x0 R_MIPS_GOT_OFST .text 0x0 +# OBJ-N32-NEXT: 0x1C R_MIPS_GOT_DISP foo 0x0 + +# OBJ-N64-LABEL: Relocations [ +# OBJ-N64: 0x4 R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# OBJ-N64-NEXT: 0xC R_MIPS_32/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# OBJ-N64-NEXT: 0x10 R_MIPS_CALL16/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# OBJ-N64-NEXT: 0x1C R_MIPS_GOT_PAGE/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# OBJ-N64-NEXT: 0x0 R_MIPS_GOT_OFST/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# OBJ-N64-NEXT: 0x1C R_MIPS_GOT_DISP/R_MIPS_NONE/R_MIPS_NONE foo 0x0 Index: test/MC/Mips/reloc-directive-negative.s =================================================================== --- test/MC/Mips/reloc-directive-negative.s +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: not llvm-mc -triple mips-unknown-linux < %s -show-encoding -target-abi=o32 \ -# RUN: 2>&1 | FileCheck %s - .text -foo: - .reloc -1, R_MIPS_32, .text # CHECK: :[[@LINE]]:9: error: expression is negative - nop