Skip to main content

TigerASM 🐯

Ultimate Complete Runtime Assembler for Python

TigerASM is a high-performance runtime assembler library for Rust with Python bindings.
It supports x86-64 and ARM64 architectures, allowing you to execute dynamic assembly instructions from Python.

✨ Features

  • 349 Total Registers Support
    • 122 x86-64 registers (GPR, XMM, YMM, ZMM, FPU, segment, control, debug)
    • 227 ARM64 registers (general purpose, SIMD, system)
  • Complete Memory Addressing
    • [reg], [reg+offset], [reg+reg*scale+disp]
    • Intel and AT&T syntax support
  • Multiple Number Formats
    • Decimal: 42
    • Hexadecimal: 0x2A
    • Binary: 0b101010
  • Advanced Memory Management
    • Built-in allocator with coalescing
    • 10MB default memory pool
    • Read/write operations with multiple sizes
  • Both Architectures Supported
    • x86-64 (Intel/AMD)
    • AArch64 (ARM64)

📦 Installation

pip install tigerasm

🏗️ Architecture Support

x86-64 Architecture

Supported on Intel and AMD processors with full instruction set support.

Available Registers:

  • General Purpose: rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, r8-r15
  • 32-bit: eax, ebx, ecx, edx, esi, edi, esp, ebp, r8d-r15d
  • 16-bit: ax, bx, cx, dx, si, di, sp, bp, r8w-r15w
  • 8-bit: al, ah, bl, bh, cl, ch, dl, dh, sil, dil, bpl, spl, r8b-r15b
  • SIMD: xmm0-xmm15, ymm0-ymm15, zmm0-zmm15
  • FPU: st0-st7, mm0-mm7
  • Segment: cs, ds, es, fs, gs, ss
  • Control: cr0-cr4
  • Debug: dr0-dr7
  • Special: rip, rflags, gdtr, idtr, ldtr, tr

ARM64 (AArch64) Architecture

Supported on ARM processors including Apple Silicon, AWS Graviton, and more.

Available Registers:

  • General Purpose: x0-x30 (64-bit), w0-w30 (32-bit)
  • Special: sp, pc, lr (x30), fp (x29), xzr/wzr (zero register)
  • SIMD/FP: v0-v31, q0-q31, d0-d31, s0-s31, h0-h31, b0-b31
  • System: pstate, cpsr, apsr
  • Exception Levels: sp_el0-sp_el3, elr_el1-elr_el3, spsr_el1-spsr_el3
  • FP Control: fpcr, fpsr

🚀 Quick Start

Basic Usage

from tigerasm import TigerASM

# Create assembler instance
asm = TigerASM()
asm.setup("x86_64")  # or "aarch64" for ARM64

# Write assembly code
asm.asm("""
    mov rax, 42
    add rax, 8
    ret
""")

# Execute and get result
asm.execute()
result = asm.get("rax")  # Returns 50
print(f"Result: {result}")

Working with Different Number Formats

asm = TigerASM()
asm.setup()

# Decimal, hexadecimal, and binary
asm.asm("""
    mov rax, 100        ; Decimal
    mov rbx, 0xFF       ; Hexadecimal
    mov rcx, 0b1010     ; Binary
    add rax, rbx
    add rax, rcx
    ret
""")

asm.execute()
print(f"Sum: {asm.get('rax')}")  # 100 + 255 + 10 = 365

📝 Instruction Set

Data Movement

# Intel syntax (default)
mov rax, 100              # Register <- Immediate
mov rbx, rax              # Register <- Register
mov rax, [rbx]            # Register <- Memory
mov [rbx], rax            # Memory <- Register
lea rax, [rbx + rcx*4]    # Load Effective Address

# AT&T syntax (also supported)
movq $100, %rax           # AT&T immediate syntax
movq %rax, %rbx           # AT&T register syntax
movq (%rbx), %rax         # AT&T memory syntax

Arithmetic Operations

add rax, 10               # Addition
sub rax, 5                # Subtraction
mul rbx                   # Unsigned multiplication (rax * rbx)
imul rax, rbx             # Signed multiplication
div rcx                   # Unsigned division
inc rax                   # Increment
dec rax                   # Decrement
neg rax                   # Negate

Logical Operations

and rax, 0xFF             # Bitwise AND
or rax, 0x0F              # Bitwise OR
xor rax, rbx              # Bitwise XOR
not rax                   # Bitwise NOT
test rax, rbx             # Test (AND without storing)

Bit Manipulation

# x86-64
shl rax, 2                # Shift left
shr rax, 1                # Shift right (logical)
sal rax, 3                # Shift arithmetic left
sar rax, 2                # Shift arithmetic right
rol rax, 4                # Rotate left
ror rax, 3                # Rotate right
rcl rax, 1                # Rotate through carry left
rcr rax, 2                # Rotate through carry right

# ARM64
lsl x0, x0, #2            # Logical shift left
lsr x0, x0, #1            # Logical shift right
asr x0, x0, #3            # Arithmetic shift right

Control Flow

# Labels and jumps
asm.asm("""
loop_start:
    dec rcx
    jnz loop_start        # Jump if not zero
    ret
""")

# Conditional jumps (x86-64)
je label                  # Jump if equal
jne label                 # Jump if not equal
jg label                  # Jump if greater
jge label                 # Jump if greater or equal
jl label                  # Jump if less
jle label                 # Jump if less or equal
ja label                  # Jump if above (unsigned)
jb label                  # Jump if below (unsigned)

# ARM64 branches
b label                   # Unconditional branch
beq label                 # Branch if equal
bne label                 # Branch if not equal
bgt label                 # Branch if greater than
blt label                 # Branch if less than
bl function               # Branch with link (call)

🧠 Register Management

Setting Register Values

asm = TigerASM()

# x86-64 registers
asm.mov("rax", 0x1234567890ABCDEF)
asm.mov("rbx", 42)
asm.mov("rcx", 0b11111111)

# ARM64 registers
asm.mov("x0", 100)
asm.mov("x1", 200)
asm.mov("sp", 0x7fff0000)

Reading Register Values

# Get specific register
value = asm.get("rax")
print(f"RAX = {value:#x}")

# Get ARM register
value = asm.get("x0")
print(f"X0 = {value}")

# Default to RAX if no register specified
default_val = asm.get()  # Returns RAX on x86-64, X0 on ARM64

Dumping All Registers

# Display all registers for current architecture
print(asm.dump_regs())

# Force specific architecture dump
print(asm.dump_regs_x86())
print(asm.dump_regs_arm())

Output example (x86-64):

=== x86-64 Registers ===
RAX=0000000000000064 RBX=00000000000000c8 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=0000000000000000
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000000000 RFLAGS=0000000000000000
Segment: CS=0000 DS=0000 ES=0000 FS=0000 GS=0000 SS=0000

💾 Memory Operations

Basic Memory Access

asm = TigerASM()

# Write to memory
asm.write_mem(0x1000, 0xDEADBEEF, 4)  # address, value, size

# Read from memory
value = asm.read_mem(0x1000, 4)  # address, size
print(f"Value at 0x1000: {value:#x}")

# Supported sizes: 1, 2, 4, 8 bytes
asm.write_mem(0x2000, 0xFF, 1)        # byte
asm.write_mem(0x2001, 0xFFFF, 2)      # word
asm.write_mem(0x2003, 0xFFFFFFFF, 4)  # dword
asm.write_mem(0x2007, 0xFFFFFFFFFFFFFFFF, 8)  # qword

Memory Addressing Modes

# Intel syntax
mov rax, [rbx]                    # [base]
mov rax, [rbx + 8]                # [base + offset]
mov rax, [rbx + rcx]              # [base + index]
mov rax, [rbx + rcx*4]            # [base + index*scale]
mov rax, [rbx + rcx*8 + 16]       # [base + index*scale + disp]
mov rax, [rip + 0x1000]           # RIP-relative

# AT&T syntax
movq (%rbx), %rax                 # (base)
movq 8(%rbx), %rax                # offset(base)
movq (%rbx,%rcx), %rax            # (base,index)
movq (%rbx,%rcx,4), %rax          # (base,index,scale)
movq 16(%rbx,%rcx,8), %rax        # offset(base,index,scale)

Memory Allocation

# Allocate memory block
address = asm.alloc(1024)  # Allocate 1KB
if address == 0:
    print("Allocation failed")
else:
    print(f"Allocated at: {address:#x}")
    
    # Use the memory
    asm.write_mem(address, 0x42, 1)
    
    # Free when done
    asm.free(address)

# Check memory statistics
used, free, blocks = asm.memory_stats()
print(f"Used: {used} bytes, Free: {free} bytes, Blocks: {blocks}")

Bulk Memory Operations

# Load binary file to memory
bytes_read = asm.load_binary_file("data.bin", 0x10000)
print(f"Loaded {bytes_read} bytes")

# Load bytes from Python
data = bytes([0x48, 0x89, 0xC3, 0xC3])  # mov rbx, rax; ret
asm.load_bytes_to_memory(data, 0x20000)

# Write bytes to memory
asm.write_bytes(0x30000, [0x90] * 10)  # 10 NOPs

# Read bytes from memory
data = asm.read_bytes(0x30000, 10)
print(f"Read: {data}")

# Save memory region to file
asm.save_memory_to_file("output.bin", 0x10000, 1024)

# Clear memory (optional range)
asm.clear_memory(0x1000, 512)  # Clear specific region
asm.clear_memory()              # Clear all memory

Memory Information

# Get total memory size
size = asm.memory_size()
print(f"Total memory: {size} bytes")

# Get raw memory pointer (advanced)
ptr = asm.get_memory_ptr()
print(f"Memory base address: {ptr:#x}")

📂 Loading Assembly Files

From String

asm = TigerASM()
code = """
    mov rax, 10
    mov rbx, 20
    add rax, rbx
    ret
"""
asm.asm(code)
asm.execute()

From File

asm = TigerASM()

# Load .asm file
asm.load_file("program.asm")
asm.execute()

# Or use asm() with file handle
with open("program.asm", "rb") as f:
    asm.asm("", file=f)
asm.execute()

Multiple Code Sections

asm = TigerASM()

# Add code incrementally
asm.asm("mov rax, 0")
asm.asm("add rax, 10")
asm.asm("add rax, 20")
asm.asm("ret")

# Execute combined code
asm.execute()
print(asm.get("rax"))  # 30

# Clear and start fresh
asm.clear()

🔧 Advanced Examples

Factorial Calculation

asm = TigerASM()
asm.setup("x86_64")

# Calculate factorial of 5
asm.asm("""
    mov rax, 5          ; n = 5
    mov rbx, 1          ; result = 1
    
factorial_loop:
    test rax, rax       ; if n == 0
    jz done             ; goto done
    
    imul rbx, rax       ; result *= n
    dec rax             ; n--
    jmp factorial_loop
    
done:
    mov rax, rbx        ; return result
    ret
""")

asm.execute()
result = asm.get("rax")
print(f"5! = {result}")  # 120

String Length (ARM64)

asm = TigerASM()
asm.setup("aarch64")

# Store string in memory
text = b"Hello, World!\x00"
asm.load_bytes_to_memory(list(text), 0x10000)

asm.asm("""
    mov x0, #0x10000    ; String address
    mov x1, #0          ; Counter
    
strlen_loop:
    ldrb w2, [x0, x1]   ; Load byte
    cbz w2, done        ; If zero, done
    add x1, x1, #1      ; counter++
    b strlen_loop
    
done:
    mov x0, x1          ; Return length
    ret
""")

asm.execute()
length = asm.get("x0")
print(f"String length: {length}")  # 13

Memory Copy

asm = TigerASM()
asm.setup()

# Source data
src_data = list(range(0, 100))
asm.load_bytes_to_memory(src_data, 0x1000)

# Copy routine
asm.asm("""
    mov rsi, 0x1000     ; Source
    mov rdi, 0x2000     ; Destination
    mov rcx, 100        ; Count
    
copy_loop:
    test rcx, rcx
    jz done
    
    mov al, [rsi]       ; Load byte
    mov [rdi], al       ; Store byte
    
    inc rsi
    inc rdi
    dec rcx
    jmp copy_loop
    
done:
    ret
""")

asm.execute()

# Verify
dest_data = asm.read_bytes(0x2000, 100)
print(f"Copy successful: {dest_data == bytes(src_data)}")

Working with SIMD (x86-64)

asm = TigerASM()
asm.setup("x86_64")

# Note: SIMD operations require extended instruction support
# This is a conceptual example
asm.asm("""
    ; Load 4 floats into XMM0
    movaps xmm0, [rsi]
    
    ; Multiply by 2.0
    mulps xmm0, xmm1
    
    ; Store result
    movaps [rdi], xmm0
    ret
""")

🎯 Architecture Detection

asm = TigerASM()

# Auto-detect (default)
asm.setup()
print(f"Detected: {asm.get_arch()}")

# Force specific architecture
asm.setup("x86_64")   # x86-64
asm.setup("aarch64")  # ARM64

# Alternative names
asm.setup("x86")      # → x86-64
asm.setup("amd64")    # → x86-64
asm.setup("arm64")    # → aarch64
asm.setup("arm")      # → aarch64

🔍 Validation

asm = TigerASM()

# Check if register is valid
if asm.is_valid_register("rax"):
    print("RAX is valid")

if asm.is_valid_register("x0"):
    print("X0 is valid")

# Check architecture
arch = asm.get_arch()
if arch == "x86_64":
    print("Running on x86-64")
elif arch == "aarch64":
    print("Running on ARM64")

💾 Saving Executable Code

asm = TigerASM()
asm.asm("""
    mov rax, 42
    ret
""")

# Compile without executing
asm.execute()  # This compiles the code

# Save compiled code to file
asm.install("output.bin")

🐛 Error Handling

from tigerasm import TigerASM

asm = TigerASM()

try:
    # Invalid register
    asm.mov("invalid_reg", 42)
except ValueError as e:
    print(f"Error: {e}")

try:
    # Invalid instruction
    asm.asm("invalid_instruction rax, rbx")
except ValueError as e:
    print(f"Parse error: {e}")

try:
    # Memory out of bounds
    asm.write_mem(0xFFFFFFFFFFFF, 42, 8)
except ValueError as e:
    print(f"Memory error: {e}")

📊 Performance Tips

  1. Batch Assembly Code: Use multi-line strings instead of multiple asm() calls
  2. Reuse Instances: Create one TigerASM instance and clear it between uses
  3. Memory Management: Free allocated memory when done to enable coalescing
  4. Register Usage: Prefer registers over memory for frequently accessed data
# Good: Single batch
asm.asm("""
    mov rax, 1
    mov rbx, 2
    add rax, rbx
""")

# Less efficient: Multiple calls
asm.asm("mov rax, 1")
asm.asm("mov rbx, 2")
asm.asm("add rax, rbx")

🔒 Safety Notes

  • Memory operations are bounds-checked
  • Invalid register names raise ValueError
  • Memory allocation failures return 0
  • Always validate addresses before use
  • The memory pool is isolated and safe

🤝 Contributing

Contributions are welcome! Please ensure:

  • Code follows Rust best practices
  • New instructions are documented
  • Tests are included for new features
  • README is updated

📄 License

License

TigerASM is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later).
For full details, see the LICENSE file included in this project.


🙏 Acknowledgments

This project was made possible with:

  • PyO3 – Rust bindings for Python
  • dynasm-rs – Dynamic assembly runtime

Happy Assembling! 🐯⚡

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tigerasm-0.1.0.tar.gz (75.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tigerasm-0.1.0-cp312-cp312-win_amd64.whl (294.6 kB view details)

Uploaded CPython 3.12Windows x86-64

File details

Details for the file tigerasm-0.1.0.tar.gz.

File metadata

  • Download URL: tigerasm-0.1.0.tar.gz
  • Upload date:
  • Size: 75.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.10.2

File hashes

Hashes for tigerasm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b0c1f3a7601082f4bda74709d0b2093b4e0b6393330c9e6b4345600dc9477090
MD5 3c80497a964ca73a7b967e4bb946737b
BLAKE2b-256 1b45190e4cd52cb2f50f45bb0bb49a0a709b2f3306419e71891156c58d82964e

See more details on using hashes here.

File details

Details for the file tigerasm-0.1.0-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for tigerasm-0.1.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 f0b3b152f5f4068f367522737d2134294d4f2fe347cfc649af4070ef8b0c6363
MD5 8802e7a4443d45a45fe19b496cb2a125
BLAKE2b-256 022b3fb07d1e886abd169b64c70e26776a9c82f391f6b1a915a1b41eeaba1d08

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page