public void Spbp_SpaceOnStack() { var m = new SsaProcedureBuilder(nameof(Spbp_SpaceOnStack)); var fp = m.Ssa.Identifiers.Add(m.Frame.FramePointer, null, null, false).Identifier; Given_StackPointer(m); var sp_1 = m.Reg("sp_1", sp); var sp_2 = m.Reg("sp_2", sp); var sp_3 = m.Reg("sp_3", sp); var sp_4 = m.Reg("sp_4", sp); var sp_5 = m.Reg("sp_5", sp); var sp_6 = m.Reg("sp_6", sp); var sp_7 = m.Reg("sp_7", sp); var sp_8 = m.Reg("sp_8", sp); var a = m.Reg("a", new RegisterStorage("a", 1, 0, PrimitiveType.Word32)); var b = m.Reg("b", new RegisterStorage("b", 2, 0, PrimitiveType.Word32)); var a_1 = m.Reg("a_1", (RegisterStorage)a.Storage); var b_1 = m.Reg("b_1", (RegisterStorage)b.Storage); m.AddDefToEntryBlock(fp); m.Assign(sp_2, m.ISub(fp, 4)); // space for a m.MStore(sp_2, a); m.Assign(sp_3, m.ISub(fp, 4)); // space for b m.MStore(sp_3, b); m.Assign(sp_4, m.ISub(fp, 40)); // 40 bytes of stack space m.MStore(sp_4, m.Word32(0xDEADBABE)); m.Call(m.Mem32(m.Word32(0x00123400)), 4, new[] { sp_4 }, new[] { sp_5 }); m.Assign(sp_6, m.IAdd(sp_5, 40)); m.Assign(b_1, m.Mem32(sp_6)); m.Assign(sp_7, m.IAdd(sp_6, 4)); m.Assign(a_1, m.Mem32(sp_7)); m.Assign(sp_8, m.IAdd(sp_7, 4)); m.Return(); m.AddUseToExitBlock(sp_8); RunTest(m.Ssa); var sExp = #region Expected @"Spbp_SpaceOnStack_entry: def fp l1: sp_2 = fp - 0x00000004 Mem13[sp_2:word32] = a sp_3 = fp - 0x00000004 Mem14[sp_3:word32] = b sp_4 = fp - 0x00000028 Mem15[sp_4:word32] = 0xDEADBABE call Mem16[0x00123400:word32] (retsize: 4;) uses: sp:sp_4 sp_5 = fp - 48 sp_6 = fp - 8 b_1 = Mem17[sp_6:word32] sp_7 = fp - 4 a_1 = Mem18[sp_7:word32] sp_8 = fp return Spbp_SpaceOnStack_exit: use sp_8 "; #endregion this.AssertStringsEqual(sExp, m.Ssa); }
public void VpReusedRegistersAtCall() { var sExp = #region Expected @"r2_1: orig: r2 def: r2_1 = Mem4[0x220200<32>:word32] uses: r4_1 = r2_1 callee(r2_1) r2_2: orig: r2 def: r2_2 = callee r4_1: orig: r4 def: r4_1 = r2_1 r25_1: orig: r25 def: r25_1 = callee Mem4: orig: Mem0 uses: r2_1 = Mem4[0x220200<32>:word32] Mem5: orig: Mem0 // SsaProcedureBuilder // Return size: 0 define SsaProcedureBuilder SsaProcedureBuilder_entry: // succ: l1 l1: r2_1 = Mem4[0x220200<32>:word32] r4_1 = r2_1 r2_2 = callee r25_1 = callee callee(r2_1) return // succ: SsaProcedureBuilder_exit SsaProcedureBuilder_exit: "; #endregion var uAddrGotSlot = m.Word32(0x0040000); var reg2 = new RegisterStorage("r2", 2, 0, PrimitiveType.Word32); var reg4 = new RegisterStorage("r4", 4, 0, PrimitiveType.Word32); var reg25 = new RegisterStorage("r25", 25, 0, PrimitiveType.Word32); var r2_1 = m.Reg("r2_1", reg2); var r2_2 = m.Reg("r2_2", reg2); var r4_1 = m.Reg("r4_1", reg4); var r25_1 = m.Reg("r25_1", reg25); m.Assign(r2_1, m.Mem32(m.Word32(0x0220200))); // fetch a string pointer perhaps m.Assign(r4_1, r2_1); m.Assign(r2_2, m.Mem32(uAddrGotSlot)); // pointer to a function in a lookup table. m.Assign(r25_1, r2_2); var stmCall = m.Call(r25_1, 0, new Identifier[] { r4_1, r2_2 }, new Identifier[] { }); m.Return(); // Initially we don't know what r2_2 is pointing to. var vp = new ValuePropagator(segmentMap, m.Ssa, program.CallGraph, dynamicLinker.Object, listener); vp.Transform(); // Later, Reko discovers information about the pointer in 0x400000<32>! var sigCallee = FunctionType.Action( new Identifier("r4", PrimitiveType.Word64, reg4)); var callee = new ProcedureConstant( PrimitiveType.Ptr32, new ExternalProcedure("callee", sigCallee)); // Add our new found knowledge to the import resolver. dynamicLinker.Setup(i => i.ResolveToImportedValue( It.IsNotNull <Statement>(), uAddrGotSlot)). Returns(callee); // Run Value propagation again with the newly gathered information. vp.Transform(); m.Ssa.Validate(s => Assert.Fail(s)); AssertStringsEqual(sExp, m.Ssa); }
public void Spbp_TwoExits() { var m = new SsaProcedureBuilder(nameof(Spbp_TwoExits)); Given_FramePointer(m); Given_StackPointer(m); var sp_1 = m.Reg("sp_1", m.Architecture.StackRegister); var sp_2 = m.Reg("sp_2", m.Architecture.StackRegister); var sp_3 = m.Reg("sp_3", m.Architecture.StackRegister); var sp_4 = m.Reg("sp_4", m.Architecture.StackRegister); var sp_5 = m.Reg("sp_5", m.Architecture.StackRegister); var sp_6 = m.Reg("sp_6", m.Architecture.StackRegister); m.AddDefToEntryBlock(fp); m.Assign(sp_1, m.ISub(fp, m.Int32(4))); m.BranchIf(m.Eq0(m.Mem32(m.Word32(0x1))), "m_eq0"); m.Label("m_ne0"); // Indirect call = hell node m.Call(m.Mem32(m.Word32(0x4)), 4, new[] { sp_1 }, new[] { sp_2 }); m.Assign(sp_3, m.IAdd(sp_2, m.Int32(4))); m.Return(); m.Label("m_eq0"); // Indirect call = hell node m.Call(m.Mem32(m.Word32(0x8)), 4, new[] { sp_1 }, new[] { sp_4 }); m.Assign(sp_5, m.IAdd(sp_4, m.Int32(4))); m.Return(); m.AddPhiToExitBlock(sp_6, (sp_3, "m_ne0"), (sp_5, "m_eq0")); m.AddUseToExitBlock(sp_6); RunTest(m.Ssa); var sExp = #region Expected @"Spbp_TwoExits_entry: def fp l1: sp_1 = fp - 4 branch Mem7[0x00000001:word32] == 0x00000000 m_eq0 goto m_ne0 m_eq0: call Mem9[0x00000008:word32] (retsize: 4;) uses: sp:sp_1 sp_4 = fp - 4 sp_5 = fp return m_ne0: call Mem8[0x00000004:word32] (retsize: 4;) uses: sp:sp_1 sp_2 = fp - 4 sp_3 = fp return Spbp_TwoExits_exit: sp_6 = PHI((sp_3, m_ne0), (sp_5, m_eq0)) use sp_6 "; #endregion AssertStringsEqual(sExp, m.Ssa); }