asm

package module
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2023 License: MIT Imports: 6 Imported by: 0

README

asm

An x86-64 assembler written in Go. It is used by the Q programming language for machine code generation.

It was born out of the need for a highly performant assembler that had next to no overhead when compiling instructions to bytecode. When I started this project, I had no idea of how x86 instructions were constructed and I was forced to do a lot of reverse engineering via NASM.

Hopefully this repository helps someone who is learning about x86 assembly and its bytecode format.

There are a few examples to get an idea of the API I was aiming for.

x86-64 bytecode

An x86-64 program consists of a list of instructions. All of these instructions are built with the following format:

Name Size in bytes Required?
Legacy prefixes 1-4
OP code 1-4 required
Mod/RM 1
SIB 1
Displacement 1-8
Immediate 1-8

Out of these only the actual OP code which decides the instruction to execute is required. The remaining components depend on what instruction and what kind of parameters you have.

The maximum size for a single instruction is limited to 15 bytes.

Mod/RM

The Mod/RM byte has the following format:

Name Size in bits
Mod 2
Reg 3
RM 3
(mod << 6) | (reg << 3) | rm
SIB

The SIB byte has the same format as Mod/RM, just with different meanings:

Name Size in bits
Scale 2
Index 3
Base 3
(scale << 6) | (index << 3) | base

The opcode directory has a few helper functions to construct these components.

Registers

The following is a list of register names you can use. I decided to stick with the original names instead of r0-r7 for rax-rbp. I might still switch to r0-r7 for the future and enable the old names as synonyms.

64 bit 32 bit 16 bit 8 bit
rax eax ax al
rcx ecx cx cl
rdx edx dx dl
rbx ebx bx bl
rsi esi si sil
rdi edi di dil
rsp esp sp spl
rbp ebp bp bpl
r8 r8d r8w r8b
r9 r9d r9w r9b
r10 r10d r10w r10b
r11 r11d r11w r11b
r12 r12d r12w r12b
r13 r13d r13w r13b
r14 r14d r14w r14b
r15 r15d r15w r15b

Resources

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Address

type Address = uint32

Address represents a memory address, usually the jump address of a label.

type Assembler

type Assembler struct {
	EnableOptimizer bool
	// contains filtered or unexported fields
}

Assembler implements machine-code encoding.

func New

func New() *Assembler

New creates a new assembler.

func (*Assembler) AddData

func (a *Assembler) AddData(data []byte) Address

AddData writes the given byte slice to the data segment and returns the address.

func (*Assembler) AddLabel

func (a *Assembler) AddLabel(name string)

AddLabelAt adds a label for the current instruction address.

func (*Assembler) AddLabelAt

func (a *Assembler) AddLabelAt(name string, address uint32)

AddLabelAt adds a label for the given address.

func (*Assembler) AddRegisterNumber

func (a *Assembler) AddRegisterNumber(registerNameTo string, number uint64)

AddRegisterNumber adds a number to the given register.

func (*Assembler) AddRegisterRegister

func (a *Assembler) AddRegisterRegister(registerNameTo string, registerNameFrom string)

AddRegisterRegister adds a register value into another register.

func (*Assembler) CPUID

func (a *Assembler) CPUID()

CPUID is used to query CPU relevant data based on the contents of EAX.

func (*Assembler) Call

func (a *Assembler) Call(label string)

Call places the return address on the top of the stack and continues program flow at the new address. The address is relative to the next instruction.

func (*Assembler) Code

func (a *Assembler) Code() []byte

Code returns the machine code.

func (*Assembler) CompareRegisterNumber

func (a *Assembler) CompareRegisterNumber(registerName string, number uint64)

CompareRegisterNumber compares a register with a number.

func (*Assembler) CompareRegisterRegister

func (a *Assembler) CompareRegisterRegister(registerNameA string, registerNameB string)

CompareRegisterRegister compares a register with a register.

func (*Assembler) Compile

func (a *Assembler) Compile() error

Compile compiles the code.

func (*Assembler) Data

func (a *Assembler) Data() []byte

Data returns the data that is needed for the code to run.

func (*Assembler) DecreaseRegister

func (a *Assembler) DecreaseRegister(registerName string)

DecreaseRegister decreases the register value by 1.

func (*Assembler) DivRegister

func (a *Assembler) DivRegister(registerName string)

DivRegister divides the value in rax (usually) by the value in the specified register. This is a signed division. Quotient: AL AX EAX RAX Remainder: AH DX EDX RDX

func (*Assembler) EndBr64

func (a *Assembler) EndBr64()

EndBr64 is a security related instruction enabling CET (Control-flow Enforcement Technology). It ensures that indirect branches go to a valid location.

func (*Assembler) Exit

func (a *Assembler) Exit(code int32)

Exit terminates the program.

func (*Assembler) IncreaseRegister

func (a *Assembler) IncreaseRegister(registerName string)

IncreaseRegister increases the register value by 1.

func (*Assembler) Jump

func (a *Assembler) Jump(label string)

Jump continues program flow at the new address. The address is relative to the next instruction.

func (*Assembler) JumpIfEqual

func (a *Assembler) JumpIfEqual(label string)

JumpIfEqual jumps if the result was equal.

func (*Assembler) JumpIfGreater

func (a *Assembler) JumpIfGreater(label string)

JumpIfGreater jumps if the result was greater.

func (*Assembler) JumpIfGreaterOrEqual

func (a *Assembler) JumpIfGreaterOrEqual(label string)

JumpIfGreaterOrEqual jumps if the result was greater or equal.

func (*Assembler) JumpIfLess

func (a *Assembler) JumpIfLess(label string)

JumpIfLess jumps if the result was less.

func (*Assembler) JumpIfLessOrEqual

func (a *Assembler) JumpIfLessOrEqual(label string)

JumpIfLessOrEqual jumps if the result was less or equal.

func (*Assembler) JumpIfNotEqual

func (a *Assembler) JumpIfNotEqual(label string)

JumpIfNotEqual jumps if the result was not equal.

func (*Assembler) LoadRegister

func (a *Assembler) LoadRegister(registerNameTo string, registerNameFrom string, offset byte, byteCount byte)

LoadRegister loads from memory into a register.

func (*Assembler) Merge

func (a *Assembler) Merge(b *Assembler)

Merge combines the contents of the assembler with another one.

func (*Assembler) MoveRegisterAddress

func (a *Assembler) MoveRegisterAddress(registerNameTo string, address uint32)

MoveRegisterAddress moves an address into the given register.

func (*Assembler) MoveRegisterNumber

func (a *Assembler) MoveRegisterNumber(registerNameTo string, number uint64) uint32

MoveRegisterNumber moves a number into the given register.

func (*Assembler) MoveRegisterRegister

func (a *Assembler) MoveRegisterRegister(registerNameTo string, registerNameFrom string)

MoveRegisterRegister moves a register value into another register.

func (*Assembler) MulRegisterNumber

func (a *Assembler) MulRegisterNumber(registerNameTo string, number uint64)

MulRegisterNumber multiplies a register with a number.

func (*Assembler) MulRegisterRegister

func (a *Assembler) MulRegisterRegister(registerNameTo string, registerNameFrom string)

MulRegisterRegister multiplies a register with another register.

func (*Assembler) Open

func (a *Assembler) Open(fileName string)

Open opens a file.

func (*Assembler) Pointers

func (a *Assembler) Pointers() []Pointer

Pointers returns the list of data references in the code.

func (*Assembler) PopRegister

func (a *Assembler) PopRegister(registerName string)

PopRegister pops a value from the stack and saves it into the register.

func (*Assembler) Position

func (a *Assembler) Position() Address

Position returns the current address.

func (*Assembler) Print

func (a *Assembler) Print(msg string)

Print prints a message on the terminal.

func (*Assembler) Println

func (a *Assembler) Println(msg string)

Print prints a message followed by a new line on the terminal.

func (*Assembler) PushRegister

func (a *Assembler) PushRegister(registerName string)

PushRegister pushes the value inside the register onto the stack.

func (*Assembler) ReadTimeStampCounterAndProcessorID

func (a *Assembler) ReadTimeStampCounterAndProcessorID()

ReadTimeStampCounterAndProcessorID is used for performance benchmarks.

func (*Assembler) Reset

func (a *Assembler) Reset()

Reset deletes the entire contents of the assembler.

func (*Assembler) Return

func (a *Assembler) Return()

Return transfers program control to a return address located on the top of the stack. The address is usually placed on the stack by a Call instruction.

func (*Assembler) SignExtendToDX

func (a *Assembler) SignExtendToDX(registerName string)

SignExtendToDX doubles the size of the register by sign-extending to DX/EDX/RDX.

func (*Assembler) StoreNumber

func (a *Assembler) StoreNumber(registerNameTo string, offset byte, byteCount byte, number uint64)

StoreNumber stores a number into the memory address included in the given register.

func (*Assembler) StoreRegister

func (a *Assembler) StoreRegister(registerNameTo string, offset byte, byteCount byte, registerNameFrom string)

StoreRegister stores the contents of a register into the memory address included in the given register.

func (*Assembler) SubRegisterNumber

func (a *Assembler) SubRegisterNumber(registerNameTo string, number uint64)

SubRegisterNumber subtracts a number from a register.

func (*Assembler) SubRegisterRegister

func (a *Assembler) SubRegisterRegister(registerNameTo string, registerNameFrom string)

SubRegisterRegister subtracts a register value from another register.

func (*Assembler) Syscall

func (a *Assembler) Syscall()

Syscall executes a syscall.

func (*Assembler) Write

func (a *Assembler) Write(code []byte) (int, error)

Write writes the given byte slice to the machine code.

func (*Assembler) WriteBytes

func (a *Assembler) WriteBytes(someBytes ...byte)

WriteBytes writes the given bytes to the machine code.

func (*Assembler) WriteUint16

func (a *Assembler) WriteUint16(number uint16)

WriteUint16 writes an unsigned 16-bit integer in little endian format to the machine code.

func (*Assembler) WriteUint32

func (a *Assembler) WriteUint32(number uint32)

WriteUint32 writes an unsigned 32-bit integer in little endian format to the machine code.

func (*Assembler) WriteUint64

func (a *Assembler) WriteUint64(number uint64)

WriteUint64 writes an unsigned 64-bit integer in little endian format to the machine code.

type Pointer

type Pointer struct {
	Address  uint32
	Position uint32
}

Pointer stores a relative memory address reference (relative to the section) that we can later turn into an absolute one. Address: The offset inside the section. Position: The machine code offset where the address was inserted.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL