CodeGenerator takes two pointers. The first pointer is the memory address to write to, and the second pointer is the memory address that the code will be executing from. This allows you to write to a buffer before copying to the final destination for execution, or to have to use dual-mapped memory blocks to avoid memory protection overhead.
Below is an example of using the oaknut-provided utility header for dual-mapped memory blocks:
If you wish to merely emit code into memory without executing it, or if you are developing a cross-compiler that is not running on an ARM64 device, you can use `oaknut::VectorCodeGenerator` instead.
Provide `oaknut::VectorCodeGenerator` with a reference to a `std::vector<std::uint32_t>` and it will append to that vector.
The second pointer argument represents the destination address the code will eventually be executed from.
| `<oaknut/oaknut.hpp>` | Yes | Provides `CodeGenerator` and `VectorCodeGenerator` for code emission, as well as the `oaknut::util` namespace. |
| `<oaknut/code_block.hpp>` | No | Utility header that provides `CodeBlock`, allocates, alters permissions of, and invalidates executable memory. |
| `<oaknut/dual_code_block.hpp>` | No | Utility header that provides `DualCodeBlock`, which allocates two mirrored memory blocks (with RW and RX permissions respectively). |
| `<oaknut/oaknut_exception.hpp>` | Yes | Provides `OaknutException` which is thrown on an error. |
| `<oaknut/feature_detection/cpu_feature.hpp>` | Yes | Utility header that provides `CpuFeatures` which can be used to describe AArch64 features. |
| `<oaknut/feature_detection/feature_detection.hpp>` | No | Utility header that provides `detect_features` and `read_id_registers` for determining available AArch64 features. |
This library also includes utility headers for CPU feature detection.
One just needs to include `<oaknut/feature_detection/feature_detection.hpp>`, then call `detect_features` to get a bitset of features in a cross-platform manner.
CPU feature detection is operating system specific, and some operating systems even have multiple methods. Here are a list of supported operating systems and implemented methods:
| Operating system | Default Method |
| ---- | ---- |
| Linux / Android | [ELF hwcaps](https://www.kernel.org/doc/html/latest/arch/arm64/elf_hwcaps.html) |
| Apple | [sysctlbyname](https://developer.apple.com/documentation/kernel/1387446-sysctlbyname) |
| Windows | [IsProcessorFeaturePresent](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent) |
| FreeBSD | ELF hwcaps |
| NetBSD | machdep.cpu%d.cpu_id sysctl |
| OpenBSD | CTL_MACHDEP.CPU_ID_* sysctl |
There are alternative methods available for advanced users to specify specific methods to detect features if they wish. (See `detect_features_via_*`.)
We also provide a crossplatform way for ID registers to be read:
| **`OAKNUT_SUPPORTS_READING_ID_REGISTERS`** | Available functionality |
| ---- | ---- |
| 0 | Reading ID registers is not supported on this operating system. |
| 1 | This operating system provides a system-wide set of ID registers, use `read_id_registers()`. |
| 2 | Per-core ID registers, use `get_core_count()` and `read_id_registers(int index)`. |
All of the above operating systems with the exception of apple also support reading ID registers, and if one prefers one can do feature detection via `detect_features_via_id_registers(*read_id_registers())`.