1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[objdump][ARM] Use correct offset when printing ARM/Thumb branch targets

llvm-objdump only uses one MCInstrAnalysis object, so if ARM and Thumb
code is mixed in one object, or if an object is disassembled without
explicitly setting the triple to match the ISA used, then branch and
call targets will be printed incorrectly.

This could be fixed by creating two MCInstrAnalysis objects in
llvm-objdump, like we currently do for SubtargetInfo. However, I don't
think there's any reason we need two separate sub-classes of
MCInstrAnalysis, so instead these can be merged into one, and the ISA
determined by checking the opcode of the instruction.

Differential revision: https://reviews.llvm.org/D97766
This commit is contained in:
Oliver Stannard 2021-03-02 13:49:14 +00:00
parent 064cc1a22c
commit 16f3f9f883
3 changed files with 90 additions and 50 deletions

View File

@ -2619,6 +2619,7 @@ def BXJ : ABI<0b0001, (outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func",
let Inst{7-4} = 0b0010;
let Inst{3-0} = func;
let isBranch = 1;
let isIndirectBranch = 1;
}
// Tail calls.

View File

@ -408,54 +408,28 @@ public:
return MCInstrAnalysis::isConditionalBranch(Inst);
}
bool evaluateBranch(const MCInst &Inst, uint64_t Addr,
uint64_t Size, uint64_t &Target) const override {
// We only handle PCRel branches for now.
if (Inst.getNumOperands() == 0 ||
Info->get(Inst.getOpcode()).OpInfo[0].OperandType !=
MCOI::OPERAND_PCREL)
return false;
int64_t Imm = Inst.getOperand(0).getImm();
Target = Addr+Imm+8; // In ARM mode the PC is always off by 8 bytes.
return true;
}
};
class ThumbMCInstrAnalysis : public ARMMCInstrAnalysis {
public:
ThumbMCInstrAnalysis(const MCInstrInfo *Info) : ARMMCInstrAnalysis(Info) {}
bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size,
uint64_t &Target) const override {
unsigned OpId;
switch (Inst.getOpcode()) {
default:
OpId = 0;
if (Inst.getNumOperands() == 0)
return false;
break;
case ARM::MVE_WLSTP_8:
case ARM::MVE_WLSTP_16:
case ARM::MVE_WLSTP_32:
case ARM::MVE_WLSTP_64:
case ARM::t2WLS:
case ARM::MVE_LETP:
case ARM::t2LEUpdate:
OpId = 2;
break;
case ARM::t2LE:
OpId = 1;
break;
}
const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
// We only handle PCRel branches for now.
if (Info->get(Inst.getOpcode()).OpInfo[OpId].OperandType !=
MCOI::OPERAND_PCREL)
// Find the PC-relative immediate operand in the instruction.
bool FoundImm = false;
int64_t Imm;
for (unsigned OpNum = 0; OpNum < Desc.getNumOperands(); ++OpNum) {
if (Inst.getOperand(OpNum).isImm() &&
Desc.OpInfo[OpNum].OperandType == MCOI::OPERAND_PCREL) {
Imm = Inst.getOperand(OpNum).getImm();
FoundImm = true;
}
}
if (!FoundImm)
return false;
// In Thumb mode the PC is always off by 4 bytes.
Target = Addr + Inst.getOperand(OpId).getImm() + 4;
// For ARM instructions the PC offset is 8 bytes, for Thumb instructions it
// is 4 bytes.
uint64_t Offset = ((Desc.TSFlags & ARMII::FormMask) == ARMII::ThumbFrm) ? 4 : 8;
Target = Addr + Imm + Offset;
return true;
}
};
@ -466,10 +440,6 @@ static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) {
return new ARMMCInstrAnalysis(Info);
}
static MCInstrAnalysis *createThumbMCInstrAnalysis(const MCInstrInfo *Info) {
return new ThumbMCInstrAnalysis(Info);
}
bool ARM::isCDECoproc(size_t Coproc, const MCSubtargetInfo &STI) {
// Unfortunately we don't have ARMTargetInfo in the disassembler, so we have
// to rely on feature bits.
@ -517,10 +487,9 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARMTargetMC() {
}
// Register the MC instruction analyzer.
for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget()})
for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget(),
&getTheThumbLETarget(), &getTheThumbBETarget()})
TargetRegistry::RegisterMCInstrAnalysis(*T, createARMMCInstrAnalysis);
for (Target *T : {&getTheThumbLETarget(), &getTheThumbBETarget()})
TargetRegistry::RegisterMCInstrAnalysis(*T, createThumbMCInstrAnalysis);
for (Target *T : {&getTheARMLETarget(), &getTheThumbLETarget()}) {
TargetRegistry::RegisterMCCodeEmitter(*T, createARMLEMCCodeEmitter);

View File

@ -0,0 +1,70 @@
@ RUN: llvm-mc < %s --triple=armv8a -mattr=+mve,+lob -filetype=obj | llvm-objdump -dr - --triple armv8a --mattr=+mve,+lob --no-show-raw-insn | FileCheck %s
@ RUN: llvm-mc < %s --triple=thumbv8a -mattr=+mve,+lob -filetype=obj | llvm-objdump -dr - --triple armv8a --mattr=+mve,+lob --no-show-raw-insn | FileCheck %s
foo:
// Branches
.arm
b foo
ble foo
@ CHECK: 0: b #-8 <foo>
@ CHECK: 4: ble #-12 <foo>
.thumb
b foo
b.w foo
ble foo
ble.w foo
le foo
le lr, foo
cbz r0, bar
cbnz r0, bar
@ CHECK: 8: b #-12 <foo>
@ CHECK: a: b.w #-14 <foo>
@ CHECK: e: ble #-18 <foo>
@ CHECK: 10: ble.w #-20 <foo>
@ CHECK: 14: le #-24 <foo>
@ CHECK: 18: le lr, #-28 <foo>
@ CHECK: 1c: cbz r0, #40 <bar>
@ CHECK: 1e: cbnz r0, #38 <bar>
// Calls without relocations (these offsets al correspond to label foo).
.arm
bl #-40
blx #-44
bleq #-48
@ CHECK: 20: bl #-40 <foo>
@ CHECK: 24: blx #-44 <foo>
@ CHECK: 28: bleq #-48 <foo>
.thumb
bl #-48
blx #-52
@ CHECK: 2c: bl #-48 <foo>
@ CHECK: 30: blx #-52 <foo>
// Calls with relocations. These currently emit a reference to their own
// location, because we don't take relocations into account when printing
// branch targets.
.arm
bl baz
blx baz
bleq baz
@ CHECK: 34: bl #-8 <$a.4>
@ CHECK: 00000034: R_ARM_CALL baz
@ CHECK: 38: blx #-8 <$a.4+0x4>
@ CHECK: 00000038: R_ARM_CALL baz
@ CHECK: 3c: bleq #-8 <$a.4+0x8>
@ CHECK: 0000003c: R_ARM_JUMP24 baz
.thumb
bl baz
blx baz
@ CHECK: 40: bl #-4 <$t.5>
@ CHECK: 00000040: R_ARM_THM_CALL baz
@ CHECK: 44: blx #-4 <$t.5+0x4>
@ CHECK: 00000044: R_ARM_THM_CALL baz
bar: