调整user下libs的libc目录结构 (#103)

* 调整user下libs的libc目录结构

* 修正.gitignore文件的问题

* 修复无法编译的问题

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
wwc-15172310230
2022-12-11 22:22:10 +08:00
committed by GitHub
parent 2291ffdece
commit 237e95c6dd
57 changed files with 229 additions and 124 deletions

View File

@ -0,0 +1,63 @@
GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ kernel
GARBAGE := $(foreach DIR,$(DIRS),$(addprefix $(DIR)/,$(GARBAGE_PATTERNS)))
all: libc
CFLAGS += -I .
libc_sub_dirs=math sys
ifeq ($(ARCH), __x86_64__)
libc_sub_dirs += sysdeps/x86_64
endif
clean:
cargo clean
rm -rf $(GARBAGE)
@list='$(libc_sub_dirs)'; for subdir in $$list; do \
echo "Clean in dir: $$subdir";\
cd $$subdir && $(MAKE) clean;\
cd .. ;\
done
libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o string.o dirent.o time.o libc_rust
@list='$(libc_sub_dirs)'; for subdir in $$list; do \
echo "make all in $$subdir";\
cd $$subdir;\
$(MAKE) all CFLAGS="$(CFLAGS) -I $(shell pwd)";\
cd ..;\
done
unistd.o: unistd.c
$(CC) $(CFLAGS) -c unistd.c -o unistd.o
fcntl.o: fcntl.c
$(CC) $(CFLAGS) -c fcntl.c -o fcntl.o
malloc.o: malloc.c
$(CC) $(CFLAGS) -c malloc.c -o malloc.o
errno.o: errno.c
$(CC) $(CFLAGS) -c errno.c -o errno.o
printf.o: printf.c
$(CC) $(CFLAGS) -c printf.c -o printf.o
stdlib.o: stdlib.c
$(CC) $(CFLAGS) -c stdlib.c -o stdlib.o
ctype.o: ctype.c
$(CC) $(CFLAGS) -c ctype.c -o ctype.o
string.o: string.c
$(CC) $(CFLAGS) -c string.c -o string.o
dirent.o: dirent.c
$(CC) $(CFLAGS) -c dirent.c -o dirent.o
time.o: time.c
$(CC) $(CFLAGS) -c time.c -o time.o
libc_rust:
rustup default nightly
cargo +nightly build --release --target ./x86_64-unknown-none.json

View File

@ -0,0 +1,20 @@
#pragma once
#pragma once
#ifdef __cplusplus
# define __BEGIN_HEADER \
extern "C" \
{
# define __END_HEADER \
}
#else
# define __BEGIN_HEADER
# define __END_HEADER
#endif

View File

@ -0,0 +1,75 @@
#include <libc/src/ctype.h>
int isprint(int c)
{
if (c >= 0x20 && c <= 0x7e)
{
return 1;
}
return 0;
}
int islower(int c)
{
if (c >= 'a' && c <= 'z')
{
return 1;
}
return 0;
}
int isupper(int c)
{
if (c >= 'A' && c <= 'Z')
{
return 1;
}
return 0;
}
int isalpha(int c)
{
if (islower(c) || isupper(c))
{
return 1;
}
return 0;
}
int isdigit(int c)
{
if (c >= '0' && c <= '9')
{
return 1;
}
return 0;
}
int toupper(int c)
{
if (c >= 'a' && c <= 'z')
{
return c - 'a' + 'A';
}
return c;
}
int tolower(int c)
{
if (c >= 'A' && c <= 'Z')
{
return c - 'A' + 'a';
}
return c;
}
int isspace(int c)
{
return (c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == ' ');
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <libc/src/sys/types.h>
#pragma once
#include <libc/src/__libc__.h>
int isalnum(int c);
int isalpha(int c);
int isdigit(int c);
int islower(int c);
int isprint(int c);
int isgraph(int c);
int iscntrl(int c);
int isgraph(int c);
int ispunct(int c);
int isspace(int c);
int isupper(int c);
int isxdigit(int c);
int isascii(int c);
int tolower(int c);
int toupper(int c);
#define _U 01
#define _L 02
#define _N 04
#define _S 010
#define _P 020
#define _C 040
#define _X 0100
#define _B 0200
extern char _ctype_[256];

View File

@ -0,0 +1,78 @@
#include "dirent.h"
#include "unistd.h"
#include "stdio.h"
#include "fcntl.h"
#include "stddef.h"
#include "stdlib.h"
#include "string.h"
#include <libsystem/syscall.h>
/**
* @brief 打开文件夹
*
* @param dirname
* @return DIR*
*/
struct DIR *opendir(const char *path)
{
int fd = open(path, O_DIRECTORY);
if (fd < 0) // 目录打开失败
{
printf("Failed to open dir\n");
return NULL;
}
// printf("open dir: %s\n", path);
// 分配DIR结构体
struct DIR *dirp = (struct DIR *)malloc(sizeof(struct DIR));
// printf("dirp = %#018lx", dirp);
memset(dirp, 0, sizeof(struct DIR));
dirp->fd = fd;
dirp->buf_len = DIR_BUF_SIZE;
dirp->buf_pos = 0;
return dirp;
}
/**
* @brief 关闭文件夹
*
* @param dirp DIR结构体指针
* @return int 成功0 失败:-1
+--------+--------------------------------+
| errno | 描述 |
+--------+--------------------------------+
| 0 | 成功 |
| -EBADF | 当前dirp不指向一个打开了的目录 |
| -EINTR | 函数执行期间被信号打断 |
+--------+--------------------------------+
*/
int closedir(struct DIR *dirp)
{
int retval = close(dirp->fd);
free(dirp);
return retval;
}
int64_t getdents(int fd, struct dirent *dirent, long count)
{
return syscall_invoke(SYS_GET_DENTS, fd, (uint64_t)dirent, count, 0, 0, 0, 0, 0);
}
/**
* @brief 从目录中读取数据
*
* @param dir
* @return struct dirent*
*/
struct dirent *readdir(struct DIR *dir)
{
// printf("dir->buf = %#018lx\n", (dir->buf));
memset((dir->buf), 0, DIR_BUF_SIZE);
// printf("memeset_ok\n");
int len = getdents(dir->fd, (struct dirent *)dir->buf, DIR_BUF_SIZE);
// printf("len=%d\n", len);
if (len > 0)
return (struct dirent *)dir->buf;
else
return NULL;
}

View File

@ -0,0 +1,66 @@
#pragma once
#include <libc/src/sys/types.h>
/**
* @brief inode的属性copy from vfs.h
*
*/
#define VFS_IF_FILE (1UL << 0)
#define VFS_IF_DIR (1UL << 1)
#define VFS_IF_DEVICE (1UL << 2)
#define DIR_BUF_SIZE 256
/**
* @brief 文件夹结构体
*
*/
struct DIR
{
int fd;
int buf_pos;
int buf_len;
char buf[DIR_BUF_SIZE];
// todo: 加一个指向dirent结构体的指针
};
struct dirent
{
ino_t d_ino; // 文件序列号
off_t d_off; // dir偏移量
unsigned short d_reclen; // 目录下的记录数
unsigned char d_type; // entry的类型
char d_name[]; // 文件entry的名字(是一个零长数组)
};
/**
* @brief 打开文件夹
*
* @param dirname
* @return DIR*
*/
struct DIR *opendir(const char *dirname);
/**
* @brief 关闭文件夹
*
* @param dirp DIR结构体指针
* @return int 成功0 失败:-1
+--------+--------------------------------+
| errno | 描述 |
+--------+--------------------------------+
| 0 | 成功 |
| -EBADF | 当前dirp不指向一个打开了的目录 |
| -EINTR | 函数执行期间被信号打断 |
+--------+--------------------------------+
*/
int closedir(struct DIR *dirp);
/**
* @brief 从目录中读取数据
*
* @param dir
* @return struct dirent*
*/
struct dirent* readdir(struct DIR* dir);

View File

@ -0,0 +1,2 @@
#include "errno.h"
int errno = 0;

103
user/libs/libc/src/errno.h Normal file
View File

@ -0,0 +1,103 @@
/**
* @file errno.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief
* @version 0.1
* @date 2022-04-22
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#define E2BIG 1 /* 参数列表过长或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */
#define EACCES 2 /* 访问被拒绝 Permission denied */
#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/
#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/
#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */
#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/
#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */
#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */
#define EBADMSG 9 /* 错误的消息 Bad message. */
#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */
#define ECANCELED 11 /* 操作被取消 Operation canceled. */
#define ECHILD 12 /* 没有子进程 No child processes. */
#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */
#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */
#define ECONNRESET 15 /* 连接被重置 Connection reset. */
#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */
#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/
#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */
#define EDQUOT 19 /* 保留使用 Reserved */
#define EEXIST 20 /* 文件已存在 File exists. */
#define EFAULT 21 /* 错误的地址 Bad address */
#define EFBIG 22 /* 文件太大 File too large. */
#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/
#define EIDRM 24 /* 标志符被移除 Identifier removed. */
#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */
#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */
#define EINTR 27 /* 被中断的函数 Interrupted function. */
#define EINVAL 28 /* 不可用的参数 Invalid argument. */
#define EIO 29 /* I/O错误 I/O error. */
#define EISCONN 30 /* 套接字已连接 Socket is connected. */
#define EISDIR 31 /* 是一个目录 Is a directory */
#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */
#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */
#define EMLINK 34 /* 链接数过多 Too many links. */
#define EMSGSIZE 35 /* 消息过大 Message too large. */
#define EMULTIHOP 36 /* 保留使用 Reserved. */
#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */
#define ENETDOWN 38 /* 网络已关闭 Network is down. */
#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */
#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */
#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/
#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */
#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */
#define ENODEV 44 /* 没有指定的设备 No such device. */
#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */
#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */
#define ENOLCK 47 /* 没有可用的锁 No locks available. */
#define ENOLINK 48 /* 保留 Reserved. */
#define ENOMEM 49 /* 没有足够的空间 Not enough space. */
#define ENOMSG 50 /* 没有期待类型的消息 No message of the desired type. */
#define ENOPROTOOPT 51 /* 协议不可用 Protocol not available. */
#define ENOSPC 52 /* 设备上没有空间 No space left on device. */
#define ENOSR 53 /* 没有STREAM资源 No STREAM resources.*/
#define ENOSTR 54 /* 不是STREAM Not a STREAM */
#define ENOSYS 55 /* 功能不支持 Function not supported. */
#define ENOTCONN 56 /* 套接字未连接 The socket is not connected. */
#define ENOTDIR 57 /* 不是目录 Not a directory. */
#define ENOTEMPTY 58 /* 目录非空 Directory not empty. */
#define ENOTRECOVERABLE 59 /* 状态不可覆盖 State not recoverable. */
#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/
#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */
#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */
#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */
#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */
#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */
#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */
#define EPERM 67 /* 操作不被允许 Operation not permitted. */
#define EPIPE 68 /* 断开的管道 Broken pipe. */
#define EPROTO 69 /* 协议错误 Protocol error. */
#define EPROTONOSUPPORT 70 /* 协议不被支持 Protocol not supported. */
#define EPROTOTYPE 71 /* 对于套接字而言,错误的协议 Protocol wrong type for socket. */
#define ERANGE 72 /* 结果过大 Result too large. */
#define EROFS 73 /* 只读的文件系统 Read-only file system. */
#define ESPIPE 74 /* 错误的寻道 Invalid seek. */
#define ESRCH 75 /* 没有这样的进程 No such process. */
#define ESTALE 76 /* 保留 Reserved. */
#define ETIME 77 /* 流式ioctl()超时 Stream ioctl() timeout */
#define ETIMEDOUT 78 /* 连接超时 Connection timed out.*/
#define ETXTBSY 79 /* 文本文件忙 Text file busy. */
#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */
#define EXDEV 81 /* 跨设备连接 Cross-device link. */
extern int errno;

View File

@ -0,0 +1,15 @@
#include <libc/src/fcntl.h>
#include <libsystem/syscall.h>
/**
* @brief 打开文件的接口
*
* @param path 文件路径
* @param options 打开选项
* @param ...
* @return int 文件描述符
*/
int open(const char *path, int options, ...)
{
return syscall_invoke(SYS_OPEN, (uint64_t)path, options, 0, 0, 0, 0, 0, 0);
}

View File

@ -0,0 +1,65 @@
/**
* @file fcntl.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief
* @version 0.1
* @date 2022-04-26
*
* @copyright Copyright (c) 2022
*
*/
#pragma once
#define O_RDONLY 00000000 // Open Read-only
#define O_WRONLY 00000001 // Open Write-only
#define O_RDWR 00000002 // Open read/write
#define O_ACCMODE 00000003 // Mask for file access modes
#define O_CREAT 00000100 // Create file if it does not exist
#define O_EXCL 00000200 // Fail if file already exists
#define O_NOCTTY 00000400 // Do not assign controlling terminal
#define O_TRUNC 00001000 // 文件存在且是普通文件并以O_RDWR或O_WRONLY打开则它会被清空
#define O_APPEND 00002000 // 文件指针会被移动到文件末尾
#define O_NONBLOCK 00004000 // 非阻塞式IO模式
#define O_EXEC 00010000 // 以仅执行的方式打开(非目录文件)
#define O_SEARCH 00020000 // Open the directory for search only
#define O_DIRECTORY 00040000 // 打开的必须是一个目录
#define O_NOFOLLOW 00100000 // Do not follow symbolic links
/*
* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is
* meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
* unlinkat. The two functions do completely different things and therefore,
* the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
* faccessat would be undefined behavior and thus treating it equivalent to
* AT_EACCESS is valid undefined behavior.
*/
// 作为当前工作目录的文件描述符用于指代cwd
#define AT_FDCWD -100
#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
#define AT_EACCESS 0x200 /* Test access permitted for effective IDs, not real IDs. */
#define AT_REMOVEDIR 0x200 /* Remove directory instead of unlinking file. */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */
#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */
#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */
#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */
#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
/**
* @brief 打开文件的接口
*
* @param path 文件路径
* @param options 打开选项
* @param ...
* @return int 文件描述符
*/
int open(const char * path, int options, ...);

View File

@ -0,0 +1,40 @@
#pragma once
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
#define SIGPWR 30
#define SIGSYS 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX MAX_SIG_NUM

21
user/libs/libc/src/lib.rs Normal file
View File

@ -0,0 +1,21 @@
#![no_std] // <1>
#![no_main] // <1>
#![feature(core_intrinsics)] // <2>
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
#[no_mangle]
pub extern "C" fn scanf() {
}

392
user/libs/libc/src/malloc.c Normal file
View File

@ -0,0 +1,392 @@
#include <libc/src/stdlib.h>
#include <libsystem/syscall.h>
#include <libc/src/stddef.h>
#include <libc/src/unistd.h>
#include <libc/src/errno.h>
#include <libc/src/stdio.h>
#define PAGE_4K_SHIFT 12
#define PAGE_2M_SHIFT 21
#define PAGE_1G_SHIFT 30
#define PAGE_GDT_SHIFT 39
// 不同大小的页的容量
#define PAGE_4K_SIZE (1UL << PAGE_4K_SHIFT)
#define PAGE_2M_SIZE (1UL << PAGE_2M_SHIFT)
#define PAGE_1G_SIZE (1UL << PAGE_1G_SHIFT)
// 屏蔽低于x的数值
#define PAGE_4K_MASK (~(PAGE_4K_SIZE - 1))
#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1))
// 将addr按照x的上边界对齐
#define PAGE_4K_ALIGN(addr) (((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
#define PAGE_2M_ALIGN(addr) (((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)
/**
* @brief 显式链表的结点
*
*/
typedef struct malloc_mem_chunk_t
{
uint64_t length; // 整个块所占用的内存区域的大小
struct malloc_mem_chunk_t *prev; // 上一个结点的指针
struct malloc_mem_chunk_t *next; // 下一个结点的指针
} malloc_mem_chunk_t;
static uint64_t brk_base_addr = 0; // 堆区域的内存基地址
static uint64_t brk_max_addr = 0; // 堆区域的内存最大地址
static uint64_t brk_managed_addr = 0; // 堆区域已经被管理的地址
// 空闲链表
// 按start_addr升序排序
static malloc_mem_chunk_t *malloc_free_list = NULL;
static malloc_mem_chunk_t *malloc_free_list_end = NULL; // 空闲链表的末尾结点
static uint64_t count_last_free_size = 0; // 统计距离上一次回收内存已经free了多少内存
/**
* @brief 将块插入空闲链表
*
* @param ck 待插入的块
*/
static void malloc_insert_free_list(malloc_mem_chunk_t *ck);
/**
* @brief 当堆顶空闲空间大于2个页的空间的时候释放1个页
*
*/
static void release_brk();
/**
* @brief 在链表中检索符合要求的空闲块best fit
*
* @param size 块的大小
* @return malloc_mem_chunk_t*
*/
static malloc_mem_chunk_t *malloc_query_free_chunk_bf(uint64_t size)
{
// 在满足best fit的前提下尽可能的使分配的内存在低地址
// 使得总的堆内存可以更快被释放
if (malloc_free_list == NULL)
{
return NULL;
}
malloc_mem_chunk_t *ptr = malloc_free_list;
malloc_mem_chunk_t *best = NULL;
// printf("query size=%d", size);
while (ptr != NULL)
{
// printf("ptr->length=%#010lx\n", ptr->length);
if (ptr->length == size)
{
best = ptr;
break;
}
if (ptr->length > size)
{
if (best == NULL)
best = ptr;
else if (best->length > ptr->length)
best = ptr;
}
ptr = ptr->next;
}
return best;
}
/**
* @brief 在链表中检索符合要求的空闲块first fit
*
* @param size
* @return malloc_mem_chunk_t*
*/
static malloc_mem_chunk_t *malloc_query_free_chunk_ff(uint64_t size)
{
if (malloc_free_list == NULL)
return NULL;
malloc_mem_chunk_t *ptr = malloc_free_list;
while (ptr)
{
if (ptr->length >= size)
{
return ptr;
}
ptr = ptr->next;
}
return NULL;
}
/**
* @brief 扩容malloc管理的内存区域
*
* @param size 扩大的内存大小
*/
static int malloc_enlarge(int64_t size)
{
if (brk_base_addr == 0) // 第一次调用,需要初始化
{
brk_base_addr = brk(-1);
// printf("brk_base_addr=%#018lx\n", brk_base_addr);
brk_managed_addr = brk_base_addr;
brk_max_addr = brk(-2);
}
int64_t free_space = brk_max_addr - brk_managed_addr;
// printf("size=%ld\tfree_space=%ld\n", size, free_space);
if (free_space < size) // 现有堆空间不足
{
if (sbrk(size - free_space) != (void *)(-1))
brk_max_addr = brk((-2));
else
{
put_string("malloc_enlarge(): no_mem\n", COLOR_YELLOW, COLOR_BLACK);
return -ENOMEM;
}
// printf("brk max addr = %#018lx\n", brk_max_addr);
}
// 扩展管理的堆空间
// 在新分配的内存的底部放置header
// printf("managed addr = %#018lx\n", brk_managed_addr);
malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)brk_managed_addr;
new_ck->length = brk_max_addr - brk_managed_addr;
// printf("new_ck->start_addr=%#018lx\tbrk_max_addr=%#018lx\tbrk_managed_addr=%#018lx\n", (uint64_t)new_ck, brk_max_addr, brk_managed_addr);
new_ck->prev = NULL;
new_ck->next = NULL;
brk_managed_addr = brk_max_addr;
malloc_insert_free_list(new_ck);
return 0;
}
/**
* @brief 合并空闲块
*
*/
static void malloc_merge_free_chunk()
{
if (malloc_free_list == NULL)
return;
malloc_mem_chunk_t *ptr = malloc_free_list->next;
while (ptr != NULL)
{
// 内存块连续
if (((uint64_t)(ptr->prev) + ptr->prev->length == (uint64_t)ptr))
{
// printf("merged %#018lx and %#018lx\n", (uint64_t)ptr, (uint64_t)(ptr->prev));
// 将ptr与前面的空闲块合并
ptr->prev->length += ptr->length;
ptr->prev->next = ptr->next;
if (ptr->next == NULL)
malloc_free_list_end = ptr->prev;
else
ptr->next->prev = ptr->prev;
// 由于内存组成结构的原因不需要free掉header
ptr = ptr->prev;
}
ptr = ptr->next;
}
}
/**
* @brief 将块插入空闲链表
*
* @param ck 待插入的块
*/
static void malloc_insert_free_list(malloc_mem_chunk_t *ck)
{
if (malloc_free_list == NULL) // 空闲链表为空
{
malloc_free_list = ck;
malloc_free_list_end = ck;
ck->prev = ck->next = NULL;
return;
}
else
{
malloc_mem_chunk_t *ptr = malloc_free_list;
while (ptr != NULL)
{
if ((uint64_t)ptr < (uint64_t)ck)
{
if (ptr->next == NULL) // 当前是最后一个项
{
ptr->next = ck;
ck->next = NULL;
ck->prev = ptr;
malloc_free_list_end = ck;
break;
}
else if ((uint64_t)(ptr->next) > (uint64_t)ck)
{
ck->prev = ptr;
ck->next = ptr->next;
ptr->next = ck;
ck->next->prev = ck;
break;
}
}
else // 在ptr之前插入
{
if (ptr->prev == NULL) // 是第一个项
{
malloc_free_list = ck;
ck->prev = NULL;
ck->next = ptr;
ptr->prev = ck;
break;
}
else
{
ck->prev = ptr->prev;
ck->next = ptr;
ck->prev->next = ck;
ptr->prev = ck;
break;
}
}
ptr = ptr->next;
}
}
}
/**
* @brief 获取一块堆内存
*
* @param size 内存大小
* @return void* 内存空间的指针
*
* 分配内存的时候结点的prev next指针所占用的空间被当做空闲空间分配出去
*/
void *malloc(ssize_t size)
{
// printf("malloc\n");
// 计算需要分配的块的大小
if (size + sizeof(uint64_t) <= sizeof(malloc_mem_chunk_t))
size = sizeof(malloc_mem_chunk_t);
else
size += sizeof(uint64_t);
// 采用best fit
malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
if (ck == NULL) // 没有空闲块
{
// printf("no free blocks\n");
// 尝试合并空闲块
malloc_merge_free_chunk();
ck = malloc_query_free_chunk_bf(size);
// 找到了合适的块
if (ck)
goto found;
// printf("before enlarge\n");
// 找不到合适的块,扩容堆区域
if (malloc_enlarge(size) == -ENOMEM)
return (void *)-ENOMEM; // 内存不足
malloc_merge_free_chunk(); // 扩容后运行合并,否则会导致碎片
// 扩容后再次尝试获取
ck = malloc_query_free_chunk_bf(size);
}
found:;
// printf("ck = %#018lx\n", (uint64_t)ck);
if (ck == NULL)
return (void *)-ENOMEM;
// printf("ck->prev=%#018lx ck->next=%#018lx\n", ck->prev, ck->next);
// 分配空闲块
// 从空闲链表取出
if (ck->prev == NULL) // 当前是链表的第一个块
{
malloc_free_list = ck->next;
}
else
ck->prev->next = ck->next;
if (ck->next != NULL) // 当前不是最后一个块
ck->next->prev = ck->prev;
else
malloc_free_list_end = ck->prev;
// 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
if ((int64_t)(ck->length) - size > sizeof(malloc_mem_chunk_t))
{
// printf("seperate\n");
malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)(((uint64_t)ck) + size);
new_ck->length = ck->length - size;
new_ck->prev = new_ck->next = NULL;
// printf("new_ck=%#018lx, new_ck->length=%#010lx\n", (uint64_t)new_ck, new_ck->length);
ck->length = size;
malloc_insert_free_list(new_ck);
}
// printf("malloc done: %#018lx, length=%#018lx\n", ((uint64_t)ck + sizeof(uint64_t)), ck->length);
// 此时链表结点的指针的空间被分配出去
return (void *)((uint64_t)ck + sizeof(uint64_t));
}
/**
* @brief 当堆顶空闲空间大于2个页的空间的时候释放1个页
*
*/
static void release_brk()
{
// 先检测最顶上的块
// 由于块按照开始地址排列,因此找最后一个块
if (malloc_free_list_end == NULL)
{
printf("release(): free list end is null. \n");
return;
}
if ((uint64_t)malloc_free_list_end + malloc_free_list_end->length == brk_max_addr && (uint64_t)malloc_free_list_end <= brk_max_addr - (PAGE_2M_SIZE << 1))
{
int64_t delta = ((brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK) - PAGE_2M_SIZE;
// printf("(brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK=%#018lx\n ", (brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK);
// printf("PAGE_2M_SIZE=%#018lx\n", PAGE_2M_SIZE);
// printf("tdfghgbdfggkmfn=%#018lx\n ", (brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK - PAGE_2M_SIZE);
// printf("delta=%#018lx\n ", delta);
if (delta <= 0) // 不用释放内存
return;
sbrk(-delta);
brk_max_addr = brk(-2);
brk_managed_addr = brk_max_addr;
malloc_free_list_end->length = brk_max_addr - (uint64_t)malloc_free_list_end;
}
}
/**
* @brief 释放一块堆内存
*
* @param ptr 堆内存的指针
*/
void free(void *ptr)
{
// 找到结点此时prev和next都处于未初始化的状态
malloc_mem_chunk_t *ck = (malloc_mem_chunk_t *)((uint64_t)ptr - sizeof(uint64_t));
// printf("free(): addr = %#018lx\t len=%#018lx\n", (uint64_t)ck, ck->length);
count_last_free_size += ck->length;
malloc_insert_free_list(ck);
if (count_last_free_size > PAGE_2M_SIZE)
{
count_last_free_size = 0;
malloc_merge_free_chunk();
release_brk();
}
}

12
user/libs/libc/src/math.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "stddef.h"
double fabs(double x);
float fabsf(float x);
long double fabsl(long double x);
double round(double x);
float roundf(float x);
long double roundl(long double x);
int64_t pow(int64_t x, int y);

View File

@ -0,0 +1,14 @@
CFLAGS += -I .
all: fabs.o round.o pow.o
fabs.o: fabs.c
$(CC) $(CFLAGS) -c fabs.c -o fabs.o
round.o: round.c
$(CC) $(CFLAGS) -c round.c -o round.o
pow.o: pow.c
$(CC) $(CFLAGS) -c pow.c -o pow.o

View File

@ -0,0 +1,29 @@
#include <libc/src/math.h>
#include <libc/src/sys/types.h>
#include "libm.h"
double fabs(double x)
{
union
{
double f;
uint64_t i;
} u = {x};
u.i &= -1ULL / 2;
return u.f;
}
#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
long double fabsl(long double x)
{
return fabs(x);
}
#elif (__LDBL_MANT_DIG__ == 64 || __LDBL_MANT_DIG__ == 113) && __LDBL_MAX_EXP__ == 16384
long double fabsl(long double x)
{
union ldshape u = {x};
u.i.se &= 0x7fff;
return u.f;
}
#endif

View File

@ -0,0 +1,75 @@
#pragma once
#include <libc/src/sys/types.h>
// ===== 描述long double 的数据比特结构
#if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
#elif __LDBL_MANT_DIG__ == 64 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
union ldshape
{
long double f;
struct
{
uint64_t m;
uint16_t se;
} i;
};
#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
union ldshape
{
long double f;
struct
{
uint64_t lo;
uint32_t mid;
uint16_t top;
uint16_t se;
} i;
struct
{
uint64_t lo;
uint64_t hi;
} i2;
};
#elif __LDBL_MANT_DIG__ == 113 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __BIG_ENDIAN
union ldshape
{
long double f;
struct
{
uint16_t se;
uint16_t top;
uint32_t mid;
uint64_t lo;
} i;
struct
{
uint64_t hi;
uint64_t lo;
} i2;
};
#else
#error Unsupported long double representation
#endif
#define FORCE_EVAL(x) \
do \
{ \
if (sizeof(x) == sizeof(float)) \
{ \
volatile float __x; \
__x = (x); \
(void)__x; \
} \
else if (sizeof(x) == sizeof(double)) \
{ \
volatile double __x; \
__x = (x); \
(void)__x; \
} \
else \
{ \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while (0)

View File

@ -0,0 +1,10 @@
#include <libc/src/math.h>
#include <libc/src/stddef.h>
int64_t pow(int64_t x, int y)
{
int64_t res = 1;
for (int i = 0; i < y; ++i)
res *= x;
return res;
}

View File

@ -0,0 +1,41 @@
#include "libm.h"
#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1
#define EPS __DBL_EPSILON__
#elif __FLT_EVAL_METHOD__ == 2
#define EPS __LDBL_EPSILON__
#endif
static const double toint = 1 / EPS;
double round(double x)
{
union
{
double f;
uint64_t i;
} u = {x};
int e = u.i >> 52 & 0x7ff;
double y;
if (e >= 0x3ff + 52)
return x;
if (u.i >> 63)
x = -x;
if (e < 0x3ff - 1)
{
/* raise inexact if x!=0 */
FORCE_EVAL(x + toint);
return 0 * u.f;
}
y = x + toint - toint - x;
if (y > 0.5)
y = y + x - 1;
else if (y <= -0.5)
y = y + x + 1;
else
y = y + x;
if (u.i >> 63)
y = -y;
return y;
}

554
user/libs/libc/src/printf.c Normal file
View File

@ -0,0 +1,554 @@
#include "printf.h"
#include <libc/src/math.h>
#include <libc/src/stdio.h>
#include <libc/src/stdlib.h>
#include <libc/src/string.h>
#include <libsystem/syscall.h>
static char *write_num(char *str, uint64_t num, int base, int field_width, int precision, int flags);
static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags);
static int skip_and_atoi(const char **s)
{
/**
* @brief 获取连续的一段字符对应整数的值
* @param:**s 指向 指向字符串的指针 的指针
*/
int ans = 0;
while (is_digit(**s))
{
ans = ans * 10 + (**s) - '0';
++(*s);
}
return ans;
}
/**
* @brief 往屏幕上输出字符串
*
* @param str 字符串指针
* @param front_color 前景色
* @param bg_color 背景色
* @return int64_t
*/
int64_t put_string(char *str, uint64_t front_color, uint64_t bg_color)
{
return syscall_invoke(SYS_PUT_STRING, (uint64_t)str, front_color, bg_color, 0, 0, 0, 0, 0);
}
int printf(const char *fmt, ...)
{
char buf[4096];
int count = 0;
va_list args;
va_start(args, fmt);
count = vsprintf(buf, fmt, args);
va_end(args);
put_string(buf, COLOR_WHITE, COLOR_BLACK);
return count;
}
int sprintf(char *buf, const char *fmt, ...)
{
int count = 0;
va_list args;
va_start(args, fmt);
count = vsprintf(buf, fmt, args);
va_end(args);
return count;
}
/**
* 将字符串按照fmt和args中的内容进行格式化然后保存到buf中
* @param buf 结果缓冲区
* @param fmt 格式化字符串
* @param args 内容
* @return 最终字符串的长度
*/
int vsprintf(char *buf, const char *fmt, va_list args)
{
// 当需要输出的字符串的指针为空时,使用该字符填充目标字符串的指针
static const char __end_zero_char = '\0';
char *str = NULL, *s = NULL;
str = buf;
int flags; // 用来存储格式信息的bitmap
int field_width; //区域宽度
int precision; //精度
int qualifier; //数据显示的类型
int len;
//开始解析字符串
for (; *fmt; ++fmt)
{
//内容不涉及到格式化,直接输出
if (*fmt != '%')
{
*str = *fmt;
++str;
continue;
}
//开始格式化字符串
//清空标志位和field宽度
field_width = flags = 0;
bool flag_tmp = true;
bool flag_break = false;
++fmt;
while (flag_tmp)
{
switch (*fmt)
{
case '\0':
//结束解析
flag_break = true;
flag_tmp = false;
break;
case '-':
// 左对齐
flags |= LEFT;
++fmt;
break;
case '+':
//在正数前面显示加号
flags |= PLUS;
++fmt;
break;
case ' ':
flags |= SPACE;
++fmt;
break;
case '#':
//在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
flags |= SPECIAL;
++fmt;
break;
case '0':
//显示的数字之前填充0来取代空格
flags |= PAD_ZERO;
++fmt;
break;
default:
flag_tmp = false;
break;
}
}
if (flag_break)
break;
//获取区域宽度
field_width = -1;
if (*fmt == '*')
{
field_width = va_arg(args, int);
++fmt;
}
else if (is_digit(*fmt))
{
field_width = skip_and_atoi(&fmt);
if (field_width < 0)
{
field_width = -field_width;
flags |= LEFT;
}
}
//获取小数精度
precision = -1;
if (*fmt == '.')
{
++fmt;
if (*fmt == '*')
{
precision = va_arg(args, int);
++fmt;
}
else if is_digit (*fmt)
{
precision = skip_and_atoi(&fmt);
}
}
//获取要显示的数据的类型
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z')
{
qualifier = *fmt;
++fmt;
}
//为了支持lld
if (qualifier == 'l' && *fmt == 'l', *(fmt + 1) == 'd')
++fmt;
//转化成字符串
long long *ip;
switch (*fmt)
{
//输出 %
case '%':
*str++ = '%';
break;
// 显示一个字符
case 'c':
//靠右对齐
if (!(flags & LEFT))
{
while (--field_width > 0)
{
*str = ' ';
++str;
}
}
*str++ = (unsigned char)va_arg(args, int);
while (--field_width > 0)
{
*str = ' ';
++str;
}
break;
//显示一个字符串
case 's':
s = va_arg(args, char *);
if (!s)
s = &__end_zero_char;
len = strlen(s);
if (precision < 0)
{
//未指定精度
precision = len;
}
else if (len > precision)
{
len = precision;
}
//靠右对齐
if (!(flags & LEFT))
while (len < field_width--)
{
*str = ' ';
++str;
}
for (int i = 0; i < len; i++)
{
*str = *s;
++s;
++str;
}
while (len < field_width--)
{
*str = ' ';
++str;
}
break;
//以八进制显示字符串
case 'o':
flags |= SMALL;
case 'O':
flags |= SPECIAL;
if (qualifier == 'l')
str = write_num(str, va_arg(args, long long), 8, field_width, precision, flags);
else
str = write_num(str, va_arg(args, int), 8, field_width, precision, flags);
break;
//打印指针指向的地址
case 'p':
if (field_width == 0)
{
field_width = 2 * sizeof(void *);
flags |= PAD_ZERO;
}
str = write_num(str, (unsigned long)va_arg(args, void *), 16, field_width, precision, flags);
break;
//打印十六进制
case 'x':
flags |= SMALL;
case 'X':
// flags |= SPECIAL;
if (qualifier == 'l')
str = write_num(str, va_arg(args, int64_t), 16, field_width, precision, flags);
else
str = write_num(str, va_arg(args, int), 16, field_width, precision, flags);
break;
//打印十进制有符号整数
case 'i':
case 'd':
flags |= SIGN;
if (qualifier == 'l')
str = write_num(str, va_arg(args, long long), 10, field_width, precision, flags);
else
str = write_num(str, va_arg(args, int), 10, field_width, precision, flags);
break;
//打印十进制无符号整数
case 'u':
if (qualifier == 'l')
str = write_num(str, va_arg(args, unsigned long long), 10, field_width, precision, flags);
else
str = write_num(str, va_arg(args, unsigned int), 10, field_width, precision, flags);
break;
//输出有效字符数量到*ip对应的变量
case 'n':
if (qualifier == 'l')
ip = va_arg(args, long long *);
else
ip = (int64_t *)va_arg(args, int *);
*ip = str - buf;
break;
case 'f':
// 默认精度为3
if (precision < 0)
precision = 3;
str = write_float_point_num(str, va_arg(args, double), field_width, precision, flags);
break;
//对于不识别的控制符,直接输出
default:
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
break;
}
}
*str = '\0';
//返回缓冲区已有字符串的长度。
return str - buf;
}
static char *write_num(char *str, uint64_t num, int base, int field_width, int precision, int flags)
{
/**
* @brief 将数字按照指定的要求转换成对应的字符串
*
* @param str 要返回的字符串
* @param num 要打印的数值
* @param base 基数
* @param field_width 区域宽度
* @param precision 精度
* @param flags 标志位
*/
// 首先判断是否支持该进制
if (base < 2 || base > 36)
return 0;
char pad, sign, tmp_num[100];
const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 显示小写字母
if (flags & SMALL)
digits = "0123456789abcdefghijklmnopqrstuvwxyz";
if (flags & LEFT)
flags &= ~PAD_ZERO;
// 设置填充元素
pad = (flags & PAD_ZERO) ? '0' : ' ';
sign = 0;
if (flags & SIGN)
{
int64_t signed_num = (int64_t)num;
if (signed_num < 0)
{
sign = '-';
num = -signed_num;
}
else
num = signed_num;
}
else
{
// 设置符号
sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
}
// sign占用了一个宽度
if (sign)
--field_width;
if (flags & SPECIAL)
if (base == 16) // 0x占用2个位置
field_width -= 2;
else if (base == 8) // O占用一个位置
--field_width;
int js_num = 0; // 临时数字字符串tmp_num的长度
if (num == 0)
tmp_num[js_num++] = '0';
else
{
num = llabs(num);
//进制转换
while (num > 0)
{
tmp_num[js_num++] = digits[num % base]; // 注意这里,输出的数字,是小端对齐的。低位存低位
num /= base;
}
}
if (js_num > precision)
precision = js_num;
field_width -= precision;
// 靠右对齐
if (!(flags & (LEFT + PAD_ZERO)))
while (field_width-- > 0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (flags & SPECIAL)
if (base == 16)
{
*str++ = '0';
*str++ = digits[33];
}
else if (base == 8)
*str++ = digits[24]; //注意这里是英文字母O或者o
if (!(flags & LEFT))
while (field_width-- > 0)
*str++ = pad;
while (js_num < precision)
{
--precision;
*str++ = '0';
}
while (js_num-- > 0)
*str++ = tmp_num[js_num];
while (field_width-- > 0)
*str++ = ' ';
return str;
}
static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags)
{
/**
* @brief 将浮点数按照指定的要求转换成对应的字符串
*
* @param str 要返回的字符串
* @param num 要打印的数值
* @param field_width 区域宽度
* @param precision 精度
* @param flags 标志位
*/
char pad, sign, tmp_num_z[100], tmp_num_d[350];
const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 显示小写字母
if (flags & SMALL)
digits = "0123456789abcdefghijklmnopqrstuvwxyz";
// 设置填充元素
pad = (flags & PAD_ZERO) ? '0' : ' ';
sign = 0;
if (flags & SIGN && num < 0)
{
sign = '-';
num = -num;
}
else
{
// 设置符号
sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
}
// sign占用了一个宽度
if (sign)
--field_width;
int js_num_z = 0, js_num_d = 0; // 临时数字字符串tmp_num_z tmp_num_d的长度
uint64_t num_z = (uint64_t)(num); // 获取整数部分
uint64_t num_decimal = (uint64_t)(round(1.0 * (num - num_z) * pow(10, precision))); // 获取小数部分
if (num == 0 || num_z == 0)
tmp_num_z[js_num_z++] = '0';
else
{
//存储整数部分
while (num_z > 0)
{
tmp_num_z[js_num_z++] = digits[num_z % 10]; // 注意这里,输出的数字,是小端对齐的。低位存低位
num_z /= 10;
}
}
while (num_decimal > 0)
{
tmp_num_d[js_num_d++] = digits[num_decimal % 10];
num_decimal /= 10;
}
field_width -= (precision + 1 + js_num_z);
// 靠右对齐
if (!(flags & LEFT))
while (field_width-- > 0)
*str++ = pad;
if (sign)
*str++ = sign;
// 输出整数部分
// while (js_num_z-- > 0)
// *str++ = tmp_num_z[js_num_z];
while (js_num_z > 0)
{
*str++ = tmp_num_z[js_num_z - 1];
--js_num_z;
}
*str++ = '.';
// 输出小数部分
int total_dec_count = js_num_d;
for (int i = 0; i < precision && js_num_d-- > 0; ++i)
*str++ = tmp_num_d[js_num_d];
while (total_dec_count < precision)
{
++total_dec_count;
*str++ = '0';
}
while (field_width-- > 0)
*str++ = ' ';
return str;
}

View File

@ -0,0 +1,13 @@
#pragma once
#define PAD_ZERO 1 // 0填充
#define LEFT 2 // 靠左对齐
#define RIGHT 4 // 靠右对齐
#define PLUS 8 // 在正数前面显示加号
#define SPACE 16
#define SPECIAL 32 // 在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
#define SMALL 64 // 十进制以上数字显示小写字母
#define SIGN 128 // 显示符号位
#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏

View File

@ -0,0 +1,13 @@
#pragma once
#include <libc/src/sys/types.h>
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
typedef __PTRDIFF_TYPE__ ptrdiff_t; // Signed integer type of the result of subtracting two pointers.

View File

@ -0,0 +1,35 @@
#pragma once
#include <libc/src/sys/types.h>
#include <stdarg.h>
// 字体颜色的宏定义
#define COLOR_WHITE 0x00ffffff //白
#define COLOR_BLACK 0x00000000 //黑
#define COLOR_RED 0x00ff0000 //红
#define COLOR_ORANGE 0x00ff8000 //橙
#define COLOR_YELLOW 0x00ffff00 //黄
#define COLOR_GREEN 0x0000ff00 //绿
#define COLOR_BLUE 0x000000ff //蓝
#define COLOR_INDIGO 0x0000ffff //靛
#define COLOR_PURPLE 0x008000ff //紫
#define SEEK_SET 0 /* Seek relative to start-of-file */
#define SEEK_CUR 1 /* Seek relative to current position */
#define SEEK_END 2 /* Seek relative to end-of-file */
#define SEEK_MAX 3
/**
* @brief 往屏幕上输出字符串
*
* @param str 字符串指针
* @param front_color 前景色
* @param bg_color 背景色
* @return int64_t
*/
int64_t put_string(char *str, uint64_t front_color, uint64_t bg_color);
int printf(const char *fmt, ...);
int sprintf(char *buf, const char *fmt, ...);
int vsprintf(char *buf, const char *fmt, va_list args);

View File

@ -0,0 +1,57 @@
#include <libc/src/unistd.h>
#include <libc/src/stdlib.h>
#include <libc/src/ctype.h>
#include <libsystem/syscall.h>
int abs(int i)
{
return i < 0 ? -i : i;
}
long labs(long i)
{
return i < 0 ? -i : i;
}
long long llabs(long long i)
{
return i < 0 ? -i : i;
}
int atoi(const char *str)
{
int n = 0, neg = 0;
while (isspace(*str))
{
str++;
}
switch (*str)
{
case '-':
neg = 1;
break;
case '+':
str++;
break;
}
/* Compute n as a negative number to avoid overflow on INT_MIN */
while (isdigit(*str))
{
n = 10 * n - (*str++ - '0');
}
return neg ? n : -n;
}
/**
* @brief 退出进程
*
* @param status
*/
void exit(int status)
{
syscall_invoke(SYS_EXIT, status, 0, 0, 0, 0, 0, 0, 0);
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <libc/src/sys/types.h>
/**
* @brief 获取一块堆内存
*
* @param size 内存大小
* @return void* 内存空间的指针
*/
void *malloc(ssize_t size);
/**
* @brief 释放一块堆内存
*
* @param ptr 堆内存的指针
*/
void free(void* ptr);
/**
* @brief 返回int的绝对值
*
* @param i
* @return int
*/
int abs(int i);
long labs(long i);
long long llabs(long long i);
/**
* @brief 字符串转int
*
* @param str
* @return int
*/
int atoi(const char * str);
/**
* @brief 退出进程
*
* @param status
*/
void exit(int status);

116
user/libs/libc/src/string.c Normal file
View File

@ -0,0 +1,116 @@
#include "string.h"
size_t strlen(const char *s)
{
register int __res = 0;
while (s[__res] != '\0')
{
++__res;
}
return __res;
}
int strcmp(const char *FirstPart, const char *SecondPart)
{
register int __res;
__asm__ __volatile__("cld \n\t"
"1: \n\t"
"lodsb \n\t"
"scasb \n\t"
"jne 2f \n\t"
"testb %%al, %%al \n\t"
"jne 1b \n\t"
"xorl %%eax, %%eax \n\t"
"jmp 3f \n\t"
"2: \n\t"
"movl $1, %%eax \n\t"
"jl 3f \n\t"
"negl %%eax \n\t"
"3: \n\t"
: "=a"(__res)
: "D"(FirstPart), "S"(SecondPart)
:);
return __res;
}
void *memset(void *dst, unsigned char C, uint64_t size)
{
int d0, d1;
unsigned long tmp = C * 0x0101010101010101UL;
__asm__ __volatile__("cld \n\t"
"rep \n\t"
"stosq \n\t"
"testb $4, %b3 \n\t"
"je 1f \n\t"
"stosl \n\t"
"1:\ttestb $2, %b3 \n\t"
"je 2f\n\t"
"stosw \n\t"
"2:\ttestb $1, %b3 \n\t"
"je 3f \n\t"
"stosb \n\t"
"3: \n\t"
: "=&c"(d0), "=&D"(d1)
: "a"(tmp), "q"(size), "0"(size / 8), "1"(dst)
: "memory");
return dst;
}
/**
* @brief 拷贝指定字节数的字符串
*
* @param dst 目标地址
* @param src 源字符串
* @param Count 字节数
* @return char*
*/
char *strncpy(char *dst, const char *src, size_t Count)
{
__asm__ __volatile__("cld \n\t"
"1: \n\t"
"decq %2 \n\t"
"js 2f \n\t"
"lodsb \n\t"
"stosb \n\t"
"testb %%al, %%al \n\t"
"jne 1b \n\t"
"rep \n\t"
"stosb \n\t"
"2: \n\t"
:
: "S"(src), "D"(dst), "c"(Count)
: "ax", "memory");
return dst;
}
/**
* @brief 拼接两个字符串将src接到dest末尾
*
* @param dest 目标串
* @param src 源串
* @return char*
*/
char *strcat(char *dest, const char *src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
/**
* @brief 拷贝整个字符串
*
* @param dst 目标地址
* @param src 源地址
* @return char* 目标字符串
*/
char *strcpy(char *dst, const char *src)
{
while (*src)
{
*(dst++) = *(src++);
}
*dst = 0;
return dst;
}

View File

@ -0,0 +1,79 @@
#pragma once
#include <libc/src/sys/types.h>
void *memset(void *dst, unsigned char C, uint64_t size);
/**
* @brief 获取字符串的大小
*
* @param s 字符串
* @return size_t 大小
*/
size_t strlen(const char *s);
/*
比较字符串 FirstPart and SecondPart
FirstPart = SecondPart => 0
FirstPart > SecondPart => 1
FirstPart < SecondPart => -1
*/
int strcmp(const char *FirstPart, const char *SecondPart);
/**
* @brief 拷贝指定字节数的字符串
*
* @param dst 目标地址
* @param src 源字符串
* @param Count 字节数
* @return char*
*/
char *strncpy(char *dst, const char *src, size_t Count);
/**
* @brief 拷贝整个字符串
*
* @param dst 目标地址
* @param src 源地址
* @return char* 目标字符串
*/
char* strcpy(char* dst, const char* src);
/**
* @brief 拼接两个字符串将src接到dest末尾
*
* @param dest 目标串
* @param src 源串
* @return char*
*/
char *strcat(char *dest, const char *src);
/**
* @brief 内存拷贝函数
*
* @param dst 目标数组
* @param src 源数组
* @param Num 字节数
* @return void*
*/
static void *memcpy(void *dst, const void *src, long Num)
{
int d0 = 0, d1 = 0, d2 = 0;
__asm__ __volatile__("cld \n\t"
"rep \n\t"
"movsq \n\t"
"testb $4,%b4 \n\t"
"je 1f \n\t"
"movsl \n\t"
"1:\ttestb $2,%b4 \n\t"
"je 2f \n\t"
"movsw \n\t"
"2:\ttestb $1,%b4 \n\t"
"je 3f \n\t"
"movsb \n\t"
"3: \n\t"
: "=&c"(d0), "=&D"(d1), "=&S"(d2)
: "0"(Num / 8), "q"(Num), "1"(dst), "2"(src)
: "memory");
return dst;
}

View File

@ -0,0 +1,11 @@
all: wait.o stat.o
CFLAGS += -I .
wait.o: wait.c
$(CC) $(CFLAGS) -c wait.c -o wait.o
stat.o: stat.c
$(CC) $(CFLAGS) -c stat.c -o stat.o

View File

@ -0,0 +1,23 @@
#include "stat.h"
#include <libsystem/syscall.h>
int mkdir(const char *path, mode_t mode)
{
return syscall_invoke(SYS_MKDIR, (uint64_t)path, (uint64_t)mode, 0, 0, 0, 0, 0, 0);
}
/**
* @brief 获取系统的内存信息
*
* @param stat 传入的内存信息结构体
* @return int 错误码
*/
int mstat(struct mstat_t *stat)
{
return syscall_invoke(SYS_MSTAT, (uint64_t)stat, 0, 0, 0, 0, 0, 0, 0);
}
int pipe(int *fd)
{
return syscall_invoke(SYS_PIPE, (uint64_t)fd, 0, 0,0,0,0,0,0);
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <libc/src/sys/types.h>
/**
* @brief 系统内存信息结构体(单位:字节)
*
*/
struct mstat_t
{
uint64_t total; // 计算机的总内存数量大小
uint64_t used; // 已使用的内存大小
uint64_t free; // 空闲物理页所占的内存大小
uint64_t shared; // 共享的内存大小
uint64_t cache_used; // 位于slab缓冲区中的已使用的内存大小
uint64_t cache_free; // 位于slab缓冲区中的空闲的内存大小
uint64_t available; // 系统总空闲内存大小包括kmalloc缓冲区
};
int mkdir(const char *path, mode_t mode);
/**
* @brief 获取系统的内存信息
*
* @param stat 传入的内存信息结构体
* @return int 错误码
*/
int mstat(struct mstat_t* stat);
int pipe(int *fd);

View File

@ -0,0 +1,83 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef long long ssize_t;
typedef int64_t pid_t;
typedef __SIZE_TYPE__ size_t;
typedef char *caddr_t;
typedef int id_t;
typedef uint64_t ino_t;
typedef int64_t off_t;
typedef uint32_t blkcnt_t;
typedef uint32_t blksize_t;
typedef uint32_t dev_t;
typedef uint16_t mode_t;
typedef uint32_t nlink_t;
typedef int64_t time_t;
typedef uint32_t useconds_t;
typedef int32_t suseconds_t;
typedef uint32_t clock_t;
typedef uint64_t fsblkcnt_t;
typedef uint64_t fsfilcnt_t;
#define __socklen_t_defined
#define __socklen_t uint32_t
typedef __socklen_t socklen_t;
struct utimbuf
{
time_t actime;
time_t modtime;
};
typedef int pthread_t;
typedef int pthread_key_t;
typedef uint32_t pthread_once_t;
typedef struct __pthread_mutex_t
{
uint32_t lock;
pthread_t owner;
int level;
int type;
} pthread_mutex_t;
typedef void *pthread_attr_t;
typedef struct __pthread_mutexattr_t
{
int type;
} pthread_mutexattr_t;
typedef struct __pthread_cond_t
{
pthread_mutex_t *mutex;
uint32_t value;
int clockid; // clockid_t
} pthread_cond_t;
typedef uint64_t pthread_rwlock_t;
typedef void *pthread_rwlockattr_t;
typedef struct __pthread_spinlock_t
{
int m_lock;
} pthread_spinlock_t;
typedef struct __pthread_condattr_t
{
int clockid; // clockid_t
} pthread_condattr_t;

View File

@ -0,0 +1,26 @@
#include "wait.h"
#include <libsystem/syscall.h>
/**
* @brief 等待所有子进程退出
*
* @param stat_loc 返回的子进程结束状态
* @return pid_t
*/
pid_t wait(int *stat_loc)
{
return waitpid((pid_t)(-1), stat_loc, 0);
}
/**
* @brief 等待指定pid的子进程退出
*
* @param pid 子进程的pid
* @param stat_loc 返回的子进程结束状态
* @param options 额外的控制选项
* @return pid_t
*/
pid_t waitpid(pid_t pid, int *stat_loc, int options)
{
return (pid_t)syscall_invoke(SYS_WAIT4, (uint64_t)pid, (uint64_t)stat_loc, options, 0, 0, 0, 0, 0);
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "types.h"
/**
* @brief 等待所有子进程退出
*
* @param stat_loc 返回的子进程结束状态
* @return pid_t
*/
pid_t wait(int *stat_loc);
/**
* @brief 等待指定pid的子进程退出
*
* @param pid 子进程的pid
* @param stat_loc 返回的子进程结束状态
* @param options 额外的控制选项
* @return pid_t
*/
pid_t waitpid(pid_t pid, int *stat_loc, int options);

View File

@ -0,0 +1,12 @@
all: start.o
ifeq ($(ARCH), __x86_64__)
start.o:
$(CC) $(CFLAGS) -c elf/start.c -o elf/start.o
endif
clean:
echo "Done."

View File

@ -0,0 +1,13 @@
#include <libc/src/stdio.h>
#include <libc/src/stdlib.h>
extern int main(int, char **);
void _start(int argc, char **argv)
{
// printf("before main\n");
int retval = main(argc, argv);
// printf("before exit, code=%d\n", retval);
exit(retval);
}

42
user/libs/libc/src/time.c Normal file
View File

@ -0,0 +1,42 @@
#include "time.h"
#include "errno.h"
#include "unistd.h"
#include <libsystem/syscall.h>
/**
* @brief 休眠指定时间
*
* @param rqtp 指定休眠的时间
* @param rmtp 返回的剩余休眠时间
* @return int
*/
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
return syscall_invoke(SYS_NANOSLEEP, (uint64_t)rqtp, (uint64_t)rmtp, 0, 0, 0, 0, 0, 0);
}
/**
* @brief 睡眠指定时间
*
* @param usec 微秒
* @return int
*/
int usleep(useconds_t usec)
{
struct timespec ts = {
tv_sec : (long int)(usec / 1000000),
tv_nsec : (long int)(usec % 1000000) * 1000UL
};
return nanosleep(&ts, NULL);
}
/**
* @brief 获取系统当前cpu时间
*
* @return clock_t
*/
clock_t clock()
{
return (clock_t)syscall_invoke(SYS_CLOCK, 0,0,0,0,0,0,0,0);
}

45
user/libs/libc/src/time.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#include "stddef.h"
// 操作系统定义时间以ns为单位
#define CLOCKS_PER_SEC 1000000
struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/
long int __tm_gmtoff; /* Seconds east of UTC. */
const char *__tm_zone; /* Timezone abbreviation. */
};
struct timespec
{
long int tv_sec; // 秒
long int tv_nsec; // 纳秒
};
/**
* @brief 休眠指定时间
*
* @param rqtp 指定休眠的时间
* @param rmtp 返回的剩余休眠时间
* @return int
*/
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
/**
* @brief 获取系统当前cpu时间
*
* @return clock_t
*/
clock_t clock();

196
user/libs/libc/src/unistd.c Normal file
View File

@ -0,0 +1,196 @@
#include <libc/src/unistd.h>
#include <libsystem/syscall.h>
#include <libc/src/errno.h>
#include <libc/src/stdio.h>
#include <libc/src/stddef.h>
#include <libc/src/string.h>
#include <libc/src/fcntl.h>
/**
* @brief 关闭文件接口
*
* @param fd 文件描述符
* @return int
*/
int close(int fd)
{
return syscall_invoke(SYS_CLOSE, fd, 0, 0, 0, 0, 0, 0, 0);
}
/**
* @brief 从文件读取数据的接口
*
* @param fd 文件描述符
* @param buf 缓冲区
* @param count 待读取数据的字节数
* @return ssize_t 成功读取的字节数
*/
ssize_t read(int fd, void *buf, size_t count)
{
return (ssize_t)syscall_invoke(SYS_READ, fd, (uint64_t)buf, count, 0, 0, 0, 0, 0);
}
/**
* @brief 向文件写入数据的接口
*
* @param fd 文件描述符
* @param buf 缓冲区
* @param count 待写入数据的字节数
* @return ssize_t 成功写入的字节数
*/
ssize_t write(int fd, void const *buf, size_t count)
{
return (ssize_t)syscall_invoke(SYS_WRITE, fd, (uint64_t)buf, count, 0, 0, 0, 0, 0);
}
/**
* @brief 调整文件的访问位置
*
* @param fd 文件描述符号
* @param offset 偏移量
* @param whence 调整模式
* @return uint64_t 调整结束后的文件访问位置
*/
off_t lseek(int fd, off_t offset, int whence)
{
return (off_t)syscall_invoke(SYS_LSEEK, fd, offset, whence, 0, 0, 0, 0, 0);
}
/**
* @brief fork当前进程
*
* @return pid_t
*/
pid_t fork(void)
{
return (pid_t)syscall_invoke(SYS_FORK, 0, 0, 0, 0, 0, 0, 0, 0);
}
/**
* @brief fork当前进程但是与父进程共享VM、flags、fd
*
* @return pid_t
*/
pid_t vfork(void)
{
return (pid_t)syscall_invoke(SYS_VFORK, 0, 0, 0, 0, 0, 0, 0, 0);
}
/**
* @brief 将堆内存调整为end_brk
*
* @param end_brk 新的堆区域的结束地址
* end_brk=-1 ===> 返回堆区域的起始地址
* end_brk=-2 ===> 返回堆区域的结束地址
* @return uint64_t 错误码
*
*/
uint64_t brk(uint64_t end_brk)
{
uint64_t x = (uint64_t)syscall_invoke(SYS_BRK, (uint64_t)end_brk, 0, 0, 0, 0, 0, 0, 0);
// printf("brk(): end_brk=%#018lx x=%#018lx", (uint64_t)end_brk, x);
return x;
}
/**
* @brief 将堆内存空间加上offset注意该系统调用只应在普通进程中调用而不能是内核线程
*
* @param increment offset偏移量
* @return uint64_t the previous program break
*/
void *sbrk(int64_t increment)
{
void *retval = (void *)syscall_invoke(SYS_SBRK, (uint64_t)increment, 0, 0, 0, 0, 0, 0, 0);
if (retval == (void *)-ENOMEM)
return (void *)(-1);
else
{
errno = 0;
return (void *)retval;
}
}
/**
* @brief 切换当前工作目录
*
* @param dest_path 目标目录
* @return int64_t 成功0,失败:负值(错误码)
*/
int64_t chdir(char *dest_path)
{
if (dest_path == NULL)
{
errno = -EFAULT;
return -1;
}
else
{
return syscall_invoke(SYS_CHDIR, (uint64_t)dest_path, 0, 0, 0, 0, 0, 0, 0);
}
}
/**
* @brief 执行新的程序
*
* @param path 文件路径
* @param argv 参数列表
* @return int
*/
int execv(const char *path, char *const argv[])
{
if (path == NULL)
{
errno = -ENOENT;
return -1;
}
int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
if (retval != 0)
return -1;
else
return 0;
}
/**
* @brief 删除文件夹
*
* @param path 绝对路径
* @return int 错误码
*/
int rmdir(const char *path)
{
return syscall_invoke(SYS_UNLINK_AT, 0, (uint64_t)path, AT_REMOVEDIR, 0, 0, 0, 0, 0);
}
/**
* @brief 删除文件
*
* @param path 绝对路径
* @return int
*/
int rm(const char * path)
{
return syscall_invoke(SYS_UNLINK_AT, 0, (uint64_t)path, 0, 0, 0, 0, 0, 0);
}
/**
* @brief 交换n字节
* @param src 源地址
* @param dest 目的地址
* @param nbytes 交换字节数
*/
void swab(void *restrict src, void *restrict dest, ssize_t nbytes)
{
unsigned char buf[32];
char *_src = src;
char *_dest = dest;
uint32_t transfer;
for (; nbytes > 0; nbytes -= transfer)
{
transfer = (nbytes > 32) ? 32 : nbytes;
memcpy(buf, _src, transfer);
memcpy(_src, _dest, transfer);
memcpy(_dest, buf, transfer);
_src += transfer;
_dest += transfer;
}
}

117
user/libs/libc/src/unistd.h Normal file
View File

@ -0,0 +1,117 @@
#pragma once
#include <stdint.h>
#include <libc/src/sys/types.h>
/**
* @brief 关闭文件接口
*
* @param fd 文件描述符
* @return int
*/
int close(int fd);
/**
* @brief 从文件读取数据的接口
*
* @param fd 文件描述符
* @param buf 缓冲区
* @param count 待读取数据的字节数
* @return ssize_t 成功读取的字节数
*/
ssize_t read(int fd, void *buf, size_t count);
/**
* @brief 向文件写入数据的接口
*
* @param fd 文件描述符
* @param buf 缓冲区
* @param count 待写入数据的字节数
* @return ssize_t 成功写入的字节数
*/
ssize_t write(int fd, void const *buf, size_t count);
/**
* @brief 调整文件的访问位置
*
* @param fd 文件描述符号
* @param offset 偏移量
* @param whence 调整模式
* @return uint64_t 调整结束后的文件访问位置
*/
off_t lseek(int fd, off_t offset, int whence);
/**
* @brief fork当前进程
*
* @return pid_t
*/
pid_t fork(void);
/**
* @brief fork当前进程但是与父进程共享VM、flags、fd
*
* @return pid_t
*/
pid_t vfork(void);
/**
* @brief 将堆内存调整为end_brk
*
* @param end_brk 新的堆区域的结束地址
* end_brk=-1 ===> 返回堆区域的起始地址
* end_brk=-2 ===> 返回堆区域的结束地址
* @return uint64_t 错误码
*
*/
uint64_t brk(uint64_t end_brk);
/**
* @brief 将堆内存空间加上offset注意该系统调用只应在普通进程中调用而不能是内核线程
*
* @param increment offset偏移量
* @return uint64_t the previous program break
*/
void *sbrk(int64_t increment);
/**
* @brief 切换当前工作目录
*
* @param dest_path 目标目录
* @return int64_t 成功0,失败:负值(错误码)
*/
int64_t chdir(char *dest_path);
/**
* @brief 执行新的程序
*
* @param path 文件路径
* @param argv 参数列表
* @return int
*/
int execv(const char *path, char *const argv[]);
/**
* @brief 睡眠指定时间
*
* @param usec 微秒
* @return int
*/
extern int usleep(useconds_t usec);
/**
* @brief 删除文件夹
*
* @param path 绝对路径
* @return int 错误码
*/
int rmdir(const char *path);
int rm(const char * path);
/**
* @brief 交换n字节
* @param src 源地址
* @param dest 目的地址
* @param nbytes 交换字节数
*/
void swab(void *restrict src, void *restrict dest, ssize_t nbytes);

View File

@ -0,0 +1,15 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"executables": true,
"features": "-mmx,-sse,+soft-float",
"disable-redzone": true,
"panic-strategy": "abort"
}