From 93cddf934b14989dd49224df5dd631acf9d7d6a7 Mon Sep 17 00:00:00 2001 From: airone01 Date: Wed, 3 Jun 2026 17:20:28 +0200 Subject: [PATCH 1/5] feat(libasm): ft_atoi_base --- pcc/libasm/Makefile | 2 +- pcc/libasm/src/ft_atoi_base.s | 143 ++++++++++++++++++++++++++++++++++ pcc/libasm/src/ft_read.s | 45 +++++------ pcc/libasm/src/ft_strcmp.s | 72 ++++++++--------- pcc/libasm/src/ft_strcpy.s | 34 ++++---- pcc/libasm/src/ft_strdup.s | 45 +++++------ pcc/libasm/src/ft_strlen.s | 26 +++---- pcc/libasm/src/ft_write.s | 45 +++++------ pcc/libasm/test.c | 86 ++++++++++++++++++++ 9 files changed, 365 insertions(+), 133 deletions(-) create mode 100644 pcc/libasm/src/ft_atoi_base.s diff --git a/pcc/libasm/Makefile b/pcc/libasm/Makefile index 1cc3ad61..1bf27b16 100644 --- a/pcc/libasm/Makefile +++ b/pcc/libasm/Makefile @@ -3,7 +3,7 @@ AR := ar ARFLAGS := rcs AS := nasm ASFLAGS := -f elf64 -Wall -Werror -SRC := strlen strcpy strcmp write read strdup +SRC := strlen strcpy strcmp write read strdup atoi_base SRC := $(addsuffix .s,$(addprefix src/ft_,$(SRC))) OBJ := $(SRC:.s=.o) diff --git a/pcc/libasm/src/ft_atoi_base.s b/pcc/libasm/src/ft_atoi_base.s new file mode 100644 index 00000000..ba7c1e44 --- /dev/null +++ b/pcc/libasm/src/ft_atoi_base.s @@ -0,0 +1,143 @@ + ; 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 + 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 diff --git a/pcc/libasm/src/ft_read.s b/pcc/libasm/src/ft_read.s index e7dab82b..0c31d7df 100644 --- a/pcc/libasm/src/ft_read.s +++ b/pcc/libasm/src/ft_read.s @@ -1,32 +1,33 @@ -; input: rdi -> file descriptor (int) -; input: rsi -> pointer to data buffer (const void*) -; input: rdx -> count of bytes of data to read (size_t) -; output: rax -> bytes read, -1 on error (size_t) + ; input: rdi -> file descriptor (int) + ; input: rsi -> pointer to data buffer (const void*) + ; input: rdx -> count of bytes of data to read (size_t) + ; output: rax -> bytes read, -1 on error (size_t) -; appendix B -default rel + ; appendix B + default rel + [warning -reloc-rel-dword] -section .text - global ft_read - extern __errno_location + section .text + global ft_read + extern __errno_location ft_read: - mov rax, 0 ; 0 is syscall no. for sys_read on Linux - ; all data already in place, we just call - syscall + mov rax, 0; 0 is syscall no. for sys_read on Linux + ; all data already in place, we just call + syscall - cmp rax, 0 - jl .lerror - ret ; after call rax will be nbytes read + cmp rax, 0 + jl .lerror + ret ; after call rax will be nbytes read .lerror: - neg rax ; invert code + neg rax; invert code - push rax ; appendix A - call __errno_location WRT ..plt ; appendix B - pop rcx ; pop back the saved code into rcx + push rax; appendix A + call __errno_location WRT ..plt; appendix B + pop rcx; pop back the saved code into rcx - mov [rax], ecx ; appendix C + mov [rax], ecx; appendix C - mov rax, -1 ; libc errors out with -1 - ret + mov rax, -1; libc errors out with -1 + ret diff --git a/pcc/libasm/src/ft_strcmp.s b/pcc/libasm/src/ft_strcmp.s index 1c5987cf..3e0463f1 100644 --- a/pcc/libasm/src/ft_strcmp.s +++ b/pcc/libasm/src/ft_strcmp.s @@ -1,46 +1,46 @@ -; input: rdi -> s1 pointer of NUL-terminated string -; input: rsi -> s2 pointer of NUL-terminated string -; output: rax -> int difference between data in pointers - -; Technically strcmp is expected to return: -; * 0 on s1 == s2 -; * any negative value on s1 < s2 -; * any positive value on s1 > s2 -; But this is an implementation closer to that of the libc. We return the -; difference between the first different character of each string. -; i.e. some optimized implementations (like Valgrind's) will return 0, -1 or 1. -; This is the reason you cannot compare the result of different strcmp -; implementations as a test, only the sign matters. -; @see strcmp(3) - -section .text - global ft_strcmp + ; input: rdi -> s1 pointer of NUL-terminated string + ; input: rsi -> s2 pointer of NUL-terminated string + ; output: rax -> int difference between data in pointers + + ; Technically strcmp is expected to return: + ; * 0 on s1 == s2 + ; * any negative value on s1 < s2 + ; * any positive value on s1 > s2 + ; But this is an implementation closer to that of the libc. We return the + ; difference between the first different character of each string. + ; i.e. some optimized implementations (like Valgrind's) will return 0, -1 or 1. + ; This is the reason you cannot compare the result of different strcmp + ; implementations as a test, only the sign matters. + ; @see strcmp(3) + + section .text + global ft_strcmp ft_strcmp: - ; xor is a fast way to bzero a reg - xor rax, rax - xor rcx, rcx + ; xor is a fast way to bzero a reg + xor rax, rax + xor rcx, rcx .find_loop: - mov al, byte [rdi] - mov cl, byte [rsi] + mov al, byte [rdi] + mov cl, byte [rsi] - ; early stop when any char diff - cmp al, cl - jne .done + ; early stop when any char diff + cmp al, cl + jne .done - ; just check rsi's because the previous check made sure they are the same - cmp al, 0 - je .done + ; just check rsi's because the previous check made sure they are the same + cmp al, 0 + je .done - inc rdi - inc rsi - jmp .find_loop + inc rdi + inc rsi + jmp .find_loop .done: - ; because rax and rcx were bzero'd, they hold only the exact positive - ; unsigned value of the characters, meaning subbing them correctly here - ; handles neg results as intended - sub rax, rcx - ret + ; because rax and rcx were bzero'd, they hold only the exact positive + ; unsigned value of the characters, meaning subbing them correctly here + ; handles neg results as intended + sub rax, rcx + ret diff --git a/pcc/libasm/src/ft_strcpy.s b/pcc/libasm/src/ft_strcpy.s index b1d4f27b..1b6e265f 100644 --- a/pcc/libasm/src/ft_strcpy.s +++ b/pcc/libasm/src/ft_strcpy.s @@ -1,27 +1,27 @@ -; input: rdi -> destination pointer -; input: rsi -> source pointer to NUL-terminated string -; output: rax -> original dest pointer + ; input: rdi -> destination pointer + ; input: rsi -> source pointer to NUL-terminated string + ; output: rax -> original dest pointer -section .text - global ft_strcpy + section .text + global ft_strcpy ft_strcpy: - mov rax, rdi ; dest ptr in rax + mov rax, rdi; dest ptr in rax .find_loop: - ; copy data byte - mov cl, byte [rsi] - mov byte [rdi], cl + ; copy data byte + mov cl, byte [rsi] + mov byte [rdi], cl - ; check if str end - cmp cl, 0 - je .done + ; check if str end + cmp cl, 0 + je .done - ; move to next dest and src bytes - inc rdi - inc rsi - jmp .find_loop + ; move to next dest and src bytes + inc rdi + inc rsi + jmp .find_loop .done: - ret ; rax still has original ptr + ret ; rax still has original ptr diff --git a/pcc/libasm/src/ft_strdup.s b/pcc/libasm/src/ft_strdup.s index 4dc808d4..f1fc93e6 100644 --- a/pcc/libasm/src/ft_strdup.s +++ b/pcc/libasm/src/ft_strdup.s @@ -1,32 +1,33 @@ -; input: rdi -> source pointer to NUL-terminated string -; output: rax -> original source pointer + ; input: rdi -> source pointer to NUL-terminated string + ; output: rax -> original source pointer -; appendix B -default rel + ; appendix B + default rel + [warning -reloc-rel-dword] -section .text - global ft_strdup - extern malloc ; byte size into rdi, allign stack - extern ft_strlen - extern ft_strcpy + section .text + global ft_strdup + extern malloc; byte size into rdi, allign stack + extern ft_strlen + extern ft_strcpy ft_strdup: - push rdi ; save original ptr - call ft_strlen WRT ..plt + push rdi; save original ptr + call ft_strlen WRT ..plt - inc rax ; ptr to NUL - mov rdi, rax ; setup for malloc + inc rax; ptr to NUL + mov rdi, rax; setup for malloc - call malloc WRT ..plt - cmp rax, 0 ; err handling - je .lerror + call malloc WRT ..plt + cmp rax, 0; err handling + je .lerror - mov rdi, rax ; setup for strcpy - pop rsi ; get back ptr + mov rdi, rax; setup for strcpy + pop rsi; get back ptr - call ft_strcpy WRT ..plt - ret + call ft_strcpy WRT ..plt + ret .lerror: - pop rdi ; appendix A - ret + pop rdi; appendix A + ret diff --git a/pcc/libasm/src/ft_strlen.s b/pcc/libasm/src/ft_strlen.s index df54dc06..c4da5bc9 100644 --- a/pcc/libasm/src/ft_strlen.s +++ b/pcc/libasm/src/ft_strlen.s @@ -1,21 +1,21 @@ -; input: rdi -> pointer to NUL-terminated string -; output: rax -> length (size_t) + ; input: rdi -> pointer to NUL-terminated string + ; output: rax -> length (size_t) -section .text - global ft_strlen + section .text + global ft_strlen ft_strlen: - mov rax, rdi ; save str ptr in rax + mov rax, rdi; save str ptr in rax .find_loop: - cmp byte [rdi], 0 - je .done - inc rdi - jmp .find_loop + cmp byte [rdi], 0 + je .done + inc rdi + jmp .find_loop .done: - ; rdi now points to NUL terminator - sub rdi, rax ; calc ptrs diff - mov rax, rdi ; ret len in rax - ret + ; rdi now points to NUL terminator + sub rdi, rax; calc ptrs diff + mov rax, rdi; ret len in rax + ret diff --git a/pcc/libasm/src/ft_write.s b/pcc/libasm/src/ft_write.s index 8d806b00..ab6e7ce4 100644 --- a/pcc/libasm/src/ft_write.s +++ b/pcc/libasm/src/ft_write.s @@ -1,32 +1,33 @@ -; input: rdi -> file descriptor (int) -; input: rsi -> pointer to data buffer (const void*) -; input: rdx -> count of bytes of data to write (size_t) -; output: rax -> bytes written, -1 on error (size_t) + ; input: rdi -> file descriptor (int) + ; input: rsi -> pointer to data buffer (const void*) + ; input: rdx -> count of bytes of data to write (size_t) + ; output: rax -> bytes written, -1 on error (size_t) -; appendix B -default rel + ; appendix B + default rel + [warning -reloc-rel-dword] -section .text - global ft_write - extern __errno_location + section .text + global ft_write + extern __errno_location ft_write: - mov rax, 1 ; 1 is syscall no. for sys_write on Linux - ; all data already in place, we just call - syscall + mov rax, 1; 1 is syscall no. for sys_write on Linux + ; all data already in place, we just call + syscall - cmp rax, 0 - jl .lerror - ret ; after call rax will be nbytes written + cmp rax, 0 + jl .lerror + ret ; after call rax will be nbytes written .lerror: - neg rax ; invert code + neg rax; invert code - push rax ; appendix A - call __errno_location WRT ..plt ; appendix B - pop rcx ; pop back the saved code into rcx + push rax; appendix A + call __errno_location WRT ..plt; appendix B + pop rcx; pop back the saved code into rcx - mov [rax], ecx ; appendix C + mov [rax], ecx; appendix C - mov rax, -1 - ret + mov rax, -1 + ret diff --git a/pcc/libasm/test.c b/pcc/libasm/test.c index ee02c684..3049889e 100644 --- a/pcc/libasm/test.c +++ b/pcc/libasm/test.c @@ -21,6 +21,9 @@ extern int ft_strcmp(const char *s1, const char *s2); extern ssize_t ft_write(int fildes, const void *buf, size_t nbyte); extern ssize_t ft_read(int fildes, void *buf, size_t nbyte); extern char *ft_strdup(const char *s); +extern int ft_atoi_base(char *str, char *base); +extern int g_invalid_base; +extern int g_no_match; void comp_ft_strcmp(const char *s1, const char *s2, const char *label) { int my_res = ft_strcmp(s1, s2); @@ -119,5 +122,88 @@ int main(void) { free(dup2); } + { +#define RESET_FLAGS() \ + do { \ + g_invalid_base = 0; \ + g_no_match = 0; \ + } while (0) + + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("123", "0123456789"), 123, + "ft_atoi_base: decimal positive"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("-456", "0123456789"), -456, + "ft_atoi_base: decimal negative"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("+42", "0123456789"), 42, + "ft_atoi_base: explicit positive sign"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base(" \t 99", "0123456789"), 99, + "ft_atoi_base: leading whitespace"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base(" -7", "0123456789"), -7, + "ft_atoi_base: whitespace then minus"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("++--9", "0123456789"), 9, + "ft_atoi_base: double negation cancels out"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("0", "0123456789"), 0, "ft_atoi_base: zero"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("ff", "0123456789abcdef"), 255, + "ft_atoi_base: hex ff"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("-ff", "0123456789abcdef"), -255, + "ft_atoi_base: hex negative"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("10", "01"), 2, "ft_atoi_base: binary 10 = 2"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("1111", "01"), 15, "ft_atoi_base: binary 1111 = 15"); + RESET_FLAGS(); + ASSERT_EQ(ft_atoi_base("z", "0z"), 1, "ft_atoi_base: custom two-char base"); + + /* invalid base: too short */ + RESET_FLAGS(); + ft_atoi_base("1", "0"); + ASSERT_EQ(g_invalid_base, 1, + "ft_atoi_base: base len 1 sets g_invalid_base"); + + /* invalid base: contains '+' */ + RESET_FLAGS(); + ft_atoi_base("1", "0+1"); + ASSERT_EQ(g_invalid_base, 1, + "ft_atoi_base: base with '+' sets g_invalid_base"); + + /* invalid base: contains '-' */ + RESET_FLAGS(); + ft_atoi_base("1", "0-1"); + ASSERT_EQ(g_invalid_base, 1, + "ft_atoi_base: base with '-' sets g_invalid_base"); + + /* invalid base: contains space */ + RESET_FLAGS(); + ft_atoi_base("1", "0 1"); + ASSERT_EQ(g_invalid_base, 1, + "ft_atoi_base: base with ' ' sets g_invalid_base"); + + /* invalid base: duplicate chars */ + RESET_FLAGS(); + ft_atoi_base("1", "001"); + ASSERT_EQ(g_invalid_base, 1, + "ft_atoi_base: duplicate base chars sets g_invalid_base"); + + /* no match: char not in base */ + RESET_FLAGS(); + ft_atoi_base("9", "01234567"); + ASSERT_EQ(g_no_match, 1, + "ft_atoi_base: digit outside base sets g_no_match"); + + /* no match: char mid-string not in base */ + RESET_FLAGS(); + ft_atoi_base("12x4", "0123456789"); + ASSERT_EQ(g_no_match, 1, + "ft_atoi_base: mid-string invalid char sets g_no_match"); + } + return 0; } From 046717b1469b8945b67691c9c98c9a3660f165d2 Mon Sep 17 00:00:00 2001 From: airone01 Date: Fri, 5 Jun 2026 10:23:23 +0200 Subject: [PATCH 2/5] feat(libasm): last bonus exercises --- pcc/libasm/Makefile | 12 ++-- pcc/libasm/src/ft_list_push_front_bonus.s | 35 +++++++++ pcc/libasm/src/ft_list_remove_if_bonus.s | 60 ++++++++++++++++ pcc/libasm/src/ft_list_size_bonus.s | 18 +++++ pcc/libasm/src/ft_list_sort_bonus.s | 54 ++++++++++++++ pcc/libasm/test.c | 82 ++++++++++++++++++++++ pcc/libasm/test_dbg | Bin 0 -> 49744 bytes 7 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 pcc/libasm/src/ft_list_push_front_bonus.s create mode 100644 pcc/libasm/src/ft_list_remove_if_bonus.s create mode 100644 pcc/libasm/src/ft_list_size_bonus.s create mode 100644 pcc/libasm/src/ft_list_sort_bonus.s create mode 100755 pcc/libasm/test_dbg diff --git a/pcc/libasm/Makefile b/pcc/libasm/Makefile index 1bf27b16..c31c4f2e 100644 --- a/pcc/libasm/Makefile +++ b/pcc/libasm/Makefile @@ -7,6 +7,9 @@ SRC := strlen strcpy strcmp write read strdup atoi_base SRC := $(addsuffix .s,$(addprefix src/ft_,$(SRC))) OBJ := $(SRC:.s=.o) +BONUS_SRC := $(addprefix src/ft_list_,push_front_bonus.s size_bonus.s sort_bonus.s remove_if_bonus.s) +BONUS_OBJ := $(BONUS_SRC:.s=.o) + TNAME := test TSRC := test.c # This tells the linker to create the ELF section and explicitly mark it as @@ -16,6 +19,9 @@ TLDFLAGS := -Wl,-z,noexecstack all: $(NAME) +bonus: $(NAME) $(BONUS_OBJ) + $(AR) $(ARFLAGS) $(NAME) $(BONUS_OBJ) + $(NAME): $(OBJ) $(AR) $(ARFLAGS) $(NAME) $(OBJ) @@ -23,7 +29,7 @@ $(NAME): $(OBJ) $(AS) $(ASFLAGS) $< -o $@ clean: - $(RM) $(OBJ) + $(RM) $(OBJ) $(BONUS_OBJ) fclean: clean $(RM) $(NAME) $(TNAME) @@ -36,6 +42,4 @@ $(TNAME): $(NAME) FORCE: -.PHONY: all clean fclean re test FORCE - - +.PHONY: all bonus clean fclean re test FORCE diff --git a/pcc/libasm/src/ft_list_push_front_bonus.s b/pcc/libasm/src/ft_list_push_front_bonus.s new file mode 100644 index 00000000..e9f5df79 --- /dev/null +++ b/pcc/libasm/src/ft_list_push_front_bonus.s @@ -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 diff --git a/pcc/libasm/src/ft_list_remove_if_bonus.s b/pcc/libasm/src/ft_list_remove_if_bonus.s new file mode 100644 index 00000000..6ccadf29 --- /dev/null +++ b/pcc/libasm/src/ft_list_remove_if_bonus.s @@ -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 diff --git a/pcc/libasm/src/ft_list_size_bonus.s b/pcc/libasm/src/ft_list_size_bonus.s new file mode 100644 index 00000000..f46505ed --- /dev/null +++ b/pcc/libasm/src/ft_list_size_bonus.s @@ -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 diff --git a/pcc/libasm/src/ft_list_sort_bonus.s b/pcc/libasm/src/ft_list_sort_bonus.s new file mode 100644 index 00000000..bf79440c --- /dev/null +++ b/pcc/libasm/src/ft_list_sort_bonus.s @@ -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 diff --git a/pcc/libasm/test.c b/pcc/libasm/test.c index 3049889e..e38331ca 100644 --- a/pcc/libasm/test.c +++ b/pcc/libasm/test.c @@ -25,6 +25,17 @@ extern int ft_atoi_base(char *str, char *base); extern int g_invalid_base; extern int g_no_match; +typedef struct s_list { + void *data; + struct s_list *next; +} t_list; + +extern void ft_list_push_front(t_list **begin_list, void *data); +extern int ft_list_size(t_list *begin_list); +extern void ft_list_sort(t_list **begin_list, int (*cmp)()); +extern void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), + void (*free_fct)(void *)); + void comp_ft_strcmp(const char *s1, const char *s2, const char *label) { int my_res = ft_strcmp(s1, s2); int std_res = strcmp(s1, s2); @@ -205,5 +216,76 @@ int main(void) { "ft_atoi_base: mid-string invalid char sets g_no_match"); } + { + t_list *list = NULL; + + /* ft_list_size: NULL list */ + ASSERT_EQ(ft_list_size(NULL), 0, "ft_list_size: empty list returns 0"); + + /* ft_list_push_front: single push */ + ft_list_push_front(&list, "hello"); + ASSERT_EQ(ft_list_size(list), 1, + "ft_list_push_front: size is 1 after one push"); + ASSERT_EQ(strcmp((char *)list->data, "hello"), 0, + "ft_list_push_front: data of first node is correct"); + + /* ft_list_push_front: second push goes to front */ + ft_list_push_front(&list, "world"); + ASSERT_EQ(ft_list_size(list), 2, + "ft_list_push_front: size is 2 after two pushes"); + ASSERT_EQ(strcmp((char *)list->data, "world"), 0, + "ft_list_push_front: new node is at front"); + ASSERT_EQ(strcmp((char *)list->next->data, "hello"), 0, + "ft_list_push_front: old node is second"); + + /* ft_list_push_front: third push */ + ft_list_push_front(&list, "!"); + ASSERT_EQ(ft_list_size(list), 3, "ft_list_size: three-element list"); + + /* ft_list_sort: sort ["!", "world", "hello"] ascending by strcmp */ + ft_list_sort(&list, (int (*)())ft_strcmp); + ASSERT_EQ(strcmp((char *)list->data, "!"), 0, + "ft_list_sort: first element after sort"); + ASSERT_EQ(strcmp((char *)list->next->data, "hello"), 0, + "ft_list_sort: second element after sort"); + ASSERT_EQ(strcmp((char *)list->next->next->data, "world"), 0, + "ft_list_sort: third element after sort"); + + /* ft_list_sort: already-sorted list is stable */ + ft_list_sort(&list, (int (*)())ft_strcmp); + ASSERT_EQ(strcmp((char *)list->data, "!"), 0, + "ft_list_sort: already-sorted list unchanged"); + + /* free the sorted list before remove_if tests */ + while (list) { + t_list *n = list->next; + free(list); + list = n; + } + + /* ft_list_remove_if: build ["a", "b", "a", "c"] using strdup data */ + list = NULL; + ft_list_push_front(&list, strdup("c")); + ft_list_push_front(&list, strdup("a")); + ft_list_push_front(&list, strdup("b")); + ft_list_push_front(&list, strdup("a")); + /* list is now: a -> b -> a -> c */ + + /* remove all "a" nodes */ + ft_list_remove_if(&list, "a", (int (*)())ft_strcmp, free); + ASSERT_EQ(ft_list_size(list), 2, + "ft_list_remove_if: size is 2 after removing two 'a' nodes"); + ASSERT_EQ(strcmp((char *)list->data, "b"), 0, + "ft_list_remove_if: first remaining node is 'b'"); + ASSERT_EQ(strcmp((char *)list->next->data, "c"), 0, + "ft_list_remove_if: second remaining node is 'c'"); + + /* remove all remaining nodes */ + ft_list_remove_if(&list, "b", (int (*)())ft_strcmp, free); + ft_list_remove_if(&list, "c", (int (*)())ft_strcmp, free); + ASSERT_EQ(list, NULL, + "ft_list_remove_if: list is NULL after removing all nodes"); + } + return 0; } diff --git a/pcc/libasm/test_dbg b/pcc/libasm/test_dbg new file mode 100755 index 0000000000000000000000000000000000000000..163fcdbb0bc0aadf7de6e962ea754d2b0f5b2588 GIT binary patch literal 49744 zcmeIb3wTu3^*6lF%$&)P011R}M~`Es`XZ@R9gkx3W^H+^>4A>YyXN>>qM$zRfJm2`&)bOb>_^;B=mj1_j{i2 zdA^=JlfBQn{MOoQU(P#fUCB*T*;|V)7?l(ZzyF_q~|HJ;FLY2l=OPqF6pB9PkJV0^}aJT zM=3c@nQz%ERD9t`5A{`aPVIUWn~GA!ub7{l?sde4^@vP*%e3Ayt;cDW*5j1pNim_{ zwwd^sBK1qE5S%*o_G>+7%JQ6Y?9clsR{4KoZ=u$E_!Q-kGc8eM!71BY1U-t&zq@fY zpR4WlR1e#AJUONMrfqUGvSxBqtiCZkxwf#jxVE;awyvc%bj77bk($e*Q>GRLtBO~( zG)!GnG$X&dHnK95UtCa9oIkZ_GIl1{R_516qRnga*G!+5Kdq#oslK3C;Zk!SfFCu} ze)whLM;rM|w#gmcC1iW$@>AKV&eHMAz%LCyYI^4|M9@ zsr=$e#oH82p^uSP)X-i-zV{lL!QwV!_a=K&WO_peh)t1)-ra5{*?6MN~D0 z!=fqHSlQel>KnpQQ5USOtq(zn8X&1Q#sYQ0NEDRNnqZ(R5)IZyt_X{ek_*+=H%Wj{ zT?0hIjg8Uz004rqNPScg1~t@a;>>w-XP+J@E|^kKV&xOLDT!=x!BjE1roJvbxv^++ zRcvy7bBu~XDRqOB{~vWCyLP0ep>kzSOG#tZnqXv2Bv{w7a_aQyS5$?jtiH5pMzA)& zIuyz;np#j?P>7C){ufy(0&^G74^)O5!_|?dSh#WV{L^deqv6HDm9=3MzPheHsv{Oq zqA3MYTW<6%13wRb^hbG9r?js&1N>`{<#8uAEP^g>it9CPP$Yux?h&`?{oic41zo}| z?$-Ow!%5yHeuaJ7_;|tNbOSXsYzy`Afa!&r?pvt%Oy~Xm3lyFDANxj>w`_Fkv%DR! z(RmyqUff29qt?ix1_|1(F=LXP%p zh}U_b3){Hav`UrhTnmFV0i_b1Xm9pXFhlKW$5pAPMv9dds- z?b9K>bG_UjNc(gs?`)9!>9kLW@Xkx*zKiy0O47Md?*H>tA*wpM#t}|c$C8TnkII&o zonN-3Z1H(0=(5U+O*6-hhj>N%ReLKomu8N}jX%X0}Zjgxu!RqsIv`Z*%@% zk;FTP3Q@M54)!~yklyB;ILLF`pQ+e9wbU=fPAY8CuJ|IDuh={)1ArCn@5LX38p4^m zVJhZbP&x~u^V&a?((!SSeVT%{b3OjW|MoqpPF)I-iuOHo+nqr7cj=7zg7Wg$k{tO98TkVs}r z+4`faGuvLlnN8XD)j-%W8~=)S$-=^Zf2hH}jP*p)Y5zEWE_tyz=Xk~1JBlPq_aKSK zQ3!B~6z4aJb3bujR-Ds_LoUA;|GlCtQL;BE*>;k>TXLqZlcbzVsq#(ydQfHHVJr$3 z3i04~U0r4E&$S-u%53`v=jKnL36QtT!EWCZKMSXdXd8nv+djv{j+ryToP$!F2yWSS z(%7*?s^v_CCDl0mh&nfp5*V4cxpX+0{1X)CwSON!L>^L=o-P|*&Uk2ARqBQU8Tj45 zy1L@m;@?x$XP~x|TKOL2$;@-{UlNG){RQ&fE)>5Jyd5h@aF6VZ2QXx{!M{W`ra>8jseooY1eK!0h~m7FGK#cc*1ku2vH?x> zDVj~sYd?$#PFF6bXSRKxEv=VrCuY&E9W;)>slk8%?ja zJZMAuL9}8kOn>>7!qgT2G19U2T21kVH7{QhGC>7hepOd7G#HR{Hi$yctGOJM(57%4~ZG&4&Fg+JyoL zKNOB9h4#bL6OQ~-_UyI?Niejx9G+bXL)>``h{L@} z!zn3kMY2bpA9B#+kD(E_9=S5J?SLFArY=#E%aO!y0k3R36>3KZ{=vuBC{Q5`z*GMT z0d9x=rOBzomFgHI4kPmcR5~3aM`qij%FJgpbZ;&_j3ho8+#NrH0aP&w!Or!TottcS z?mJ4%sgEh$ok$#ZK0;G#Ju)$~tw34Xs3dPDEBnAJ+dh#BbBij>nU;}!n~^eQWWG{e z(cQ>;X(W`{won;4UP+dakxFSKL`H5`M$#=Kdm+FP`^ynolDIrvlnQVhB^e=&9L;Ro zkBUc`pH`A@Ac=QjyxwsK;1Mr4OYwRMW0tCyl{PD@m6dCh?p7oYE58L&>k*6{du0=x zx=cwnla<@$Q9%wTTUAkRw2XWQ0WQh_Wn`36y&Z|e$U*?oIPf+`54d_9B)FN!U;9SJ zK`YPbuAB|!(k|G~Y}=tC@dXX+n@jsaHvY97@`%0TUghJ5;Hp3@hXDInr_4N|R9{Ep z@bO^)l^Td;X4^^1%ymlkK_u}Tz};~_3?Sengi_oLy0Sz5upLv`*`su?N8+$E2S}|) zT$yc8sDS@WNv=c^A1@0-vyvSTsluECvNA$YY~-%PGG?TMIGlmRVdOoG9ylmt^OG|=5j z@()PjE2I&cC+&Dd8M)Uo@+<_{$QxhFl7yA&4M-eDasV_hl!4Cvr*>;KgI8YM< zdOg75K@FL1Rgm)7wYl_^?vT%->=xv6xJINQcO*g5(Gie21X-vcJL!P5xipT%;bpxY z^85tk&LqeQ3i4U#$N%RmS@54I$eX)Ejn6D&Z?opU~0TBP- zOIh;IF}wluq3)Ptk}#jc8H4uo%_PiUD$E#R-U!U1u8KY78zCa%S%@8tHyt=TK~LQQ zNo%~Rgy_7@;f*L_He8@1^3P$gV$)R{<8L9;dISZTjeEvsdNB?!+j{Vbf8>1 zAcurb<-nDe11&ZOHUm*R@Et}Ga^M2(K&Fa9lih(83Gsf?-&r`3oF329Dvv3j8|*5R zz*9bdOFq}q$U;H82btC*?##A*IQNs3EufTbr%A?+FO<&Il*h4tS*<8b^zzu-X#V?h`SLIm> zGBt!LN@=J~DSlx>SI?M3!a|-?VxdwD&6kwi%H)8K^guW zvkPv4@bC+TYw<$Nk&o$fixvmZ?GAlDT>`jWyQz|l2U!Pnf zGA~$)R1@3?LYW(aNy_Ib<>|>`ZI{aZ9xI>{QE|?PO9)xKK^66O#ZZlSI)!5?81pvG z-#8yFtE~&|mnPUlQ8HZ+6wm`3fa*u$ID>oZkGbtE=-@KqbjCNG9yoLIHMfrW)BsV)Lo$ z)JaAuOTxdAO0Euah~Kp&`Ac$hbIt{52ewAHidex>AAPgEagc z4ngQc_5sLpXns!$=i#(serO*Fe{F*vubgO6&^M7}7oC+UcmHmad_+01KuOk+b2a4UncbJv`8QAfF^k6^f-sP1K5VPj9}|QZV{-zc zg&`Iyh(#7ewSuTgZW)URB8ZluLp_i?0Ia>P!qOiQC~O`{-j2d*$t;`Xl}hqMj2@8u z?jR(KWms}@!LfP#S7NZy?dN0m1kgBykA;p!^feENse? zh&5lH8swI-TyuXW)*14AA?Lni)=px*DJS4L=Owf5 zC031M`I1@f#QLY4tLA)!VZr8MlvvB?puah1U^44GV$G6q%sDBUHJw=hP^^C?M}HKt z8WpQE*$o%58dSNel35>jg7unmenhgZmx#3pjSwEbm2B(R#M-ZHIm&elv3?_GsX0GM z2E3A3XDHT!WY#6bdP~kjbNVK;%87NUV!e{=#zbO$qGI?2hA>-rGo_YdU6suGDo$Fe zTyv9IZxgE;EV^R$JzX=r6%!5`G?uDCV?WxnI%wPgO&&DvCbgfS$ypcLI<#6usgpbUupAUP>kSG&=VrxMGjTK#w&(rjA8iIoY!_^yw; zy6ApH(Wi6UUs+Mn{@04u4-YL|jFJ@XLr*S(U{}uZc|v?uRggKl4PMG|axN$po6Xsj z%s3Lu!L1B0<#8*cPuBrGFWSxXqs^tmr2N!@luY=(qWw_CGoPJS@yro-h4DhgE8oWk z0pRr$6o9YmKvm}GIYO{L`M185*rIvTl8V;S$0&=N46(iyn@XR+PW);VBVGw#Uod}# zedA*2Ch2!xPS*$2e2wl;(0z&V741vjs%URMfZG!B_!ES=2|Jsvins5Mzxg*gE^m0J zV$+hh$}+b;^UT4~h)UUnw>Rvg{P( zrFZ@cNU}U62cF@zc>6j#z^rILvi>v?Gb_6G96VexVGs6qC!$@2I|WCs>%TE`{ZSF~ zL8hYXg@d2l1Uf2k&?(w?UD|d1r|)gKe5TjP5sWM<8RGPInY{6k z`GmWAbHz8UM?I@EXZm9qGbhE;X685h%D#EGqHFiT1LZ|s5P<{!qJ48_bY4|hmife> zzSH-|JYCNm{H#3l(eKKPKa%9z$fLU-IXHZeSw2=h`d75;VBbCFDb`+D08`0}%PzW* z+b_y1Z}-X4?!=&l>%AXRl%DfZhv`?bDWjsj!Z)woU(xO+y+q~9c7y8O&=vC`zMIzh z4t}{?$1j12aLn5@Y5s;!W5shfl}peGb2nXu=3H3T^%^Q;?I687x4ju1XS#~Y{7rSf zgZs)i9BzJ^d||IU9Q8A|{q?!+FIQ}Gle2|5*PPe>x3aF+H|%O2K5x@0b2pvogWGdA zomSTM#ys2=`0RtOu7j_T_~vE4gL@Ov5Y~N9>rN*^@t^HK5%~XE1n6nT5f@G=uB%@) z;=;l@|G1`fQ4_{vr6>9?uWzia6jd=iCfQgUj{2Kw>YHmTiHt{4B{kI0!qmoathq7j zuM9WEq<&DL;AzP&@&1o~^8Rf%zJKf8Vsd48_2g)CZLL@g!AP{)4rid*O8sZaIliCNZW-)#ZyYAPCIG(41t`;M_x=SDHeWzAODOQNb*k-lP2Zo z&miq!tUeN08Egul?7t%1ST7RF!Ih!PaFs)*CcMU9RVDKAOI9XEG+d2GWmktqQK5so z5>MJTw)l$*{iXh5QG`ttULgu6A<4(jk6$5v+HttOrbOh5kXT8vFRD9xfsVa@JRTbl z`^QyIIN4vmrXd`Pg)9BzYAa9lSJ%fVgVPMP!MpC&;=eo+tMP~H8e*uI7##HOw5)IYYHH2f~Xw3iD^*{E{Z3+fM{<5Y> zUHxh*FA!}N9;!#>SD`Akr6j*dZoKqk0#{u_Z4lPaSu)S=e+s!M3d)Zrg#8WVCMjwA zbq$PHg9cIyf%>Kh)rr3{f;z*a3(C)Ka$I-Ek_%tfjAy1}bnYv+Zg>=9=N7({o*Lip6QD$;PWKO}pu3@x4;A3wn#tM@}b=3kA%qDxZ`w91?0 zkA})G^4CZGcw)R>7u4x@Q#eNKXnl7%*@2JY=D+7BAtmB$9~h)(emr;XZ)n7$@r|`y zf$-BV*OQx~3_T)R-5f-Bh}8sR{>u7rQ#3E;uL+`Uh4H9NORR>*D|8=J1lmY#i$5G} zilBZFOBk(g4A%K0QPRdxiD%*&NA{&T;b;`9=SE_onh1qjwJSWy&vhmr(GSMZurSVC z?yn2i)nh~nR#rBKo6uIe$;p)J{;1fNE{s2`3utB@tjRn|A-H32=~qv3~w7&>d4sDUY1 z2QH8Q82E7nD4OcD8*0X@M0Nhy<@Nd0mHl);Qb5UeiSDOkZIK@>waH%{h(u)PnvsYWFux=oQvt*f>0 zhDu!!okoY<5%;=CWxhJlq3fx!OvbmnGVImjJ&-^X-iJ9^A0ml>V<1gjn*20aVq>|6 z=BAoJRU>-U$$rwIj$h;tR-v_Hgu`(M{GQ}1gRvlu+EtN87>L%RNYD<|H#XvcF0J%# zr&!xTbCGt!s{c#>?S4_eWpoT#(pwFmvK;l8y|H{#7$XJ-Q!cNHORNU380Cj+!*w(X zAcIc4rus%iM3s!?R8)v#!;^B#ia&**Wmn2!Y;CMeC6@3{$^~m_FmK5xTR85@3T%#| z%A?g`b!1@NMvR}U!+}UuqWUmPq!jYH z&?yu`d8y=ODbPSLn9kERZ@GvuI^mu%!hH%gQxm_~Yh7Jb;<2xHbzP6N1nEmiKg5MJ znqs|%%hUHF9fTik#ueuZV@;MZqHmh71DD&0j+_3X1M;{?gUJ$nhxKI{=i&c}VBLY=C1eM8LM*xYH@a`|Y&Ng=wx+os$|8j_T)wn64{~IWVsPd; zON48^*hMrHNp8%ied5!GyL|G!NxAd?(m#Gbi{Hm$f3DH?@W`axcIdRPPWh!Q++mR0 z5ef{pVJflS1H-*zx#8NW+;BTlZu~wN)g^7rr#R5oK!wNl_4i%%l+xW(+9-asZPXcD z2b9|(&F2%1TXjLW4seH0Zg{LCY13+=W`QERH208BslCvKYmsuJDyOYMJIwUkbcW0E zmJ*Zi%Tku@;|Vgku^jFL$@0NnNy5{Aa=$|3;nE-Tr5{551WaS- zeM&JCV5&A%tk+La=pEX~0c~0K;uMD80DvhBsXUsd<)hqZ4pw2N*q_EdMXUBPd=)U) z$CY*iC7!g)DDkD$Qet?|l00(}r2QTfuf~FBehZ9TU)ImT^E^A^67bTmz(0sD0%;88 zv+hOC{AkD=VqT4Z$J3?Utb0K9o|8>?Jb-f;I51TWV*2ku8awC@$PQbM?4Uj14X50= z_d&}tMrM75ot($8GpZUnk#jBzbsQ0WB7HxSEDw0bXgB3gC_vslqVMNOBnZ&Fq z^fu(i--v%+>1NvhAe;8P{>|Y1f~e$$7J zN5mqVB8}o|43+*ObSD!!NJ6m2Gh<*))<^c$AD=>B|Pb&_gdt{gkl6F zV_d)4;H499$N&(0RfaUNf;B`MWsMw(vzDn|x__c@CVmL(eI9l7+d@oLf)a3zZ0XR$ zM3wa*y&CdM?Dx6H)t>}ui3Tr~Oa2pSL*RfhFq7PSm(@gC9(L19q*wnWsw@YAp;FI= zM%o>cmxHX$P+A3n4U(+FWY(k@l#L>jfSi5HxMRb~I3&*oYhfDhi!_Pp85C*U8JDX8 zWY&ur1IYLp_|3vEvneW0k(3`|ZykO^SK;4j>4f9nvVNV%kM8*dZsgNuSh+!pAWF?| z;GKIignkLqgZR1rOG{G_3}cB=Y#57OS0THok9&NvRumHWRSTGN<23(NGlD~u1l|qO zGX#7j1#lnt`XZ$w@lPt`opW8jQw?L8>jyBr+_e^DY4OB?T0n4)VnbV*`7B#}2fJ_M z=bEjhQx#=la#0ppz?|cv%r*;f5S2yw5};oY@ah!6j-ss5_=bU^%%-CFR_j8%oC^$s z5uBq|Mq8PAJKM^jhK--=ke0R=!eNWcB5jqymVr3Rcztb|;@m`K303dGq(Bzyc$mp0 zQ^Ut7W-q3=1xQn+c2i??z+8fJJgJ#&Ud*OWfteX(YPy!To8nf+q0?nJdA#zQ03+{Yc) z%~hC>XdxOFMxnP7!dj=$ak`-p(kXT!7tTmrYc+Q*xTO9A6tsT;|9qG~W>!^-^ZL** zL8Em9KTj$8=~r6EuyWi3&g=goEV$=E=mALIho5^Hc6K2{wu^og()MC;jJO^&aJtn+Imh$u3)8-4V49wtLBON5^et!=vbh|vA}*`)3JZ;M z>?R_D6AT%Vi-2?ip>=5KRBm!8w3|0;QA2Q!fmfLKGjI%`jRgG5UVynibsKq`$64`n zM0jbM7pFba%j*Gj9f5tXCG1{0+BUa4*|wMJ5zstAH@_7?DFm$Q&T`0DWA(B{=msWt zFp|8WS4nz-h&GbE$}Z_z2mD1C^LTmqzcE_MYCILvGx2lL zLwU5lt9+Gn7)Ld3wQ2>&=NhU;_$y6qvrKVL6GSBK1f0lAQ|H6XVlwqy3RB$uE-6uN z=;oKjE{l&qkECs2uqc3P32dsC=*4fwl+7=qo1gT%K`Xli=eXO{q`k|gu7#O4GIebV zQ|vd#25qNC7mr3Ydbf~jo?6Xfd8}K6pqcmEM8>8NK{I_xi%>J2X^99IM?|7KkWoMK zfX73rM{rIzXA$oIdtk`}-km7Y9r(!u-V@0DhRR5<6VhfK@NTjyeX%t~I;4dR!MO=a zOEj4DsI#o@7XbGhK@QVbMtZ5C?IlWI)=&d#C~*+U)7pmMoF2TyW#*6A*1NFt7qT_) z*tQPXZCysKfe#|P$0{#ef^*y&8qB}5slzby6`6WlOWTXZt%1vbsIE5)L!&};h4$jvWFz3eT zGPIf<4E!g6?kC_O+N!-pI?9kWP3g-rwA#z?^6`p;Gc29sq4#Q2VEB+__ylI+Wa_Y% z>BSTmMVh*rOcmk0)EYw=!4#b1R@`bXXL~N3NeKL0ea9;A?DjZjTqYf}0b0~0IL8HP zG3iBRS&-oX9ZJA6QUE(*#_dWLq@`Oy7{L^rkzkZZIUT<|pXs zKFlKIN3HYWI zz>ccU!l8gRS=ArNs@A4{WtD+*T!s%#AHpch&<-;{Bva3%FvYbzOWV-E2dy%2j?2(# zHZkze0lJldv-MSedvF|OSYt0kCzYXCn<~)ChTt5R;S=*EHnjt0o+MMVQ<&m1Jdj+5 zpasl12L8J_4)--=a9#oE9|^d*7vQ&&fwyW=lwRjJIA53@4BQFOj|q5B3SdWY1de4^ z1%E-onWBU9FRg3{&gsq}zBW7Al!2=S^fsGopl;;$df?!U*ETe8krp)s=Qudun6q&* zDT6Z%z(eqJmG=U?Fd4YU0_Ge8A2ol9n(+8$#^b?(>r=&$bd{)TSs($;fY z+Yp@NLSz{`*j5YdTu!$BoWd5@XVxh~ZxYzZReOfu90LzD1`gMS*aFZS33!N>wikkd zXC(ulZvk^|jJ7+}Sj)f<0`z_YUXudY5uFB&FQYS5Mu*N2s3uO<(6~UTb9|BWsM*Q3 zo`Id6WGkR$?1gaH;wB_V&ZATjY^qW#8-jCe>Kk+M2pzAtVdhOT)qZSK+zq6uZ|tUS zuuO4|O?_zYWK&iT1w;$cmi`d*uogTrEL^2s?iHPD~~stn-OFtd(KwWOE~I{Fol5isRWAIN=J z+FGl%4Z%6Km1R7_wr+==Tglcv$F{`-owSveWa|OT7U$5N({XJDA{^C zg)JWRc*xcRQDB^caS6^b@E7JK47?AZdkDB$OWOw`2IfP%2Htpr0yYHa7`W5i!NBhW z^gRN;Q%k1;<_VPszQ+RQ90Pw~4)p6#90lk%1iYgcV4iJa-E$g~myG97aE^h88mkz1 z0IoS_;^$hWrBiv#13yj}{Cavx_pGl02&VaT5p;nj)BWxH71^b4*Ia;sTW-E(HeDaj zunEZgh33#{$N{O2`#hGSx!;Cv=JL6Pys|sOLVw$i&U0UheuAEg5&Ef89q5*#x!lIS znAr*AZJJF*yC&KA6-8XM&02`;`FL(AjlZoqzX0bcyShBXnxH2;Kpy&x4brFu=s!t96@Ce@33rfj&0p;rejE#1^YSdY$aRI9oyD+yRF-$t&p~5;FL;7 zSm!3_{X5LnY-vzyvsH+83FigRpgr+G7*dJtylM!#$Ku}vMYo7!nN^@U}Mb8PB)Q%usOdIn~8 zk||oG_86tgnyy4-*LvP=YK~Sm1n1b)i{>geMeAC=Nv0ylHZ{v`>P5S$+bmO@V^gn~ zZ?LH^VCHi&^@n4dT4Oi$irv)TEmNFhQ*WAOc#vH-_C9!8APqm)06hinr3G%Yn|f25 zl20AotEV^^4lr{mG4EpdTtJT|_V0CRWHzy=QPwBf3y&N1-w=3WN=H9#LF;2~NjRgAeyYv7R4lhk_Qo+e5&`y#Vu6LIa;<0dtOlJIpH>_KIN33yyDz(HV*-A- z7hs-7Yma|z0dtOlaZ13zMn9Yq5b&N}fcabi7rD|0DA)J8gm@kx@_Ni5^a{C|e0_k} zA9iQ2uxbBGv0Y6-y=|b<|Ha9;%2T3I`RbLtAhKASzy*pv?gtQWW$!VYVw4pVvbO6` zQgOef_?%7gcBKeU=y^2y4;x1;(RXd4e_|UeEq`F+5^D#Few0f&$B$T3sWPVOQdL^A zP)zJVaiOJn&R~V`5#}%_vEtKq#mDuIF!_20$%c+0`?wAFMwWdxHSQ}m+20*QcEpf` zzaO*gp47N}nS%Vy#xY1XpdMt`+i*`~*%wpe@+AqvU3CoEk8HTNvh1HyvX0-e_lsIf z_FbFo6qaq)Y)4zaH&^vHI@+AAWaZ(6PtM4<%Nc{imyF@-&=+3h7mbHq0YG}-eE1w> z`UtsC!?)Zo5|dAN!}~n1^W|3K4!T!0qNzya-UP*598`zkH=+rvJP~0DcFxAH@Iveu zd1XXv$NoC}GUD)leA;r5p2Y6sL|O~d1WEdD?7m2(KcOs>B#EBE{xgw|gVc$VbQrt; zz)zk7@7Gu34Ee5Kf&2DT^dzD$o^npdZ{(L+!alW3x<>E5e4$sKlHw#tVjj^Nc$EZx z7PvnEW)Z#am+toHdfYlPOP>rU!!jR-`JZSMddtxbWwZnLmSwQC*u7<;SGXS3e7aNQ z;E7RrAi81{CVG7-`$@U$zZLrf#3*`U);)=sRmA)qg5{o+O<~TyR#Gn7w$E6Rk#TB=X1hk4JI4XEiyTP0ya=PD=p{t&l{$k%{G%n2PM4A?K?O7G)UnU>3){W zxdZ2BPsbT2t{=#v=ekjjT!YZi#jJRk_IM0UU{ZAS>|rlVmcM&I89~8}9xY87gYz+X*&<8Bqj`>lcss(+&oS92A^H zC+KL{8iEiLEqxgc74AtEQ8yW?*jYobkT568y42N1CCbk*h)*W)O=kos;}l?7t!8pE zm>sInUah)i7s*x**kW>b=CEjg)ktvPFhM{h?izr`j<@0KsIM5tw^;of33@QD%TR8# zCk=VJ10BI{KYlJ_v?~+C9dCn4a5ViJPyY(>&qZ&Cy36R_S@e(I>vUg)f5xShYs5eF zFsvWIL%I6|!*pkx72W|IX4cu}fPH4x)u!7!*&N^n!+U`_jM59uVP~4-&oW1pnrWwi zTxyO0c~X^`HWPcNVwpsbYnjJo8txYa#0Pl{6K!M1Is>$H_a1T9%$Y<2g`|k$_r*ZL z*P}fU+%5%sRMx6*u<9~|$IL<@4rHlNxC;%_^!f%7n(rF?cYE)Y-aI3G1#rhq_Zk4f zcd0#Y_aD~z{1R!mnCUAZvKKTXn+jogKg55Rw?k_0l4T)fAGr^?r`H*S%}f-1@W*E6 zPeCaiWDdrzd4W0j4(!TE7~W+PWvQc4VlelSaJX@iEC z{ZT>dR;k`<_C`QGiBnGJ8o%H<=6;lPv~PO-8o& z8We7@Dks&ex78dZQy<rhy28UWzl4``4v6yR&Zp8hJLGJWx z4DXw-d#kR|UCXXfY4uCjc&#!V$lmO3@(;@v9Zbki(DI{F%PWsoB;*<2-<$k}-Q|z( zO@3KIp8YwYH~A$AdG=>QDtVVzRnWN{Q670tM04mdIt#m_7oup9qu~hprC4P%eoF8U$~Y(#Y!+rP#y=kb#`>a{0#oe;W8O=Q+LQO zQ$t?Y4e~3j0HbYJ!ArKiv76xG)V5o@+y0hHE(cx1>!YIcu-&zmTMHityHZ>KE+MF= z1XmlDn|IpW{I;7Q-mn|2#@1xphZB-C#`cvU?&~qdq4|vaALd9(yfe)cWqOu5ozi7W z5Ci;$=4dZw3{CRDGMbJC;2X=lzXDzFJk`t2HeYM^rtr75-I~H}iE`Q__hGX4IB@+W zA!t7`{pq+2qPCe6(3tD?y3bTxYqEyng}5}wfo?!?M<*JIO%?Sj zkrOqp$0l;e>%Q7h6XQh7Nn(E{6g$zSlGvS^ee=2)_f0iVRN!5jooK&F+J`ke(Pxs_ zUukxt?Ltpa{S!H*sWql)qt2~sHj*oh=0flKiY?$LAVs(nmYKFaZFv_ z9118;V^~qmW3-wzfk~(#)@V_(DiUoi$>X2s0wvmPf(?&v)9k-ljW7X@lawnYHqX;A zA(9Qm>s~GC!*%sMl_*6&@`a~t3JMd#uyS#j)t0PA3LEnj)0)309Dsi~Ns*;{CUII~ zv*yO&CfTit0n!#y_oa$!&5G4Pr|POkRpnsICrc4N;rJqP6Nes472J1p8%i9*?A+Hi zH*qkubN{HhiKD8;MR6x6r=TD+1u|*4)Hg#?CEOxYmrw;vqiM74M90 zHo=>wconI5C5m@eDqfM|%}>Qc8>Yc^VS*<+hZ>}Us{M@Gn;5Fqxnod`)T8x4Es1o- zB(XBOi8m?neztKPL8?&V)_HWI%Ycc4hXhL;S9CvwXJ9ufu61swJGJ4y&oEqAmC@+7 zeyyl)j8qqkKwxEaq!yoO2sB_-X6(v^>8k>v8r#Poq-+tbX=|C^J3mH6|k{rL-u{rOc3=bn!LO|f8TRelJcMySchitaJ2)*Qj&-}zPa<%s+c*5b`? zZVFfCH-@X5N@cFP0T#5L)~Ii!6{+j7PH=t|{G!#VL$Q4NqCr({{pE@%optz$UHalh zep5JHS-LtJDhU;?ZVaB}&(Fu_27+~^O-&8?2wqhf_*jp+w1ny;7^@Lj52sjE2dss% z>sqkLH5N%nt-v@UFRHMpv$gOrDT`Y2PyVBdQcGi75{V_IMN_O&fvMVuNi41(4d9~z z!6r*yF8rMQEdRLBsy&!wn~06AJ6sKWx?Oe+?l+Ipix2^&5UOhs(eN6C6m7jABqrD3LjaQ- zizZjaCO3palWQYb7rjnQjz-o@#)|Nb;mMayk2E%h3hNry6c*2@yu7fnE?C)gX-jSO zNi|c7TB4!+YUqUWiwjDM^QRW&)Av*GosQb(%JAfs5p+x&R8uHe*icn6?b5n6tAizl zmj!E9g)VPtni?vqUA<~rv^c*y6v|hNx{@Q4u{#+ZAuz2Zzd5=pT7P*oA73A7UXx!P zZJw;@D2-RXwRtD0Ua=glqL{AmR;XVmncTV2Cx8ia%Z64t<7J58ix{QlFPx?3JBH5I8 zUmlWs@}JH(E~2Z`*lh9}{OQ)Zep{h)U!Hw`Z{E>-+rCtm01qY`yx3UbdC7m+k7P^! z!}-Pv81nJbn}clk+lX$hmzi!YfVq|E)~c2cd23NhySz*IUd~nijB(I;wa0M|Ixo#Q z*p3ezURg1TZWR?7Z#r%+(B=^%5Z)0_7zpUi$89?f$@;N3jRozdvA2!I-m?>qPLNUd z@pCi)<&_3yAuYPAXe$tXydv6oyR!&JyEd5=JjlPV=@T6C*1~*tItn+MZU$mYDjev% z2wt}LF1q`On-9XrOW7sK!WUkNE{P6bcvZBdKoeH-=3O{Q5jW*b#wy7k{NPon`g-sBIoBeuC6y#g_jGyl z^4eM+v43c~+lPmrXxr-fY}hx)+4q0se*~jLg8!j^JseByx1VtD3HJS+Cp>50SFrf+ zU7?HR5!tAd>`T#89v`)P6!N=A9Uf&3ORV7KuDAm6O_d^hy9k@o#tM_mht z6a2eJ|6#O!|I5)gj%_4Z zb+O9>$6AxcLARDvanP+5QS5ZsZSl*f2&diWG(9Pduxsd}kdtmL{b8>TR1+`Lk<`V3 z!)t0d>AV0&5*>c-)B}4G9XOpm(0LsQr#vs(;H2{k3rTeN&&wes(P5XDE^yL$nSrGE z0EbrzNTLIWU-Ea-`5pZvI&k(P2i*HQ2MOlp!maQK?Tx_brwsVg;Hmk(pji=mi45wNa|EborOxLLhGn`srO#} zl%PIA%fT@hZIYiI9TC&ifCje2X7cF`ou5*u{gQqOe6#1da390})=Mz$02+o>%?%=6deWdp6Ir zGyl)|!sHVekJ#t({PMULj`Q3y_K~rkYsdY5oae0xH%?3}^2~62%7WRSXYd4J@@a!d zWO@cdo+r&7aihy~ZSH^PdS1x;F33KP;Gt2YMz+Yv1o*Vq$U}5rjp^?(~*{TjB zjh|53hIh$&*${A4*cV++kvC~bCvW$-Dp^T5i*7tCbIOo68TNr#rPQ_NAUNSBoY7G@FV;N2Tq5SA7p*MiRB+f zCRMq1N`ZbNo8LRt3a@JVCdL9%TIC0du2iTi8&5>4(O@;8K>pXcgWMzcUZwk zT+{%KAqiFQ9Tw zchEo9^l}HCJ{UmqiyibFm!elY=#w5UHha!udtpf_v!O%6JJEQ$QN*+IWg z)9-Z9pVstk4*Hv#{(A?Vp2H^m=N#Mu823&Do#Odh zhy3Z9{-J|@fu?`zpkLMl{*|B`crN|{dBr0UPs*k8r(Mbq7S8XK-6ZX1iHB*xv~9nT z@xe4ej6@l zX>Dgey#S!cd8SwNfU_KQ@}FOYVEK@w54DaLOuv+HT>S-q&yVR18mGbGe+$X8kS+bO zlpiJrIsCjwt@)u9MJuCg3gZx zeE=R!=kLz3NDY$9dVcV+-fx4@1TDs%hgYG z=y}2k+HRee=lOspix$wSogc_j6#n|%T1jWAM7m42|Ah|!Zh)*f)SflhIA z`ty6x{Rwkc?hVFww3B!b_}_v)#?nq?2IEovfv$84YVvkos4-SlP>=g$!IhCf3^(!g zy)V#LhN~md^T4bOp@Of~TPl=ysu0boQrD1BLB5*`Xm%BOw^V7U zY_0sVIXgi&RTWp}l9}pmuVoH*ehZQXtef;oCb5gp!$)yzo<2&A!rSOI;n1o8-33h| z137?iHHRC!lOs{wXYWpy_e7I0aJw2XvH}wJ=q)TfXb`T7tVzZQR<5QmaHr%cd9)PN zRgww$QE9766INs$NMrnxR1pK}hZ ztjD*=Rn0h9Ni9V3@`q(LPRIOE*1`Q?G~bLIpBA~0w9Ic4+b zo(?h|EeVuYXl})vb4B3Hc?)Kj%?m6zCdJpXhW2p0$O zsd+(9*(3=oO!)*tSUvK9b{ip6>WK>Ha|xDmiSw}tt6->4^>~9NOI|VC_SlDd(jrL; zLouGaQ02$n`bIqIki-Xy)iDr->bm-<4i>5=P}x);z(=|(QP9BL1z=R-!6JHsMu!eV z0iFt?$2*chZBMmesILUj%BCjmgM5g{{#cTwIR&q{!5#Sk3O(;(F;qPw?A&CiKKQ_t zR2v)65fd}u}HMP{mf-8~68dX}uIr(%_gDAkW76mnU z;7AlywnQPW(paP7;HjY|dc;JE>74+0jp5oLDd=27ZA_r2!ejxm1=aP)#ON^;I^IMe zR4-dlL6|;iPshrdN`UYlzH5PJoummo!_*LNjJ0S|+3dObbVQff>Nu((IS&_tb&(L9 zriXG0P&=XkkHgT{<3S6rY_5hReViS1wHt|6)pI_$a%E$9HSgislQ8EICC(BVRi4k;%Z1_4#|=oZhA#CLbxw`ZyDk8{OxoBC|ey zhln;#Z*>&du`5a;OW)dNeg3{Sr(+}-&y_;_@qBu%klTgIXz_4#~Z=j;wRsA1s&69wefser_{de8^?iZ zHONp*S>LbqINipAI(5Jc>IZiH{aS!imS-3)Kc_!%==1pvr$a`vrb?Z7*Esa~{FhVP z%e@l7S^kY$pX-m$137(=8nW}qn7GMWk&1ovVO(oWU_M6jB zz_IIF*LP+q6}H0wtjGI@kRck|=kx5WSxUmG?~MP~5F`7AO5FO-`p#<=Bug8oSpM0{ zONRb8W|qq6MD5@|>oK7p2u>RDR?edTSYO0(JS1Elz2S)97vz6C_{zdDR z!oB*LNUh#Ye~Q+3#!uX&G?w;YpUZ*w( Date: Fri, 5 Jun 2026 20:11:12 +0200 Subject: [PATCH 3/5] ci(gha): exact zig version --- .github/workflows/zig-build.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/zig-build.yml b/.github/workflows/zig-build.yml index 466bcda5..3b0dad41 100644 --- a/.github/workflows/zig-build.yml +++ b/.github/workflows/zig-build.yml @@ -18,8 +18,24 @@ jobs: sudo apt-get install -y \ libx11-dev \ libxext-dev \ - libreadline-dev \ - nasm + libreadline-dev + - name: Cache NASM + id: cache-nasm + uses: actions/cache@v4 + with: + path: ~/nasm-install + key: nasm-3.01-${{ runner.os }} + - name: Build and install NASM + if: steps.cache-nasm.outputs.cache-hit != 'true' + run: | + wget https://www.nasm.us/pub/nasm/releasebuilds/3.01/nasm-3.01.tar.gz + tar xzf nasm-3.01.tar.gz + cd nasm-3.01 + ./configure --prefix=$HOME/nasm-install + make -j$(nproc) + make install + - name: Add NASM to PATH + run: echo "$HOME/nasm-install/bin" >> $GITHUB_PATH - name: Install Zig uses: mlugg/setup-zig@v2 with: From 8e101bef68aa364a3fde94a90935cfd46d93ebdf Mon Sep 17 00:00:00 2001 From: airone01 Date: Fri, 5 Jun 2026 21:34:38 +0200 Subject: [PATCH 4/5] chore(libasm): organize sources --- .github/workflows/zig-build.yml | 20 ++++++------------ pcc/libasm/Makefile | 4 +++- pcc/libasm/build.zig | 5 +---- .../{ft_atoi_base.s => ft_atoi_base_bonus.s} | 0 pcc/libasm/test_dbg | Bin 49744 -> 0 bytes 5 files changed, 11 insertions(+), 18 deletions(-) rename pcc/libasm/src/{ft_atoi_base.s => ft_atoi_base_bonus.s} (100%) delete mode 100755 pcc/libasm/test_dbg diff --git a/.github/workflows/zig-build.yml b/.github/workflows/zig-build.yml index 3b0dad41..5d5e3b8c 100644 --- a/.github/workflows/zig-build.yml +++ b/.github/workflows/zig-build.yml @@ -19,23 +19,17 @@ jobs: libx11-dev \ libxext-dev \ libreadline-dev - - name: Cache NASM - id: cache-nasm - uses: actions/cache@v4 - with: - path: ~/nasm-install - key: nasm-3.01-${{ runner.os }} - name: Build and install NASM - if: steps.cache-nasm.outputs.cache-hit != 'true' run: | - wget https://www.nasm.us/pub/nasm/releasebuilds/3.01/nasm-3.01.tar.gz - tar xzf nasm-3.01.tar.gz - cd nasm-3.01 - ./configure --prefix=$HOME/nasm-install + 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 - - name: Add NASM to PATH - run: echo "$HOME/nasm-install/bin" >> $GITHUB_PATH + echo "$HOME/.local/bin" >> $GITHUB_PATH + nasm --version - name: Install Zig uses: mlugg/setup-zig@v2 with: diff --git a/pcc/libasm/Makefile b/pcc/libasm/Makefile index c31c4f2e..9fedc766 100644 --- a/pcc/libasm/Makefile +++ b/pcc/libasm/Makefile @@ -3,7 +3,9 @@ AR := ar ARFLAGS := rcs AS := nasm ASFLAGS := -f elf64 -Wall -Werror -SRC := strlen strcpy strcmp write read strdup atoi_base +SRC := strlen strcpy strcmp write read strdup +SRCB := atoi_base list_push_front list_size list_sort list_remove_if +SRC += $(addsuffix _bonus,$(SRCB)) SRC := $(addsuffix .s,$(addprefix src/ft_,$(SRC))) OBJ := $(SRC:.s=.o) diff --git a/pcc/libasm/build.zig b/pcc/libasm/build.zig index e87b11b6..83c17e1c 100644 --- a/pcc/libasm/build.zig +++ b/pcc/libasm/build.zig @@ -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, .{ diff --git a/pcc/libasm/src/ft_atoi_base.s b/pcc/libasm/src/ft_atoi_base_bonus.s similarity index 100% rename from pcc/libasm/src/ft_atoi_base.s rename to pcc/libasm/src/ft_atoi_base_bonus.s diff --git a/pcc/libasm/test_dbg b/pcc/libasm/test_dbg deleted file mode 100755 index 163fcdbb0bc0aadf7de6e962ea754d2b0f5b2588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49744 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 Date: Sat, 6 Jun 2026 03:04:35 +0200 Subject: [PATCH 5/5] fix(libasm): last minute patches --- pcc/libasm/Makefile | 16 ++++++++-------- pcc/libasm/src/ft_atoi_base_bonus.s | 3 +++ pcc/libasm/src/ft_read.s | 4 ++-- pcc/libasm/src/ft_strdup.s | 12 +++++++++--- pcc/libasm/src/ft_write.s | 4 ++-- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/pcc/libasm/Makefile b/pcc/libasm/Makefile index 9fedc766..5f7d99b6 100644 --- a/pcc/libasm/Makefile +++ b/pcc/libasm/Makefile @@ -3,14 +3,14 @@ AR := ar ARFLAGS := rcs AS := nasm ASFLAGS := -f elf64 -Wall -Werror + SRC := strlen strcpy strcmp write read strdup -SRCB := atoi_base list_push_front list_size list_sort list_remove_if -SRC += $(addsuffix _bonus,$(SRCB)) SRC := $(addsuffix .s,$(addprefix src/ft_,$(SRC))) OBJ := $(SRC:.s=.o) -BONUS_SRC := $(addprefix src/ft_list_,push_front_bonus.s size_bonus.s sort_bonus.s remove_if_bonus.s) -BONUS_OBJ := $(BONUS_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 @@ -21,8 +21,8 @@ TLDFLAGS := -Wl,-z,noexecstack all: $(NAME) -bonus: $(NAME) $(BONUS_OBJ) - $(AR) $(ARFLAGS) $(NAME) $(BONUS_OBJ) +bonus: $(NAME) $(OBJB) + $(AR) $(ARFLAGS) $(NAME) $(OBJB) $(NAME): $(OBJ) $(AR) $(ARFLAGS) $(NAME) $(OBJ) @@ -31,7 +31,7 @@ $(NAME): $(OBJ) $(AS) $(ASFLAGS) $< -o $@ clean: - $(RM) $(OBJ) $(BONUS_OBJ) + $(RM) $(OBJ) $(OBJB) fclean: clean $(RM) $(NAME) $(TNAME) @@ -39,7 +39,7 @@ fclean: clean re: fclean $(MAKE) all -$(TNAME): $(NAME) +$(TNAME): bonus $(NAME) $(CC) $(TSRC) $(TLDFLAGS) $(NAME) -o $(TNAME) FORCE: diff --git a/pcc/libasm/src/ft_atoi_base_bonus.s b/pcc/libasm/src/ft_atoi_base_bonus.s index ba7c1e44..6fad61ad 100644 --- a/pcc/libasm/src/ft_atoi_base_bonus.s +++ b/pcc/libasm/src/ft_atoi_base_bonus.s @@ -41,6 +41,9 @@ ft_atoi_base: 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 diff --git a/pcc/libasm/src/ft_read.s b/pcc/libasm/src/ft_read.s index 0c31d7df..0017c0c5 100644 --- a/pcc/libasm/src/ft_read.s +++ b/pcc/libasm/src/ft_read.s @@ -3,8 +3,8 @@ ; input: rdx -> count of bytes of data to read (size_t) ; output: rax -> bytes read, -1 on error (size_t) - ; appendix B - default rel + ; appendix B + default rel [warning -reloc-rel-dword] section .text diff --git a/pcc/libasm/src/ft_strdup.s b/pcc/libasm/src/ft_strdup.s index f1fc93e6..ce9ba273 100644 --- a/pcc/libasm/src/ft_strdup.s +++ b/pcc/libasm/src/ft_strdup.s @@ -1,8 +1,9 @@ ; input: rdi -> source pointer to NUL-terminated string ; output: rax -> original source pointer - ; appendix B - default rel + extern __errno_location + ; appendix B + default rel [warning -reloc-rel-dword] section .text @@ -29,5 +30,10 @@ ft_strdup: ret .lerror: - pop rdi; appendix A + ; RSP is 16-byte aligned here (one push rdi at entry, one call ft_strlen + ; one call malloc — net effect: aligned), so we can call directly. + call __errno_location WRT ..plt + mov dword [rax], 12; ENOMEM = 12 + xor eax, eax; return NULL + pop rdi; balance the initial push rdi ret diff --git a/pcc/libasm/src/ft_write.s b/pcc/libasm/src/ft_write.s index ab6e7ce4..933e7f22 100644 --- a/pcc/libasm/src/ft_write.s +++ b/pcc/libasm/src/ft_write.s @@ -3,8 +3,8 @@ ; input: rdx -> count of bytes of data to write (size_t) ; output: rax -> bytes written, -1 on error (size_t) - ; appendix B - default rel + ; appendix B + default rel [warning -reloc-rel-dword] section .text