【问题标题】:How to add and initialize byte[] field with Mono.Cecil如何使用 Mono.Cecil 添加和初始化 byte[] 字段
【发布时间】:2013-09-09 01:29:44
【问题描述】:

我想将byte[] 类型的字段添加到<Module> 类,并使用Mono.Cecil 将其初始化为任意字节数组。以下不起作用。

TypeDefinition moduleClass = ModuleDefinition
    .GetAllTypes()
    .Single(typedef => typedef.Name == "<Module>");

FieldDefinition myBytes = new FieldDefinition("myBytes"
    ,FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.HasFieldRVA
    ,ModuleDefinition.Import(typeof(byte[])));

myBytes.InitialValue = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

moduleClass.Fields.Add(myBytes);

这是 ILSpy 中的结果(使用“IL”视图)。

.class private auto ansi '<Module>'
{
    // Fields
    .field private static uint8[] myBytes at I_00000000

} // end of class <Module>

当我尝试执行修改后的程序集时,我收到一个 TypeLoadException 消息“Type '&lt;Module&gt;' from assembly 'TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' has a field of an非法类型。”

如果我删除 FieldAttributes.HasFieldRVA,我不会收到任何错误,但 at I_00000000 会消失,我认为这意味着该字段不会被初始化。

【问题讨论】:

    标签: .net mono.cecil


    【解决方案1】:

    对于初始化一个原始值,例如,如果您只想初始化 bytefiled.InitialValue 就完美了。我不知道为什么它在这里不起作用。也许 Jb Evain 可以说出来。

    请注意,如果您定义 s 静态字段并设置初始值,则发生的情况是您设置了 RVA,然后在静态构造函数中,该字段将使用此 RVA toekn 中存在的数据进行初始化。

    因此,为了解决这个问题,我建议您在静态构造函数中自己初始化字段,而不使用 RVA。在我的例子中,我初始化了一个 2 字节的字节数组。

    var staticConstructorAttributes = 
        Mono.Cecil.MethodAttributes.Private|
        Mono.Cecil.MethodAttributes.HideBySig |
        Mono.Cecil.MethodAttributes.SpecialName |
        Mono.Cecil.MethodAttributes.RTSpecialName |
        Mono.Cecil.MethodAttributes.Static;
    
    MethodDefinition staticConstructor = new MethodDefinition(".cctor", staticConstructorAttributes, module.TypeSystem.Void);
    type.Methods.Add(staticConstructor);
    type.IsBeforeFieldInit = false;
    var il = staticConstructor.Body.GetILProcessor();
    
    il.Emit(OpCodes.Ldc_I4_2); // if your array size is bigger than 4 you need to emit Ldc_I4_S or Ldc_I4
    il.Emit(OpCodes.Newarr, module.TypesSystem.Byte); //create a new byte array
    il.Emit(OpCodes.Stsfld, myBytesField); //store it in the myBytes static field
    il.Emit(OpCodes.Ldsfld, myBytesField); // load the field
    il.Emit(OpCodes.Ldc_I4_0); // index
    il.Emit(OpCodes.Ldc_I4_0); // value
    il.Emit(OpCodes.Stelem_I1); // store the byte value in the given index
    il.Emit(OpCodes.Ldsfld, myBytesField);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Stelem_I1);
    il.Emit(OpCodes.Ret);
    

    【讨论】:

      【解决方案2】:

      您可以为&lt;Module&gt; 类创建一个构造函数(静态)并在其中分配值。每当调用该类时,都会首先初始化构造函数,为您提供值。我个人不确定如何设置初始值,但您可以使用一些 CIL 或简单地使用导入器将字节从另一个程序集导入到您自己的程序集中。

      您可以在另一个问题中找到这样的示例:Inject Method with Mono.Cecil

      【讨论】:

      • 如果您不确定,请不要发布答案。所以其他人可能很难找到问题的答案。
      猜你喜欢
      • 1970-01-01
      • 2018-05-15
      • 1970-01-01
      • 2011-03-16
      • 2014-03-21
      • 1970-01-01
      • 2012-12-18
      • 1970-01-01
      • 2010-12-27
      相关资源
      最近更新 更多