fxos/lib/passes/pcrel.cpp

76 lines
1.8 KiB
C++

//---
// fxos.passes.pcrel: Resolution of PC-relative addresses
//---
#include <fxos/disasm-passes/pcrel.h>
namespace FxOS {
PcrelPass::PcrelPass(Disassembly &disasm):
InstructionDisassemblyPass(disasm, "pcrel")
{
}
bool PcrelPass::analyze(uint32_t pc, ConcreteInstruction &ci)
{
Instruction const *i = ci.inst;
if(!i)
return false;
for(size_t n = 0; n < i->arg_count; n++)
{
Argument const &a = i->args[n];
ConcreteInstructionArg &ca = ci.args[n];
if(a.kind == Argument::PcRel &&
(i->opsize == 2 || i->opsize == 4))
{
uint32_t addr = (pc & ~(a.opsize - 1)) + 4 + a.disp;
ca.location = RelConstDomain().constant(addr);
/* Also compute the value. This is sign-extended from 16-bit with
mov.w. There is no mov.b for this instruction. */
VirtualSpace &space = m_disasm.space();
uint32_t v = -1;
if(i->opsize == 2 && v.covers(addr, 2))
{
v = space.read_i16(addr);
ca.value = DataValue(IntegerType::u32);
ca.value.write(0, 4, v);
}
if(i->opsize == 4 && v.covers(addr, 4))
{
v = space.read_i32(addr);
ca.value = DataValue(IntegerType::u32);
ca.value.write(0, 4, v);
}
}
else if(a.kind == Argument::PcJump)
{
uint32_t addr = pc + 4 + a.disp;
ca.location = RelConstDomain().constant(addr);
ca.value = DataValue(IntegerType::u32);
ca.value.write(0, 4, addr);
}
else if(a.kind == Argument::PcAddr
&& m_disasm.passes.count("cfg"))
{
uint32_t addr = (pc & ~3) + 4 + a.disp;
/* SH3 manual says that the semantics of mova change in a delay
slot. GNU as says they don't. */
// if(ci.delayslot) addr = (ci.jmptarget&~3) + 4 + a.disp;
ca.location = RelConstDomain().constant(addr);
ca.value = DataValue(IntegerType::u32);
ca.value.write(0, 4, addr);
}
}
return true;
}
} /* namespace FxOS */