Compare commits

...

20 Commits

Author SHA1 Message Date
eec7ce3900 Merge branch 'main' into update-libc.obj
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 1m6s
Build system / Build (pull_request) Successful in 16m59s
2026-02-20 14:32:42 +00:00
2a5f192267 libc.obj: fix strtok && update change path to exit code
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 1m33s
Build system / Build (pull_request) Successful in 10m23s
2026-02-20 18:16:15 +05:00
89e26439d5 Merge branch 'update-libc.obj' of https://git.kolibrios.org/Egor00f/kolibrios into update-libc.obj
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 39s
Build system / Build (pull_request) Successful in 16m21s
2026-02-19 12:03:06 +05:00
eacda328be libc.obj: Added saving/reading of exit status && update system
idk why, but tests don't run `exit` after `main`
2026-02-19 12:03:03 +05:00
97e7404c9e libc.obj: add strtok_s
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 47s
Build system / Build (pull_request) Successful in 17m25s
2026-02-16 23:12:22 +05:00
7505baa105 libc.obj: some small changes
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 50s
Build system / Build (pull_request) Successful in 16m34s
кусок кода в `realloc`, провереющий на свободную ноду безсмысленен, т.к. в `free` в любом случае сливает освобождаемую ноду с предыдущей.
2026-02-04 17:49:44 +05:00
cb29ecffb7 libc.obj: fixes and optimizations for allocator && add new samples to sh build
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 41s
Build system / Build (pull_request) Successful in 16m37s
fix: in `__mem_MERGE_MEM_NODES` `base->free = base->size`, its wrong.
forgot to set size for new block
optimization: add `__last_mem_node`. usually  its node with max free space among other nodes. firstly `malloc` try find space in it.
update(fix and optimizations) `realloc`.
now sdltest is working!
2026-02-04 12:42:00 +05:00
8e6c43113a libc.obj: translate crt0.asm
Some checks failed
Build system / Build (pull_request) Failing after 1s
Build system / Check kernel codestyle (pull_request) Successful in 1m14s
2026-01-24 11:20:51 +05:00
eee5a71fdd Merge branch 'update-libc.obj' of https://git.kolibrios.org/Egor00f/kolibrios into update-libc.obj
Some checks failed
Build system / Build (pull_request) Failing after 2s
Build system / Check kernel codestyle (pull_request) Successful in 1m12s
2026-01-22 21:31:40 +05:00
169b4642ef libc.obj: add malloc test && use SHELL in system && direct call exit in crt0.asm 2026-01-22 21:30:39 +05:00
e9ab6eee9d Merge branch 'main' into update-libc.obj
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 1m9s
Build system / Build (pull_request) Successful in 17m12s
2026-01-19 16:36:07 +00:00
de8b5f9993 libc.obj: small fixes
Some checks failed
Build system / Build (pull_request) Failing after 1s
Build system / Check kernel codestyle (pull_request) Successful in 1m7s
2026-01-19 21:34:18 +05:00
2818bf25e2 libc.obj: add system
Some checks failed
Build system / Build (pull_request) Failing after 2s
Build system / Check kernel codestyle (pull_request) Successful in 1m20s
2026-01-19 21:21:42 +05:00
16b520dd67 Merge branch 'main' into update-libc.obj
Some checks failed
Build system / Build (pull_request) Failing after 2s
Build system / Check kernel codestyle (pull_request) Successful in 1m10s
2026-01-17 15:01:48 +00:00
61633d4dcc libc.obj: update comments
Some checks failed
Build system / Build (pull_request) Failing after 2s
Build system / Check kernel codestyle (pull_request) Successful in 1m8s
2026-01-17 13:16:07 +05:00
15f27eb1c3 libc.obj: add call exit after main && add build for ctr0.o && use return instead exit in samples
Some checks failed
Build system / Build (pull_request) Failing after 1s
Build system / Check kernel codestyle (pull_request) Successful in 1m18s
нен работает
по стандартам после `main` должно быть закрыте всего, что закрывается в `exit`
ну терпите, crt увеличиласть на несколько байт
обертка для `exit` в crt нужна т.к. `exit` импортируется.

зачем вообще было держать бинарь `libc.obj/lib/crt0.o`, если абсолютно такой же лежит в `bin/lib/` всемсте `tcc`? Нет, зачем вообще тащить бинари в репку?
2026-01-15 21:19:10 +05:00
9a559fdae4 update malloc/calloc/realloc/free && update build scripts 2026-01-14 14:19:10 +05:00
bb59eac8d6 libc.obj: update malloc/free/realloc
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 1m7s
Build system / Build (pull_request) Successful in 15m52s
гавно говна, нужно доработать
2026-01-14 00:03:55 +05:00
8322ec954b libc.obj: add void abort(), int atexit( void (*func)(void) ), EXIT_ SUCCESS/FAILURE
Some checks failed
Build system / Build (pull_request) Failing after 1s
Build system / Check kernel codestyle (pull_request) Successful in 1m12s
2026-01-10 23:20:18 +05:00
0e4c573cb5 add strpbrk to EXPORTS
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 1m12s
Build system / Build (pull_request) Successful in 16m3s
видимо в экспорт забыли добавить
2026-01-08 16:53:10 +00:00
43 changed files with 1039 additions and 72 deletions

View File

@@ -52,7 +52,10 @@ atol
atoll
atof
calloc
_exit
exit
atexit
abort
free
itoa
labs
@@ -65,6 +68,7 @@ rand
qsort
strtod
__assert_fail
system
;____STRING____
memchr
memcmp
@@ -86,6 +90,7 @@ strrev
strspn
strstr
strtok
strtok_r
strxfrm
__errno
;____SYS____

View File

@@ -0,0 +1,6 @@
.vscode/*
.tup/*
*.o
*.kex
*.obj

View File

@@ -11,6 +11,9 @@
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define EXIT_SUCCESS 0 // Successful execution of a program
#define EXIT_FAILURE 1 // Unsuccessful execution of a program
typedef struct {
int quot;
int rem;
@@ -48,7 +51,15 @@ DLLAPI void free(void* ptr);
DLLAPI long int strtol(const char* str, char** endptr, int base);
DLLAPI void _exit(int status);
#ifndef _Exit
#define _Exit(status) _exit(status)
#endif
DLLAPI void abort();
DLLAPI void exit(int status);
DLLAPI int atexit(void (*func)(void));
DLLAPI void srand(unsigned s);
DLLAPI int rand(void);
@@ -68,4 +79,6 @@ DLLAPI int abs(int);
DLLAPI long labs(long);
DLLAPI long long llabs(long long);
DLLAPI int system(const char* command);
#endif

View File

@@ -32,6 +32,8 @@ DLLAPI char* strrchr(const char* s, int c);
DLLAPI size_t strspn(const char* s1, const char* s2);
DLLAPI char* strstr(const char* s1, const char* s2);
DLLAPI char* strtok(char* s1, const char* s2);
DLLAPI char* strtok_r(char* s1, const char* s2, char** saveptr);
DLLAPI char* strerror(int errnum);
DLLAPI size_t strlen(const char* s);
DLLAPI char* strrev(char* str);

View File

@@ -27,7 +27,10 @@ BIN = \
libc_test.kex \
pipe.kex \
defgen.kex \
futex.kex
futex.kex \
atexit_test.kex \
malloc_test.kex \
system_test.kex
all: $(BIN)

View File

@@ -7,4 +7,6 @@ int main()
{
assert(a != b);
assert(a == b);
return 0;
}

View File

@@ -0,0 +1,18 @@
#include <stdlib.h>
#include <stdio.h>
void f()
{
static int c = 1;
printf("exit #%d\n", c);
c++;
}
int main()
{
atexit(&f);
atexit(&f);
atexit(&f);
return 0;
}

View File

@@ -23,5 +23,7 @@ cp clayer/logo.png /tmp0/1/tcc_samples/logo.png
../tcc defgen.c -o /tmp0/1/tcc_samples/defgen
../tcc pipe.c -o /tmp0/1/tcc_samples/pipe
../tcc futex.c -o /tmp0/1/tcc_samples/futex
../tcc malloc_test.c -o /tmp0/1/tcc_samples/malloc_test
../tcc atexit_test.c -o /tmp0/1/tcc_samples/atexit_test
"/sys/File managers/Eolite" /tmp0/1/tcc_samples
exit

View File

@@ -5,4 +5,6 @@ int main()
msgbox* msg1 = NULL;
msg1 = kolibri_new_msgbox("Title", "Text in window", 0, "Ok");
kolibri_start_msgbox(msg1, NULL);
return 0;
}

View File

@@ -43,7 +43,7 @@ int main()
case KSYS_EVENT_BUTTON:
if (_ksys_get_button() == 1)
exit(0);
return 0;
break;
};
}

View File

@@ -18,4 +18,5 @@ int main()
}
(*con_exit)(0);
return 0;
}

View File

@@ -41,4 +41,6 @@ int main()
path = getcwd(NULL, PATH_MAX);
printf("Move to the directory: %s\n", path);
free(path);
return 0;
}

View File

@@ -47,4 +47,5 @@ int main(int argc, char** argv)
puts("TEST: FAIL!");
}
fclose(f);
return 0;
}

View File

@@ -55,5 +55,5 @@ int main()
close(sock);
puts("\n goodbye)\n");
exit(0);
return 0;
}

View File

@@ -86,5 +86,5 @@ int main()
printf(asctime(libc_tm));
puts("End testing.");
exit(0);
return 0;
}

View File

@@ -0,0 +1,296 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "../source/stdlib/_mem.h"
#define RUN_TEST(func) \
do { \
printf("---\tRUN TEST: %s\t---\n", #func); \
if (func()) { \
printf("[SUCCESS]\tTest %s is ok.\n\n", #func); \
} else { \
printf("[FAIL]\tTest %s failed.\n\n", #func); \
exit(EXIT_FAILURE); \
} \
} while (0)
// c between a and b
#define IN_RANGE(a, b, c, len) ((a > c && c > b) || ((a > c + len && c + len > b)))
bool test_malloc_basic_allocation()
{
void* ptr = malloc(sizeof(int));
if (ptr)
free(ptr);
return ptr;
}
bool test_malloc_zero_bytes()
{
return malloc(0) == NULL;
}
bool test_malloc_multiple_allocations()
{
void* ptr[512];
for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) {
ptr[i] = malloc(i);
if (ptr[i] == NULL) {
return false;
}
}
for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) {
for (int j = 1; j < sizeof(ptr) / sizeof(*ptr); j++) {
if (i != j) {
if (ptr[i] == ptr[j]) {
printf("ptrs[%d] == ptrs[%d].\n", i, j);
return false;
} else if (IN_RANGE(
(char*)GET_MEM_NODE_HEADER(ptr[i]) + GET_MEM_NODE_HEADER(ptr[i])->size,
(char*)GET_MEM_NODE_HEADER(ptr[i]),
(char*)GET_MEM_NODE_HEADER(ptr[j]),
GET_MEM_NODE_HEADER(ptr[j])->size)) {
printf("node %p in node %p", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[j]));
// additional info
printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %p\n", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[i])->size, GET_MEM_NODE_HEADER(ptr[i])->free, GET_MEM_NODE_HEADER(ptr[i])->next, GET_MEM_NODE_HEADER(ptr[i])->last);
printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %p\n", GET_MEM_NODE_HEADER(ptr[j]), GET_MEM_NODE_HEADER(ptr[j])->size, GET_MEM_NODE_HEADER(ptr[j])->free, GET_MEM_NODE_HEADER(ptr[j])->next, GET_MEM_NODE_HEADER(ptr[j])->last);
exit(EXIT_FAILURE);
}
}
}
}
for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) {
free(ptr[i]);
}
return true;
}
bool test_malloc_data_integrity()
{
const char* As = "AAA";
const char* Cs = "CCC";
char* A = (char*)malloc(10);
char* B = (char*)malloc(10);
char* C = (char*)malloc(10);
if (!A || !B || !C) {
printf("can't alloc\n");
free(A);
free(B);
free(C);
return false;
}
strcpy(A, As);
strcpy(C, Cs);
free(B);
if (strcmp(A, As) != 0) {
printf("A data is broken after free(B). A = '%s'\n", A);
free(A);
free(C);
return false;
}
if (strcmp(C, Cs) != 0) {
printf("C data is broken after free(B). C = '%s'\n", C);
free(A);
free(C);
return false;
}
free(A);
free(C);
return true;
}
bool test_malloc_large_allocation()
{
void* ptr = malloc(1024 * 1024 * 16); // alloc 16mb
if (ptr)
free(ptr);
return ptr;
}
bool test_malloc_allocation_and_free()
{
free(malloc(sizeof(int)));
return true;
}
void fill_buffer(void *ptr, size_t size, unsigned char pattern) {
if (ptr) {
memset(ptr, pattern, size);
}
}
bool check_buffer(void *ptr, size_t size, unsigned char pattern) {
if (!ptr) {
return false; // Нельзя проверить NULL
}
unsigned char *byte_ptr = (unsigned char *)ptr;
for (size_t i = 0; i < size; ++i) {
if (byte_ptr[i] != pattern) {
fprintf(stderr, "Ошибка: Байт %zu не соответствует паттерну. Ожидалось %02X, получено %02X\n",
i, pattern, byte_ptr[i]);
return false;
}
}
return true;
}
bool test_realloc_basic_grow() {
size_t old_size = 10;
size_t new_size = 20;
int *ptr = (int *)malloc(old_size * sizeof(int));
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, old_size * sizeof(int), 0xAA);
int *new_ptr = (int *)realloc(ptr, new_size * sizeof(int));
if (new_ptr == NULL) {
free(ptr); // Оригинальный блок все еще действителен
return false;
}
// Проверяем, что старые данные сохранились
if (!check_buffer(new_ptr, old_size * sizeof(int), 0xAA)) {
free(new_ptr);
return false;
}
// Проверяем, что новый участок доступен для записи
fill_buffer(new_ptr + old_size, (new_size - old_size) * sizeof(int), 0xBB);
if (!check_buffer(new_ptr + old_size, (new_size - old_size) * sizeof(int), 0xBB)) {
free(new_ptr);
return false;
}
free(new_ptr);
return true;
}
bool test_realloc_basic_shrink() {
size_t old_size = 20;
size_t new_size = 10;
int *ptr = (int *)malloc(old_size * sizeof(int));
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, old_size * sizeof(int), 0xCC);
int *new_ptr = (int *)realloc(ptr, new_size * sizeof(int));
if (new_ptr == NULL) {
free(ptr);
return false;
}
if (!check_buffer(new_ptr, new_size * sizeof(int), 0xCC)) {
free(new_ptr);
return false;
}
free(new_ptr);
return true;
}
bool test_realloc_same_size() {
size_t size = 15;
int *ptr = (int *)malloc(size * sizeof(int));
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, size * sizeof(int), 0xDD);
int *new_ptr = (int *)realloc(ptr, size * sizeof(int));
if (new_ptr == NULL) {
free(ptr);
return false;
}
// Проверяем, что данные сохранились
if (!check_buffer(new_ptr, size * sizeof(int), 0xDD)) {
free(new_ptr);
return false;
}
free(new_ptr);
return true;
}
bool test_realloc_null_ptr() {
size_t size = 25;
void *ptr = realloc(NULL, size);
if (ptr == NULL) {
return false;
}
// Проверяем, что память доступна
fill_buffer(ptr, size, 0xEE);
if (!check_buffer(ptr, size, 0xEE)) {
free(ptr);
return false;
}
free(ptr);
return true;
}
bool test_realloc_to_zero_size() {
size_t old_size = 30;
void *ptr = malloc(old_size);
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, old_size, 0xFF);
void *new_ptr = realloc(ptr, 0);
// Стандарт C11 (7.22.3.5) говорит, что realloc(ptr, 0) может вернуть NULL
// или указатель, который можно передать free().
// Если возвращается NULL, оригинальный указатель ptr все еще действителен и должен быть освобожден.
// Если возвращается не-NULL, оригинальный ptr недействителен, а новый ptr должен быть освобожден.
if (new_ptr == NULL) {
printf("realloc(ptr, 0) return NULL.\n");
free(ptr); // Освобождаем оригинальный ptr
} else {
printf("realloc(ptr, 0) return: %p.\n", new_ptr);
free(new_ptr); // Освобождаем новый ptr
}
return true;
}
int main()
{
RUN_TEST(test_malloc_basic_allocation);
RUN_TEST(test_malloc_zero_bytes);
RUN_TEST(test_malloc_multiple_allocations);
RUN_TEST(test_malloc_data_integrity);
RUN_TEST(test_malloc_large_allocation);
RUN_TEST(test_malloc_basic_allocation);
RUN_TEST(test_malloc_allocation_and_free);
RUN_TEST(test_realloc_basic_grow);
RUN_TEST(test_realloc_basic_shrink);
RUN_TEST(test_realloc_same_size);
RUN_TEST(test_realloc_null_ptr);
RUN_TEST(test_realloc_to_zero_size);
return 0;
}

View File

@@ -38,4 +38,5 @@ int main()
result = frexp(param, &n);
printf("%f = %f * 2^%d\n", param, result, n);
}
return 0;
}

View File

@@ -23,7 +23,7 @@ void tmain()
printf("RECV: %s\n", recv_message);
assert(!strcmp(recv_message, send_message));
puts("Successful pipe test");
exit(0);
_ksys_exit();
}
void create_thread(void)
@@ -42,7 +42,7 @@ void create_thread(void)
printf("New thread created (TID=%u)\n", tid);
}
void main()
int main()
{
if (_ksys_posix_pipe2(pipefd, 0)) {
puts("Pipe creation error!");
@@ -51,4 +51,5 @@ void main()
printf("SEND: %s\n", send_message);
_ksys_posix_write(pipefd[1], send_message, MESSAGE_SIZE);
create_thread();
return 0;
}

View File

@@ -17,5 +17,6 @@ int main()
string[0] = shell_getc();
shell_printf("\n\rYou pressed: %c", string[0]);
shell_exit();
return 0;
}

View File

@@ -16,4 +16,5 @@ int main(int argc, char** argv)
printf("memcpy: Failure\n");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,15 @@
#include <stdlib.h>
#include <stdio.h>
#include <sys/ksys.h>
#define EXIT_CODE_FORMAT "Exit Code: %d\n"
int main()
{
printf(EXIT_CODE_FORMAT, system("ls ."));
_ksys_delay(500);
printf(EXIT_CODE_FORMAT, system("/sys/sysmon"));
return 0;
}

View File

@@ -64,9 +64,10 @@ int main()
create_thread();
break;
case BTN_QUIT:
_ksys_exit();
return 0;
}
break;
}
}
return 0;
}

View File

@@ -30,7 +30,7 @@ int main()
ksys_drv_hand_t tmpdisk_drv = _ksys_load_driver("tmpdisk");
if (!tmpdisk_drv) {
puts("tmpdisk.sys driver not load!");
exit(0);
return 0;
} else {
puts("tmpdisk.sys driver is load!");
}
@@ -53,5 +53,6 @@ int main()
} else {
puts(tmpdisk_res_text[6]);
}
exit(0);
return 0;
}

View File

@@ -19,9 +19,6 @@ FILE* out = stdout;
FILE* out = stderr;
#endif
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define fprintf fprintf
void show_help()
@@ -51,18 +48,18 @@ int main(int argc, char* argv[])
domain = strdup(argv[1]);
if ((out = fopen(argv[3], "w")) == NULL) {
printf("Error writing to file: '%s' !\n", argv[3]);
exit(0);
return 0;
}
} else {
show_help();
exit(0);
return 0;
}
if (out == stdout) {
con_init();
(*con_set_title)("Whois");
}
get_whois_data(domain, &data);
exit(0);
return 0;
}
/*

View File

@@ -1,6 +1,10 @@
if tup.getconfig("NO_TCC") ~= "" then return end
if tup.getconfig("NO_TCC") ~= "" then
return
end
CFLAGS = " -r -nostdinc -nostdlib -DGNUC -D_BUILD_LIBC "
CC = "kos32-tcc"
CFLAGS = " -r -nostdinc -nostdlib -DGNUC -D_BUILD_LIBC -Wall -Werror"
INCLUDES = " -I../include"
GAS_SRC = {
@@ -29,14 +33,18 @@ GAS_SRC = {
"math/sqrt.s",
"math/tan.s",
"string/memset.s",
"string/memmove.s"
"string/memmove.s",
}
OBJS = {"libc.c"}
FASM_SRC = {
"crt/crt0.asm",
}
tup.append_table(OBJS,
tup.foreach_rule(GAS_SRC, "as --32 %f -o %o", "%B.o")
)
LIBC_OBJS = { "libc.c" }
tup.rule(OBJS, "kos32-tcc" .. CFLAGS .. INCLUDES .. " %f -o %o " .. " && strip %o --strip-unneeded " , "libc.o")
tup.append_table(LIBC_OBJS, tup.foreach_rule(GAS_SRC, "as --32 %f -o %o", "%B.o"))
tup.rule(LIBC_OBJS, CC .. CFLAGS .. INCLUDES .. " %f -o %o " .. " && strip %o --strip-unneeded ", "libc.o")
tup.rule("libc.o", "objconv -fcoff32 %f %o " .. tup.getconfig("KPACK_CMD"), "%B.obj")
tup.rule(FASM_SRC, "fasm %f %o", "%B.o")

View File

@@ -14,6 +14,7 @@ public start
public start as '_start'
extrn main
extrn exit
include '../../../../../../proc32.inc'
include '../../../../../../macros.inc'
@@ -38,36 +39,36 @@ start:
call push_param
; retrieving parameters
mov esi, params
xor edx, edx ; dl - èä¸ò ïàðàìåòð(1) èëè ðàçäåëèòåëè(0)
; dh - ñèìâîë ñ êîòîðîãî íà÷àëñÿ ïàðàìåòð (1 êàâû÷êè, 0 îñòàëüíîå)
xor edx, edx ; dl - is it a parameter (1) or delimiters (0)
; dh - character with which the parameter started (1 quotes, 0 everything else)
mov ecx, 1 ; cl = 1
; ch = 0 ïðîñòî íîëü
; ch = 0 just zero
.parse:
lodsb
test al, al
jz .run
test dl, dl
jnz .findendparam
;{åñëè áûë ðàçäåëèòåëü
;{if it was a delimiter
cmp al, ' '
jz .parse ;çàãðóæåí ïðîáåë, ãðóçèì ñëåäóþùèé ñèìâîë
mov dl, cl ;íà÷èíàåòñÿ ïàðàìåòð
jz .parse ; space loaded, load next character
mov dl, cl ; parameter starts
cmp al, '"'
jz @f ;çàãðóæåíû êàâû÷êè
mov dh, ch ;ïàðàìåòð áåç êàâû÷åê
jz @f ; quotes loaded
mov dh, ch ; parameter without quotes
dec esi
call push_param
inc esi
jmp .parse
@@:
mov dh, cl ;ïàðàìåòð â êàâû÷åêàõ
call push_param ;åñëè íå ïðîáåë çíà÷èò íà÷èíàåòñÿ êàêîé òî ïàðàìåòð
jmp .parse ;åñëè áûë ðàçäåëèòåëü}
mov dh, cl ; parameter in quotes
call push_param ; if not a space, then some parameter starts
jmp .parse ; if it was a delimiter}
.findendparam:
test dh, dh
jz @f ; áåç êàâû÷åê
jz @f ; without quotes
cmp al, '"'
jz .clear
jmp .parse
@@ -86,10 +87,9 @@ start:
push [argc]
call main
.exit:
xor eax,eax
dec eax
int 0x40
dd -1
push eax
call dword [exit]
dd -1
.crash:
jmp .exit
;============================

View File

@@ -82,6 +82,7 @@
#include "string/strstr.c"
#include "string/strtok.c"
#include "string/strxfrm.c"
#include "stdlib/abs.c"
#include "stdlib/assert.c"
#include "stdlib/atof.c"
@@ -89,6 +90,8 @@
#include "stdlib/atol.c"
#include "stdlib/atoll.c"
#include "stdlib/calloc.c"
#include "stdlib/atexit.c" // must be before exit.c
#include "stdlib/_exit.c"
#include "stdlib/exit.c"
#include "stdlib/free.c"
#include "stdlib/itoa.c"
@@ -100,6 +103,8 @@
#include "stdlib/realloc.c"
#include "stdlib/strtod.c"
#include "stdlib/strtol.c"
#include "stdlib/abort.c"
#include "stdlib/system.c"
#include "math/acosh.c"
#include "math/asinh.c"
@@ -170,6 +175,8 @@ ksys_dll_t EXPORTS[] = {
{ "atoll", &atoll },
{ "atof", &atof },
{ "calloc", &calloc },
{ "atexit", &atexit },
{ "_exit", &_exit },
{ "exit", &exit },
{ "free", &free },
{ "itoa", &itoa },
@@ -178,6 +185,8 @@ ksys_dll_t EXPORTS[] = {
{ "malloc", &malloc },
{ "realloc", &realloc },
{ "strtol", &strtol },
{ "abort", &abort},
{ "system", &system },
{ "srand", &srand },
{ "rand", &rand },
{ "qsort", &qsort },
@@ -203,6 +212,7 @@ ksys_dll_t EXPORTS[] = {
{ "strspn", &strspn },
{ "strstr", &strstr },
{ "strtok", &strtok },
{ "strtok_r", &strtok_r},
{ "strxfrm", &strxfrm },
{ "strpbrk", &strpbrk },
{ "__errno", &__errno },

View File

@@ -4,11 +4,13 @@
#include <stdio.h>
#include <stdlib.h>
//#include "format_print.h"
// #include "format_print.h"
int printf(const char *format, ...)
int printf(const char* format, ...)
{
va_list arg;
va_start(arg, format);
return vprintf(format, arg);
va_list arg;
va_start(arg, format);
int ret = vprintf(format, arg);
va_end(arg);
return ret;
}

View File

@@ -0,0 +1,29 @@
#include <conio.h>
#include <stdio.h>
#include <sys/ksys.h>
#include "_exit.h"
void _exit(int status)
{
__libc_exit(status, NULL);
}
void __libc_exit(int status, void (*before_exit)(int status))
{
// return error and this is not abort
if (status && status != 128) {
fprintf(stderr, "\nexit code: %d\n", status);
}
WRITE_EXIT_CODE(status);
if (before_exit) {
before_exit(status);
}
if (__con_is_load) {
con_exit(0);
}
_ksys_exit();
}

View File

@@ -0,0 +1,69 @@
#ifndef __STDLIB_EXIT_H__
#define __STDLIB_EXIT_H__
#include <stdio.h>
#include <sys/dir.h>
#include <sys/ksys.h>
#define __PATH_TO_STATUS_FILE "/tmp0/1/.libc"
#define __STATUS_FILE_EXTENSION ".status"
#define __STATUS_FILE_FORMAT "%d"
#define __FULL_STATUS_FILE_NAME __PATH_TO_STATUS_FILE "/%d" __STATUS_FILE_EXTENSION
#define __FULL_STATUS_FILE_NAME_SIZE (sizeof(__PATH_TO_STATUS_FILE) + 32 + sizeof(__STATUS_FILE_EXTENSION))
void __libc_exit(int status, void (*before_exit)(int status));
// Save exit code
inline void WRITE_EXIT_CODE(int status)
{
mkdir(__PATH_TO_STATUS_FILE);
char buff[__FULL_STATUS_FILE_NAME_SIZE];
ksys_thread_t t;
_ksys_thread_info(&t, -1);
snprintf(buff, sizeof(buff), __FULL_STATUS_FILE_NAME, t.pid);
FILE* f = fopen(buff, "w");
if (f) {
snprintf(buff, sizeof(buff), __STATUS_FILE_FORMAT, status);
fputs(buff, f);
fflush(f);
fclose(f);
} else {
_ksys_debug_puts("error while write status\n");
}
}
// Read exit code
inline int READ_EXIT_CODE(int pid, ksys_thread_t* t)
{
char buff[__FULL_STATUS_FILE_NAME_SIZE];
int status = 0;
bool free_t = false;
if (!t) {
t = malloc(sizeof(ksys_thread_t));
_ksys_thread_info(t, -1);
free_t = true;
}
snprintf(buff, sizeof(buff), __FULL_STATUS_FILE_NAME, t->pid);
FILE* f = fopen(buff, "r");
if (f) {
fscanf(f, __STATUS_FILE_FORMAT, &status);
fclose(f);
} else if (t && t->slot_state == 4) // it was stopped before it created status file
{
status = -1;
}
if (free_t) {
free(t);
}
return status;
}
#endif // __STDLIB_EXIT_H__

View File

@@ -0,0 +1,81 @@
#ifndef _LIBC_STDLIB__MEM_
#define _LIBC_STDLIB__MEM_
#include <stddef.h>
struct mem_node {
size_t free; // Amount of free space in this node. When equal to size, the entire node is free.
size_t size; // Total size of this memory node.
struct mem_node* last; // Pointer to the previous memory node in the linked list.
struct mem_node* next; // Pointer to the next memory node in the linked list.
};
struct mem_block {
size_t size; // Size of the allocated memory block.
size_t a; // align to 8bytes
};
// Size of the blocks allocated by `_ksys_alloc`
#define ALLOC_BLOCK_SIZE 4096
// Macro to get a pointer to the user data area from a mem_node pointer.
// This is done by adding the size of the mem_node structure to the mem_node pointer.
#define GET_MEM_NODE_PTR(node) (char*)((char*)(node) + sizeof(struct mem_node))
// Macro to check if a memory node is completely free.
#define MEM_NODE_IS_FREE(node) (node->free == node->size)
// Macro to get the amount of used memory in a memory node.
#define GET_MEM_NODE_USED_MEM(node) (node->size - node->free)
// Macro to get a pointer to the mem_node structure from a user data pointer.
// This is done by subtracting the size of the mem_node structure from the user data pointer.
#define GET_MEM_NODE_HEADER(ptr) ((struct mem_node*)(((char*)ptr) - sizeof(struct mem_node)))
// Macro to check if two adjacent memory nodes are in the same block.
// Checks if the end of the left node's allocated space is the start of the right node.
#define MEM_NODES_ARE_IN_ONE_BLOCK(left, right) (GET_MEM_NODE_PTR(left) + ((struct mem_node*)left)->size == (char*)right)
// Macro to merge two adjacent memory nodes.
#define CHECK_SIDE_IN_OTHER_BLOCK(node, side) (side == NULL || ((side != NULL) && !MEM_NODES_ARE_IN_ONE_BLOCK(node, side)))
// align a value to a specified alignment.
// Ensures that the allocated memory is aligned to a certain boundary
inline size_t __mem_align(size_t value, size_t align)
{
return ((value + align - 1) & ~(align - 1));
}
#define __mem_default_align(value) __mem_align(value, 8)
inline struct mem_node* __mem_MERGE_MEM_NODES(struct mem_node* base, struct mem_node* addition)
{
// addition is free && nodes base and addition both in one block, else merge is impossible
if (MEM_NODE_IS_FREE(addition) && MEM_NODES_ARE_IN_ONE_BLOCK(base, addition)) {
// just change size
const size_t s = addition->size + sizeof(struct mem_node);
base->size += s;
base->free += s;
// and delete addition from list
if (addition->next != NULL) {
addition->next->last = base;
base->next = addition->next;
} else {
base->next = NULL;
}
return base;
}
return NULL;
}
// Static pointer to the first memory node in the linked list.
// This acts as the head of the memory pool.
static struct mem_node* __mem_node = NULL;
static struct mem_node* __last_biggest_mem_node = NULL;
#endif // _LIBC_STDLIB_MEM_

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/ksys.h>
void abort()
{
ksys_thread_t t;
_ksys_thread_info(&t, -1);
fprintf(stderr, "\nAbort in %d\n", t.pid);
_exit(128);
}

View File

@@ -0,0 +1,35 @@
#include <stdlib.h>
struct atexit_n {
struct atexit_n* last;
void (*func)(void);
};
static struct atexit_n* __last_n = NULL;
int atexit(void (*func)(void))
{
struct atexit_n* n = malloc(sizeof(struct atexit_n));
if (n == NULL) {
return 1;
}
n->last = __last_n;
n->func = func;
__last_n = n;
return 0;
}
void __run_atexit()
{
struct atexit_n* n = __last_n;
while (n != NULL) {
n->func();
struct atexit_n* to_free = n;
n = n->last;
free(to_free);
}
}

View File

@@ -1,14 +1,11 @@
#include <errno.h>
#include <stdlib.h>
#include <sys/ksys.h>
void* calloc(size_t num, size_t size)
{
void* ptr = _ksys_alloc(num * size);
if (!ptr) {
__errno = ENOMEM;
return NULL;
void* ptr = malloc(num * size);
if (ptr) {
memset(ptr, 0, num * size);
}
memset(ptr, 0, num * size);
return ptr;
}

View File

@@ -1,12 +1,34 @@
/* Copyright (C) 2021 Logaev Maxim (turbocat2001), GPLv2 */
#include <conio.h>
#include <stdlib.h>
#include <sys/ksys.h>
#include "_exit.h"
#include "_mem.h"
static void __close_all()
{
}
static void __free_all_mem()
{
struct mem_node* current_node = __mem_node;
while (current_node != NULL) {
struct mem_node* tmp = current_node;
current_node = current_node->next;
free(GET_MEM_NODE_PTR(tmp));
}
}
void __normal_exit(int status)
{
__run_atexit();
__close_all();
__free_all_mem();
}
void exit(int status)
{
if (__con_is_load) {
con_exit(status);
}
_ksys_exit();
__libc_exit(status, &__normal_exit);
}

View File

@@ -1,7 +1,97 @@
#include <stdlib.h>
#include <stdbool.h>
#include <sys/ksys.h>
#include "_mem.h"
void free(void* ptr)
{
_ksys_free(ptr);
}
// Handle NULL pointer.
if (ptr == NULL)
return;
// Get a pointer to the mem_node header from the user data pointer.
struct mem_node* node = GET_MEM_NODE_HEADER(ptr);
// Mark the memory node as free.
node->free = node->size;
if (__last_biggest_mem_node == node) {
if (node->last) {
__last_biggest_mem_node = node->last; // anyway node will be merged with next
// and last and last will have size = last + node + next(if its free too)
}
}
// Merge with the next node if possible.
if (node->next != NULL)
__mem_MERGE_MEM_NODES(node, node->next);
// Merge with the previous node if possible.
if (node->last != NULL)
node = __mem_MERGE_MEM_NODES(node->last, node);
if (node) {
// If the current node is not adjacent to either the next or previous node,
// it might be a separate block that can be freed.
if (MEM_NODE_IS_FREE(node) // check it because node maybe was merged with last
&& (node->last == NULL || !MEM_NODES_ARE_IN_ONE_BLOCK(node, node->next))
&& (node->next == NULL || !MEM_NODES_ARE_IN_ONE_BLOCK(node->last, node))) {
// Get a pointer to the mem_block header from the mem_node header.
struct mem_block* block = (struct mem_block*)(((char*)node) - sizeof(struct mem_block));
// Check if the block size matches the node size.
if (block->size == node->size + sizeof(struct mem_block) + sizeof(struct mem_node)) {
// Update the linked list pointers to remove the current node.
if (node->last != NULL)
node->last->next = node->next;
if (node->next != NULL)
node->next->last = node->last;
// Update the head of the linked list if necessary.
if (__mem_node == node) {
if (node->last != NULL) {
__mem_node = node->last;
} else if (node->next != NULL) {
__mem_node = node->next;
} else {
__mem_node = NULL;
}
}
struct mem_node* a = node->next;
struct mem_node* b = node->last;
if (!a && !b) {
__last_biggest_mem_node = NULL;
} else if (a && !b) {
__last_biggest_mem_node = a;
} else if (!a && b) {
__last_biggest_mem_node = b;
} else if (a && b) {
__last_biggest_mem_node = (a->free > b->free) ? a : b;
}
if (__last_biggest_mem_node == node) {
if (node->next && !(node->last)) {
__last_biggest_mem_node = node->next;
} else if (node->last && !(node->next)) {
__last_biggest_mem_node = node->last;
} else if (node->next && node->last) {
if (node->last->free > node->next->free) {
__last_biggest_mem_node = node->last;
} else {
__last_biggest_mem_node = node->next;
}
}
}
// Free the memory block using the ksys_free function.
_ksys_free(block);
}
}
}
}

View File

@@ -1,7 +1,128 @@
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ksys.h>
#include <stdbool.h>
#include "_mem.h"
static struct mem_node* __new_mem_node_from_exist(struct mem_node* current_node, size_t size, bool* from_empty_node)
{
struct mem_node* new_node = NULL;
// Check if the current node has enough free space for the requested size.
if (size + sizeof(struct mem_node) <= current_node->free) {
*from_empty_node = MEM_NODE_IS_FREE(current_node);
if (*from_empty_node) {
new_node = current_node;
} else {
// Calculate the used memory in current node
const size_t s = GET_MEM_NODE_USED_MEM(current_node);
// Create a new memory node after the current node's used space.
new_node = (struct mem_node*)(GET_MEM_NODE_PTR(current_node) + s);
// Update current node's size
current_node->size = s;
// Set the size of the new node.
// for new node give all free space in current node
new_node->size = current_node->free - sizeof(struct mem_node);
// Mark current node as used.
current_node->free = 0;
}
}
return new_node;
}
void* malloc(size_t size)
{
return _ksys_alloc(size);
}
char b[32];
// Handle zero-size allocation.
if (size == 0) {
return NULL;
}
// Align the size to 8 bytes.
size = __mem_default_align(size);
struct mem_node* current_node = __mem_node;
struct mem_node* new_node = NULL; // Pointer to the new node that will be created.
bool from_empty_node = false;
if (__last_biggest_mem_node != NULL)
new_node = __new_mem_node_from_exist(__last_biggest_mem_node, size, &from_empty_node); // try find free space in last created node
// if cant find in __last_biggest_mem_node
if (new_node == NULL) {
// Iterate through the linked list of memory nodes.
while (current_node != NULL) {
new_node = __new_mem_node_from_exist(current_node, size, &from_empty_node);
if (new_node)
break; // Found a suitable node, exit the loop.
current_node = current_node->next; // Move to the next node in the list.
}
}
// If no suitable node was found in the existing list:
if (new_node == NULL) {
// Calculate the size of the new block, including the mem_block header, mem_node header and alignment.
const size_t s = __mem_align(size + sizeof(struct mem_block) + sizeof(struct mem_node), ALLOC_BLOCK_SIZE);
// Allocate a new block of memory using the ksys_alloc function (presumably a kernel-level allocation function).
struct mem_block* block = (struct mem_block*)_ksys_alloc(s);
// Check if the allocation was successful.
if (block == NULL) {
__errno = ENOMEM; // Set the error number to indicate memory allocation failure.
return NULL; // Return NULL to indicate allocation failure.
}
block->size = s;
// Create a new memory node after the mem_block header.
new_node = (struct mem_node*)(((char*)block) + sizeof(struct mem_block));
// Set the size of the new node.
new_node->size = s - sizeof(struct mem_block) - sizeof(struct mem_node);
}
// Set the free space in the new node.
new_node->free = new_node->size - size;
if (!from_empty_node) {
// Set the last pointer of the new node to the current node.
new_node->last = current_node;
// Link the new node into the linked list.
if (current_node != NULL) {
// Set the next pointer of the current node to the new node.
new_node->next = current_node->next;
// Update the last pointer of the next node, if it exists.
if (current_node->next != NULL) {
current_node->next->last = new_node;
}
current_node->next = new_node;
} else {
// If the current node is NULL, the new node is the first node in the list.
new_node->next = NULL;
}
}
// If the linked list was empty, set the head to the new node.
if (__mem_node == NULL) {
__mem_node = new_node;
}
if (__last_biggest_mem_node == NULL || new_node->free > __last_biggest_mem_node->free) {
__last_biggest_mem_node = new_node;
}
// Return a pointer to the user data area of the new node.
return GET_MEM_NODE_PTR(new_node);
}
#undef __mem_align

View File

@@ -1,7 +1,76 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ksys.h>
#include "_mem.h"
// realloc mem. using if other ways not working
static void* fail_realloc(void* ptr, size_t newsize)
{
// Allocate a new block of memory with the new size.
void* new_ptr = malloc(newsize);
// If both the old pointer and the new pointer are not NULL:
if (ptr != NULL && new_ptr != NULL) {
// Copy the data from the old block to the new block.
memcpy(new_ptr, ptr, min(newsize, GET_MEM_NODE_USED_MEM(GET_MEM_NODE_HEADER(ptr))));
}
if (ptr) {
free(ptr); // Free the old block.
}
return new_ptr;
}
void* realloc(void* ptr, size_t newsize)
{
return _ksys_realloc(ptr, newsize);
void* new_ptr = NULL;
struct mem_node* node = NULL;
if (ptr && newsize) {
// Get a pointer to the mem_node header from the user data pointer.
node = GET_MEM_NODE_HEADER(ptr);
newsize = __mem_default_align(newsize);
if (node->size >= newsize) { // current node have enough mem
// it work always if newsize is smaller
// Update the free space in the current node.
node->free = node->size - newsize;
// Return the original pointer.
new_ptr = ptr;
} else if (node->last && MEM_NODE_IS_FREE(node->last) && node->size + node->last->size >= newsize) {
// So what happens here is that the node merges with the last node if their volume is sufficient.
// And a reallock is called in the hopes that the first condition will be met.
// if merge failed realloc anyway return pointer, but it will got from `fail_realloc`
struct mem_node* l = node->last;
l = __mem_MERGE_MEM_NODES(l, node);
if (l) {
memmove(GET_MEM_NODE_PTR(l), ptr, GET_MEM_NODE_USED_MEM(node));
new_ptr = realloc(GET_MEM_NODE_PTR(l), newsize);
}
}
}
if (new_ptr == NULL) {
// Allocate a new block of memory with the new size.
new_ptr = malloc(newsize);
// If both the old pointer and the new pointer are not NULL:
if (ptr != NULL && new_ptr != NULL) {
// Copy the data from the old block to the new block.
memcpy(new_ptr, ptr, min(newsize, GET_MEM_NODE_USED_MEM(GET_MEM_NODE_HEADER(ptr))));
}
if (ptr) {
free(ptr); // Free the old block.
}
}
// Return the new pointer.
return new_ptr;
}

View File

@@ -0,0 +1,44 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ksys.h>
#include "_exit.h"
int system(const char* command)
{
const char shell[] = "/sys/shell";
if (command == NULL || *command == '\0') {
FILE* f = fopen(shell, "r");
if (f) {
fclose(f);
}
return f != 0;
}
FILE* f = tmpfile();
if (!f)
return -1;
fputs("#SHS\n", f);
fputs(command, f);
fputs("\nexit\n", f);
int pid = _ksys_exec(shell, f->name);
fclose(f);
if (pid < 0) {
return -1;
}
// wait of end of shell
ksys_thread_t t;
while (_ksys_thread_info(&t, pid) != -1 && t.slot_state != 3 && t.slot_state != 4 && t.slot_state != 9) {
_ksys_thread_yield();
}
return READ_EXIT_CODE(pid, &t);
}

View File

@@ -4,7 +4,9 @@
char* strdup(const char* str)
{
char* buf = malloc(strlen(str) + 1);
buf[strlen(str)] = '\0';
strcpy(buf, str);
if (buf) {
buf[strlen(str)] = '\0';
strcpy(buf, str);
}
return buf;
}

View File

@@ -1,14 +1,12 @@
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
#include <string.h>
char* strtok(char* s, const char* delim)
char* strtok_r(char* s, const char* delim, char** last)
{
const char* spanp;
char *spanp, *tok;
int c, sc;
char* tok;
static char* last;
if (s == NULL && (s = last) == NULL)
if (s == NULL && (s = *last) == NULL)
return (NULL);
/*
@@ -16,13 +14,13 @@ char* strtok(char* s, const char* delim)
*/
cont:
c = *s++;
for (spanp = delim; (sc = *spanp++) != 0;) {
for (spanp = (char*)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
last = NULL;
*last = NULL;
return (NULL);
}
tok = s - 1;
@@ -33,17 +31,24 @@ cont:
*/
for (;;) {
c = *s++;
spanp = delim;
spanp = (char*)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
last = s;
s[-1] = '\0';
*last = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
char *strtok(char *s, const char *delim)
{
static char *last;
return (strtok_r(s, delim, &last));
}