//--- // fxos.disasm-passes.cfg: Control Flow Graph construction // // This pass explores functions and computes the [jmptarget] field of concrete // instructions as it goes. This is required for other passes that work by // traversing the CFG, such as the abstract interpretor. // // This is the main exploration pass. Other passes do not typically load new // instructions from the underlying disassembly. Straightforward passes such as // [print] iterate on instructions loaded by this pass. // // The main gimmick of this pass is to "resolve delay slots" by forcing down // the properties of delayed instructions into their respective delay slots. // For instance, in // jmp @r0 // mov #1, r4 // the jump is delayed until after the move. To handle this, fxos makes the jmp // a no-op and applies dual move-jump semantics to the mov below it. // // This could be tricky for the abstract interpreter because the jump target // has to be computed with the environment before the jmp, which is not // available when considering the mov. Luckily all delayed jumps are state // no-ops so the state before the mov can be used instead. // // Note that jumping into a delay slot will activate the jump in fxos, which is // not the actual behavior of the processor. fxos usually complains about the // crazy compiler when this occurs. Note that if it happens but we don't know // that it's a delay slot (ie. the instruction from above is never executed in // the current function), then everything's fine. // // Take-home message: delay slots are a pain to analyze, so we get rid of them // as soon as possible and proceed with normal semantics. //--- #ifndef LIBFXOS_DISASM_PASSES_CFG_H #define LIBFXOS_DISASM_PASSES_CFG_H #include namespace FxOS { class CfgPass: public DisassemblyPass { public: CfgPass(Disassembly &disasm); void analyze(uint32_t pc, ConcreteInstruction &inst) override; }; } /* namespace FxOS */ #endif /* LIBFXOS_DISASM_PASSES_CFG_H */