Skip to content

Instantly share code, notes, and snippets.

@DeadlySurgeon
Created May 7, 2026 22:35
Show Gist options
  • Select an option

  • Save DeadlySurgeon/86b0a735d2f2b4ddc1f1da97fdf170cf to your computer and use it in GitHub Desktop.

Select an option

Save DeadlySurgeon/86b0a735d2f2b4ddc1f1da97fdf170cf to your computer and use it in GitHub Desktop.
Ring Buffer
%define RB_CAPACITY (50)
struc ring_buffer
.head: resq 1
.tail: resq 1
.limit: resq 1
.buffer: resb RB_CAPACITY
endstruc
section .data
read_rb:
istruc ring_buffer
at ring_buffer.head, dq 0
at ring_buffer.tail, dq 0
at ring_buffer.limit, dq RB_CAPACITY
at ring_buffer.buffer, times RB_CAPACITY db 0
iend
write_rb:
istruc ring_buffer
at ring_buffer.head, dq 0
at ring_buffer.tail, dq 0
at ring_buffer.limit, dq RB_CAPACITY
at ring_buffer.buffer, times RB_CAPACITY db 0
iend
section .text
; Input:
; %rdi = &ring_buffer
; Output:
; %rax = pointer
; %rdx = length
; Clobbers:
; %r8
; %r9
; %r10
rb_read_span:
mov r8, [rdi + ring_buffer.head] ; Head
mov r9, [rdi + ring_buffer.tail] ; Tail
mov qword r10, [rdi + ring_buffer.limit]
; If the tail is at the limit, skip padding and wrap.
cmp r9, r10
jne .tail_ok
xor r9, r9
mov [rdi + ring_buffer.tail], r9 ; setting the tail to be zero
mov qword [rdi + ring_buffer.limit], RB_CAPACITY ; Reset the limit to RB_CAPACITY
mov r10, RB_CAPACITY ; Limit is now RB_CAPACITY
.tail_ok:
cmp r8, r9
je .empty
; Load where the tail is
lea rax, [rdi + ring_buffer.buffer + r9]
cmp r8, r9
jae .head_after_tail
mov rdx, r10
sub rdx, r9
ret
.head_after_tail:
mov rdx, r8
sub rdx, r9
ret
.empty:
xor rax, rax
xor rdx, rdx
ret
; Input:
; %rdi = &ring_buffer
; %rsi = length
; Output:
; %rax = pointer
; Clobbers:
; %r8
; %r9
; %r10
; %r11
rb_write_span_len:
; If the length requested is zero, fail.
test rsi, rsi
jz .fail
; If the length requested is bigger than the capacity, fail.
cmp rsi, RB_CAPACITY - 1
ja .fail
mov r8, [rdi + ring_buffer.head]
mov r9, [rdi + ring_buffer.tail]
mov r10, [rdi + ring_buffer.limit]
; if the limit != RB_CAPACITY, we already have an artificial wrap.
; In that state head must be before tail, only [head ... tail-1] is writable
cmp r10, RB_CAPACITY
jne .artificial_wrap_active
cmp r8, r9
jb .head_before_tail
.head_after_or_equal_tail:
; try head ... RB_CAPACITY
mov r11, RB_CAPACITY
sub r11, r8
; if tail == 0, reserve one byte
test r9, r9
jnz .check_end_space
dec r11
.check_end_space:
cmp r11, rsi
jae .use_current_head ; We can use this.
; not enough at end, try wrapping to [0...tail-1]
test r9, r9
jz .fail
mov r11, r9
dec r11
cmp r11, rsi
jb .fail ; Not enough space.
; Abandon [head ... RB_CAPACITY] as padding.
; Reader will stop at limit=head and then wrap tail to 0
mov [rdi + ring_buffer.limit], r8
xor r8, r8
mov [rdi + ring_buffer.head], r8
lea rax, [rdi + ring_buffer.buffer]
ret
.head_before_tail:
; writable span is [head .. tail-1]
mov r11, r9 ; Load tail
sub r11, r8 ; Subtract tail
dec r11 ; Minus one
; If the data is too little, return failure
cmp r11, rsi
jb .fail
; Should be good to go
jmp .use_current_head
.artificial_wrap_active:
; limit < RB_CAPACITY means tail side readable region ends at limit
; The writer has already wrapped, so only [head ... tail-1] is safe
cmp r8, r9
jae .fail
mov r11, r9
sub r11, r8
dec r11
cmp r11, rsi
jb .fail
; Head == %r8
.use_current_head:
lea rax, [rdi + ring_buffer.buffer + r8]
ret
.fail:
mov rax, -1
ret
; Input:
; %rdi = &ring_buffer
; %rsi = amount
; Clobbers:
; %rax
; %rcx
rb_advance_tail:
mov rax, [rdi + ring_buffer.tail]
mov rcx, [rdi + ring_buffer.limit]
add rax, rsi ; Add the amount
cmp rax, rcx ; Check if we've gone over.
jb .store ; Good to go
cmp rax, rcx
jne .overflow_advance
xor rax, rax ; zero out the tail.
mov qword [rdi + ring_buffer.limit], RB_CAPACITY
.store:
mov [rdi + ring_buffer.tail], rax
ret
.overflow_advance:
; consumed crossed limit. Convert excess into new tail position.
; excess = rax - limit
sub rax, rcx
mov qword [rdi + ring_buffer.limit], RB_CAPACITY
mov [rdi + ring_buffer.tail], rax
ret
; Input:
; %rdi = &ring_buffer
; %rsi = amount
; Clobbers:
; %rax
rb_advance_head:
mov rax, [rdi + ring_buffer.head] ; Load the RB's current head
add rax, rsi ; Add the amount
cmp rax, RB_CAPACITY ; Check if we've gone over.
jb .store ; Good to go
sub rax, RB_CAPACITY ; Trim the fat
.store:
mov [rdi + ring_buffer.head], rax
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment