libc: Document functions in headers #11

Merged
apio merged 12 commits from descriptive_headers into main 2022-10-12 10:11:45 +00:00
13 changed files with 207 additions and 87 deletions

View File

@ -7,6 +7,8 @@
#include "memory/VMM.h" #include "memory/VMM.h"
#include <stddef.h> #include <stddef.h>
// FIXME: Round size up instead of down. (use get_blocks_from_size)
#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) #define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno)
void sys_mmap(Context* context, void* address, size_t size, int flags) void sys_mmap(Context* context, void* address, size_t size, int flags)

View File

@ -1,15 +1,16 @@
#ifndef _ERRNO_H #ifndef _ERRNO_H
#define _ERRNO_H #define _ERRNO_H
/* The last error encountered during a call to a library or system function. */
extern int errno; extern int errno;
#define EPERM 1 #define EPERM 1 // Operation not permitted
#define ENOENT 2 #define ENOENT 2 // No such file or directory
#define EBADF 9 #define EBADF 9 // Bad file descriptor
#define ENOMEM 12 #define ENOMEM 12 // Cannot allocate memory
#define EISDIR 21 #define EISDIR 21 // Is a directory
#define EINVAL 22 #define EINVAL 22 // Invalid argument
#define EMFILE 24 #define EMFILE 24 // Too many open files
#define ENOSYS 38 #define ENOSYS 38 // Function not implemented
#endif #endif

View File

@ -1,8 +1,11 @@
#ifndef _FCNTL_H #ifndef _FCNTL_H
#define _FCNTL_H #define _FCNTL_H
/* Open for reading only. */
#define O_RDONLY 1 #define O_RDONLY 1
/* Open for writing only. */
#define O_WRONLY 2 #define O_WRONLY 2
/* Open for reading and writing. */
#define O_RDWR 3 #define O_RDWR 3
#ifdef __cplusplus #ifdef __cplusplus
@ -10,7 +13,8 @@ extern "C"
{ {
#endif #endif
int open(const char*, int); /* Opens the file specified by pathname. Returns a file descriptor on success, or -1 on error. */
int open(const char* pathname, int flags);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -9,8 +9,13 @@ extern "C"
{ {
#endif #endif
/* Returns the current program's thread identifier. */
pid_t gettid(); pid_t gettid();
unsigned int msleep(unsigned int);
/* Sleeps for ms milliseconds. */
unsigned int msleep(unsigned int ms);
/* Prints a message to standard error and aborts the program. */
noreturn void __luna_abort(const char* message); noreturn void __luna_abort(const char* message);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -13,8 +13,8 @@ typedef struct
int f_err; int f_err;
} FILE; } FILE;
extern FILE* __stderr; extern FILE* __stderr; // The standard error stream.
extern FILE* __stdout; extern FILE* __stdout; // The standard output stream.
#define stderr __stderr #define stderr __stderr
#define stdout __stdout #define stdout __stdout
@ -22,31 +22,80 @@ extern FILE* __stdout;
extern "C" extern "C"
{ {
#endif #endif
int fclose(FILE*);
int fflush(FILE*); /* Closes the file handle stream. */
FILE* fopen(const char*, const char*); int fclose(FILE* stream);
int fprintf(FILE*, const char*, ...);
size_t fread(void*, size_t, size_t, FILE*); /* Does not do anything for now, since buffered IO is not implemented yet. */
int fflush(FILE* stream);
/* Opens the file specified by pathname. Returns the file handle on success, or NULL on error. */
FILE* fopen(const char* pathname, const char* mode);
/* Writes formatted output according to the string format to the file stream. */
int fprintf(FILE* stream, const char* format, ...);
/* Reads nmemb items of size size from the file stream into buf. */
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream);
int fseek(FILE*, long, int); // Not implemented. int fseek(FILE*, long, int); // Not implemented.
long ftell(FILE*); // Not implemented. long ftell(FILE*); // Not implemented.
size_t fwrite(const void*, size_t, size_t, FILE*);
int ferror(FILE*); /* Writes nmemb items of size size from buf into the file stream. */
int feof(FILE*); size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream);
void clearerr(FILE*);
/* Returns nonzero if the error flag in stream was set. */
int ferror(FILE* stream);
/* Returns nonzero if the end-of-file flag in stream was set. */
int feof(FILE* stream);
/* Clears the error and end-of-file flags from stream. */
void clearerr(FILE* stream);
void setbuf(FILE*, char*); // Not implemented. void setbuf(FILE*, char*); // Not implemented.
int vfprintf(FILE*, const char*, va_list);
int printf(const char*, ...); /* Writes formatted output according to the string format to the file stream. */
int vprintf(const char*, va_list); int vfprintf(FILE* stream, const char* format, va_list ap);
int sprintf(char*, const char*, ...);
int snprintf(char*, size_t, const char*, ...); /* Writes formatted output according to the string format to standard output. */
int vsprintf(char*, const char*, va_list); int printf(const char* format, ...);
int vsnprintf(char*, size_t, const char*, va_list);
int puts(const char*); /* Writes formatted output according to the string format to standard output. */
int fputs(const char*, FILE*); int vprintf(const char* format, va_list ap);
int fputc(int, FILE*);
int putc(int, FILE*); /* Writes formatted output according to the string format to the string str. This function is unsafe, use snprintf
int putchar(int); * instead. */
void perror(const char*); int sprintf(char* str, const char* format, ...);
/* Writes at most max bytes of formatted output according to the string format to the string str.*/
int snprintf(char* str, size_t max, const char* format, ...);
/* Writes formatted output according to the string format to the string str. This function is unsafe, use vsnprintf
* instead. */
int vsprintf(char* str, const char* format, va_list ap);
/* Writes at most max bytes of formatted output according to the string format to the string str. */
int vsnprintf(char* str, size_t max, const char* format, va_list ap);
/* Writes the string str followed by a trailing newline to stdout. */
int puts(const char* str);
/* Writes the string str to the file stream. */
int fputs(const char* str, FILE* stream);
/* Writes the character c to the file stream. */
int fputc(int c, FILE* stream);
/* Writes the character c to the file stream. */
int putc(int c, FILE* stream);
/* Writes the character c to standard output. */
int putchar(int c);
/* Prints a message to standard error consisting of the string str followed by a colon and the string representation
* of the last error encountered during a call to a system or library function. */
void perror(const char* str);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -9,13 +9,37 @@ extern "C"
{ {
#endif #endif
/* Aborts the program. */
noreturn void abort(); noreturn void abort();
noreturn void exit(int);
/* Exits the program with the specified status code. */
noreturn void exit(int status);
/* Not implemented. */
int atexit(void (*)(void)); int atexit(void (*)(void));
/* Not implemented.*/
int atoi(const char*); int atoi(const char*);
void free(void*);
/* Not implemented. */
char* getenv(const char*); char* getenv(const char*);
void* malloc(size_t);
/* Allocates n bytes of memory and returns a pointer to it. This memory should be freed by calling free() when it is
* not in use anymore. */
void* malloc(size_t n);
/* Allocates enough bytes of memory for an array containing nmemb items of size n and returns a pointer to it. This
* memory should be freed by calling free() when it is not in use anymore. */
void* calloc(size_t nmemb, size_t n);
/* Resizes memory allocated by malloc() or calloc() to n bytes. Returns a pointer to the new resized region of
* memory, which should be used instead of the old one. This memory should be freed by calling free() when it is not
* in use anymore. */
void* realloc(void* ptr, size_t n);
/* Frees a pointer to memory allocated by malloc(), calloc() or realloc(). Accessing the contents of ptr afterwards
* is undefined behavior. */
void free(void* ptr);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -9,21 +9,37 @@ extern "C"
{ {
#endif #endif
void* memcpy(void*, const void*, size_t); /* Copies n bytes from src to dst. */
void* memset(void*, int, size_t); void* memcpy(void* dest, const void* src, size_t n);
void* memclr(void*, size_t);
size_t strlen(const char*); /* Sets n bytes of buf to c, cast to a character. */
void* memset(void* buf, int c, size_t n);
deprecated("strcpy is unsafe and should not be used; use strncpy instead") char* strcpy(char*, const char*); /* Clears n bytes of buf. */
char* strncpy(char*, const char*, size_t); void* memclr(void* buf, size_t n);
char* strchr(const char*, int); /* Returns the length of the string str. */
size_t strlen(const char* str);
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char*, const char*); /* Copies the string src into dest. This function is unsafe, use strncpy instead. */
char* strncat(char*, const char*, size_t); deprecated("strcpy is unsafe and should not be used; use strncpy instead") char* strcpy(char* dest,
const char* src);
char* strerror(int); /* Copies at most max bytes from the string src into dest. */
char* strncpy(char* dest, const char* src, size_t max);
/* Returns a pointer to the first occurrence of the character c in str, or NULL if it is not found. */
char* strchr(const char* str, int c);
/* Concatenates the string src into dest. This function is unsafe, use strncat instead. */
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char* dest,
const char* src);
/* Concatenates at most max bytes of the string src into dest. */
char* strncat(char* dest, const char* src, size_t max);
/* Returns the error string associated with the error number err. */
char* strerror(int err);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -5,6 +5,7 @@
typedef unsigned long off_t; typedef unsigned long off_t;
/* Address returned by mmap when it fails. */
#define MAP_FAILED (void*)-1 #define MAP_FAILED (void*)-1
#define PROT_READ_WRITE 1 #define PROT_READ_WRITE 1
@ -16,8 +17,13 @@ extern "C"
{ {
#endif #endif
void* mmap(void*, size_t, int, int, int, off_t); /* Maps size bytes of memory (rounded down to the nearest page-aligned size) into the current process's address
int munmap(void* addr, size_t len); * space at addr. If addr is null, the kernel will choose an address. */
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset);
/* Unmaps size bytes of memory (rounded down to the nearest page-aligned size) at addr from the current process's
* address space. */
int munmap(void* addr, size_t size);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,8 +1,13 @@
#ifndef _SYS_TYPES_H #ifndef _SYS_TYPES_H
#define _SYS_TYPES_H #define _SYS_TYPES_H
/* The type of a process identifier. */
typedef long int pid_t; typedef long int pid_t;
/* The type returned by sizeof(). */
typedef unsigned long int size_t; typedef unsigned long int size_t;
/* Signed version of size_t. */
typedef long int ssize_t; typedef long int ssize_t;
#endif #endif

View File

@ -8,16 +8,29 @@ extern "C"
{ {
#endif #endif
/* Not implemented. */
int execv(const char*, char* const[]); int execv(const char*, char* const[]);
/* Not implemented. */
int execve(const char*, char* const[], char* const[]); int execve(const char*, char* const[], char* const[]);
/* Not implemented. */
int execvp(const char*, char* const[]); int execvp(const char*, char* const[]);
/* Not implemented. */
pid_t fork(void); pid_t fork(void);
long syscall(long, ...);
unsigned int sleep(unsigned int);
ssize_t read(int, void*, size_t); /* Calls the kernel for a specific service, determined by number. */
ssize_t write(int, const void*, size_t); long syscall(long number, ...);
int close(int);
/* Suspends execution for a chosen amount of seconds. */
unsigned int sleep(unsigned int seconds);
/* Reads count bytes from the file descriptor fd into the memory at buf. */
ssize_t read(int fd, void* buf, size_t count);
/* Writes count bytes of the memory at buf to the file descriptor fd. */
ssize_t write(int fd, const void* buf, size_t count);
/* Closes the file descriptor fd. */
int close(int fd);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -5,8 +5,6 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#define noreturn __attribute__((noreturn))
extern "C" extern "C"
{ {
pid_t gettid() pid_t gettid()
@ -21,7 +19,7 @@ extern "C"
noreturn void __luna_abort(const char* message) noreturn void __luna_abort(const char* message)
{ {
fwrite(message, strlen(message), 1, stdout); fputs(message, stderr);
abort(); abort();
} }
} }

View File

@ -3,11 +3,6 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#define noreturn __attribute__((noreturn))
#define maybe_unused __attribute__((maybe_unused))
#define unused __attribute__((unused))
extern "C" extern "C"
{ {
noreturn void abort() noreturn void abort()
@ -25,10 +20,12 @@ extern "C"
{ {
NOT_IMPLEMENTED("atexit"); NOT_IMPLEMENTED("atexit");
} }
int atoi(const char*) int atoi(const char*)
{ {
NOT_IMPLEMENTED("atoi"); NOT_IMPLEMENTED("atoi");
} }
char* getenv(const char*) char* getenv(const char*)
{ {
NOT_IMPLEMENTED("getenv"); NOT_IMPLEMENTED("getenv");

View File

@ -10,18 +10,18 @@ extern "C"
return dest; return dest;
} }
void* memset(void* dest, int c, size_t n) void* memset(void* buf, int c, size_t n)
{ {
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = (char)c; } for (size_t i = 0; i < n; ++i) { *((char*)buf + i) = (char)c; }
return dest; return buf;
} }
size_t strlen(const char* s) size_t strlen(const char* str)
{ {
const char* i = s; const char* i = str;
for (; *i; ++i) for (; *i; ++i)
; ;
return (i - s); return (i - str);
} }
char* strcpy(char* dest, const char* src) char* strcpy(char* dest, const char* src)
@ -30,10 +30,10 @@ extern "C"
return dest; return dest;
} }
char* strncpy(char* dest, const char* src, size_t n) char* strncpy(char* dest, const char* src, size_t max) // FIXME: Implement strncpy according to the specification.
{ {
size_t src_len = strlen(src) + 1; // NULL byte size_t src_len = strlen(src) + 1; // NULL byte
memcpy(dest, src, src_len > n ? n : src_len); memcpy(dest, src, src_len > max ? max : src_len);
return dest; return dest;
} }
@ -49,40 +49,40 @@ extern "C"
return dest; return dest;
} }
char* strncat(char* dest, const char* src, size_t n) char* strncat(char* dest, const char* src, size_t max)
{ {
size_t dest_len = strlen(dest); size_t dest_len = strlen(dest);
size_t i; size_t i;
for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i); for (i = 0; i < max && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
*(char*)(dest + dest_len + i) = '\0'; *(char*)(dest + dest_len + i) = '\0';
return dest; return dest;
} }
char* strchr(const char* str, int chr) char* strchr(const char* str, int c)
{ {
while (*str && *str != (char)chr) str++; while (*str && *str != (char)c) str++;
if (*str) return const_cast<char*>(str); if (*str) return const_cast<char*>(str);
return NULL; return NULL;
} }
void* memclr(void* start, size_t count) void* memclr(void* buf, size_t n)
{ {
// "i" is our counter of how many bytes we've cleared // "i" is our counter of how many bytes we've cleared
size_t i; size_t i;
// find out if "m_start" is aligned on a SSE_XMM_SIZE boundary // find out if "m_start" is aligned on a SSE_XMM_SIZE boundary
if ((size_t)start & (15)) if ((size_t)buf & (15))
{ {
i = 0; i = 0;
// we need to clear byte-by-byte until "m_start" is aligned on an SSE_XMM_SIZE boundary // we need to clear byte-by-byte until "m_start" is aligned on an SSE_XMM_SIZE boundary
// ... and lets make sure we don't copy 'too' many bytes (i < m_count) // ... and lets make sure we don't copy 'too' many bytes (i < m_count)
while (((size_t)start + i) & (15) && i < count) while (((size_t)buf + i) & (15) && i < n)
{ {
asm("stosb;" ::"D"((size_t)start + i), "a"(0)); asm("stosb;" ::"D"((size_t)buf + i), "a"(0));
i++; i++;
} }
} }
@ -93,42 +93,42 @@ extern "C"
} }
// clear 64-byte chunks of memory (4 16-byte operations) // clear 64-byte chunks of memory (4 16-byte operations)
for (; i + 64 <= count; i += 64) for (; i + 64 <= n; i += 64)
{ {
asm volatile(" pxor %%xmm0, %%xmm0; " // set XMM0 to 0 asm volatile(" pxor %%xmm0, %%xmm0; " // set XMM0 to 0
" movdqa %%xmm0, 0(%0); " // move 16 bytes from XMM0 to %0 + 0 " movdqa %%xmm0, 0(%0); " // move 16 bytes from XMM0 to %0 + 0
" movdqa %%xmm0, 16(%0); " " movdqa %%xmm0, 16(%0); "
" movdqa %%xmm0, 32(%0); " " movdqa %%xmm0, 32(%0); "
" movdqa %%xmm0, 48(%0); " ::"r"((size_t)start + i)); " movdqa %%xmm0, 48(%0); " ::"r"((size_t)buf + i));
} }
// copy the remaining bytes (if any) // copy the remaining bytes (if any)
asm(" rep stosb; " ::"a"((size_t)(0)), "D"(((size_t)start) + i), "c"(count - i)); asm(" rep stosb; " ::"a"((size_t)(0)), "D"(((size_t)buf) + i), "c"(n - i));
// "i" will contain the total amount of bytes that were actually transfered // "i" will contain the total amount of bytes that were actually transfered
i += count - i; i += n - i;
// we return "m_start" + the amount of bytes that were transfered // we return "m_start" + the amount of bytes that were transfered
return (void*)(((size_t)start) + i); return (void*)(((size_t)buf) + i);
} }
#pragma GCC push_options #pragma GCC push_options
#pragma GCC diagnostic ignored "-Wwrite-strings" #pragma GCC diagnostic ignored "-Wwrite-strings"
char* strerror(int errnum) char* strerror(int err)
{ {
switch (errnum) switch (err)
{ {
case EPERM: return "Operation not permitted"; case EPERM: return "Operation not permitted";
case EINVAL: return "Invalid argument"; case EINVAL: return "Invalid argument";
case ENOMEM: return "Out of memory"; case ENOMEM: return "Cannot allocate memory";
case ENOSYS: return "Function not implemented"; case ENOSYS: return "Function not implemented";
case ENOENT: return "No such file or directory"; case ENOENT: return "No such file or directory";
case EBADF: return "Bad file descriptor"; case EBADF: return "Bad file descriptor";
case EMFILE: return "Too many open files"; case EMFILE: return "Too many open files";
case EISDIR: return "Is a directory"; case EISDIR: return "Is a directory";
case 0: return "Success"; case 0: return "Success";
default: return (char*)(unsigned long int)errnum; default: return (char*)(unsigned long int)err;
} }
} }