diff options
Diffstat (limited to 'llvm/lib/MC/MCObjectStreamer.cpp')
-rw-r--r-- | llvm/lib/MC/MCObjectStreamer.cpp | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index e39c4a0..78ee215 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -665,6 +665,68 @@ void MCObjectStreamer::emitGPRel64Value(const MCExpr *Value) { DF->getContents().resize(DF->getContents().size() + 8, 0); } +static Optional<std::pair<bool, std::string>> +getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset, + MCDataFragment *&DF) { + if (Symbol.isVariable()) { + const MCExpr *SymbolExpr = Symbol.getVariableValue(); + MCValue OffsetVal; + if(!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr, nullptr)) + return std::make_pair(false, + std::string("symbol in .reloc offset is not " + "relocatable")); + if (OffsetVal.isAbsolute()) { + RelocOffset = OffsetVal.getConstant(); + MCFragment *Fragment = Symbol.getFragment(); + // FIXME Support symbols with no DF. For example: + // .reloc .data, ENUM_VALUE, <some expr> + if (!Fragment || Fragment->getKind() != MCFragment::FT_Data) + return std::make_pair(false, + std::string("symbol in offset has no data " + "fragment")); + DF = cast<MCDataFragment>(Fragment); + return None; + } + + if (OffsetVal.getSymB()) + return std::make_pair(false, + std::string(".reloc symbol offset is not " + "representable")); + + const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA()); + if (!SRE.getSymbol().isDefined()) + return std::make_pair(false, + std::string("symbol used in the .reloc offset is " + "not defined")); + + if (SRE.getSymbol().isVariable()) + return std::make_pair(false, + std::string("symbol used in the .reloc offset is " + "variable")); + + MCFragment *Fragment = SRE.getSymbol().getFragment(); + // FIXME Support symbols with no DF. For example: + // .reloc .data, ENUM_VALUE, <some expr> + if (!Fragment || Fragment->getKind() != MCFragment::FT_Data) + return std::make_pair(false, + std::string("symbol in offset has no data " + "fragment")); + RelocOffset = SRE.getSymbol().getOffset() + OffsetVal.getConstant(); + DF = cast<MCDataFragment>(Fragment); + } else { + RelocOffset = Symbol.getOffset(); + MCFragment *Fragment = Symbol.getFragment(); + // FIXME Support symbols with no DF. For example: + // .reloc .data, ENUM_VALUE, <some expr> + if (!Fragment || Fragment->getKind() != MCFragment::FT_Data) + return std::make_pair(false, + std::string("symbol in offset has no data " + "fragment")); + DF = cast<MCDataFragment>(Fragment); + } + return None; +} + Optional<std::pair<bool, std::string>> MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc, @@ -698,10 +760,17 @@ MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name, std::string(".reloc offset is not representable")); const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA()); - if (SRE.getSymbol().isDefined()) { - // FIXME SRE.getSymbol() may not be relative to DF. + const MCSymbol &Symbol = SRE.getSymbol(); + if (Symbol.isDefined()) { + uint32_t SymbolOffset = 0; + Optional<std::pair<bool, std::string>> Error; + Error = getOffsetAndDataFragment(Symbol, SymbolOffset, DF); + + if (Error != None) + return Error; + DF->getFixups().push_back( - MCFixup::create(SRE.getSymbol().getOffset() + OffsetVal.getConstant(), + MCFixup::create(SymbolOffset + OffsetVal.getConstant(), Expr, Kind, Loc)); return None; } |