MC: Rework .reloc directive and fix the offset when it evaluates to a constant
* Fix `.reloc constant` to mean section_symbol+constant instead of .+constant . The initial .reloc support from MIPS incorrectly interpreted the offset. * Delay the evaluation of the offset expression after MCAssembler::layout, deleting a lot of code working with MCFragment. * Delete many FIXME from https://reviews.llvm.org/D79625 * Some lld/ELF/Arch/LoongArch.cpp relaxation tests rely on .reloc ., R_LARCH_ALIGN generating ALIGN relocations at specific location. Sort the relocations.
This commit is contained in:
parent
34c8533742
commit
3cb0c7f45b
@ -1671,8 +1671,9 @@ void RelocationScanner::scan(Relocs<RelTy> rels) {
|
||||
}
|
||||
|
||||
// Sort relocations by offset for more efficient searching for
|
||||
// R_RISCV_PCREL_HI20, R_PPC64_ADDR64 and the branch-to-branch optimization.
|
||||
if (ctx.arg.emachine == EM_RISCV ||
|
||||
// R_RISCV_PCREL_HI20, ALIGN relocations, R_PPC64_ADDR64 and the
|
||||
// branch-to-branch optimization.
|
||||
if (is_contained({EM_RISCV, EM_LOONGARCH}, ctx.arg.emachine) ||
|
||||
(ctx.arg.emachine == EM_PPC64 && sec->name == ".toc") ||
|
||||
ctx.arg.branchToBranch)
|
||||
llvm::stable_sort(sec->relocs(),
|
||||
|
||||
@ -69,6 +69,13 @@ private:
|
||||
|
||||
SmallVector<const MCSymbol *, 0> Symbols;
|
||||
|
||||
struct RelocDirective {
|
||||
const MCExpr &Offset;
|
||||
const MCExpr *Expr;
|
||||
uint32_t Kind;
|
||||
};
|
||||
SmallVector<RelocDirective, 0> relocDirectives;
|
||||
|
||||
mutable SmallVector<std::pair<SMLoc, std::string>, 0> PendingErrors;
|
||||
|
||||
MCDwarfLineTableParams LTParams;
|
||||
@ -205,6 +212,7 @@ public:
|
||||
|
||||
LLVM_ABI bool registerSection(MCSection &Section);
|
||||
LLVM_ABI bool registerSymbol(const MCSymbol &Symbol);
|
||||
void addRelocDirective(RelocDirective RD);
|
||||
|
||||
LLVM_ABI void reportError(SMLoc L, const Twine &Msg) const;
|
||||
// Record pending errors during layout iteration, as they may go away once the
|
||||
|
||||
@ -141,7 +141,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void finalizeCGProfileEntry(const MCSymbolRefExpr *&S, uint64_t Offset);
|
||||
void finalizeCGProfileEntry(const MCSymbolRefExpr *Sym, uint64_t Offset,
|
||||
const MCSymbolRefExpr *&S);
|
||||
void finalizeCGProfile();
|
||||
|
||||
bool SeenIdent = false;
|
||||
|
||||
@ -40,14 +40,6 @@ class MCObjectStreamer : public MCStreamer {
|
||||
std::unique_ptr<MCAssembler> Assembler;
|
||||
bool EmitEHFrame;
|
||||
bool EmitDebugFrame;
|
||||
struct PendingMCFixup {
|
||||
const MCSymbol *Sym;
|
||||
MCFixup Fixup;
|
||||
MCFragment *DF;
|
||||
PendingMCFixup(const MCSymbol *McSym, MCFragment *F, MCFixup McFixup)
|
||||
: Sym(McSym), Fixup(McFixup), DF(F) {}
|
||||
};
|
||||
SmallVector<PendingMCFixup, 2> PendingFixups;
|
||||
|
||||
struct PendingAssignment {
|
||||
MCSymbol *Symbol;
|
||||
@ -63,7 +55,6 @@ class MCObjectStreamer : public MCStreamer {
|
||||
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
|
||||
void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
|
||||
void emitInstructionImpl(const MCInst &Inst, const MCSubtargetInfo &STI);
|
||||
void resolvePendingFixups();
|
||||
|
||||
protected:
|
||||
MCObjectStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
|
||||
@ -162,9 +153,8 @@ public:
|
||||
void emitCVStringTableDirective() override;
|
||||
void emitCVFileChecksumsDirective() override;
|
||||
void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;
|
||||
std::optional<std::pair<bool, std::string>>
|
||||
emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr,
|
||||
SMLoc Loc, const MCSubtargetInfo &STI) override;
|
||||
void emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc Loc = {}) override;
|
||||
using MCStreamer::emitFill;
|
||||
void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
|
||||
SMLoc Loc = SMLoc()) override;
|
||||
|
||||
@ -1048,13 +1048,9 @@ public:
|
||||
|
||||
virtual void emitSyntaxDirective();
|
||||
|
||||
/// Record a relocation described by the .reloc directive. Return std::nullopt
|
||||
/// if succeeded. Otherwise, return a pair (Name is invalid, error message).
|
||||
virtual std::optional<std::pair<bool, std::string>>
|
||||
emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr,
|
||||
SMLoc Loc, const MCSubtargetInfo &STI) {
|
||||
return std::nullopt;
|
||||
}
|
||||
/// Record a relocation described by the .reloc directive.
|
||||
virtual void emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc Loc = {}) {}
|
||||
|
||||
virtual void emitAddrsig() {}
|
||||
virtual void emitAddrsigSym(const MCSymbol *Sym) {}
|
||||
|
||||
@ -407,9 +407,8 @@ public:
|
||||
const MCPseudoProbeInlineStack &InlineStack,
|
||||
MCSymbol *FnSym) override;
|
||||
|
||||
std::optional<std::pair<bool, std::string>>
|
||||
emitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr,
|
||||
SMLoc Loc, const MCSubtargetInfo &STI) override;
|
||||
void emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc Loc) override;
|
||||
|
||||
void emitAddrsig() override;
|
||||
void emitAddrsigSym(const MCSymbol *Sym) override;
|
||||
@ -2468,10 +2467,8 @@ void MCAsmStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index,
|
||||
EmitEOL();
|
||||
}
|
||||
|
||||
std::optional<std::pair<bool, std::string>>
|
||||
MCAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc,
|
||||
const MCSubtargetInfo &STI) {
|
||||
void MCAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc) {
|
||||
OS << "\t.reloc ";
|
||||
MAI->printExpr(OS, Offset);
|
||||
OS << ", " << Name;
|
||||
@ -2480,7 +2477,6 @@ MCAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
MAI->printExpr(OS, *Expr);
|
||||
}
|
||||
EmitEOL();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void MCAsmStreamer::emitAddrsig() {
|
||||
|
||||
@ -398,6 +398,10 @@ bool MCAssembler::registerSymbol(const MCSymbol &Symbol) {
|
||||
return Changed;
|
||||
}
|
||||
|
||||
void MCAssembler::addRelocDirective(RelocDirective RD) {
|
||||
relocDirectives.push_back(RD);
|
||||
}
|
||||
|
||||
/// Write the fragment \p F to the output file.
|
||||
static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
|
||||
const MCFragment &F) {
|
||||
@ -695,6 +699,27 @@ void MCAssembler::layout() {
|
||||
// helps check whether a PC-relative fixup is fully resolved.
|
||||
this->HasFinalLayout = true;
|
||||
|
||||
// Resolve .reloc offsets and add fixups.
|
||||
for (auto &PF : relocDirectives) {
|
||||
MCValue Res;
|
||||
auto &O = PF.Offset;
|
||||
if (!O.evaluateAsValue(Res, *this)) {
|
||||
getContext().reportError(O.getLoc(), ".reloc offset is not relocatable");
|
||||
continue;
|
||||
}
|
||||
auto *Sym = Res.getAddSym();
|
||||
auto *F = Sym ? Sym->getFragment() : nullptr;
|
||||
auto *Sec = F ? F->getParent() : nullptr;
|
||||
if (Res.getSubSym() || !Sec) {
|
||||
getContext().reportError(O.getLoc(),
|
||||
".reloc offset is not relative to a section");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t Offset = Sym ? Sym->getOffset() + Res.getConstant() : 0;
|
||||
F->addFixup(MCFixup::create(Offset, PF.Expr, PF.Kind));
|
||||
}
|
||||
|
||||
// Evaluate and apply the fixups, generating relocation entries as necessary.
|
||||
for (MCSection &Sec : *this) {
|
||||
for (MCFragment &F : Sec) {
|
||||
|
||||
@ -314,8 +314,9 @@ void MCELFStreamer::emitIdent(StringRef IdentString) {
|
||||
popSection();
|
||||
}
|
||||
|
||||
void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE,
|
||||
uint64_t Offset) {
|
||||
void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *Sym,
|
||||
uint64_t Offset,
|
||||
const MCSymbolRefExpr *&SRE) {
|
||||
const MCSymbol *S = &SRE->getSymbol();
|
||||
if (S->isTemporary()) {
|
||||
if (!S->isInSection()) {
|
||||
@ -328,13 +329,9 @@ void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE,
|
||||
S->setUsedInReloc();
|
||||
SRE = MCSymbolRefExpr::create(S, getContext(), SRE->getLoc());
|
||||
}
|
||||
const MCConstantExpr *MCOffset = MCConstantExpr::create(Offset, getContext());
|
||||
if (std::optional<std::pair<bool, std::string>> Err =
|
||||
MCObjectStreamer::emitRelocDirective(
|
||||
*MCOffset, "BFD_RELOC_NONE", SRE, SRE->getLoc(),
|
||||
*getContext().getSubtargetInfo()))
|
||||
report_fatal_error("Relocation for CG Profile could not be created: " +
|
||||
Twine(Err->second));
|
||||
auto *O = MCBinaryExpr::createAdd(
|
||||
Sym, MCConstantExpr::create(Offset, getContext()), getContext());
|
||||
MCObjectStreamer::emitRelocDirective(*O, "BFD_RELOC_NONE", SRE);
|
||||
}
|
||||
|
||||
void MCELFStreamer::finalizeCGProfile() {
|
||||
@ -347,9 +344,11 @@ void MCELFStreamer::finalizeCGProfile() {
|
||||
pushSection();
|
||||
switchSection(CGProfile);
|
||||
uint64_t Offset = 0;
|
||||
auto *Sym =
|
||||
MCSymbolRefExpr::create(CGProfile->getBeginSymbol(), getContext());
|
||||
for (auto &E : W.getCGProfile()) {
|
||||
finalizeCGProfileEntry(E.From, Offset);
|
||||
finalizeCGProfileEntry(E.To, Offset);
|
||||
finalizeCGProfileEntry(Sym, Offset, E.From);
|
||||
finalizeCGProfileEntry(Sym, Offset, E.To);
|
||||
emitIntValue(E.Count, sizeof(uint64_t));
|
||||
Offset += sizeof(uint64_t);
|
||||
}
|
||||
|
||||
@ -46,35 +46,6 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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.
|
||||
void MCObjectStreamer::resolvePendingFixups() {
|
||||
for (PendingMCFixup &PendingFixup : PendingFixups) {
|
||||
if (!PendingFixup.Sym || PendingFixup.Sym->isUndefined ()) {
|
||||
getContext().reportError(PendingFixup.Fixup.getLoc(),
|
||||
"unresolved relocation offset");
|
||||
continue;
|
||||
}
|
||||
PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset() +
|
||||
PendingFixup.Fixup.getOffset());
|
||||
|
||||
// If the location symbol to relocate is in MCEncodedFragment,
|
||||
// put the Fixup into location symbol's fragment. Otherwise
|
||||
// put into PendingFixup.DF
|
||||
MCFragment *F = PendingFixup.Sym->getFragment();
|
||||
if (F->isEncoded())
|
||||
F->addFixup(PendingFixup.Fixup);
|
||||
else
|
||||
PendingFixup.DF->addFixup(PendingFixup.Fixup);
|
||||
}
|
||||
PendingFixups.clear();
|
||||
}
|
||||
|
||||
// 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's fixed
|
||||
// part.
|
||||
@ -607,76 +578,14 @@ void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
|
||||
insert(getContext().allocFragment<MCOrgFragment>(*Offset, Value, Loc));
|
||||
}
|
||||
|
||||
static std::optional<std::pair<bool, std::string>>
|
||||
getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset,
|
||||
MCFragment *&DF) {
|
||||
if (Symbol.isVariable()) {
|
||||
const MCExpr *SymbolExpr = Symbol.getVariableValue();
|
||||
MCValue OffsetVal;
|
||||
if (!SymbolExpr->evaluateAsRelocatable(OffsetVal, 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<MCFragment>(Fragment);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (OffsetVal.getSubSym())
|
||||
return std::make_pair(false,
|
||||
std::string(".reloc symbol offset is not "
|
||||
"representable"));
|
||||
|
||||
const MCSymbol &SA = *OffsetVal.getAddSym();
|
||||
if (!SA.isDefined())
|
||||
return std::make_pair(false,
|
||||
std::string("symbol used in the .reloc offset is "
|
||||
"not defined"));
|
||||
|
||||
if (SA.isVariable())
|
||||
return std::make_pair(false,
|
||||
std::string("symbol used in the .reloc offset is "
|
||||
"variable"));
|
||||
|
||||
MCFragment *Fragment = SA.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 = SA.getOffset() + OffsetVal.getConstant();
|
||||
DF = cast<MCFragment>(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<MCFragment>(Fragment);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::pair<bool, std::string>>
|
||||
MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc Loc,
|
||||
const MCSubtargetInfo &STI) {
|
||||
void MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
const MCExpr *Expr, SMLoc Loc) {
|
||||
std::optional<MCFixupKind> MaybeKind =
|
||||
Assembler->getBackend().getFixupKind(Name);
|
||||
if (!MaybeKind)
|
||||
return std::make_pair(true, std::string("unknown relocation name"));
|
||||
if (!MaybeKind) {
|
||||
getContext().reportError(Loc, "unknown relocation name");
|
||||
return;
|
||||
}
|
||||
|
||||
MCFixupKind Kind = *MaybeKind;
|
||||
if (Expr)
|
||||
@ -685,38 +594,14 @@ MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||
Expr =
|
||||
MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext());
|
||||
|
||||
MCFragment *DF = getOrCreateDataFragment(&STI);
|
||||
MCValue OffsetVal;
|
||||
if (!Offset.evaluateAsRelocatable(OffsetVal, nullptr))
|
||||
return std::make_pair(false,
|
||||
std::string(".reloc offset is not relocatable"));
|
||||
if (OffsetVal.isAbsolute()) {
|
||||
if (OffsetVal.getConstant() < 0)
|
||||
return std::make_pair(false, std::string(".reloc offset is negative"));
|
||||
DF->addFixup(MCFixup::create(OffsetVal.getConstant(), Expr, Kind));
|
||||
return std::nullopt;
|
||||
auto *O = &Offset;
|
||||
int64_t Val;
|
||||
if (Offset.evaluateAsAbsolute(Val, nullptr)) {
|
||||
auto *SecSym = getCurrentSectionOnly()->getBeginSymbol();
|
||||
O = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(SecSym, getContext()),
|
||||
O, getContext(), Loc);
|
||||
}
|
||||
if (OffsetVal.getSubSym())
|
||||
return std::make_pair(false,
|
||||
std::string(".reloc offset is not representable"));
|
||||
|
||||
const MCSymbol &Symbol = *OffsetVal.getAddSym();
|
||||
if (Symbol.isDefined()) {
|
||||
uint32_t SymbolOffset = 0;
|
||||
std::optional<std::pair<bool, std::string>> Error =
|
||||
getOffsetAndDataFragment(Symbol, SymbolOffset, DF);
|
||||
|
||||
if (Error != std::nullopt)
|
||||
return Error;
|
||||
|
||||
DF->addFixup(
|
||||
MCFixup::create(SymbolOffset + OffsetVal.getConstant(), Expr, Kind));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
PendingFixups.emplace_back(
|
||||
&Symbol, DF, MCFixup::create(OffsetVal.getConstant(), Expr, Kind));
|
||||
return std::nullopt;
|
||||
getAssembler().addRelocDirective({*O, Expr, Kind});
|
||||
}
|
||||
|
||||
void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
|
||||
@ -799,6 +684,5 @@ void MCObjectStreamer::finishImpl() {
|
||||
// Emit pseudo probes for the current module.
|
||||
MCPseudoProbeTable::emit(this);
|
||||
|
||||
resolvePendingFixups();
|
||||
getAssembler().Finish();
|
||||
}
|
||||
|
||||
@ -3079,7 +3079,6 @@ bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {
|
||||
bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {
|
||||
const MCExpr *Offset;
|
||||
const MCExpr *Expr = nullptr;
|
||||
SMLoc OffsetLoc = Lexer.getTok().getLoc();
|
||||
|
||||
if (parseExpression(Offset))
|
||||
return true;
|
||||
@ -3105,13 +3104,7 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {
|
||||
if (parseEOL())
|
||||
return true;
|
||||
|
||||
const MCTargetAsmParser &MCT = getTargetParser();
|
||||
const MCSubtargetInfo &STI = MCT.getSTI();
|
||||
if (std::optional<std::pair<bool, std::string>> Err =
|
||||
getStreamer().emitRelocDirective(*Offset, Name, Expr, DirectiveLoc,
|
||||
STI))
|
||||
return Error(Err->first ? NameLoc : OffsetLoc, Err->second);
|
||||
|
||||
getStreamer().emitRelocDirective(*Offset, Name, Expr, NameLoc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -559,8 +559,7 @@ void AArch64TargetELFStreamer::finish() {
|
||||
if (!Sym.isMemtag())
|
||||
continue;
|
||||
auto *SRE = MCSymbolRefExpr::create(&Sym, Ctx);
|
||||
(void)S.emitRelocDirective(*Zero, "BFD_RELOC_NONE", SRE, SMLoc(),
|
||||
*Ctx.getSubtargetInfo());
|
||||
S.emitRelocDirective(*Zero, "BFD_RELOC_NONE", SRE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2101,7 +2101,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
|
||||
TOut.getStreamer().emitRelocDirective(
|
||||
*TmpExpr, inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
|
||||
RelocJalrExpr, IDLoc, *STI);
|
||||
RelocJalrExpr);
|
||||
TOut.getStreamer().emitLabel(TmpLabel);
|
||||
}
|
||||
|
||||
|
||||
@ -166,7 +166,7 @@ static void emitDirectiveRelocJalr(const MachineInstr &MI,
|
||||
OutStreamer.emitRelocDirective(
|
||||
*OffsetExpr,
|
||||
Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
|
||||
CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo());
|
||||
CaleeExpr);
|
||||
OutStreamer.emitLabel(OffsetLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -9,15 +9,18 @@
|
||||
# ASM-NEXT: .reloc .Ltmp1-1, R_X86_64_NONE, foo
|
||||
# ASM-NEXT: .Ltmp2:
|
||||
# ASM-NEXT: .reloc 2+.Ltmp2, R_X86_64_NONE, local
|
||||
# ASM-NEXT: .reloc 1+foo+3, R_X86_64_NONE, data+1
|
||||
# ASM-NEXT: .Ltmp3:
|
||||
# ASM-NEXT: .reloc .Ltmp3, BFD_RELOC_NONE, unused
|
||||
|
||||
# CHECK: 0x2 R_X86_64_NONE foo 0x0
|
||||
# CHECK-NEXT: 0x0 R_X86_64_NONE foo 0x0
|
||||
# CHECK-NEXT: 0x3 R_X86_64_NONE local 0x0
|
||||
# CHECK-NEXT: 0x4 R_X86_64_NONE data 0x1
|
||||
# CHECK-NEXT: 0x1 R_X86_64_NONE unused 0x0
|
||||
# CHECK-NEXT: 0x4 R_X86_64_NONE data 0x1
|
||||
|
||||
# CHECK: .rela.my {
|
||||
# CHECK: 0x0 R_X86_64_NONE foo 0x0
|
||||
# CHECK-NEXT: 0x4 R_X86_64_NONE foo 0x0
|
||||
# CHECK-NEXT: 0x8 R_X86_64_NONE foo 0x0
|
||||
# CHECK-NEXT: }
|
||||
|
||||
.text
|
||||
.globl foo
|
||||
@ -27,17 +30,25 @@ local:
|
||||
.reloc .+3-2, R_X86_64_NONE, foo
|
||||
.reloc .-1, R_X86_64_NONE, foo
|
||||
.reloc 2+., R_X86_64_NONE, local
|
||||
.reloc 1+foo+3, R_X86_64_NONE, data+1
|
||||
.reloc ., BFD_RELOC_NONE, unused
|
||||
.space 3
|
||||
|
||||
.data
|
||||
.globl data
|
||||
data:
|
||||
.reloc 1+foo+3, R_X86_64_NONE, data+1
|
||||
.long 0
|
||||
|
||||
# RUN: not llvm-mc -filetype=obj -triple=x86_64 --defsym=ERR=1 %s 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
## Constant offsets are relative to the section start.
|
||||
.section .my
|
||||
.word 0
|
||||
.reloc 0, BFD_RELOC_NONE, foo
|
||||
.word 0
|
||||
.p2align 3
|
||||
.reloc 2+2, BFD_RELOC_NONE, foo
|
||||
.p2align 4
|
||||
.reloc 8, BFD_RELOC_NONE, foo
|
||||
|
||||
.ifdef ERR
|
||||
.text
|
||||
.globl a, b
|
||||
a: ret
|
||||
@ -45,22 +56,26 @@ b: ret
|
||||
x: ret
|
||||
y: ret
|
||||
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:10: error: expected comma
|
||||
# RUN: not llvm-mc -filetype=obj -triple=x86_64 --defsym=PARSE=1 %s 2>&1 | FileCheck %s --check-prefix=PARSE
|
||||
# RUN: not llvm-mc -filetype=obj -triple=x86_64 --defsym=ERR=1 %s 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
|
||||
.ifdef PARSE
|
||||
# PARSE: {{.*}}.s:[[#@LINE+1]]:10: error: expected comma
|
||||
.reloc 0 R_X86_64_NONE, a
|
||||
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:8: error: .reloc offset is negative
|
||||
.reloc -1, R_X86_64_NONE, a
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:8: error: .reloc offset is not relocatable
|
||||
.reloc 2*., R_X86_64_NONE, a
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:8: error: .reloc offset is not relocatable
|
||||
.reloc a+a, R_X86_64_NONE, a
|
||||
## GNU as accepts a-a but rejects b-a.
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:8: error: .reloc offset is not representable
|
||||
.reloc a-a, R_X86_64_NONE, a
|
||||
## TODO GNU as accepts x-x and y-x.
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:8: error: .reloc offset is not representable
|
||||
.reloc x-x, R_X86_64_NONE, a
|
||||
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:8: error: directional label undefined
|
||||
# PARSE: {{.*}}.s:[[#@LINE+1]]:8: error: directional label undefined
|
||||
.reloc 1f, R_X86_64_NONE, a
|
||||
.endif
|
||||
|
||||
.ifdef ERR
|
||||
.reloc -1, R_X86_64_NONE, a
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:9: error: .reloc offset is not relocatable
|
||||
.reloc 2*., R_X86_64_NONE, a
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:9: error: .reloc offset is not relocatable
|
||||
.reloc a+a, R_X86_64_NONE, a
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:9: error: .reloc offset is not relative to a section
|
||||
.reloc b-a, R_X86_64_NONE, a
|
||||
# ERR: {{.*}}.s:[[#@LINE+1]]:9: error: .reloc offset is not relative to a section
|
||||
.reloc x-x, R_X86_64_NONE, a
|
||||
|
||||
.endif
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
# RUN: -target-abi=o32 -filetype=obj -o /dev/null 2>&1 | FileCheck %s
|
||||
.text
|
||||
nop
|
||||
.reloc foo, R_MIPS_32, .text # CHECK: :[[@LINE]]:24: error: unresolved relocation offset
|
||||
.reloc foo, R_MIPS_32, .text # CHECK: :[[@LINE]]:8: error: .reloc offset is not relative to a section
|
||||
nop
|
||||
nop
|
||||
.reloc bar, R_MIPS_32, .text # CHECK: :[[@LINE]]:24: error: unresolved relocation offset
|
||||
.reloc bar, R_MIPS_32, .text # CHECK: :[[@LINE]]:8: error: .reloc offset is not relative to a section
|
||||
nop
|
||||
|
||||
@ -58,18 +58,18 @@ bar:
|
||||
|
||||
# OBJ-N32-LABEL: Relocations [
|
||||
# OBJ-N32: 0x4 R_MIPS_NONE .text
|
||||
# OBJ-N32-NEXT: 0x1C R_MIPS_GOT_OFST .text
|
||||
# OBJ-N32-NEXT: 0x0 R_MIPS_32 .text
|
||||
# OBJ-N32-NEXT: 0xC R_MIPS_32 .text
|
||||
# OBJ-N32-NEXT: 0x10 R_MIPS_CALL16 foo
|
||||
# OBJ-N32-NEXT: 0x20 R_MIPS_GOT_DISP foo
|
||||
# OBJ-N32-NEXT: 0x24 R_MIPS_GOT_PAGE .text
|
||||
# OBJ-N32-NEXT: 0x1C R_MIPS_GOT_OFST .text
|
||||
# OBJ-N32-NEXT: 0x0 R_MIPS_32 .text
|
||||
|
||||
# OBJ-N64-LABEL: Relocations [
|
||||
# OBJ-N64: 0x4 R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE .text 0x0
|
||||
# OBJ-N64-NEXT: 0x1C R_MIPS_GOT_OFST/R_MIPS_NONE/R_MIPS_NONE .text 0x0
|
||||
# OBJ-N64-NEXT: 0x0 R_MIPS_32/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: 0x20 R_MIPS_GOT_DISP/R_MIPS_NONE/R_MIPS_NONE foo 0x0
|
||||
# OBJ-N64-NEXT: 0x24 R_MIPS_GOT_PAGE/R_MIPS_NONE/R_MIPS_NONE .text 0x0
|
||||
# OBJ-N64-NEXT: 0x1C R_MIPS_GOT_OFST/R_MIPS_NONE/R_MIPS_NONE .text 0x0
|
||||
# OBJ-N64-NEXT: 0x0 R_MIPS_32/R_MIPS_NONE/R_MIPS_NONE .text 0x0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user