1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[MC] Support labels as offsets in .reloc directive

Currently, expressions like

  .reloc 1f, R_MIPS_JALR, foo
  1: nop

are not allowed, ie. an offset in .reloc can only be absolute value.
This patch adds support for labels as offsets.
If offset is a forward declared label, MCObjectStreamer keeps the fixup locally
and adds it to the fixups vector after the label (and its offset) is defined.
label+number is not supported yet.

Differential revision: https://reviews.llvm.org/D53990

llvm-svn: 347397
This commit is contained in:
Vladimir Stefanovic 2018-11-21 16:28:39 +00:00
parent 880705470f
commit d431e5c490
7 changed files with 157 additions and 29 deletions

View File

@ -39,12 +39,21 @@ class MCObjectStreamer : public MCStreamer {
bool EmitEHFrame;
bool EmitDebugFrame;
SmallVector<MCSymbol *, 2> PendingLabels;
struct PendingMCFixup {
const MCSymbol *Sym;
MCFixup Fixup;
MCDataFragment *DF;
PendingMCFixup(const MCSymbol *McSym, MCDataFragment *F, MCFixup McFixup)
: Sym(McSym), Fixup(McFixup), DF(F) {}
};
SmallVector<PendingMCFixup, 2> PendingFixups;
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 resolvePendingFixups();
protected:
MCObjectStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,

View File

@ -59,6 +59,27 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
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.
void MCObjectStreamer::resolvePendingFixups() {
for (PendingMCFixup &PendingFixup : PendingFixups) {
if (!PendingFixup.Sym || PendingFixup.Sym->isUndefined ()) {
getContext().reportError(PendingFixup.Fixup.getLoc(),
"unresolved relocation offset");
continue;
}
flushPendingLabels(PendingFixup.DF, PendingFixup.DF->getContents().size());
PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset());
PendingFixup.DF->getFixups().push_back(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.
static Optional<uint64_t>
@ -603,16 +624,6 @@ void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) {
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<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name);
if (!MaybeKind.hasValue())
return true;
@ -622,10 +633,33 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
if (Expr == nullptr)
Expr =
MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext());
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<MCSymbolRefExpr>(Offset);
if (SRE.getSymbol().isDefined()) {
DF->getFixups().push_back(MCFixup::create(SRE.getSymbol().getOffset(),
Expr, Kind, Loc));
return false;
}
PendingFixups.emplace_back(&SRE.getSymbol(), DF,
MCFixup::create(-1, Expr, Kind, Loc));
return false;
}
void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
SMLoc Loc) {
MCDataFragment *DF = getOrCreateDataFragment();
@ -689,5 +723,6 @@ void MCObjectStreamer::FinishImpl() {
MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams());
flushPendingLabels();
resolvePendingFixups();
getAssembler().Finish();
}

View File

@ -2938,20 +2938,20 @@ bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {
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();

View File

@ -0,0 +1,9 @@
# RUN: not llvm-mc -triple mips-unknown-linux %s -show-encoding \
# RUN: -target-abi=o32 -filetype=obj 2>&1 | FileCheck %s
.text
nop
.reloc foo, R_MIPS_32, .text # CHECK: :[[@LINE]]:2: error: unresolved relocation offset
nop
nop
.reloc bar, R_MIPS_32, .text # CHECK: :[[@LINE]]:2: error: unresolved relocation offset
nop

View File

@ -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 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

View File

@ -0,0 +1,74 @@
# 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
.reloc 3f, R_MIPS_GOT_PAGE, foo # ASM-32: .reloc ($tmp4), R_MIPS_GOT_PAGE, foo
# ASM-64: .reloc .Ltmp4, R_MIPS_GOT_PAGE, foo
nop
bar:
2:
nop
3:
nop
.reloc bar, R_MIPS_GOT_OFST, foo # ASM: .reloc bar, R_MIPS_GOT_OFST, foo
nop
.reloc foo, R_MIPS_32, foo # ASM: .reloc foo, R_MIPS_32, foo
nop
1:
nop
# OBJ-O32-LABEL: Relocations [
# OBJ-O32: 0x0 R_MIPS_32 .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_OFST .text 0x0
# OBJ-O32-NEXT: 0x20 R_MIPS_GOT_PAGE .text 0x0
# OBJ-N32-LABEL: Relocations [
# OBJ-N32: 0x4 R_MIPS_NONE .text 0x0
# OBJ-N32-NEXT: 0x1C R_MIPS_GOT_OFST .text 0x0
# OBJ-N32-NEXT: 0x0 R_MIPS_32 .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_DISP foo 0x0
# OBJ-N32-NEXT: 0x20 R_MIPS_GOT_PAGE .text 0x0
# 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: 0x1C R_MIPS_GOT_DISP/R_MIPS_NONE/R_MIPS_NONE foo 0x0
# OBJ-N64-NEXT: 0x20 R_MIPS_GOT_PAGE/R_MIPS_NONE/R_MIPS_NONE .text 0x0

View File

@ -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