Tag: cil

OpCodes.Castclass。 有必要吗?

当你准备调用带有类型参数的方法时,当你在堆栈顶部引用(B)的实例时,是否需要发出OpCode.CastClass(typeof(A)),其中B是类,派生自A一个? 加成: interface IFoo { void IFoo(); } public class A:IFoo { public void IFoo() { } } public class B:A,IFoo { new public void IFoo() { } } var b = new B(); (b as IFoo).Foo(); ((b as A) as IFoo).Foo();

ldstr在内部实现newobj吗?

众所周知,字符串是隐式实例化的,这意味着我们不必使用new来获取对象的对象的引用。 因此,我始终相信框架正在处理这个问题,因此如果我做了类似的事情,我会得到相同的IL: String first = new String(new char[] {‘a’}); string second = “a”; 然而,似乎第一行是使用newobj instance void [mscorlib]System.String::.ctor(char[])和第二行ldstr “a” 。 所以为了获得一个字符串引用, ldstr内部调用newobj ,在哪里可以看到规范/细节来支持它?

“操作可以使运行时不稳定”和DynamicMethod使用值类型

我试图推广以下IL(来自Reflector): .method private hidebysig instance void SetValue(valuetype Test.TestFixture/ValueSource& thing, string ‘value’) cil managed { .maxstack 8 L_0000: nop L_0001: ldarg.1 L_0002: ldarg.2 L_0003: call instance void Test.TestFixture/ValueSource::set_Value(string) L_0008: nop L_0009: ret } 但是,当我尝试使用DynamicMethod重现此IL时: [Test] public void Test_with_DynamicMethod() { var sourceType = typeof(ValueSource); PropertyInfo property = sourceType.GetProperty(“Value”); var setter = property.GetSetMethod(true); var method = new DynamicMethod(“Set” […]

Reflection.Emit.ILGeneratorexception处理“离开”指令

首先,一些背景信息: 我正在为一个学校项目编写一个编译器。 它已经在工作,我正在花费大量精力修复和/或优化它。 我最近遇到的一个问题是,当我调用以下任何成员方法时,我发现ILGenerator对象会生成一个额外的leave指令: BeginCatchBlock() BeginExceptFilterBlock() BeginFaultBlock() BeginFinallyBlock() EndExceptionBlock() 因此,您通过调用BeginExceptionBlock()启动try语句,使用BeginExceptionBlock()添加几个catch子句,可能使用BeginCatchBlock()添加finally子句,然后使用BeginFinallyBlock()结束受保护的代码区域。 我列出的方法会自动生成一条leave指令,该指令分支到try语句后的第一条指令。 出于两个原因,我不想要这些。 一,因为它总是生成一个leave.s优化的leave指令,而不是一个leave.s指令,即使它只是两个字节的分支。 第二,因为你无法控制离开指令的去向。 所以,如果你想分支到代码中的其他位置,你必须添加一个编译器生成的局部变量,根据你想要进入try语句的位置来设置它,让EndExceptionBlock()自动生成leave指令,然后在try块下面生成一个switch语句。 或者,您可以在调用之前的方法之前自己发出leave或leave.s指令,导致一个丑陋且无法访问的额外5个字节,如下所示: L_00ca: leave.s L_00e5 L_00cc: leave L_00d1 这两个选项对我来说都是不可接受的。 有没有办法阻止自动生成leave指令,或者是否有任何其他方式来指定受保护区域而不是使用这些方法(这些方法非常烦人且实际上没有记录)? 编辑注意:C#编译器本身就是这样做的,所以并不是说有充分的理由强迫它在我们身上。 例如,如果您有.NET 4.5 beta,请反汇编以下代码并检查它们的实现:(内部添加exception块) public static async Task TestAsync(int ms) { var local = ms / 1000; Console.WriteLine(“In async call, before await ” + local.ToString() + “-second delay.”); await System.Threading.Tasks.Task.Delay(ms); Console.WriteLine(“In […]

符号在MSIL中的含义是什么?

反编译后我有这个代码 SampleClass sampleClass; SampleClass g__initLocal0; int y; sampleClass = null; Label_0018: try { g__initLocal0 = new SampleClass(); g__initLocal0.X = 5; g__initLocal0.Y = 10; sampleClass = g__initLocal0; goto Label_003A; } catch (Exception) { Label_0035: goto Label_003A; } Label_003A: y = sampleClass.Y; 在某些操作之前,我不知道操作符/符号是什么意思。 有人知道吗?

如何在C#/ IL中改变盒装值类型(原语或结构)

与如何使用IL改变盒装结构相关我试图以通用方式更改盒装值类型的值,因此尝试实现以下方法: void MutateValueType(object o, T v) where T : struct 所以以下应该是可能的: var oi = (object)17; MutateValueType(oi, 43); Console.WriteLine(oi); // 43 var od = (object)17.7d; MutateValueType(od, 42.3); Console.WriteLine(od); // 42.3 我没有得到它在.NET Framework上工作(请参阅@hvd的评论,没有typeof(Program).Module适用于其他运行时)。 我已经实现了这个,如下所示。 但是,在使用以下命令调用委托del时,这会失败: System.Security.VerificationException: ‘Operation could destabilize the runtime.’ 这是我提出的实现: public static void MutateValueType(object o, T v) { var dynMtd = new DynamicMethod(“EvilMutateValueType”, typeof(void), new […]

调试器StepInto自动生成代码和JMC问题

我正在使用MDBG示例制作托管.NET调试器。 目前我正在努力解决StepInto行为,而StepOut和StepOver似乎也有效。 为了实现Just-My-Code步进,我在模块加载时调用SetJMCStatus 。 这很好,允许我调试我的代码。 但由于我将整个模块设置为JMC,因此一些自动生成的代码会起作用并破坏步入。 此类代码的示例可以是自动属性。 由于调试器正在执行Il指令,因此我将逐步进入自动生成的get_propertyName和set_propertyName方法,这些方法被标记为我的代码,因为它们是我的模块的一部分。 为了区分这些自动生成的代码和我的代码,我可以使用调试符号的存在,在自动生成的代码的情况下丢失。 然后我可以简单地将方法标记为不是我的代码,以便在步进期间跳过它。 问题是我不知道在踏入过程中进入内部之前哪些方法是自动生成的。 当我进入一个没有调试符号的方法时,我可以将它标记为不是我的代码,但是为时已晚 – 调试器停在它应该不停止的地方。 从理论上讲,我可以使用IMetadataImport迭代我的模块方法,并在调试器启动时设置它们的JMCStatus,但它似乎相当昂贵: foreach (var methodToken in mdbgModule.Importer.EnumerateAllMethodTokens()) { var func = mdbgModule.GetFunction(methodToken); if (func.SymMethod == null) func.CorFunction.JMCStatus = false; } 如果我只知道接下来要执行什么function,那么我将能够设置它的状态并防止第一次进入自动生成的代码。 我坚持使用MDBG方法进行步进,而不是改变任何东西,只需要调用SetJMCStatus,所以我不确定提供任何代码是否有意义…如果是这样,我会编辑问题,只需添加一条评论! 任何关于主题的建议都非常感谢! 问候,

内联MSIL / CIL

我创建了以下简单方法: public static void Main () { Console.WriteLine(“Hello world!”); Console.ReadKey(true); } 然后我使用ILSpy来获取MSIL代码: .method public hidebysig static void Main() cil managed { .entrypoint .maxstack 8 nop ldstr “Hello world!” call void [mscorlib]System.Console::WriteLine(string) nop ldc.i4.1 call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool) pop ret } 最后,我尝试使用我在这里找到的#if IL技巧将MSIL代码写入我的C#代码。 public static void Main () { #if IL nop ldstr “Hello world!” call […]

检查类型TA是否可以在运行时强制转换为TB? (考虑的不仅仅是inheritance)

所以我知道这有效: class A { } class B : A { } [Test] public void CanCast() { Assert.That(typeof(A).IsAssignableFrom(typeof(B))); Assert.That(!typeof(B).IsAssignableFrom(typeof(A))); } 但是,让我们说这两种类型是Int32和Int64。 在运行时,我可以将Int32值转换为Int64变量,但不是相反。 如何在运行时检查这种类型的转换兼容性? (IsAssignableFrom不适用于此,它总是为Int32和Int64提供false) 编辑:我不能简单地尝试施放,因为我没有这些类型的任何值,我问的是假设有两种类型A和B,没有两个值a和b。

.NET CIL操纵评估堆栈

我有这个CIL代码序列,我通过使用Mono.Cecil注入。 但是,修改后的.NET C#应用程序将无法运行。 目标:从堆栈中手动加载和弹出值以在Console.WriteLine显示 for (int i = 0; i < 3; i++) { int z = some value popped manually from stack; Console.WriteLine(z); } 这是我修改的简单main()程序: .method private hidebysig static void Main(string[] args) cil managed { .entrypoint .maxstack 5 .locals init ( [0] int32 num, [1] int32 num2) L_0000: ldc.i4.6 //manually push value 6 to […]