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
- Decimal:
- 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
- Batch Assembly Code: Use multi-line strings instead of multiple
asm()calls - Reuse Instances: Create one
TigerASMinstance and clear it between uses - Memory Management: Free allocated memory when done to enable coalescing
- 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
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:
Happy Assembling! 🐯⚡
Metadata
Release files for tigerasm 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tigerasm-0.1.0.tar.gz | 75.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tigerasm-0.1.0-cp312-cp312-win_amd64.whl | CPython 3.12 | CPython 3.12 | Windows x86-64 | Details |
Total release size: 370.2 kB
Release files / tigerasm-0.1.0.tar.gz
| Download URL | tigerasm-0.1.0.tar.gz |
|---|---|
| Size | 75.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b0c1f3a7601082f4bda74709d0b2093b4e0b6393330c9e6b4345600dc9477090
|
|
BLAKE2b-256 checksum How to use checksums |
1b45190e4cd52cb2f50f45bb0bb49a0a709b2f3306419e71891156c58d82964e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.10.2
|
Release files / tigerasm-0.1.0-cp312-cp312-win_amd64.whl
| Download URL | tigerasm-0.1.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 294.6 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
f0b3b152f5f4068f367522737d2134294d4f2fe347cfc649af4070ef8b0c6363
|
|
BLAKE2b-256 checksum How to use checksums |
022b3fb07d1e886abd169b64c70e26776a9c82f391f6b1a915a1b41eeaba1d08
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.10.2
|