Newlib的構成
Newlib由三部分構成:libgloss、libc、libm,三者在Newlib原始碼中的儲存位置如下。
- newlib-x.y.z
- libgloss
- newlib
- libc
- libm
libc是標準C庫,libm是標準數學庫,那libgloss是幹啥的?
C庫的部分函式需要引用系統呼叫,裸機系統沒有這些系統呼叫,那麼就由C庫中的libgloss來提
供,gloss這個單詞的本意是"假象"。
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>
#include <serial.h>
#include <timer.h>
/*
* file operations
*/
/* Read from a file. */
ssize_t _read(int file, char *ptr, size_t len)
{
size_t id;
int ch;
for (id = 0; id < len; id++) {
while (serial_getc(&ch) != 0);
*ptr = ch;
ptr++;
serial_putc(ch);
if ((ch == '\r')) {
break;
}
}
return id + 1;
}
/* Write to a file. */
ssize_t _write(int file, const void *ptr, size_t len)
{
const char *bptr = ptr;
for (size_t i = 0; i < len; ++i) {
serial_putc(bptr[i]);
}
return len;
}
/* Close a file. */
int _close(int file)
{
return 0;
}
/* Status of an open file. The sys/stat.h header file required is
distributed in the include subdirectory for this C library. */
int _fstat(__attribute__((unused)) int file)
{
return 0;
}
/* Set position in a file. */
off_t _lseek(int file, off_t ptr, int dir)
{
return 0;
}
/* Query whether output stream is a terminal. For consistency with the
other minimal implementations, which only support output to stdout,
this minimal implementation is suggested by the newlib docs. */
int _isatty(int file)
{
return (file == STDOUT_FILENO);
}
#include <sys/types.h>
/* brk is handled entirely within the C library. This limits METAL programs
* that use the C library to be disallowed from dynamically allocating memory
* without talking to the C library, but that sounds like a sane way to go
* about it. Note that there is no error checking anywhere in this file, users
* will simply get the relevant error when actually trying to use the memory
* that's been allocated. */
extern char metal_segment_heap_target_start;
extern char metal_segment_heap_target_end;
static char *__brk = &metal_segment_heap_target_start;
char *_sbrk(ptrdiff_t incr)
{
char *old = __brk;
/* If __heap_size == 0, we can't allocate memory on the heap */
if (&metal_segment_heap_target_start == &metal_segment_heap_target_end) {
return (void *) -1;
}
/* Don't move the break past the end of the heap */
if ((__brk + incr) < &metal_segment_heap_target_end) {
__brk += incr;
} else {
__brk = &metal_segment_heap_target_end;
return (void *) -1;
}
return old;
}
/* Get process id. This is sometimes used to generate strings unlikely
to conflict with other processes. Minimal implementation for a
system without processes just returns 1. */
int _getpid()
{
return 1;
}
/* Send a signal. Minimal implementation for a system without processes just causes an error. */
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
/* Exit a program without cleaning up files. */
void _exit(int exit_status)
{
while (1);
}
clock_t _times(struct tms *buf)
{
uint64_t ticks;
ticks = get_timestamp_us();
buf->tms_stime = 0;
buf->tms_cutime = 0;
buf->tms_cstime = 0;
return buf->tms_utime = ticks;
}