尝试在 C# 中创建基本编译器,获取访问冲突错误
Trying to create basic compiler in C#, getting Access Violation Errors
我正在尝试了解一些有关编译器的知识。我正在使用 NASM 来编译我的目标文件,并使用链接将它们转换为 dll。我正在使用 dependency walker 来验证我的 dll 的内容。到目前为止,在代码中编译我的 dll 非常好,我可以使用 GetProcAddress 检索它。但是,当我尝试调用它时出现以下错误:
Unhandled Exception: System.AccessViolationException: Attempted to
read or write protected memory. This is often an indication that other
memory is corrupt.
我所做的只是将 eax 设置为 1,所以我得到错误的原因并不是 100%。我不确定是什么内存被损坏了,如果我能提供任何帮助来正确调用这个 dll,我将不胜感激。
编辑:我在 Windows x64 上使用 32 位程序集,在工作中可能会尝试 x64 assembly/assembler,当我回到家时看看它是否有效。
动态生成程序集文件
global DllMain
export DllMain
global testfunc
export testfunc
section .code use32
DllMain: ; This code is required in .dll files
mov eax,1
ret 12
testfunc:
mov eax, 1
ret
C# 代码
namespace KCompiler
{
public static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int TestFuncDelegate();
static int Main(string[] args)
{
/*
AntlrFileStream stream = new AntlrFileStream("../../example.k");
CLexer lexer = new CLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CParser parser = new CParser(tokens);
ParseTreeWalker tree = new ParseTreeWalker();
CListener listener = new CListener();
tree.Walk(listener, parser.file());
*/
KAssembler assembler = new KAssembler();
//assembler.PushR("ebp");
//assembler.Mov32RR("ebp", "esp");
assembler.Mov32RI("eax", 1);
//assembler.PopR("ebp");
assembler.Return();
string RelativeDirectory = @"..\..";
string fullAssembly = File.ReadAllText(Path.Combine(RelativeDirectory,"k_template.asm")).Replace("{ASSEMBLY}", assembler.ToString());
Console.WriteLine(fullAssembly);
File.WriteAllText(Path.Combine(RelativeDirectory,"k.asm"), fullAssembly);
ProcessStartInfo nasmInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"nasm.exe"),
RedirectStandardOutput = true,
Arguments = @"-fobj ..\..\k.asm",
};
using (Process nasm = Process.Start(nasmInfo))
{
nasm.WaitForExit();
Console.WriteLine($"NASM exited with code: {nasm.ExitCode}");
if (nasm.ExitCode != 0) return nasm.ExitCode;
}
ProcessStartInfo alinkInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"alink.exe"),
RedirectStandardOutput = true,
Arguments = Path.Combine(RelativeDirectory,"k.obj") + " -oPE -dll",
};
using (Process alink = Process.Start(alinkInfo))
{
alink.WaitForExit();
Console.WriteLine($"alink exited with code: {alink.ExitCode}");
if (alink.ExitCode != 0) return alink.ExitCode;
}
IntPtr dll = new IntPtr(0);
try
{
dll = NativeMethods.LoadLibrary(Path.Combine(RelativeDirectory, "k.dll"));
Console.WriteLine(dll.ToInt32() == 0 ? "Unable to Load k.dll" : "Loaded k.dll");
if (dll.ToInt32() == 0) return 1;
IntPtr TestFunctionPtr = NativeMethods.GetProcAddress(dll, "testfunc");
Console.WriteLine(TestFunctionPtr.ToInt32() == 0 ? "Unable to Load 'testfunc'" : "Loaded 'testfunc'");
if (TestFunctionPtr.ToInt32() == 0) return 1;
TestFuncDelegate Test = Marshal.GetDelegateForFunctionPointer<TestFuncDelegate>(TestFunctionPtr);
int result = Test(); //Error right here
Console.WriteLine($"Test Function Returned: {result}");
}
finally
{
if(dll.ToInt32() != 0)
NativeMethods.FreeLibrary(dll);
}
return 0;
}
}
}
好的,我找到了解决方案。 alink 在将 -fwin32 格式链接到 dll 时遇到困难,因此我切换到 golink 链接器。所以现在我正在使用
NASM assembler with the golink 链接器并能够使用与以前相同的设置工作,下面提供了代码。
此外,如果您不在代码顶部放置 [bits #],NASM 默认为 16 位模式,因此必须将其切换为 32 位。如果将 64 放在那里,则必须编写 64 位程序集才能使其正常工作。
ASM 代码
[bits 32]
global DllMain
global testfunc
export DllMain
export testfunc
section .text
DllMain: ; This code is required in .dll files
mov eax,1
ret 12
testfunc:
mov eax, 32
ret
C# 代码
using System;
using Antlr4;
using System.IO;
using Antlr4.Runtime;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Tree;
using System.Collections.Generic;
using KCompiler.KCore;
using KCompiler.Assembler;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace KCompiler
{
public static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class Program
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate int TestFuncDelegate();
static int Main(string[] args)
{
/*
AntlrFileStream stream = new AntlrFileStream("../../example.k");
CLexer lexer = new CLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CParser parser = new CParser(tokens);
ParseTreeWalker tree = new ParseTreeWalker();
CListener listener = new CListener();
tree.Walk(listener, parser.file());
*/
KAssembler assembler = new KAssembler();
assembler.Mov32RI("eax", 32);
string RelativeDirectory = @"..\..";
string fullAssembly = File.ReadAllText(Path.Combine(RelativeDirectory,"k_template.asm")).Replace("{ASSEMBLY}", assembler.ToString());
Console.WriteLine(fullAssembly);
File.WriteAllText(Path.Combine(RelativeDirectory,"k.asm"), fullAssembly);
ProcessStartInfo nasmInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"nasm.exe"),
RedirectStandardOutput = true,
Arguments = @"-fwin32 "+ Path.Combine(RelativeDirectory,"k.asm")
};
using (Process nasm = Process.Start(nasmInfo))
{
nasm.WaitForExit();
Console.WriteLine($"NASM exited with code: {nasm.ExitCode}");
if (nasm.ExitCode != 0) return nasm.ExitCode;
}
ProcessStartInfo golinkInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"GoLink.exe"),
RedirectStandardOutput = true,
//Arguments = Path.Combine(RelativeDirectory,"k.obj") + " -c -oPE -dll -subsys windows",
Arguments = Path.Combine(RelativeDirectory, "k.obj") + " /dll",
};
using (Process golink = Process.Start(golinkInfo))
{
golink.WaitForExit();
Console.WriteLine($"alink exited with code: {golink.ExitCode}");
if (golink.ExitCode != 0) return golink.ExitCode;
}
IntPtr dll = new IntPtr(0);
try
{
dll = NativeMethods.LoadLibrary(Path.Combine(RelativeDirectory, "k.dll"));
Console.WriteLine(dll.ToInt32() == 0 ? "Unable to Load k.dll" : "Loaded k.dll");
if (dll.ToInt32() == 0) return 1;
IntPtr TestFunctionPtr = NativeMethods.GetProcAddress(dll, "testfunc");
Console.WriteLine(TestFunctionPtr.ToInt32() == 0 ? "Unable to Load 'testfunc'" : "Loaded 'testfunc'");
if (TestFunctionPtr.ToInt32() == 0) return 1;
TestFuncDelegate Test = Marshal.GetDelegateForFunctionPointer<TestFuncDelegate>(TestFunctionPtr);
int result = Test();
Console.WriteLine($"Test Function Returned: {result}");
}
finally
{
if(dll.ToInt32() != 0)
NativeMethods.FreeLibrary(dll);
}
return 0;
}
}
}
我正在尝试了解一些有关编译器的知识。我正在使用 NASM 来编译我的目标文件,并使用链接将它们转换为 dll。我正在使用 dependency walker 来验证我的 dll 的内容。到目前为止,在代码中编译我的 dll 非常好,我可以使用 GetProcAddress 检索它。但是,当我尝试调用它时出现以下错误:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
我所做的只是将 eax 设置为 1,所以我得到错误的原因并不是 100%。我不确定是什么内存被损坏了,如果我能提供任何帮助来正确调用这个 dll,我将不胜感激。
编辑:我在 Windows x64 上使用 32 位程序集,在工作中可能会尝试 x64 assembly/assembler,当我回到家时看看它是否有效。
动态生成程序集文件
global DllMain
export DllMain
global testfunc
export testfunc
section .code use32
DllMain: ; This code is required in .dll files
mov eax,1
ret 12
testfunc:
mov eax, 1
ret
C# 代码
namespace KCompiler
{
public static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int TestFuncDelegate();
static int Main(string[] args)
{
/*
AntlrFileStream stream = new AntlrFileStream("../../example.k");
CLexer lexer = new CLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CParser parser = new CParser(tokens);
ParseTreeWalker tree = new ParseTreeWalker();
CListener listener = new CListener();
tree.Walk(listener, parser.file());
*/
KAssembler assembler = new KAssembler();
//assembler.PushR("ebp");
//assembler.Mov32RR("ebp", "esp");
assembler.Mov32RI("eax", 1);
//assembler.PopR("ebp");
assembler.Return();
string RelativeDirectory = @"..\..";
string fullAssembly = File.ReadAllText(Path.Combine(RelativeDirectory,"k_template.asm")).Replace("{ASSEMBLY}", assembler.ToString());
Console.WriteLine(fullAssembly);
File.WriteAllText(Path.Combine(RelativeDirectory,"k.asm"), fullAssembly);
ProcessStartInfo nasmInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"nasm.exe"),
RedirectStandardOutput = true,
Arguments = @"-fobj ..\..\k.asm",
};
using (Process nasm = Process.Start(nasmInfo))
{
nasm.WaitForExit();
Console.WriteLine($"NASM exited with code: {nasm.ExitCode}");
if (nasm.ExitCode != 0) return nasm.ExitCode;
}
ProcessStartInfo alinkInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"alink.exe"),
RedirectStandardOutput = true,
Arguments = Path.Combine(RelativeDirectory,"k.obj") + " -oPE -dll",
};
using (Process alink = Process.Start(alinkInfo))
{
alink.WaitForExit();
Console.WriteLine($"alink exited with code: {alink.ExitCode}");
if (alink.ExitCode != 0) return alink.ExitCode;
}
IntPtr dll = new IntPtr(0);
try
{
dll = NativeMethods.LoadLibrary(Path.Combine(RelativeDirectory, "k.dll"));
Console.WriteLine(dll.ToInt32() == 0 ? "Unable to Load k.dll" : "Loaded k.dll");
if (dll.ToInt32() == 0) return 1;
IntPtr TestFunctionPtr = NativeMethods.GetProcAddress(dll, "testfunc");
Console.WriteLine(TestFunctionPtr.ToInt32() == 0 ? "Unable to Load 'testfunc'" : "Loaded 'testfunc'");
if (TestFunctionPtr.ToInt32() == 0) return 1;
TestFuncDelegate Test = Marshal.GetDelegateForFunctionPointer<TestFuncDelegate>(TestFunctionPtr);
int result = Test(); //Error right here
Console.WriteLine($"Test Function Returned: {result}");
}
finally
{
if(dll.ToInt32() != 0)
NativeMethods.FreeLibrary(dll);
}
return 0;
}
}
}
好的,我找到了解决方案。 alink 在将 -fwin32 格式链接到 dll 时遇到困难,因此我切换到 golink 链接器。所以现在我正在使用 NASM assembler with the golink 链接器并能够使用与以前相同的设置工作,下面提供了代码。
此外,如果您不在代码顶部放置 [bits #],NASM 默认为 16 位模式,因此必须将其切换为 32 位。如果将 64 放在那里,则必须编写 64 位程序集才能使其正常工作。
ASM 代码
[bits 32]
global DllMain
global testfunc
export DllMain
export testfunc
section .text
DllMain: ; This code is required in .dll files
mov eax,1
ret 12
testfunc:
mov eax, 32
ret
C# 代码
using System;
using Antlr4;
using System.IO;
using Antlr4.Runtime;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Tree;
using System.Collections.Generic;
using KCompiler.KCore;
using KCompiler.Assembler;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace KCompiler
{
public static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class Program
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate int TestFuncDelegate();
static int Main(string[] args)
{
/*
AntlrFileStream stream = new AntlrFileStream("../../example.k");
CLexer lexer = new CLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CParser parser = new CParser(tokens);
ParseTreeWalker tree = new ParseTreeWalker();
CListener listener = new CListener();
tree.Walk(listener, parser.file());
*/
KAssembler assembler = new KAssembler();
assembler.Mov32RI("eax", 32);
string RelativeDirectory = @"..\..";
string fullAssembly = File.ReadAllText(Path.Combine(RelativeDirectory,"k_template.asm")).Replace("{ASSEMBLY}", assembler.ToString());
Console.WriteLine(fullAssembly);
File.WriteAllText(Path.Combine(RelativeDirectory,"k.asm"), fullAssembly);
ProcessStartInfo nasmInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"nasm.exe"),
RedirectStandardOutput = true,
Arguments = @"-fwin32 "+ Path.Combine(RelativeDirectory,"k.asm")
};
using (Process nasm = Process.Start(nasmInfo))
{
nasm.WaitForExit();
Console.WriteLine($"NASM exited with code: {nasm.ExitCode}");
if (nasm.ExitCode != 0) return nasm.ExitCode;
}
ProcessStartInfo golinkInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = Path.Combine(RelativeDirectory,"GoLink.exe"),
RedirectStandardOutput = true,
//Arguments = Path.Combine(RelativeDirectory,"k.obj") + " -c -oPE -dll -subsys windows",
Arguments = Path.Combine(RelativeDirectory, "k.obj") + " /dll",
};
using (Process golink = Process.Start(golinkInfo))
{
golink.WaitForExit();
Console.WriteLine($"alink exited with code: {golink.ExitCode}");
if (golink.ExitCode != 0) return golink.ExitCode;
}
IntPtr dll = new IntPtr(0);
try
{
dll = NativeMethods.LoadLibrary(Path.Combine(RelativeDirectory, "k.dll"));
Console.WriteLine(dll.ToInt32() == 0 ? "Unable to Load k.dll" : "Loaded k.dll");
if (dll.ToInt32() == 0) return 1;
IntPtr TestFunctionPtr = NativeMethods.GetProcAddress(dll, "testfunc");
Console.WriteLine(TestFunctionPtr.ToInt32() == 0 ? "Unable to Load 'testfunc'" : "Loaded 'testfunc'");
if (TestFunctionPtr.ToInt32() == 0) return 1;
TestFuncDelegate Test = Marshal.GetDelegateForFunctionPointer<TestFuncDelegate>(TestFunctionPtr);
int result = Test();
Console.WriteLine($"Test Function Returned: {result}");
}
finally
{
if(dll.ToInt32() != 0)
NativeMethods.FreeLibrary(dll);
}
return 0;
}
}
}