1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System;
9 using System.Runtime.InteropServices;
10 using Antmicro.Renode.Exceptions;
11 
12 namespace Antmicro.Renode.Peripherals.CPU.Assembler
13 {
14     public class LLVMAssembler : IAssembler
15     {
LLVMAssembler(ICPU cpu)16         public LLVMAssembler(ICPU cpu)
17         {
18             if(!LLVMArchitectureMapping.IsSupported(cpu))
19             {
20                 throw new ArgumentOutOfRangeException(nameof(cpu));
21             }
22             this.cpu = cpu;
23         }
24 
AssembleBlock(ulong pc, string code, uint flags)25         public byte[] AssembleBlock(ulong pc, string code, uint flags)
26         {
27             LLVMArchitectureMapping.GetTripleAndModelKey(cpu, flags, out var triple, out var model);
28             // We need to initialize the architecture to be used before trying to assemble.
29             // It's OK and cheap to initialize it multiple times, as this only sets a few pointers.
30             init_llvm_architecture(triple);
31             bool ok;
32             IntPtr output;
33             IntPtr outLen;
34             try
35             {
36                 ok = llvm_asm(triple, model, flags, code, pc, out output, out outLen);
37             }
38             catch(EntryPointNotFoundException e)
39             {
40                 throw new RecoverableException("Old version of libllvm-disas is in use, assembly is not available: ", e);
41             }
42             if(!ok)
43             {
44                 var error = Marshal.PtrToStringAnsi(output);
45                 llvm_free_asm_result(output);
46                 throw new RecoverableException(string.Format("Failed to assemble. Reason: {0}", error));
47             }
48 
49             var result = new byte[(int)outLen];
50             Marshal.Copy(output, result, 0, (int)outLen);
51             llvm_free_asm_result(output);
52             return result;
53         }
54 
55         private readonly ICPU cpu;
56 
57         [DllImport("libllvm-disas")]
init_llvm_architecture(string triple)58         private static extern IntPtr init_llvm_architecture(string triple);
59 
60         [DllImport("libllvm-disas")]
llvm_asm(string arch, string cpu, uint flags, string instructions, ulong addr, out IntPtr output, out IntPtr outLen)61         private static extern bool llvm_asm(string arch, string cpu, uint flags, string instructions, ulong addr, out IntPtr output, out IntPtr outLen);
62 
63         [DllImport("libllvm-disas")]
llvm_free_asm_result(IntPtr result)64         private static extern void llvm_free_asm_result(IntPtr result);
65     }
66 }
67