Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions coolify-backup-asm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/coolify-backup-asm
/src/*.o
/tests/objdump-*.txt
31 changes: 31 additions & 0 deletions coolify-backup-asm/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
NASM ?= nasm
LD ?= ld
NASMFLAGS ?= -f elf64 -Wall -Werror
LDFLAGS ?= -nostdlib -static -z noexecstack
TARGET := coolify-backup-asm
SRCS := src/main.asm
OBJS := $(SRCS:.asm=.o)
SIZE_LIMIT := 65536

all: $(TARGET)

$(TARGET): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^
@size=$$(stat -c%s $@); \
if [ $$size -gt $(SIZE_LIMIT) ]; then \
echo "ERROR: Binary size $$size exceeds 64KB limit ($(SIZE_LIMIT) bytes)"; \
rm -f $@; \
exit 1; \
fi; \
echo "Binary size: $$size bytes (limit: $(SIZE_LIMIT))"

%.o: %.asm
$(NASM) $(NASMFLAGS) -o $@ $<

test: $(TARGET)
bash tests/test_runner.sh

clean:
rm -f $(OBJS) $(TARGET)

.PHONY: all test clean
37 changes: 37 additions & 0 deletions coolify-backup-asm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# coolify-backup-asm

Initial x86_64 NASM, zero-libc skeleton for the Coolify bare-metal backup daemon.

This directory intentionally builds a single statically-linked ELF using only Linux syscalls. The first milestone keeps the binary small while establishing the project layout, syscall discipline, argument parsing, status JSON output, and reproducible tests requested in issue #2.

## Build

```sh
make -C coolify-backup-asm
```

The Makefile enforces the 64 KiB binary limit at link time.

## Test

```sh
make -C coolify-backup-asm test
```

The test runner verifies:

- static ELF output
- binary size <= 65536 bytes
- direct syscall-only behavior through `strace`
- `version`, `backup --dry-run`, and invalid command exit paths
- `objdump` disassembly capture for PR review

## Current CLI

```text
Usage: coolify-backup-asm <command> [options]
Commands: version, backup
Options: --dry-run, --backup-id <id>, --verbose
```

`backup --dry-run` emits JSON and exits without starting external tools. Later modules can replace the dry-run stub with the full pipeline while preserving the syscall and argument parsing boundary introduced here.
41 changes: 41 additions & 0 deletions coolify-backup-asm/src/args.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
; Minimal argv parser for the first milestone.
%ifndef COOLIFY_ARGS_ASM
%define COOLIFY_ARGS_ASM

parse_args:
; rdi=argc, rsi=argv. rax command: 1 version, 2 backup dry-run, 0 usage, -1 error
cmp rdi, 2
jl .usage
mov rbx, rsi
mov rdi, [rbx + 8]
lea rsi, [rel cmd_version]
call streq_z
cmp rax, 1
je .version
mov rdi, [rbx + 8]
lea rsi, [rel cmd_backup]
call streq_z
cmp rax, 1
je .backup
jmp .error
.version:
mov eax, 1
ret
.backup:
cmp qword [rsp_argc_shadow], 3
jl .error
mov rdi, [rbx + 16]
lea rsi, [rel opt_dry_run]
call streq_z
cmp rax, 1
jne .error
mov eax, 2
ret
.usage:
xor eax, eax
ret
.error:
mov rax, -1
ret

%endif
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/config.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/crypto/aesni.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/crypto/ghash.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/crypto/hmac.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/crypto/random.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/crypto/sha256.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/db/postgres.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
74 changes: 74 additions & 0 deletions coolify-backup-asm/src/main.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
BITS 64
default rel

global _start

section .text
%include "src/syscall.asm"
%include "src/string.asm"
%include "src/memory.asm"
%include "src/args.asm"
%include "src/pipeline/db_dump.asm"

_start:
mov rdi, [rsp] ; argc
mov [rsp_argc_shadow], rdi
lea rsi, [rsp + 8] ; argv
call parse_args
cmp rax, 1
je .version
cmp rax, 2
je .backup_dry_run
cmp rax, 0
je .usage
jmp .bad_args

.version:
lea rsi, [rel version_msg]
mov edx, version_msg_len
mov edi, STDOUT
call write_all
xor edi, edi
call exit_process

.backup_dry_run:
lea rdi, [rel ring_meta]
call ring_init
call db_dump_dry_run
xor edi, edi
call exit_process

.usage:
lea rsi, [rel usage_msg]
mov edx, usage_msg_len
mov edi, STDERR
call write_all
mov edi, 3
call exit_process

.bad_args:
lea rsi, [rel error_msg]
mov edx, error_msg_len
mov edi, STDERR
call write_all
mov edi, 3
call exit_process

section .data
cmd_version: db "version", 0
cmd_backup: db "backup", 0
opt_dry_run: db "--dry-run", 0

version_msg: db "coolify-backup-asm 0.1.0 asm-skeleton x86_64 zero-libc", 10
version_msg_len equ $ - version_msg
usage_msg: db "Usage: coolify-backup-asm <version|backup --dry-run>", 10
usage_msg_len equ $ - usage_msg
error_msg: db "coolify-backup-asm: invalid arguments", 10, "Usage: coolify-backup-asm <version|backup --dry-run>", 10
error_msg_len equ $ - error_msg
json_dry_run: db "{", 34, "status", 34, ":", 34, "dry-run", 34, ",", 34, "pipeline", 34, ":", 34, "db_dump", 34, ",", 34, "libc", 34, ":false}", 10
json_dry_run_len equ $ - json_dry_run

section .bss align=16
rsp_argc_shadow: resq 1
ring_meta: resq 3
ring_buffer: resb 65536
14 changes: 14 additions & 0 deletions coolify-backup-asm/src/memory.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
; Fixed ring-buffer metadata. Storage is .bss-backed; no heap allocation.
%ifndef COOLIFY_MEMORY_ASM
%define COOLIFY_MEMORY_ASM

%define RING_CAPACITY 65536

ring_init:
; rdi = metadata base: [0]=read_pos qword, [8]=write_pos qword, [16]=capacity qword
mov qword [rdi], 0
mov qword [rdi + 8], 0
mov qword [rdi + 16], RING_CAPACITY
ret

%endif
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/net/http.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/net/s3.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
2 changes: 2 additions & 0 deletions coolify-backup-asm/src/net/socket.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; Reserved module file for the coolify-backup-asm pipeline.
; Implementations are added incrementally while preserving zero-libc syscall-only boundaries.
12 changes: 12 additions & 0 deletions coolify-backup-asm/src/pipeline/db_dump.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; db_dump module placeholder: dry-run milestone validates CLI and JSON contract.
%ifndef COOLIFY_DB_DUMP_ASM
%define COOLIFY_DB_DUMP_ASM

db_dump_dry_run:
lea rsi, [rel json_dry_run]
mov edx, json_dry_run_len
mov edi, STDOUT
call write_all
ret

%endif
50 changes: 50 additions & 0 deletions coolify-backup-asm/src/string.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; Small string helpers using the SysV integer registers only.
%ifndef COOLIFY_STRING_ASM
%define COOLIFY_STRING_ASM

strlen_z:
; rdi = nul-terminated string, rax = length
xor rax, rax
.loop:
cmp byte [rdi + rax], 0
je .done
inc rax
jmp .loop
.done:
ret

streq_z:
; rdi=a, rsi=b, rax=1 if equal else 0
.loop:
mov al, [rdi]
mov dl, [rsi]
cmp al, dl
jne .no
test al, al
je .yes
inc rdi
inc rsi
jmp .loop
.yes:
mov eax, 1
ret
.no:
xor eax, eax
ret

memcpy_bytes:
; rdi=dst, rsi=src, rdx=len. Returns original dst in rax.
mov rax, rdi
test rdx, rdx
je .done
.loop:
mov cl, [rsi]
mov [rdi], cl
inc rsi
inc rdi
dec rdx
jne .loop
.done:
ret

%endif
30 changes: 30 additions & 0 deletions coolify-backup-asm/src/syscall.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; Linux x86_64 syscall wrappers. No libc, no PLT.
%ifndef COOLIFY_SYSCALL_ASM
%define COOLIFY_SYSCALL_ASM

%define SYS_READ 0
%define SYS_WRITE 1
%define SYS_EXIT 60
%define SYS_GETPID 39
%define SYS_ARCH_PRCTL 158
%define SYS_EXIT_GROUP 231

%define STDOUT 1
%define STDERR 2

write_all:
; rdi=fd, rsi=buf, rdx=len. Returns bytes/negative errno in rax.
mov rax, SYS_WRITE
syscall
ret

exit_process:
; rdi=exit code
mov rax, SYS_EXIT_GROUP
syscall
mov rax, SYS_EXIT
syscall
.hang:
jmp .hang

%endif
36 changes: 36 additions & 0 deletions coolify-backup-asm/tests/test_runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."

bin=./coolify-backup-asm
[ -x "$bin" ]

size=$(stat -c%s "$bin")
echo "binary size: $size bytes"
[ "$size" -le 65536 ]

file "$bin" | grep -q 'statically linked'

out=$($bin version)
[[ "$out" == *"zero-libc"* ]]

json=$($bin backup --dry-run)
[[ "$json" == '{"status":"dry-run","pipeline":"db_dump","libc":false}' ]]

set +e
$bin nope >/tmp/coolify-backup-asm-nope.out 2>/tmp/coolify-backup-asm-nope.err
code=$?
set -e
[ "$code" -eq 3 ]
grep -q 'invalid arguments' /tmp/coolify-backup-asm-nope.err

strace -f -e trace=write,exit_group "$bin" version >/tmp/coolify-backup-asm-strace.out 2>/tmp/coolify-backup-asm-strace.err
grep -q 'write(1,' /tmp/coolify-backup-asm-strace.err
grep -q 'exit_group(0)' /tmp/coolify-backup-asm-strace.err

objdump_file=${TMPDIR:-/tmp}/coolify-backup-asm-objdump-main.txt
objdump -drwC "$bin" > "$objdump_file"
[ -s "$objdump_file" ]
echo "objdump captured: $objdump_file"

echo "all coolify-backup-asm tests passed"