[nnyeah] Fix for branch targets and AVMediaTypes (#15561)

* Fix for branch targets and AVMediaTypes
This commit is contained in:
Steve Hawley 2022-07-22 10:24:40 -04:00 коммит произвёл GitHub
Родитель c957b0402a
Коммит 0b872a1683
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 119 добавлений и 4 удалений

Просмотреть файл

@ -0,0 +1,50 @@
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Microsoft.MaciOS.Nnyeah {
public static class InstructionExtensions {
// The ctor for Instruction is internal and there is no clone/copy method,
// therefore we have to drill through the types.
public static Instruction Copy (this Instruction i)
{
if (i.Operand is null)
return Instruction.Create (i.OpCode);
switch (i.Operand) {
case TypeReference tr:
return Instruction.Create (i.OpCode, tr);
case CallSite cs:
return Instruction.Create (i.OpCode, cs);
case MethodReference mr:
return Instruction.Create (i.OpCode, mr);
case FieldReference fr:
return Instruction.Create (i.OpCode, fr);
case string str:
return Instruction.Create (i.OpCode, str);
case sbyte sb:
return Instruction.Create (i.OpCode, sb);
case byte b:
return Instruction.Create (i.OpCode, b);
case int it:
return Instruction.Create (i.OpCode, it);
case long lg:
return Instruction.Create (i.OpCode, lg);
case float ft:
return Instruction.Create (i.OpCode, ft);
case double db:
return Instruction.Create (i.OpCode, db);
case Instruction instr:
return Instruction.Create (i.OpCode, instr);
case Instruction [] instrArr:
return Instruction.Create (i.OpCode, instrArr);
case VariableDefinition vd:
return Instruction.Create (i.OpCode, vd);
case ParameterDefinition pd:
return Instruction.Create (i.OpCode, pd);
default: // can't happen (in theory)
throw new InvalidOperationException ();
}
}
}
}

Просмотреть файл

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Linq;
namespace Microsoft.MaciOS.Nnyeah {
public class MethodTransformations {
@ -446,6 +447,20 @@ namespace Microsoft.MaciOS.Nnyeah {
allTransforms.Add (NewFuncXform ("System.TypeCode System.nfloat::GetTypeCode()", moduleToEdit, nfloatTypeRef, typeCodeRef, "GetTypeCode"));
var getConstantRef = GetGetConstantRef (modules.MicrosoftModule, moduleToEdit);
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Video()", 0));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Audio()", 1));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Text()", 2));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_ClosedCaption()", 3));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Subtitle()", 4));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Timecode()", 5));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_TimedMetadata()", 6));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Muxed()", 7));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_MetadataObject()", 8));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_Metadata()", 9));
allTransforms.Add (AVMediaTypeTransform (getConstantRef, "Foundation.NSString AVFoundation.AVMediaType::get_DepthData()", 10));
transformTable = new Dictionary<string, Transformation> ();
foreach (var xform in allTransforms) {
@ -454,6 +469,24 @@ namespace Microsoft.MaciOS.Nnyeah {
return transformTable;
}
static Transformation AVMediaTypeTransform (MethodReference getConstantRef, string oldSignature, int constant)
{
return new Transformation (oldSignature,
TransformationAction.Replace,
new List<Instruction> () {
Instruction.Create (OpCodes.Ldc_I4, constant),
Instruction.Create (OpCodes.Call, getConstantRef),
});
}
static MethodReference GetGetConstantRef (ModuleDefinition msModule, ModuleDefinition moduleToEdit)
{
var mediaTypesExtensionsDef = msModule.GetType ("AVFoundation.AVMediaTypesExtensions");
var avMediaTypesExtensionsRef = moduleToEdit.ImportReference (mediaTypesExtensionsDef);
var getConstantDef = mediaTypesExtensionsDef.Methods.FirstOrDefault (m => m.Name == "GetConstant");
return moduleToEdit.ImportReference (getConstantDef);
}
static Transformation NewOneParamCtorXform (string oldSignature, ModuleDefinition moduleToEdit, TypeReference owningType,
TypeReference parameterType)
{

Просмотреть файл

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
namespace Microsoft.MaciOS.Nnyeah {
public class Transformation {
@ -39,33 +40,64 @@ namespace Microsoft.MaciOS.Nnyeah {
public bool TryPerformTransform (Instruction old, MethodBody body)
{
var instructionsCopy = CopyInstructions ();
var il = body.GetILProcessor ();
body.SimplifyMacros ();
switch (Action) {
case TransformationAction.Remove:
var @new = Instruction.Create (OpCodes.Nop);
il.InsertAfter (old, @new);
PatchReferences (body, old, @new);
il.Remove (old);
break;
case TransformationAction.Insert:
foreach (var instr in Instructions) {
foreach (var instr in instructionsCopy) {
il.InsertBefore (old, AddVariableIfNeeded (body, instr));
}
break;
case TransformationAction.Append:
foreach (var instr in Enumerable.Reverse (Instructions)) {
foreach (var instr in Enumerable.Reverse (instructionsCopy)) {
il.InsertAfter (old, AddVariableIfNeeded (body, instr));
}
break;
case TransformationAction.Replace:
foreach (var instr in Instructions) {
il.InsertBefore (old, AddVariableIfNeeded (body, instr));
foreach (var instr in Enumerable.Reverse (instructionsCopy)) {
il.InsertAfter (old, AddVariableIfNeeded (body, instr));
}
var newInstr = instructionsCopy [0];
PatchReferences (body, old, @newInstr);
il.Remove (old);
break;
case TransformationAction.Warn:
body.OptimizeMacros ();
return false;
}
body.OptimizeMacros ();
return true;
}
List<Instruction> CopyInstructions ()
{
var instrs = new List<Instruction> (Instructions.Count);
instrs.AddRange (Instructions.Select (i => i. Copy()));
return instrs;
}
static void PatchReferences (MethodBody body, Instruction old, Instruction @new)
{
foreach (var instruction in body.Instructions) {
if (instruction.Operand is Instruction target && target == old) {
instruction.Operand = @new;
} else if (instruction.Operand is Instruction [] targets) {
for (int i = 0; i < targets.Length; i++) {
if (targets [i] == old) {
targets [i] = @new;
}
}
}
}
}
static Instruction AddVariableIfNeeded (MethodBody body, Instruction instr)
{
if (instr.Operand is VariableDefinition variable && !body.Variables.Contains (variable))