Easy to use, extremely fast Runtime Assembler.
uint8_t* x64as(x64 code, size_t len, uint32_t* outlen);
#### Assembles and soft links code, dealing with `$riprel` and `rel()` syntax and returning the assembled code.
- Returns NULL if an error occured, retrieved with `x64error()`.
- Validates `code`, `len` and `outlen` for NULL pointers or 0s, ensuring your errors don't cause mayhem too!
- The length of the assembled code is stored in `outlen`.
- Internally allocates returned code, freed with `free()`.
- If you happen to input more than a billion instructions into this function, the internal linking is performed using 32 bit integers holding instruction boundaries, so watch out for x64 internal overflows.
### uint32_t x64emit(const x64Ins* ins, uint8_t* opcode_dest);
#### Assembles a single instruction and stores it in `opcode_dest`.
- Returns the length of the instruction in bytes. If it returns 0, an error has occurred.
- `opcode_dest` needs to be a buffer of at least 15 bytes to accomodate any/all x86 instructions.
- This function does not perform any linking, so in the case of there being no relative references in your code, it's slightly (10% max) faster to loop with this function than to use `x64as()`.
### void (*x64exec(void* mem, uint32_t size))();
#### Uses a Syscall to allocate memory with the EXecute bit set, so you can execute your code.
- Returns a function pointer to the code, which you can call to run your code.
- Free this memory with `x64exec_free()`.
### void x64exec_free(void* mem, uint32_t size);
#### Frees memory allocated by `x64exec()`.
> [!note]
> Store the size of the memory you requested with `x64exec()` as you will need to pass it in here, at least for Unix.
### char* x64stringify(const x64 p, uint32_t num);
#### Stringifies the IR. Useful for debugging and inspecting it.
- Returns a string, NULL if an error occurred which will be accessible with `x64error()`.
- Returned string uses Intel ASM Syntax, like `mov [rax + rdx * 2], 20`. Multiple instructions are preceeded with a tab.
### char* x64error(int* errcode);
#### Gets the error message of the last error that occured.
- Returns a string with a description of the error.
- If `errcode` is not NULL, it will be set to the error code.
Limitations
-----------
- No support for 32 bit legacy / protected mode instructions.
- Does not play well with Windows headers.
- No support for AVX-512.
- Trying to change this, maybe with syntax like `ymm(10, k1, z)`.
- No support for architectures other than x86-64 (like ARM).
- Labels, as they are extremely difficult to implement in a sane manner and take up too much memory.
If people seem to need support for any of these limitations, I will try my best to add them! In my personal use, I haven't needed them so I haven't gone through the effort.
I have tried very hard to add labels, and nothing seems to be elegant. I'm open to it if someone can draft a good plan for it! My goal is to support it fully without limiting strings to string literals only, if I were to support it at all. You can still see remnants of previous attempts in [`asm_x64.c`](asm_x64.c).
Also, support for other instruction sets will come when I get to them, and I when get some good tables that give me the exact information I need! I currently use a modified table from [StanfordPL/x64asm](https://github.com/StanfordPL/x64asm). Their table has some incorrect instructions, so I wouldn't suggest using that one for your own projects.
License
-------
Chasm is dual licensed under the MIT Licence and Public Domain. You can choose the licence that suits your project the best. The MIT Licence is a permissive licence that is short and to the point. The Public Domain licence is a licence that makes the software available to the public for free and with no copyright.
FAQ
---
### Why the name **chasm**?
> A chasm is a deep ravine or hole formed through millenia of erosion and natural processes. This name struck a chord in my heart, as I have been working on this library for over a year, and it's the best way I know of getting low and deep into the heart of computing. I also loved that it had "asm" and "c" in it, which are big parts of what this library is about.
### This library doesn't fit me. What are some others?
> - [asmjit/asmjit](https://github.com/asmjit/asmjit) - A popular choice for C++ developers and many times more complex and feature rich than chasm.
> - [aengelke/fadec](https://github.com/aengelke/fadec) - Similar library to chasm but a completely different API that might be more flexible but harder for some.
> - [bitdefender/bddisasm](https://github.com/bitdefender/bddisasm) - Fast, easy to use Disassembler library.
> - [garc0/CTAsm](https://github.com/garc0/CTAsm) - Compile time assembler for C++ using only templates.
### Where did you get the idea to make something like this?
> The first time I saw a library like this was when I found https://github.com/StanfordPL/x64asm. I loved the idea, but I couldn't use their library from C or Windows, so I took the liberty to redesign some of their library. I use their table to generate my own table in [`asm_x64.c`](asm_x64.c) and while I haven't used any of their code, I did take inspiration from how they did instruction operands.
### Where is the full source for all scripts and tests shown?
> All source is in [aqilc/rustscript](https://github.com/aqilc/rustscript/tree/main/lib/asm). Tests testing all the features and operands are [here](https://github.com/aqilc/rustscript/blob/main/tests/asm.c).