Skip to content

Commit

Permalink
Merge pull request #143 from zyantific/api-update
Browse files Browse the repository at this point in the history
Update
  • Loading branch information
ZehMatt authored Sep 20, 2024
2 parents 87f86ee + d0ee331 commit 8de41a6
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 39 deletions.
22 changes: 17 additions & 5 deletions examples/decode_to_assembler/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ int main()
using namespace zasm;

const uint64_t baseAddr = 0x00007FF6BC738ED4;
const std::array<uint8_t, 24> code = {
const std::array<uint8_t, 48> code = {
0x40, 0x53, // push rbx
0x45, 0x8B, 0x18, // mov r11d, dword ptr ds:[r8]
0x48, 0x8B, 0xDA, // mov rbx, rdx
0x41, 0x83, 0xE3, 0xF8, // and r11d, 0xFFFFFFF8
0x4C, 0x8B, 0xC9, // mov r9, rcx
0x41, 0xF6, 0x00, 0x04, // test byte ptr ds:[r8], 0x4
0x4C, 0x8B, 0xD1, // mov r10, rcx
0x74, 0x13, // je 0x00007FF6BC738EFF
0x40, 0x53, // push rbx
0x45, 0x8B, 0x18, // mov r11d, dword ptr ds:[r8]
0x48, 0x8B, 0xDA, // mov rbx, rdx
Expand Down Expand Up @@ -37,15 +45,19 @@ int main()
return EXIT_FAILURE;
}

const auto& instrInfo = *decoderRes;

const auto instr = instrInfo.getInstruction();
const auto& instr = decoderRes.value();
if (auto res = assembler.emit(instr); res != zasm::ErrorCode::None)
{
std::cout << "Failed to emit instruction " << std::hex << curAddress << ", " << res.getErrorName() << "\n";
}

bytesDecoded += instrInfo.getLength();
bytesDecoded += instr.getLength();

if (x86::isBranching(instr))
{
// Decode only a single branch.
break;
}
}

Serializer serializer;
Expand Down
124 changes: 106 additions & 18 deletions zasm/include/zasm/base/instruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,60 @@

namespace zasm
{
/// <summary>
/// Base type for Instruction and InstructionDetail, not to be used directly.
/// </summary>
template<typename TBase, std::size_t TMaxOperands> class InstructionBase
class Instruction;
class InstructionDetail;

namespace detail
{
template<typename T, typename = void> struct IsInstructionType : std::false_type
{
};

template<typename T> struct IsInstructionType<T, std::void_t<decltype(T::kInstrType)>> : std::true_type
{
};
} // namespace detail

class InstructionBase
{
public:
using Length = std::uint8_t;
using Mnemonic = InstrMnemonic;
using Attribs = InstrAttribs;
using Category = InstrCategory;

using OperandCount = std::uint8_t;
using Operands = std::array<Operand, TMaxOperands>;

enum class Type : uint8_t
{
Signanture,
Detail,
};

protected:
Attribs _attribs{};
OperandCount _opCount{};
Mnemonic _mnemonic{};
Operands _operands{};
Type _type{};

protected:
constexpr InstructionBase() = default;
constexpr InstructionBase(Attribs attribs, Mnemonic mnemonic, OperandCount opCount, const Operands& ops) noexcept
: _attribs{ attribs }
constexpr InstructionBase(Type type, Attribs attribs, Mnemonic mnemonic, OperandCount opCount) noexcept
: _type{ type }
, _attribs{ attribs }
, _opCount{ opCount }
, _mnemonic{ mnemonic }
, _operands{ ops }
{
}

public:
constexpr bool operator==(const InstructionBase& other) const
{
return _attribs == other._attribs && _mnemonic == other._mnemonic && _opCount == other._opCount
&& _operands == other._operands;
}

constexpr bool operator!=(const InstructionBase& other) const
/// <summary>
/// Returns the instruction type of this object. The type can be detail or signature. This is only
/// relevant when casting between types.
/// </summary>
/// <returns>Instruction type</returns>
constexpr Type getType() const noexcept
{
return !(*this == other);
return _type;
}

/// <summary>
Expand All @@ -60,6 +74,80 @@ namespace zasm
return _mnemonic;
}

/// <summary>
/// Sets a new mnemonic for this instructions, this must be one of the architecture defined mnemonic
/// ex.: x86::Mnemonic::Mov
/// </summary>
/// <param name="mnemonic">New mnemonic</param>
/// <returns>Instruction&</returns>
template<typename T> constexpr InstructionBase& setMnemonic(T mnemonic)
{
_mnemonic = static_cast<Mnemonic>(mnemonic);
return *this;
}

/// <summary>
/// Casts this object to T. T must be a type that inherits InstructionBase and has kInstrType.
/// Casting to the wrong type is UB.
/// </summary>
/// <typeparam name="T">New type</typeparam>
/// <returns>Reference as T</returns>
template<typename T> T& as()
{
static_assert(detail::IsInstructionType<T>::value, "T is not a supported instruction type.");

assert(T::kInstrType == _type);

return static_cast<T&>(*this);
}

/// <summary>
/// Casts this object to T. T must be a type that inherits InstructionBase and has kInstrType.
/// Casting to the wrong type is UB.
/// </summary>
/// <typeparam name="T">New type</typeparam>
/// <returns>Reference as T</returns>
template<typename T> const T& as() const
{
static_assert(detail::IsInstructionType<T>::value, "T is not a supported instruction type.");

assert(T::kInstrType == _type);

return static_cast<const T&>(*this);
}
};

/// <summary>
/// Base type for Instruction and InstructionDetail, not to be used directly.
/// </summary>
template<typename TBase, std::size_t TMaxOperands> class TInstructionBase : public InstructionBase
{
public:
using Operands = std::array<Operand, TMaxOperands>;

protected:
Operands _operands{};

protected:
constexpr TInstructionBase() = default;
constexpr TInstructionBase(Attribs attribs, Mnemonic mnemonic, OperandCount opCount, const Operands& ops) noexcept
: InstructionBase(TBase::kInstrType, attribs, mnemonic, opCount)
, _operands{ ops }
{
}

public:
constexpr bool operator==(const TInstructionBase& other) const
{
return _attribs == other._attribs && _mnemonic == other._mnemonic && _opCount == other._opCount
&& _operands == other._operands;
}

constexpr bool operator!=(const TInstructionBase& other) const
{
return !(*this == other);
}

/// <summary>
/// Sets a new mnemonic for this instructions, this must be one of the architecture defined mnemonic
/// ex.: x86::Mnemonic::Mov
Expand Down
2 changes: 1 addition & 1 deletion zasm/include/zasm/core/packed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace zasm
/// <summary>
/// Container to tightly pack multiple elements with a given bit size to store
/// in the provided underlying type.
/// Example: Specifying the underlying type as uint32_t and element bit size of 10 allows you to store 3 elements.
/// Example: Specifying the underlying type as uint32_t and element bit size of 10 allows to store 3 elements.
/// </summary>
/// <typeparam name="TUnderlying">The underlying storage type</typeparam>
/// <typeparam name="TElement">Value type of each element packed</typeparam>
Expand Down
Loading

0 comments on commit 8de41a6

Please sign in to comment.