Skip to content
Merged
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
14 changes: 12 additions & 2 deletions .github/workflows/zig-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@ jobs:
sudo apt-get install -y \
libx11-dev \
libxext-dev \
libreadline-dev \
nasm
libreadline-dev
- name: Build and install NASM
run: |
export NASM_VER="3.01"
wget https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VER}/nasm-${NASM_VER}.tar.gz
tar xzf nasm-${NASM_VER}.tar.gz
cd nasm-${NASM_VER}
./configure --prefix=$HOME/.local
make -j$(nproc)
make install
echo "$HOME/.local/bin" >> $GITHUB_PATH
nasm --version
- name: Install Zig
uses: mlugg/setup-zig@v2
with:
Expand Down
16 changes: 11 additions & 5 deletions pcc/libasm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ AR := ar
ARFLAGS := rcs
AS := nasm
ASFLAGS := -f elf64 -Wall -Werror

SRC := strlen strcpy strcmp write read strdup
SRC := $(addsuffix .s,$(addprefix src/ft_,$(SRC)))
OBJ := $(SRC:.s=.o)

SRCB := atoi_base list_push_front list_size list_sort list_remove_if
SRCB := $(addsuffix _bonus.s,$(addprefix src/ft_,$(SRCB)))
OBJB := $(SRCB:.s=.o)

TNAME := test
TSRC := test.c
# This tells the linker to create the ELF section and explicitly mark it as
Expand All @@ -16,26 +21,27 @@ TLDFLAGS := -Wl,-z,noexecstack

all: $(NAME)

bonus: $(NAME) $(OBJB)
$(AR) $(ARFLAGS) $(NAME) $(OBJB)

$(NAME): $(OBJ)
$(AR) $(ARFLAGS) $(NAME) $(OBJ)

%.o: %.s Makefile FORCE
$(AS) $(ASFLAGS) $< -o $@

clean:
$(RM) $(OBJ)
$(RM) $(OBJ) $(OBJB)

fclean: clean
$(RM) $(NAME) $(TNAME)

re: fclean
$(MAKE) all

$(TNAME): $(NAME)
$(TNAME): bonus $(NAME)
$(CC) $(TSRC) $(TLDFLAGS) $(NAME) -o $(TNAME)

FORCE:

.PHONY: all clean fclean re test FORCE


.PHONY: all bonus clean fclean re test FORCE
5 changes: 1 addition & 4 deletions pcc/libasm/build.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
const std = @import("std");

const src_dir = "pcc/libasm/src";
const asm_sources = &[_][]const u8{
"ft_strlen.s", "ft_strcpy.s", "ft_strcmp.s",
"ft_write.s", "ft_read.s", "ft_strdup.s",
};
const asm_sources = &[_][]const u8{ "ft_strlen.s", "ft_strcpy.s", "ft_strcmp.s", "ft_write.s", "ft_read.s", "ft_strdup.s", "ft_atoi_base_bonus.s", "ft_list_push_front_bonus.s", "ft_list_remove_if_bonus.s", "ft_list_size_bonus.s", "ft_list_sort_bonus.s" };

fn nasmAtLeast3(b: *std.Build) bool {
const result = std.process.run(b.allocator, b.graph.io, .{
Expand Down
146 changes: 146 additions & 0 deletions pcc/libasm/src/ft_atoi_base_bonus.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
; input: rdi -> str, rsi -> base
; output: rax -> integer value, sets g_invalid_base or g_no_match on error

; Callee-saved layout:
; rbx = current str pointer
; r12 = base pointer
; r13d = base length
; r14d = sign (+1 or -1)
; r15d = accumulated result

default rel
[warning -reloc-rel-dword]

section .bss
global g_invalid_base
global g_no_match
g_invalid_base: resd 1
g_no_match: resd 1

section .text
global ft_atoi_base

ft_atoi_base:
push rbx
push r12
push r13
push r14
push r15

mov rbx, rdi
mov r12, rsi

; --- count base length, reject '+', '-', ' ' ---
xor r13d, r13d

.count_base:
movzx eax, byte [r12 + r13]
test al, al
jz .check_len
cmp al, '+'
je .invalid_base
cmp al, '-'
je .invalid_base
; whitespace: 9-13 (\t \n \v \f \r)
lea ecx, [eax - 9]
je .invalid_base
cmp al, ' '
je .invalid_base
inc r13d
jmp .count_base

.check_len:
cmp r13d, 2
jl .invalid_base

; --- reject duplicate chars in base ---
xor r14d, r14d; i = 0

.dup_outer:
cmp r14d, r13d
jge .no_dups
movzx ecx, byte [r12 + r14]; cl = base[i]
lea r15d, [r14d + 1]; j = i + 1

.dup_inner:
cmp r15d, r13d
jge .dup_next
movzx eax, byte [r12 + r15]
cmp al, cl
je .invalid_base
inc r15d
jmp .dup_inner

.dup_next:
inc r14d
jmp .dup_outer

.no_dups:
; --- skip leading whitespace and parse sign ---
mov r14d, 1

.skip_prefix:
movzx eax, byte [rbx]
; whitespace: 9-13 (\t \n \v \f \r)
lea ecx, [eax - 9]
cmp ecx, 4
jbe .advance_prefix
cmp al, ' '
je .advance_prefix
cmp al, '+'
je .advance_prefix
cmp al, '-'
jne .prefix_done
neg r14d

.advance_prefix:
inc rbx
jmp .skip_prefix

.prefix_done:
; --- convert each digit ---
xor r15d, r15d

.digit_loop:
movzx eax, byte [rbx]
test al, al
jz .apply_sign
; find al in base
xor ecx, ecx

.find_digit:
cmp ecx, r13d
jge .no_match
movzx edx, byte [r12 + rcx]
cmp al, dl
je .digit_found
inc ecx
jmp .find_digit

.digit_found:
imul r15d, r13d
add r15d, ecx
inc rbx
jmp .digit_loop

.apply_sign:
imul r15d, r14d
mov eax, r15d
jmp .return

.invalid_base:
mov dword [rel g_invalid_base], 1
xor eax, eax
jmp .return

.no_match:
mov dword [rel g_no_match], 1
xor eax, eax

.return:
pop r15
pop r14
pop r13
pop r12
pop rbx
ret
35 changes: 35 additions & 0 deletions pcc/libasm/src/ft_list_push_front_bonus.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
; input: rdi -> begin_list (t_list **), rsi -> data (void *)
; output: (none) — prepends a new node to the list

; appendix B
default rel
[warning -reloc-rel-dword]

section .text
global ft_list_push_front
extern malloc

ft_list_push_front:
push rbx
push r12
sub rsp, 8; 2 pushes + 8 = 24 bytes total: (8+24)%16=0, aligned for call

mov rbx, rdi; rbx = begin_list
mov r12, rsi; r12 = data

mov rdi, 16; sizeof(t_list)
call malloc WRT ..plt

add rsp, 8
test rax, rax
jz .done

mov rcx, [rbx]; rcx = old *begin_list
mov [rax + 8], rcx; new->next = old head
mov [rax], r12; new->data = data
mov [rbx], rax; *begin_list = new node

.done:
pop r12
pop rbx
ret
60 changes: 60 additions & 0 deletions pcc/libasm/src/ft_list_remove_if_bonus.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
; input: rdi -> begin_list (t_list **), rsi -> data_ref (void *)
; rdx -> cmp (fn ptr), rcx -> free_fct (fn ptr)
; output: (none) — removes all nodes where cmp(node->data, data_ref) == 0

; appendix B
default rel
[warning -reloc-rel-dword]

section .text
global ft_list_remove_if
extern free

ft_list_remove_if:
push rbx
push r12
push r13
push r14
push r15; 5 pushes = 40 bytes: (8+40)%16=0, aligned for call

mov rbx, rdi; rbx = cursor (t_list **), walks &(*node)->next
mov r12, rsi; r12 = data_ref
mov r13, rdx; r13 = cmp
mov r14, rcx; r14 = free_fct

.loop:
mov rax, [rbx]; rax = current node
test rax, rax
jz .done

mov rdi, [rax]; cmp(node->data, data_ref)
mov rsi, r12
call r13

test eax, eax
jnz .skip

; match: unlink then free data then free node
mov r15, [rbx]; r15 = node to remove
mov rax, [r15 + 8]
mov [rbx], rax; *cursor = node->next

mov rdi, [r15]
call r14; free_fct(node->data)

mov rdi, r15
call free WRT ..plt; free(node)
jmp .loop; re-check new *cursor without advancing

.skip:
mov rax, [rbx]; advance cursor to &(node->next)
lea rbx, [rax + 8]
jmp .loop

.done:
pop r15
pop r14
pop r13
pop r12
pop rbx
ret
18 changes: 18 additions & 0 deletions pcc/libasm/src/ft_list_size_bonus.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; input: rdi -> begin_list (t_list *)
; output: eax -> number of elements (int)

section .text
global ft_list_size

ft_list_size:
xor eax, eax

.loop:
test rdi, rdi
jz .done
inc eax
mov rdi, [rdi + 8]; node = node->next
jmp .loop

.done:
ret
54 changes: 54 additions & 0 deletions pcc/libasm/src/ft_list_sort_bonus.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
; input: rdi -> begin_list (t_list **), rsi -> cmp (fn ptr)
; output: (none) — sorts list ascending via cmp, swapping data pointers

section .text
global ft_list_sort

ft_list_sort:
push rbx
push r12
push r13
push r14
push r15; 5 pushes = 40 bytes: (8+40)%16=0, aligned for call

mov rbx, rdi; rbx = begin_list
mov r12, rsi; r12 = cmp function pointer

.outer:
xor r14d, r14d; swapped = 0
mov r13, [rbx]; r13 = curr = *begin_list

.inner:
test r13, r13
jz .check
mov r15, [r13 + 8]; r15 = next = curr->next (save before call clobbers rax)
test r15, r15
jz .check

mov rdi, [r13]; cmp(curr->data, next->data)
mov rsi, [r15]
call r12; rax = return value; r13 (curr) and r15 (next) survive

cmp eax, 0
jle .advance

mov rdi, [r13]; swap data pointers
mov rsi, [r15]; r15 still holds next (callee-saved)
mov [r13], rsi
mov [r15], rdi
mov r14d, 1; swapped = 1

.advance:
mov r13, [r13 + 8]; curr = curr->next (r13 still holds old curr)
jmp .inner

.check:
test r14d, r14d
jnz .outer

pop r15
pop r14
pop r13
pop r12
pop rbx
ret
Loading
Loading