🆕 malloc 、printf

This commit is contained in:
fslongjin
2022-05-07 13:46:23 +08:00
parent 78a219b715
commit fd0147e04c
29 changed files with 1587 additions and 56 deletions

View File

@ -2,11 +2,34 @@ all: libc
CFLAGS += -I .
libc_sub_dirs=math
libc: unistd.o fcntl.o
libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o
@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
gcc $(CFLAGS) -c unistd.c -o unistd.o
fcntl.o: fcntl.c
gcc $(CFLAGS) -c fcntl.c -o fcntl.o
malloc.o: malloc.c
gcc $(CFLAGS) -c malloc.c -o malloc.o
errno.o: errno.c
gcc $(CFLAGS) -c errno.c -o errno.o
printf.o: printf.c
gcc $(CFLAGS) -c printf.c -o printf.o
stdlib.o: stdlib.c
gcc $(CFLAGS) -c stdlib.c -o stdlib.o
ctype.o: ctype.c
gcc $(CFLAGS) -c ctype.c -o ctype.o

20
user/libs/libc/__libc__.h Normal file
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

75
user/libs/libc/ctype.c Normal file
View File

@ -0,0 +1,75 @@
#include <libc/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 == ' ');
}

38
user/libs/libc/ctype.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <libc/sys/types.h>
#pragma once
#include <libc/__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];

2
user/libs/libc/errno.c Normal file
View File

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

View File

@ -98,4 +98,6 @@
#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. */
#define EXDEV 81 /* 跨设备连接 Cross-device link. */
extern int errno;

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

@ -0,0 +1,392 @@
#include <libc/stdlib.h>
#include <libsystem/syscall.h>
#include <libc/stddef.h>
#include <libc/unistd.h>
#include <libc/errno.h>
#include <libc/stdio.h>
/**
* @brief 显式链表的结点
*
*/
typedef struct malloc_mem_chunk_t
{
uint64_t start_addr; // 整个块所在内存区域的起始地址包括header
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;
// 已分配链表
// 使用LIFO策略。基于假设程序运行早期分配的内存会被最晚释放
static malloc_mem_chunk_t *malloc_allocated_list = NULL;
/**
* @brief 获取一块堆内存(不尝试扩大堆内存)
*
* @param size
* @return void* 内存的地址指针,获取失败时返回-ENOMEM
*/
static void *malloc_no_enlarge(ssize_t size);
/**
* @brief 将块插入空闲链表
*
* @param ck 待插入的块
*/
static void malloc_insert_free_list(malloc_mem_chunk_t *ck);
/**
* @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)
{
printf("free list is none.\n");
return NULL;
}
malloc_mem_chunk_t *ptr = malloc_free_list;
malloc_mem_chunk_t *best = NULL;
printf("query size=%d", size);
while (ptr)
{
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(int32_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 tmp = brk_managed_addr + size - brk_max_addr;
if (tmp > 0) // 现有堆空间不足
{
if (sbrk(tmp) != (-1))
brk_max_addr = brk((-1));
else
{
put_string("malloc_enlarge(): no_mem", COLOR_YELLOW, COLOR_BLACK);
return -ENOMEM;
}
}
// 扩展管理的堆空间
// 在新分配的内存的底部放置header
malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)brk_managed_addr;
new_ck->start_addr = (uint64_t)new_ck;
new_ck->length = brk_max_addr - brk_managed_addr;
printf("new_ck->start_addr=%#018lx\tbrk_max_addr=%#018lx\tbrk_managed_addr=%#018lx\n", new_ck->start_addr, brk_max_addr, brk_managed_addr);
new_ck->prev = 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)
{
// 内存块连续
if (ptr->prev->start_addr + ptr->prev->length == ptr->start_addr)
{
// 将ptr与前面的空闲块合并
ptr->prev->length += ptr->length;
ptr->prev->next = ptr->next;
// 由于内存组成结构的原因不需要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;
ck->prev = ck->next = NULL;
return;
}
else
{
uint64_t ck_end = ck->start_addr + ck->length;
malloc_mem_chunk_t *ptr = malloc_free_list;
while (ptr)
{
if (ptr->start_addr < ck->start_addr)
{
if (ptr->next == NULL) // 当前是最后一个项
{
ptr->next = ck;
ck->next = NULL;
ck->prev = ptr;
break;
}
else if (ptr->next->start_addr > ck->start_addr)
{
ck->prev = ptr;
ck->next = ptr->next;
ck->prev->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* 内存的地址指针,获取失败时返回-ENOMEM
*/
static void *malloc_no_enlarge(ssize_t size)
{
// 加上header的大小
size += sizeof(malloc_mem_chunk_t);
// 采用best fit
malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
if (ck == NULL) // 没有空闲块
{
// 尝试合并空闲块
malloc_merge_free_chunk();
ck = malloc_query_free_chunk_bf(size);
// 找到了合适的块
if (ck)
goto found;
else
return -ENOMEM; // 内存不足
}
found:;
// 分配空闲块
// 从空闲链表取出
if (ck->prev == NULL) // 当前是链表的第一个块
{
malloc_free_list = ck->next;
}
else
ck->prev->next = ck->next;
if (ck->next != NULL) // 当前不是最后一个块
ck->next->prev = ck->prev;
// 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
if (ck->length - size > sizeof(malloc_mem_chunk_t))
{
malloc_mem_chunk_t *new_ck = ((uint64_t)ck) + ck->length;
new_ck->length = ck->length - size;
new_ck->start_addr = (uint64_t)new_ck;
new_ck->prev = new_ck->next = NULL;
ck->length = size;
malloc_insert_free_list(new_ck);
}
// 插入到已分配链表
// 直接插入到链表头符合LIFO
ck->prev = NULL;
if (malloc_allocated_list) // 已分配链表不为空
{
malloc_allocated_list->prev = ck;
ck->next = malloc_allocated_list;
malloc_allocated_list = ck;
}
else // 已分配链表为空
{
malloc_allocated_list = ck;
ck->next = NULL;
}
return (void *)(ck->start_addr + sizeof(malloc_mem_chunk_t));
}
/**
* @brief 获取一块堆内存
*
* @param size 内存大小
* @return void* 内存空间的指针
*/
void *malloc(ssize_t size)
{
// 加上header的大小
size += sizeof(malloc_mem_chunk_t);
// 采用best fit
malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
if (ck == NULL) // 没有空闲块
{
// 尝试合并空闲块
printf("merge\n");
malloc_merge_free_chunk();
ck = malloc_query_free_chunk_bf(size);
// 找到了合适的块
if (ck)
goto found;
// 找不到合适的块,扩容堆区域
printf("enlarge\n");
if (malloc_enlarge(size) == -ENOMEM)
return -ENOMEM; // 内存不足
// 扩容后再次尝试获取
printf("query\n");
ck = malloc_query_free_chunk_bf(size);
}
found:;
if (ck == NULL)
return -ENOMEM;
// 分配空闲块
// 从空闲链表取出
if (ck->prev == NULL) // 当前是链表的第一个块
{
malloc_free_list = ck->next;
}
else
ck->prev->next = ck->next;
if (ck->next != NULL) // 当前不是最后一个块
ck->next->prev = ck->prev;
// 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
if (ck->length - size > sizeof(malloc_mem_chunk_t))
{
malloc_mem_chunk_t *new_ck = ((uint64_t)ck) + ck->length;
new_ck->length = ck->length - size;
new_ck->start_addr = (uint64_t)new_ck;
new_ck->prev = new_ck->next = NULL;
ck->length = size;
malloc_insert_free_list(new_ck);
}
// 插入到已分配链表
// 直接插入到链表头符合LIFO
ck->prev = NULL;
if (malloc_allocated_list) // 已分配链表不为空
{
malloc_allocated_list->prev = ck;
ck->next = malloc_allocated_list;
malloc_allocated_list = ck;
}
else // 已分配链表为空
{
malloc_allocated_list = ck;
ck->next = NULL;
}
printf("ck=%lld\n", (uint64_t)ck);
printf("ck->start_addr=%lld\n", ck->start_addr);
return (void *)(ck->start_addr + sizeof(malloc_mem_chunk_t));
}
/**
* @brief 释放一块堆内存
*
* @param ptr 堆内存的指针
*/
void free(void *ptr)
{
}

10
user/libs/libc/math.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
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);

View File

@ -0,0 +1,11 @@
all: fabs.o round.o
CFLAGS += -I .
fabs.o: fabs.c
gcc $(CFLAGS) -c fabs.c -o fabs.o
round.o: round.c
gcc $(CFLAGS) -c round.c -o round.o

View File

@ -0,0 +1,29 @@
#include <libc/math.h>
#include <libc/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/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,43 @@
#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;
}

536
user/libs/libc/printf.c Normal file
View File

@ -0,0 +1,536 @@
#include "printf.h"
#include <libc/stdio.h>
#include <libsystem/syscall.h>
#include <libc/string.h>
#include <libc/math.h>
#include <libc/stdlib.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);
/**
* @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;
}
int vsprintf(char *buf, const char *fmt, va_list args)
{
/**
* 将字符串按照fmt和args中的内容进行格式化然后保存到buf中
* @param buf 结果缓冲区
* @param fmt 格式化字符串
* @param args 内容
* @return 最终字符串的长度
*/
char *str, *s;
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 = 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 = 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 = '\0';
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
// printk("1111\n");
// va_arg(args, double);
// printk("222\n");
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((num - num_z) * precision)); // 获取小数部分
if (num == 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];
*str++ = '.';
// 输出小数部分
while (js_num_d-- > 0)
*str++ = tmp_num_d[js_num_d];
while (js_num_d < precision)
{
--precision;
*str++ = '0';
}
while (field_width-- > 0)
*str++ = ' ';
return str;
}

13
user/libs/libc/printf.h Normal file
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') // 用来判断是否是数字的宏

13
user/libs/libc/stddef.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <libc/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

@ -1,7 +1,35 @@
#pragma once
#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 */
#include <libc/sys/types.h>
#include <stdarg.h>
#define SEEK_MAX 3
// 字体颜色的宏定义
#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);

45
user/libs/libc/stdlib.c Normal file
View File

@ -0,0 +1,45 @@
#include <libc/unistd.h>
#include <libc/stdlib.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;
}

35
user/libs/libc/stdlib.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include <libc/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);

37
user/libs/libc/string.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <libc/sys/types.h>
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;
}
size_t strlen(const char *s)
{
register size_t __res = 0;
while (s[__res] != '\0')
{
++__res;
}
return __res;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef unsigned char u_char;
typedef unsigned short u_short;

View File

@ -1,18 +1,8 @@
#include <libc/unistd.h>
#include <libsystem/syscall.h>
#include <libc/errno.h>
#include <libc/stdio.h>
/**
* @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);
}
/**
* @brief 关闭文件接口
*
@ -81,4 +71,38 @@ pid_t fork(void)
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;
}
}

View File

@ -2,27 +2,9 @@
#include <stdint.h>
#include <libc/sys/types.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 //紫
/**
* @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);
/**
@ -77,3 +59,21 @@ pid_t fork(void);
*/
pid_t vfork(void);
/**
* @brief 将堆内存调整为end_brk
*
* @param end_brk 新的堆区域的结束地址
* end_brk=0 ===> 返回堆区域的起始地址
* end_brk=-1 ===> 返回堆区域的结束地址
* @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);