Skip to content
Merged

Next #16

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9ad13e1
Created RISC-V language module
magistermaks May 7, 2026
4fbecd9
Added basic Risc-V encodings
magistermaks May 7, 2026
2b5b473
Added some basic Risc-V instructions
magistermaks May 14, 2026
81616df
Finish R64 load/stores
magistermaks May 15, 2026
052ffc4
Add Risc-V branch instructions
magistermaks May 18, 2026
19faf0d
Add Risc-V jump instructions
magistermaks May 18, 2026
9e35e23
Add Risc-V LUI instruction
magistermaks May 19, 2026
03dfeb5
Add RV32M extension instructions
magistermaks May 19, 2026
aee1e29
Finish RV64M extension
magistermaks May 20, 2026
ed5dad8
Flexible condition encoding in branaches
magistermaks May 20, 2026
a5d96ae
Added RV32I aliases
magistermaks May 20, 2026
8134fd6
Register name alises
magistermaks May 20, 2026
39a6d6e
Add RV64A extension instructions
magistermaks May 23, 2026
d4e8520
Test on RiscV (QEMU on Linux)
magistermaks May 24, 2026
3fcf12a
Allow RiscV target architecture
magistermaks May 24, 2026
3970c37
Add USE_MOLD CMake option
magistermaks May 24, 2026
f5829fb
Runtime RiscV test
magistermaks May 24, 2026
671b602
Use uraimo/run-on-arch-action GHA
magistermaks Jun 9, 2026
3f13582
Merge pull request #15 from dark-tree/riscv
magistermaks Jun 13, 2026
6d65122
Condition code cleanup
magistermaks Aug 13, 2026
27cddd5
Add Docker setup for Risc-V
magistermaks Aug 14, 2026
9b6ee2f
Risc-V 64 bit immediate encoder
magistermaks Aug 14, 2026
250049b
Update VSTL, add Risc-V mov fuzzer
magistermaks Aug 14, 2026
a02114d
Update VSTL
magistermaks Aug 16, 2026
d4c86ee
Split util functions into separate files
magistermaks Aug 16, 2026
558e8c2
Clenaup x86 Locations
magistermaks Aug 20, 2026
c98f040
Allow taking the buffer from ExecutableBuffer
magistermaks Aug 20, 2026
e102ac2
New function trait system
magistermaks Aug 20, 2026
84181e9
Linkage cleanup and new Risc-V types
magistermaks Aug 21, 2026
f94d6dd
Add AUIPC Risc-v instruction
magistermaks Aug 21, 2026
9289e34
Test external calls on AArch64
magistermaks Aug 21, 2026
0dba262
Add axon function utilities
magistermaks Aug 21, 2026
3ffbedc
Minor axon cleanup
magistermaks Aug 30, 2026
3254b43
Minor changes around linkages
magistermaks Sep 1, 2026
25ee00c
Add SegmentedBuffer merging support
magistermaks Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
name: ci.yml

on:
push:
branches: ['master', 'next']
pull_request:
types: [ opened, synchronize, reopened ]
branches: ['master', 'next']

on: [ push, pull_request ]
jobs:
linux-x86:
runs-on: ubuntu-latest
Expand All @@ -27,6 +21,26 @@ jobs:
- name: Test x86
run: cd build && ./test

linux-qemu-riscv:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v3
name: Run commands
with:
arch: riscv64
distro: ubuntu24.04
shell: /bin/sh

install: |
apt-get update
apt-get install -y cmake g++ git python3

run: |
cmake -B build
cmake --build build
cd build && ./test

linux-aarch64:
runs-on: ubuntu-24.04-arm
steps:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
cmake-build-*
cmake-build-*
docker-build-*
28 changes: 17 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.31)
cmake_minimum_required(VERSION 2.28...3.31)
project(ASMIOV C CXX)
include(FetchContent)

Expand All @@ -7,31 +7,36 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Python3 COMPONENTS Interpreter)

option(USE_MOLD "Use mold linker if installed" ON)

# Use the mold linker automatically for GCC if available,
# as it is faster, more modern, and produces better errors.
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
find_program(MOLD_PROGRAM mold)

if (MOLD_PROGRAM)
message(STATUS "The MOLD linker was found: ${MOLD_PROGRAM}")
set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=mold")
set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=mold")
else()
message(STATUS "The MOLD linker was NOT found!")
if (USE_MOLD)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
find_program(MOLD_PROGRAM mold)

if (MOLD_PROGRAM)
message(STATUS "The MOLD linker was found: ${MOLD_PROGRAM}")
set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=mold")
set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=mold")
else()
message(STATUS "The MOLD linker was NOT found!")
endif()
endif()
endif()

FetchContent_Declare(
vstl
GIT_REPOSITORY https://github.com/magistermaks/lib-vstl
GIT_TAG c7f1069ea12fbe8087067841c491940fc3f6dc7f
GIT_TAG v3.5
)

FetchContent_MakeAvailable(vstl)

set(ASMIO_WRITERS
src/asmio/x86/writer.hpp
src/asmio/aarch64/writer.hpp
src/asmio/riscv/writer.hpp
)

set(ASMIO_BRIDGES "${ASMIO_WRITERS}")
Expand Down Expand Up @@ -68,6 +73,7 @@ add_executable(test
test/x86.cpp
test/aarch64.cpp
test/elf.cpp
test/riscv.cpp
)
target_link_libraries(test PRIVATE asmiov)
target_include_directories(test PRIVATE ${ASMIOV_INCLUDE_DIRS})
Expand Down
33 changes: 22 additions & 11 deletions src/asmio/aarch64/argument/condition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,35 @@
namespace asmio::arm {

enum struct Condition : uint8_t {
EQ = 0b0000, NE = 0b0001,
CS = 0b0010, CC = 0b0011,
MI = 0b0100, PL = 0b0101,
VS = 0b0110, VC = 0b0111,
HI = 0b1000, LS = 0b1001,
GE = 0b1010, LT = 0b1011,
GT = 0b1100, LE = 0b1101,
EQ = 0b0000, // equal
NE = 0b0001, // not equal
CS = 0b0010, // carry set
CC = 0b0011, // carry clear
MI = 0b0100, // minus
PL = 0b0101, // plus
VS = 0b0110, // overflow set
VC = 0b0111, // overflow clear
HI = 0b1000, // higher
LS = 0b1001, // lower or same
GE = 0b1010, // greater or equal
LT = 0b1011, // less than
GT = 0b1100, // greater than
LE = 0b1101, // less or equal
AL = 0b1110, // always
NV = 0b1111, // never, unused and treated the same as AL

// the NV condition code is unused and treated the same as AL
AL = 0b1110, NV = 0b1111,
GEU = CC, // greater or equal unsigned
LTU = CS, // less than unsigned
GTU = HI, // greater than unsigned
LEU = LS, // less or equal unsigned
};

/**
* Invert the condition as if it had been negated,
* always true condition can't be inverted as AArch64 dropped support for the 'never' condition code.
* the always true condition can't be inverted as there is no functional 'never' condition code.
*/
constexpr Condition invert(Condition condition) {
if (condition == Condition::AL) throw std::runtime_error {"The 'always' condition can't be inverted, as there is no 'never' condition!"};
if (condition == Condition::AL) throw std::runtime_error {"The 'always' condition can't be inverted, as there is no functional 'never' condition!"};
return static_cast<Condition>(static_cast<uint32_t>(condition) ^ 1);
}

Expand Down
63 changes: 32 additions & 31 deletions src/asmio/aarch64/argument/registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,39 +55,40 @@ namespace asmio::arm {
constexpr Registry SP {QWORD, 31, Registry::STACK};
constexpr Registry LR = X(30);
constexpr Registry FP = X(29);
constexpr Registry XR = X(8);

// general purpose QWORD registers
constexpr Registry X0 = X(0);
constexpr Registry X1 = X(1);
constexpr Registry X2 = X(2);
constexpr Registry X3 = X(3);
constexpr Registry X4 = X(4);
constexpr Registry X5 = X(5);
constexpr Registry X6 = X(6);
constexpr Registry X7 = X(7);
constexpr Registry X8 = X(8);
constexpr Registry X9 = X(9);
constexpr Registry X10 = X(10);
constexpr Registry X11 = X(11);
constexpr Registry X12 = X(12);
constexpr Registry X13 = X(13);
constexpr Registry X14 = X(14);
constexpr Registry X15 = X(15);
constexpr Registry X16 = X(16);
constexpr Registry X17 = X(17);
constexpr Registry X18 = X(18);
constexpr Registry X19 = X(19);
constexpr Registry X20 = X(20);
constexpr Registry X21 = X(21);
constexpr Registry X22 = X(22);
constexpr Registry X23 = X(23);
constexpr Registry X24 = X(24);
constexpr Registry X25 = X(25);
constexpr Registry X26 = X(26);
constexpr Registry X27 = X(27);
constexpr Registry X28 = X(28);
constexpr Registry X29 = X(29);
constexpr Registry X30 = X(30);
constexpr Registry X0 = X(0); // argument register
constexpr Registry X1 = X(1); // argument register
constexpr Registry X2 = X(2); // argument register
constexpr Registry X3 = X(3); // argument register
constexpr Registry X4 = X(4); // argument register
constexpr Registry X5 = X(5); // argument register
constexpr Registry X6 = X(6); // argument register
constexpr Registry X7 = X(7); // argument register
constexpr Registry X8 = X(8); // indirect return value pointer
constexpr Registry X9 = X(9); // temporary register
constexpr Registry X10 = X(10); // temporary register
constexpr Registry X11 = X(11); // temporary register
constexpr Registry X12 = X(12); // temporary register
constexpr Registry X13 = X(13); // temporary register
constexpr Registry X14 = X(14); // temporary register
constexpr Registry X15 = X(15); // temporary register
constexpr Registry X16 = X(16); // temporatry intra-procedure-call register
constexpr Registry X17 = X(17); // temporatry intra-procedure-call register
constexpr Registry X18 = X(18); // platform register
constexpr Registry X19 = X(19); // calee saved register
constexpr Registry X20 = X(20); // calee saved register
constexpr Registry X21 = X(21); // calee saved register
constexpr Registry X22 = X(22); // calee saved register
constexpr Registry X23 = X(23); // calee saved register
constexpr Registry X24 = X(24); // calee saved register
constexpr Registry X25 = X(25); // calee saved register
constexpr Registry X26 = X(26); // calee saved register
constexpr Registry X27 = X(27); // calee saved register
constexpr Registry X28 = X(28); // calee saved register
constexpr Registry X29 = X(29); // frame pointer
constexpr Registry X30 = X(30); // procedure link register

// general purpose DWARD registers
constexpr Registry W0 = W(0);
Expand Down
2 changes: 1 addition & 1 deletion src/asmio/elf/dwarf/abbrev.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace asmio {
}

void DwarfAbbrevHeader::rehash(const DwarfFormatedAttributeEntry* attribute_array) {
hash = util::hash_djb2(reinterpret_cast<const char*>(attribute_array), size);
hash = util::djb2(reinterpret_cast<const char*>(attribute_array), size);
hash ^= (static_cast<int>(tag) * 31) ^ (children * 109);
}

Expand Down
2 changes: 1 addition & 1 deletion src/asmio/elf/dwarf/abbrev.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include <cstdint>
#include <unordered_set>
#include <asmio/util.hpp>
#include <asmio/util/hash.hpp>
#include <asmio/util/macro.hpp>
#include <asmio/util/chunk.hpp>
#include <asmio/util/codecs.hpp>
Expand Down
2 changes: 1 addition & 1 deletion src/asmio/elf/export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ namespace asmio {
for (auto& linkage : symbols) {
auto mapping = section_map[linkage.target.section];
ElfModel::Symbol* symbol = model.symbol(mapping.content, linkage.label.view(), ElfSymbolBinding::GLOBAL, ElfSymbolVisibility::DEFAULT, nullptr, 0, 0);
model.relocation(linkage.type.relocation, symbol, mapping.section, linkage.target.offset, linkage.addend);
model.relocation(linkage.type->relocation, symbol, mapping.section, linkage.target.offset, linkage.addend);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/asmio/elf/header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ namespace asmio {
#if ARCH_X86
NATIVE = X86_64,
#endif

#if ARCH_RISCV64
NATIVE = RISCV,
#endif
};

enum struct ElfClass : uint8_t {
Expand Down
1 change: 1 addition & 0 deletions src/asmio/elf/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "object.hpp"

#include <filesystem>
#include <unistd.h>
#include <asmio/util/platform.hpp>

namespace asmio {
Expand Down
29 changes: 28 additions & 1 deletion src/asmio/external.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,33 @@
# define ARCH_AARCH64 false
#endif

#if !(ARCH_X86 || ARCH_AARCH64)
#if defined(__riscv)
# if (__riscv_xlen == 64)
# define ARCH_RISCV64 true
# else
# define ARCH_RISCV64 false
# endif
#else
# define ARCH_RISCV64 false
#endif

// platforms
#if defined(_WIN32)
# define PLATFORM_WINDOWS true
#else
# define PLATFORM_WINDOWS false
#endif

#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
# define PLATFORM_UNIX true
#else
# define PLATFORM_UNIX false
#endif

#if !(ARCH_X86 || ARCH_AARCH64 || ARCH_RISCV64)
# error "Unsupported target architecture!"
#endif

#if !(PLATFORM_WINDOWS || PLATFORM_UNIX)
# error "Unsupported target platform!"
#endif
21 changes: 18 additions & 3 deletions src/asmio/program/executable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "executable.hpp"

#include <asmio/util/platform.hpp>
#include <asmio/util.hpp>

namespace asmio {

Expand All @@ -25,6 +26,10 @@ namespace asmio {

}

ExecutableBuffer::ExecutableBuffer(uint8_t* buffer, size_t length) noexcept
: buffer(buffer), length(length) {
}

ExecutableBuffer::ExecutableBuffer(ExecutableBuffer&& other) noexcept {
labels = std::move(other.labels);

Expand Down Expand Up @@ -85,8 +90,18 @@ namespace asmio {
return buffer;
}

uint8_t* ExecutableBuffer::address(Label label) const {
return buffer + labels.at(label);
uint8_t* ExecutableBuffer::own() {
uint8_t* ptr = buffer;
buffer = nullptr;
return ptr;
}

uint8_t* ExecutableBuffer::address(const Label& label) const {
return buffer + offset(label);
}

uint64_t ExecutableBuffer::offset(const Label& label) const {
return labels.at(label);
}

size_t ExecutableBuffer::size() const {
Expand All @@ -106,7 +121,7 @@ namespace asmio {
ExecutableBuffer buffer {segmented.total()};

// now that we have a buffer allocated we can link
segmented.link((uint64_t) buffer.address());
segmented.link(reinterpret_cast<uint64_t>(buffer.address()));

// finally copy data and setting to the final image
buffer.bake(segmented);
Expand Down
9 changes: 8 additions & 1 deletion src/asmio/program/executable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace asmio {

ExecutableBuffer() = default;
explicit ExecutableBuffer(size_t total);
explicit ExecutableBuffer(uint8_t* buffer, size_t length) noexcept;

ExecutableBuffer(ExecutableBuffer&& other) noexcept;
explicit ExecutableBuffer(const ExecutableBuffer& other);
Expand All @@ -55,8 +56,14 @@ namespace asmio {
/// Get the base address of this buffer
uint8_t* address() const;

/// Take ownership of the underlying buffer, delete it with free_pages(uint8_t*, size_t)
uint8_t* own();

/// Get the address of a specific label
uint8_t* address(Label label) const;
uint8_t* address(const Label& label) const;

/// Get the offset of a specific label
uint64_t offset(const Label& label) const;

/// get the total size, in bytes
size_t size() const;
Expand Down
Loading
Loading