TigerASM - Runtime assembler for Python (x86-64 & ARM64)
Project description
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! 🐯⚡
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0c1f3a7601082f4bda74709d0b2093b4e0b6393330c9e6b4345600dc9477090
|
|
| MD5 |
3c80497a964ca73a7b967e4bb946737b
|
|
| BLAKE2b-256 |
1b45190e4cd52cb2f50f45bb0bb49a0a709b2f3306419e71891156c58d82964e
|
File details
Details for the file tigerasm-0.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: tigerasm-0.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 294.6 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0b3b152f5f4068f367522737d2134294d4f2fe347cfc649af4070ef8b0c6363
|
|
| MD5 |
8802e7a4443d45a45fe19b496cb2a125
|
|
| BLAKE2b-256 |
022b3fb07d1e886abd169b64c70e26776a9c82f391f6b1a915a1b41eeaba1d08
|