Skip to main content

Boron is a hobby project that implements an x86-64 assembler in Python.

Project description

BORON Assembler

UNDER DEVELOPMENT - TRY IT AT YOUR OWN RISK

STILL NEEDS TO DEVELOPED

What is Boron?

Boron is a hobby project that implements an x86-64 assembler in Python.
You can dynamically assemble instructions at runtime and execute them immediately.

Why Boron?

  • Live machine code generation: Assemble instructions directly in Python and execute them on the fly.
  • Full control: Every instruction, operand, and offset is manipulable from Python objects.
  • Learn by doing: Experiment with instructions, syscalls, and memory layout without writing intermediate files.
  • Transparent and hackable: More comments and documentation will be added soon to help you understand the inner workings.

Unlike NASM or GCC assemblers, Boron lets you experiment and run machine code directly in Python. Multi-file projects or libraries like libc still require the system linker, but single-file programs can be assembled and executed dynamically (soon).

Limitations

  • No built-in runtime execution yet: You have to handle relocations manually.
  • Relocatable ELF32/ELF64 files only: COFF format and other outputs are not supported yet.
  • Under active development: Bugs and breaking changes are expected.
  • Not commented yet: I will add comments to the code.

What's New

  • Simple built-in runtime execution : An class added for it but I need to work on it more
  • Simple disassembler : YAY!

Next steps

Current Goals

  • Built-in runtime execution: I will add an class for it.
  • More instructions: I will add more x64 instructions. Currently Boron have a few instructions (24)
  • Documentation: I will fill the documentation folder and comment the code.

Future Goals

  • Other architecthtures: I will add x16/x86 architecthure
  • More file formats: Like coff
  • Disassembler: From flat binary
  • Improvement of the readme: I will add more examples.
  • And others

How to use Boron?

Simple "Hello, World!"

import mmap, ctypes
from boron.assembler.x64.General import instructions, operands
from boron.assembler.x64.General.registers import GPRegisters

# Message
hello = b"Hello, world!\n"
hello_len = len(hello)
hello_buf = ctypes.create_string_buffer(hello)  # buffer in memory
buf_addr = ctypes.addressof(hello_buf)         # raw byte address

# Assembly program
program = [
    # write(1, buf, len)
    instructions.INSTRUCTIONS.MOV.R_IMM(GPRegisters.rax, operands.Immediate(1, 8)),  # sys_write
    instructions.INSTRUCTIONS.MOV.R_IMM(GPRegisters.rdi, operands.Immediate(1, 8)),  # stdout
    instructions.INSTRUCTIONS.MOV.R_IMM(GPRegisters.rsi, operands.Immediate(buf_addr, 8)),
    instructions.INSTRUCTIONS.MOV.R_IMM(GPRegisters.rdx, operands.Immediate(hello_len, 8)),
    instructions.INSTRUCTIONS.SYSCALL(),

    # exit(0)
    instructions.INSTRUCTIONS.MOV.R_IMM(GPRegisters.rax, operands.Immediate(60, 8)),  
    instructions.INSTRUCTIONS.XOR.R_R(GPRegisters.rdi, GPRegisters.rdi),
    instructions.INSTRUCTIONS.SYSCALL(),
]

# Assemble to machine code
code = b""
for instr in program:
    for i in instr.emit():
        code += i.emit()

# Allocate executable memory and copy code
mem = mmap.mmap(-1, len(code), prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC,
                flags=mmap.MAP_PRIVATE | mmap.MAP_ANONYMOUS)
mem.write(code)

# Execute
addr = ctypes.c_void_p.from_buffer(mem)
entry = ctypes.CFUNCTYPE(None)(ctypes.addressof(addr))
entry()

Prints the string in hello directly. No NASM or linker required. Works on Linux.

And yes that was for just a "Hello, World!"

simple "Hello, World!" but as a file

from boron.codegen.builder import Builder
from boron.assembler.assembler import x64,ASSEMBLER,SECTION,ARCH,FILE
from boron.codegen.file import elf
from boron.codegen.section import SectionKind, SectionFlags, SymbolBinding
#required modules in boron

builder = ASSEMBLER(ARCH.x64,True)
msg = b"Hello, World!\n"
# TEXT SECTION
text = builder.add_section(
    SECTION(".text", SectionKind.CODE, SectionFlags.EXEC, alignment=0x1000)
)


a = text.add_label("_start", binding=SymbolBinding.GLOBAL)

# write syscall
# rax = 1 (sys_write)
text.add(x64.General.instructions.INSTRUCTIONS.MOV.R_IMM(
    x64.General.registers.GPRegisters.eax,
    x64.General.operands.Immediate(1,4)
))

# rdi = 1 (stdout)
text.add(x64.General.instructions.INSTRUCTIONS.MOV.R_IMM(
    x64.General.registers.GPRegisters.edi,
    x64.General.operands.Immediate(1,4)
))

# rsi = &msg
text.add(x64.General.instructions.INSTRUCTIONS.MOV.R_IMM(
    x64.General.registers.GPRegisters.rsi,
    x64.General.operands.SYMBOL("msg", 8, False, 0))
)
# rdx = len
text.add(x64.General.instructions.INSTRUCTIONS.MOV.R_IMM(
    x64.General.registers.GPRegisters.edx,
    x64.General.operands.Immediate(len(msg),4)  # "Hello, world!\n"
))

b = text.add(x64.General.instructions.INSTRUCTIONS.SYSCALL())


# exit syscall
# rax = 60
text.add(x64.General.instructions.INSTRUCTIONS.MOV.R_IMM(
    x64.General.registers.GPRegisters.rax,
    x64.General.operands.Immediate(60,4)
))

# rdi = 0
text.add(x64.General.instructions.INSTRUCTIONS.MOV.R_IMM(
    x64.General.registers.GPRegisters.rdi,
    x64.General.operands.Immediate(0,4)
))

text.add(x64.General.instructions.INSTRUCTIONS.SYSCALL())


# DATA SECTION
data = builder.add_section(
    SECTION(".data", SectionKind.DATA,
            SectionFlags.READ | SectionFlags.WRITE,
            alignment=0x10)
)
data.add_label("msg", binding=SymbolBinding.LOCAL)
data.db(msg)

# WRITE FILE
with open("out", "wb") as f:
    out = builder.build(FILE.ELF)
    f.write(out)

It may be require admin permissions (sudo) you need to link it with ld out -o hello

Project details


Download files

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

Source Distribution

boron_assembler-0.2.0.tar.gz (36.8 kB view details)

Uploaded Source

Built Distribution

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

boron_assembler-0.2.0-py3-none-any.whl (44.8 kB view details)

Uploaded Python 3

File details

Details for the file boron_assembler-0.2.0.tar.gz.

File metadata

  • Download URL: boron_assembler-0.2.0.tar.gz
  • Upload date:
  • Size: 36.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for boron_assembler-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9335ece4a8a02d9454f1b0f978ab720a581495b78c01852be099d412f251ae53
MD5 3eb9d1c0f6a1596dd65a4d57095ba5f1
BLAKE2b-256 68aec72985d52ea2c9d86b65c20418b5d37fcfd0b95c64b400b80f197a2b5230

See more details on using hashes here.

Provenance

The following attestation bundles were made for boron_assembler-0.2.0.tar.gz:

Publisher: python-package.yml on TAN-JANT/BORON

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file boron_assembler-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for boron_assembler-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5046e02fd1eb4aafb576381df7f21cce47b3d4f594b10bbafac0b6f925bd50cd
MD5 7d9cfbca8974dc5140d8fdc144cc44cf
BLAKE2b-256 0cd05217a3dc44734bdfd613d1ccaec3da44d2e078cba14654927a077f05f455

See more details on using hashes here.

Provenance

The following attestation bundles were made for boron_assembler-0.2.0-py3-none-any.whl:

Publisher: python-package.yml on TAN-JANT/BORON

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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