Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -503,10 +503,12 @@ bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); if (!IsConstantImm) { IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); - return IsValid && VK == RISCVMCExpr::VK_RISCV_PCREL_HI; + return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI); } else { return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || - VK == RISCVMCExpr::VK_RISCV_PCREL_HI); + VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI); } } @@ -859,8 +861,8 @@ case Match_InvalidUImm20AUIPC: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 20) - 1, - "operand must be a symbol with %pcrel_hi() modifier or an integer in " - "the range"); + "operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier " + "or an integer in the range"); case Match_InvalidSImm21Lsb0JAL: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -80,6 +80,7 @@ { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_pcrel_lo12_i", 20, 12, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_pcrel_lo12_s", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel }, Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -34,21 +34,26 @@ switch ((unsigned)Fixup.getKind()) { default: return false; + case RISCV::fixup_riscv_got_hi20: + return true; case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_s: // For pcrel_lo12, MCAssembler determines if the fixup can be resolved - // based on the difference between pcrel_hi20 and pcrel_lo12. However, - // it should actually be based on pcrel_lo12 and the target of pcrel_hi20. + // based on the difference between the AUIPC and pcrel_lo12. However, it + // should actually be based on pcrel_lo12, the type of the corresponding + // hi20, and the target of the hi20. // - // Force a relocation here if the target isn't in same section. - const MCExpr *T = cast(Fixup.getValue())->getPCRelHiExpr(); + // Force a relocation here if the target isn't in same section, or if the + // target is something other than a pcrel_hi20 (such as a got_hi20). + const MCFixup *T = cast(Fixup.getValue())->getPCRelHiFixup(); if (!T) { Asm.getContext().reportError(Fixup.getLoc(), "could not find corresponding %pcrel_hi"); return false; } - return T->findAssociatedFragment() != + return (unsigned)T->getKind() != RISCV::fixup_riscv_pcrel_hi20 + || T->getValue()->findAssociatedFragment() != Fixup.getValue()->findAssociatedFragment(); } } @@ -179,6 +184,7 @@ return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); case RISCV::fixup_riscv_hi20: case RISCV::fixup_riscv_pcrel_hi20: + case RISCV::fixup_riscv_got_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: { Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -84,6 +84,8 @@ return ELF::R_RISCV_PCREL_LO12_I; case RISCV::fixup_riscv_pcrel_lo12_s: return ELF::R_RISCV_PCREL_LO12_S; + case RISCV::fixup_riscv_got_hi20: + return ELF::R_RISCV_GOT_HI20; case RISCV::fixup_riscv_jal: return ELF::R_RISCV_JAL; case RISCV::fixup_riscv_branch: Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -35,6 +35,9 @@ // fixup_riscv_pcrel_lo12_s - 12-bit fixup corresponding to pcrel_lo(foo) for // the S-type store instructions fixup_riscv_pcrel_lo12_s, + // fixup_riscv_got_hi20 - 20-bit fixup corresponding to got_pcrel_hi(foo) for + // instructions like auipc + fixup_riscv_got_hi20, // fixup_riscv_jal - 20-bit fixup for symbol references in the jal // instruction fixup_riscv_jal, Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -235,6 +235,9 @@ case RISCVMCExpr::VK_RISCV_PCREL_HI: FixupKind = RISCV::fixup_riscv_pcrel_hi20; break; + case RISCVMCExpr::VK_RISCV_GOT_HI: + FixupKind = RISCV::fixup_riscv_got_hi20; + break; case RISCVMCExpr::VK_RISCV_CALL: FixupKind = RISCV::fixup_riscv_call; break; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -29,6 +29,7 @@ VK_RISCV_HI, VK_RISCV_PCREL_LO, VK_RISCV_PCREL_HI, + VK_RISCV_GOT_HI, VK_RISCV_CALL, VK_RISCV_Invalid }; @@ -53,12 +54,12 @@ const MCExpr *getSubExpr() const { return Expr; } - /// Get the MCExpr of the VK_RISCV_PCREL_HI Fixup that the - /// VK_RISCV_PCREL_LO points to. + /// Get the corresponding PC-relative HI fixup that a VK_RISCV_PCREL_LO + /// points to. /// /// \returns nullptr if this isn't a VK_RISCV_PCREL_LO pointing to a - /// VK_RISCV_PCREL_HI. - const MCExpr *getPCRelHiExpr() const; + /// known PC-relative HI fixup. + const MCFixup *getPCRelHiFixup() const; void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -41,7 +41,7 @@ OS << ')'; } -const MCExpr *RISCVMCExpr::getPCRelHiExpr() const { +const MCFixup *RISCVMCExpr::getPCRelHiFixup() const { MCValue AUIPCLoc; if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr)) return nullptr; @@ -56,16 +56,19 @@ return nullptr; const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); - const MCExpr *TargetExpr = nullptr; for (const MCFixup &F : DF->getFixups()) { - if ((unsigned)F.getKind() != RISCV::fixup_riscv_pcrel_hi20) + switch ((unsigned)F.getKind()) { + default: continue; + case RISCV::fixup_riscv_got_hi20: + case RISCV::fixup_riscv_pcrel_hi20: + break; + } if (F.getOffset() != AUIPCSymbol->getOffset()) continue; - TargetExpr = F.getValue(); - break; + return &F; } - return TargetExpr; + return nullptr; } bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, @@ -91,12 +94,13 @@ if (!AUIPCSymbol) return false; - const MCExpr *TargetExpr = getPCRelHiExpr(); - if (!TargetExpr) + const MCFixup *TargetFixup = getPCRelHiFixup(); + if (!TargetFixup || + (unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20) return false; MCValue Target; - if (!TargetExpr->evaluateAsValue(Target, *Layout)) + if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout)) return false; if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection()) @@ -131,6 +135,7 @@ case VK_RISCV_HI: case VK_RISCV_PCREL_LO: case VK_RISCV_PCREL_HI: + case VK_RISCV_GOT_HI: return false; } } @@ -148,6 +153,7 @@ .Case("hi", VK_RISCV_HI) .Case("pcrel_lo", VK_RISCV_PCREL_LO) .Case("pcrel_hi", VK_RISCV_PCREL_HI) + .Case("got_pcrel_hi", VK_RISCV_GOT_HI) .Default(VK_RISCV_Invalid); } @@ -163,6 +169,8 @@ return "pcrel_lo"; case VK_RISCV_PCREL_HI: return "pcrel_hi"; + case VK_RISCV_GOT_HI: + return "got_pcrel_hi"; } } @@ -170,7 +178,7 @@ MCValue Value; if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || - Kind == VK_RISCV_CALL) + Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_CALL) return false; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) Index: test/MC/RISCV/relocations.s =================================================================== --- test/MC/RISCV/relocations.s +++ test/MC/RISCV/relocations.s @@ -65,6 +65,40 @@ # INSTR: sb t1, %pcrel_lo(.L0)(a2) # FIXUP: fixup A - offset: 0, value: %pcrel_lo(.L0), kind: fixup_riscv_pcrel_lo12_s +.L1: +auipc t1, %got_pcrel_hi(foo) +# RELOC: R_RISCV_GOT_HI20 foo 0x0 +# INSTR: auipc t1, %got_pcrel_hi(foo) +# FIXUP: fixup A - offset: 0, value: %got_pcrel_hi(foo), kind: fixup_riscv_got_hi20 + +addi t1, t1, %pcrel_lo(.L1) +# RELOC: R_RISCV_PCREL_LO12_I .L1 0x0 +# INSTR: addi t1, t1, %pcrel_lo(.L1) +# FIXUP: fixup A - offset: 0, value: %pcrel_lo(.L1), kind: fixup_riscv_pcrel_lo12_i + +sb t1, %pcrel_lo(.L1)(a2) +# RELOC: R_RISCV_PCREL_LO12_S .L1 0x0 +# INSTR: sb t1, %pcrel_lo(.L1)(a2) +# FIXUP: fixup A - offset: 0, value: %pcrel_lo(.L1), kind: fixup_riscv_pcrel_lo12_s + +# Check that GOT relocations aren't evaluated to a constant when the symbol is +# in the same object file. +.L2: +auipc t1, %got_pcrel_hi(.L1) +# RELOC: R_RISCV_GOT_HI20 .L1 0x0 +# INSTR: auipc t1, %got_pcrel_hi(.L1) +# FIXUP: fixup A - offset: 0, value: %got_pcrel_hi(.L1), kind: fixup_riscv_got_hi20 + +addi t1, t1, %pcrel_lo(.L2) +# RELOC: R_RISCV_PCREL_LO12_I .L2 0x0 +# INSTR: addi t1, t1, %pcrel_lo(.L2) +# FIXUP: fixup A - offset: 0, value: %pcrel_lo(.L2), kind: fixup_riscv_pcrel_lo12_i + +sb t1, %pcrel_lo(.L2)(a2) +# RELOC: R_RISCV_PCREL_LO12_S .L2 0x0 +# INSTR: sb t1, %pcrel_lo(.L2)(a2) +# FIXUP: fixup A - offset: 0, value: %pcrel_lo(.L2), kind: fixup_riscv_pcrel_lo12_s + jal zero, foo # RELOC: R_RISCV_JAL # INSTR: jal zero, foo Index: test/MC/RISCV/rv32i-invalid.s =================================================================== --- test/MC/RISCV/rv32i-invalid.s +++ test/MC/RISCV/rv32i-invalid.s @@ -40,7 +40,7 @@ ## uimm20 lui a0, -1 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] lui s0, 1048576 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] -auipc zero, -0xf # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] +auipc zero, -0xf # CHECK: :[[@LINE]]:13: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier or an integer in the range [0, 1048575] ## simm21_lsb0 jal gp, -1048578 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] @@ -105,7 +105,7 @@ ## uimm20 lui a0, %lo(1) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] -auipc a1, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] +auipc a1, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier or an integer in the range [0, 1048575] ## simm21_lsb0 jal gp, %lo(1) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] @@ -125,10 +125,10 @@ lui a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] lui a0, %pcrel_hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] -auipc a0, foo # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] -auipc a0, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] -auipc a0, %hi(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] -auipc a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] +auipc a0, foo # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier or an integer in the range [0, 1048575] +auipc a0, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier or an integer in the range [0, 1048575] +auipc a0, %hi(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier or an integer in the range [0, 1048575] +auipc a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi modifier or an integer in the range [0, 1048575] # Unrecognized operand modifier addi t0, sp, %modifer(255) # CHECK: :[[@LINE]]:15: error: unrecognized operand modifier