繁体   English   中英

尝试在C#中创建基本编译器,但出现访问冲突错误

[英]Trying to create basic compiler in C#, getting Access Violation Errors

我正在尝试学习一些有关编译器的知识。 我正在使用NASM编译我的目标文件,并链接将其转换为dll。 我正在使用依赖关系遍历程序来验证我的dll的内容。 到目前为止,可以很好地在代码中编译我的dll,并且可以使用GetProcAddress检索它。 但是,当我尝试调用它时,出现以下错误:

未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存。 这通常表明其他内存已损坏。

我所做的只是将eax设置为1,而不是100%为什么会收到错误消息。 我不确定哪个内存已损坏,我可以做些什么来正确调用此dll,将不胜感激。

编辑:我在Windows x64上使用32位程序集,在工作时,我回到家时尝试使用x64程序集/汇编程序以查看其是否有效。

动态生成的程序集文件

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汇编器与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;
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM