libc glossy 嵌入式底層移植

zephyr~發表於2024-05-28

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;
}

相關文章