/// <summary> /// Make a function signature based on use and def information. /// </summary> /// <param name="ssa"></param> /// <param name="uses"></param> /// <param name="definitions"></param> /// <returns></returns> public FunctionType MakeSignature(SsaState ssa, IEnumerable <CallBinding> uses, IEnumerable <CallBinding> definitions) { var implicitRegs = platform.CreateImplicitArgumentRegisters(); var arch = ssa.Procedure.Architecture; var frame = arch.CreateFrame(); var sb = new SignatureBuilder(frame, arch); var seqs = uses.Select(u => u.Storage as SequenceStorage) .Where(s => s != null) .OrderBy(s => s.Name); foreach (var seq in seqs) { sb.AddSequenceArgument(seq); } //$TODO: sort these by some ABI order? var regs = uses.Select(u => u.Storage as RegisterStorage) .Where(r => r != null && !implicitRegs.Contains(r)) .OrderBy(r => r.Number); foreach (var reg in regs) { sb.AddRegisterArgument(reg); } var stargs = uses.Select(u => u.Storage as StackStorage) .Where(s => s != null) .OrderBy(r => r.StackOffset); foreach (var arg in stargs) { var id = frame.EnsureIdentifier(arg); sb.AddInParam(id); } var outs = definitions.Select(d => d.Storage) .OfType <RegisterStorage>() .Where(r => !implicitRegs.Contains(r)) .OrderBy(r => r.Number); foreach (var o in outs) { var id = frame.EnsureIdentifier(o); sb.AddOutParam(id); } var sig = sb.BuildSignature(); return(sig); }
/// <summary> /// Make a function signature based on the procedure flow <paramref name="flow"/>. /// </summary> /// <returns>A valid function signature.</returns> public FunctionType MakeSignature(SsaState ssa, IStorageBinder frame, ProcedureFlow flow) { var allLiveOut = flow.BitsLiveOut; var sb = new SignatureBuilder(frame, platform.Architecture); var implicitRegs = platform.CreateImplicitArgumentRegisters(); var liveOutFlagGroups = flow.grfLiveOut.Select(de => platform.Architecture.GetFlagGroup(de.Key, de.Value) !); AddModifiedFlags(frame, liveOutFlagGroups, sb); var mayUseSeqs = flow.BitsUsed.Keys.OfType <SequenceStorage>().ToHashSet(); var seqRegs = mayUseSeqs.SelectMany(s => s.Elements).Distinct().ToHashSet(); //$BUG: should be sorted by ABI register order. foreach (var seq in mayUseSeqs.OrderBy(r => r.Name)) { sb.AddSequenceArgument(seq); } var mayUseRegs = flow.BitsUsed .Select(de => (Key: de.Key as RegisterStorage, de.Value)) .Where(b => { return(b.Key is RegisterStorage reg && !implicitRegs.Contains(reg)); }) .Select(MakeRegisterParameter) .ToDictionary(de => de.Item1, de => de.Item2); //$BUG: should be sorted by ABI register order. Need a new method // IPlatform.CreateAbiRegisterCollator(). foreach (var reg in mayUseRegs.OrderBy(r => r.Key.Number)) { if (!IsSubRegisterOfRegisters(reg.Key, mayUseRegs) && !seqRegs.Contains(reg.Key)) { sb.AddRegisterArgument(reg.Key); } } foreach (var id in GetSortedStackArguments((Frame)frame, flow.BitsUsed)) { sb.AddInParam(id.Item2); } foreach (var oFpu in flow.BitsUsed .Where(f => f.Key is FpuStackStorage) .OrderBy(r => ((FpuStackStorage)r.Key).FpuStackOffset)) { var fpu = (FpuStackStorage)oFpu.Key; var id = frame.EnsureFpuStackVariable(fpu.FpuStackOffset, fpu.DataType); sb.AddFpuStackArgument(fpu.FpuStackOffset, id); } var liveOut = allLiveOut .Select(de => (Key: de.Key as RegisterStorage, de.Value)) .Where(de => { return(de.Key != null && !implicitRegs.Contains(de.Key)); }) .Select(MakeRegisterParameter) .ToDictionary(de => de.Item1, de => de.Item2); // Sort the names in a stable way to avoid regression tests failing. foreach (var r in liveOut.OrderBy(r => r.Key.Number).ThenBy(r => r.Key.BitAddress)) { if (!IsSubRegisterOfRegisters(r.Key, liveOut)) { var regOut = sb.AddOutParam(frame.EnsureRegister(r.Key)); if (regOut.Storage is OutArgumentStorage && !ssa.Identifiers.TryGetValue(regOut, out var sidOut)) { // Ensure there are SSA identifiers for 'out' registers. ssa.Identifiers.Add(regOut, null, null, false); } } } foreach (var fpu in allLiveOut.Keys.OfType <FpuStackStorage>().OrderBy(r => r.FpuStackOffset)) { sb.AddOutParam(frame.EnsureFpuStackVariable(fpu.FpuStackOffset, fpu.DataType)); } var sig = sb.BuildSignature(); return(sig); }