以下示例程序是我试图掌握ldvirtftn操作码的用法.您会看到名称表明这是在将虚函数指针加载到堆栈时使用的操作码.在示例代码中,我正在创建一个具有2个静态方法的类型,Ldftn并且Ldvirtftn这两个方法都返回Base.Method()第一个函数的开放委托Ldftn使用ldftn操作码,并且意外地工作,就像Base.Method虚拟一样.第二种方法使用Ldvirtftn并显然创建了一个无效的程序.我究竟做错了什么?除了混淆之外,这个操作码的目的是什么?
public class Base
{
public virtual void Method()
{
Console.WriteLine("Base");
}
}
public class Child : Base
{
public override void Method()
{
Console.WriteLine("Child");
}
}
class Program
{
static void Main(string[] args)
{
AssemblyBuilder ab =AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"),AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule("TestModule");
TypeBuilder tb = mb.DefineType("TestType");
MethodBuilder method = tb.DefineMethod("Ldftn",MethodAttributes.Public | MethodAttributes.Static, typeof(Action<Base>), Type.EmptyTypes);
var ilgen = method.GetILGenerator();
ilgen.Emit(OpCodes.Ldnull);
ilgen.Emit(OpCodes.Ldftn, typeof(Base).GetMethod("Method"));
ilgen.Emit(OpCodes.Newobj, typeof(Action<Base>).GetConstructors()[0]); …Run Code Online (Sandbox Code Playgroud) 如何按名称获取MethodReference到基类的方法?
我试过了
type.BaseType.Resolve().Methods;
Run Code Online (Sandbox Code Playgroud)
如果我将包含基类的dll添加到assemblyresolver,它将返回方法.但是,如果我使用添加呼叫
MSILWorker.Create(OpCodes.Call, baseMethod);
Run Code Online (Sandbox Code Playgroud)
(通过从解析的TypeDefinition中预处理方法找到baseMethod),生成的IL不可读,甚至Reflector冻结并退出.
现在有些IL:
如果在类型上调用私有方法:
call instance void SomeNamespace.MyClass::RaisePropertyChanged(string)
Run Code Online (Sandbox Code Playgroud)
如果在基类型上调用protected方法:
call instance void [OtherAssembly]BaseNamespace.BaseClass::RaisePropertyChanged(string)
Run Code Online (Sandbox Code Playgroud)
那么,我如何使用Mono.Cecil生成后者呢?
我在命令行上使用MSBuild在构建服务器上的C#项目的嵌入资源有问题.在Visual Studio中构建和运行测试时,该项目工作得很好,但是当从命令行运行MSBuild时,运行测试时会出现以下问题:
System.Resources.MissingManifestResourceException:找不到适合指定文化或中性文化的任何资源.确保".Properties.Resources.resources"在编译时正确嵌入或链接到程序集"",或者所有所需的附属程序集都是可加载和完全签名的.
System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture,Boolean)中的System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo文化,Dictionary`2 localResourceSets,Boolean tryParents,Boolean createIfNotExists,StackCrawlMark和stackMark)中的System.Resources.ManifestBasedResourceGroveler.HandleResourceStreamMissing(String fileName)位于System.Resources.get_SomeResource()的System.Resources.ResourceManager.GetString(String name,CultureInfo culture)的System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture,Boolean createIfNotExists,Boolean tryParents)中的createIfNotExists,Boolean tryParents,StackCrawlMark和stackMark\Properties\Resources.Designer.cs:第87行
我已将问题跟踪到生成的IL(我使用ildasm).在Visual Studio中进行扩展时,在程序集的清单中设置以下内容:
.mresource public <PROJECTNAME>.Properties.Resources.resources
{
// Offset: 0x00000000 Length: 0x00000236
}
Run Code Online (Sandbox Code Playgroud)
但是在使用MSBuild构建时会生成以下输出:
.mresource public '../..//Build/<PROJECTNAME>_AnyCPU_Debug_Obj/<PROJECTNAME>.Properties.Resources.resources'
{
// Offset: 0x00000000 Length: 0x00000236
}
Run Code Online (Sandbox Code Playgroud)
因为可以看到资源的路径突然成为资源名称的一部分.
有没有人有任何想法如何解决这个问题?
我在F#中编写了一些小的字符串解析函数 - 以便更好地了解F#并了解如何使用它来解决此类任务.我尝试遍历字符串并通过递归搜索特定字符.
逻辑确实有效,但在我看来,生成的版本构建的IL代码(启用了优化)确实看起来很奇怪.所以我想有更好的方法在F#中以高效的方式编写这些东西.
这是解析函数的一部分:
let eatTag (input : string) index =
let len = input.Length
let nothing = 0, null, TagType.Open
// more functions used in the same way
// ...
let rec findName i =
if i >= len then nothing
else
let chr = input.[i]
if isWhitespace chr then
findName (i+1)
elif chr = '/' then
getName (i+1) (i+1) true
else getName (i+1) i false
let rec findStart i =
if i >= len then nothing
elif …Run Code Online (Sandbox Code Playgroud) 还有在一些CIL加载指令,例如ldc.i4.0,ldc.i4.1,ldc.i4.2,ldc.i4.3 ...
我在想,是不是可以使用ldc.i4 1,而不是ldc.i4.1或ldc.i4 5代替ldc.i4.5?
我目前正在浏览反编译的C#IL(使用ILSpy),以便了解如何System.Runtime.InteropServices(可能)实现某些方法.当我想检查如何Marshal.Copy()实现时,我发现它只调用CopyToNative(),其定义如下:
// System.Runtime.InteropServices.Marshal
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void CopyToNative(object source, int startIndex, IntPtr destination, int length);
Run Code Online (Sandbox Code Playgroud)
它在哪里实施?有没有机会查看它(反编译)的源代码?如果没有,有没有人知道如何实施?
我有两种情况:
static void CreateCopyOfString()
{
string s = "Hello";
ProcessString(s);
}
Run Code Online (Sandbox Code Playgroud)
和
static void DoNotCreateCopyOfString()
{
ProcessString("Hello");
}
Run Code Online (Sandbox Code Playgroud)
这两种情况的IL看起来像这样:
.method private hidebysig static void CreateCopyOfString() cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init ([0] string s)
IL_0000: nop
IL_0001: ldstr "Hello"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call void ConsoleApplication1.Program::ProcessString(string)
IL_000d: nop
IL_000e: ret
} // end of method Program::CreateCopyOfString
Run Code Online (Sandbox Code Playgroud)
和
.method private hidebysig static void DoNotCreateCopyOfString() cil managed
{
// Code size 13 (0xd)
.maxstack 8 …Run Code Online (Sandbox Code Playgroud) 我在定义以下界面的应用程序中有一个程序集:
public void Method1()
Run Code Online (Sandbox Code Playgroud)
然后我有一个实现此接口的程序集插件.它在运行时被发现并加载.
后来我修改了界面以包含一个新方法:
public void Method1()
public void Method2()
Run Code Online (Sandbox Code Playgroud)
我创建了一个新的程序集插件,实现了新版本的界面.
有没有办法在应用程序上只部署新接口和新插件?目前客户端永远不会在第一个插件上调用Method2(),因此它不应该是一个问题(如果在第一个插件上调用Method2的话,我可以抛出异常).
我以为我能做到,但我得到一个TypeLoadException说法:
程序集'Provider2,Version2.0.0.0,Culture = neutral,PublicKeyToken = null'中的类型'Provider2.Class2'中的方法'Method2'没有实现.
(这是真的但是因为没有调用Method2应该不是问题)
我们遇到.NET应用程序的问题.它在关闭时随机产生本机访问冲突(因此不是.NET异常).
来自Windows事件日志的错误报告看起来像这样(省略了应用程序和模块名称,我从德语翻译了条目):
Exceptioncode: 0xc0000005
Offset: 0x00006a9e
Process ID: 0xfe8
...
Run Code Online (Sandbox Code Playgroud)
我发现0xc0000005是一种访问冲突.由于.NET NullReferenceException,也可能发生这种情况.当Windows错误报告对话框打开时,我们已经使用ProcDump标志-ma 创建了一个完整的内存转储.
当我打开这个转储时,除了.exe文件本身之外,我找不到任何加载的.NET模块.我不是本地编程方面的专家,只知道一些关于WinDbg的基础知识.
所以我做了什么:
使用设置符号路径
.sympath SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols;C:\PathToMatchingPDBs\ForTheProgram
Run Code Online (Sandbox Code Playgroud)重新加载所有符号
.reload /d /f
Reloading current modules
...*** ERROR: Symbol file could not be found. Defaulted to export symbols for sysfer.dll -
...
Run Code Online (Sandbox Code Playgroud)~* k 输出
. 0 Id: 1560.19a4 Suspend: 0 Teb: ff20e000 Unfrozen
ChildEBP RetAddr
0058f0e8 7744c752 ntdll!ZwWaitForMultipleObjects+0xc
0058f26c 76d256c0 KERNELBASE!WaitForMultipleObjectsEx+0x10b
0058f2e0 76d2586a kernel32!WerpReportFaultInternal+0x1c4
0058f2f4 …Run Code Online (Sandbox Code Playgroud)我有以下代码,基本上创建一个DynamicAssembly有两种类型,每种类型都有一个公共方法.
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly
(new AssemblyName("TestAssembly"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("Main");
var type1 = module.DefineType("type1");
var method1 = type1.DefineMethod
(
"Method1", MethodAttributes.Public, typeof(void), null
);
var gen = method1.GetILGenerator();
gen.Emit(OpCodes.Ret);
var t1 = type1.CreateType();
var createdMethod1 = t1.GetMethod("Method1");
var type2 = module.DefineType("type2");
var method2 = type2.DefineMethod
(
"Method2", MethodAttributes.Public, typeof(void), null
);
byte[] ilCodes = new byte[5];
ilCodes[0] = (byte)OpCodes.Jmp.Value;
ilCodes[1] = (byte)(createdMethod1.MetadataToken & 0xFF);
ilCodes[2] = (byte)(createdMethod1.MetadataToken >> 8 & 0xFF);
ilCodes[3] = (byte)(createdMethod1.MetadataToken >> 16 & 0xFF); …Run Code Online (Sandbox Code Playgroud) il ×10
c# ×7
.net ×5
cil ×2
assemblies ×1
clr ×1
f# ×1
inheritance ×1
interface ×1
interop ×1
memory-dump ×1
mono.cecil ×1
msbuild ×1
native ×1
parsing ×1
performance ×1
string ×1
windbg ×1