9os

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 96f288f4dba92525cc687ec043d4154e98b64183
parent 3f5c3cc04b6ddfad477a47ce25281cfd0286468c
Author: Roberto Vargas <roberto.vargas@arm.com>
Date:   Fri, 19 Oct 2018 15:32:20 +0100

[libc] Synchronize with scc libc

Change-Id: I70a848111aa8ae5801c6b2dd10a6e15cde2fe0c3

Diffstat:
Minclude/bits/arm64/arch/stdlib.h | 2++
Msrc/libc/Makefile | 22+++++++++++++++++++++-
Msrc/libc/arch/amd64/linux/.gitignore | 1+
Msrc/libc/arch/arm64/linux/syscall.lst | 1+
Asrc/libc/calloc.c | 18++++++++++++++++++
Asrc/libc/fread.c | 25+++++++++++++++++++++++++
Asrc/libc/fwrite.c | 24++++++++++++++++++++++++
Msrc/libc/malloc.c | 166++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Asrc/libc/malloc.h | 16++++++++++++++++
Msrc/libc/strcspn.c | 2+-
Dsrc/libc/strftime.c | 246-------------------------------------------------------------------------------
Msrc/libc/strpbrk.c | 2+-
Msrc/libc/strspn.c | 2+-
13 files changed, 255 insertions(+), 272 deletions(-)

diff --git a/include/bits/arm64/arch/stdlib.h b/include/bits/arm64/arch/stdlib.h @@ -11,3 +11,5 @@ typedef unsigned long size_t; #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 + +#define _ALIGNTYPE long double diff --git a/src/libc/Makefile b/src/libc/Makefile @@ -30,6 +30,24 @@ COBJ = abort.o \ isspace.o \ isupper.o \ isxdigit.o \ + strcat.o\ + strchr.o\ + strcmp.o\ + strcoll.o\ + strcpy.o\ + strcspn.o\ + strerror.o\ + strlen.o\ + strncat.o\ + strncmp.o\ + strncpy.o\ + strnlen.o \ + strpbrk.o\ + strrchr.o\ + strspn.o\ + strstr.o\ + strtok.o\ + strxfrm.o\ printf.o \ putc.o \ snprintf.o \ @@ -39,7 +57,6 @@ COBJ = abort.o \ vsnprintf.o \ vsprintf.o \ toupper.o \ - strnlen.o \ ferror.o \ _flsbuf.o \ errno.o \ @@ -52,6 +69,8 @@ COBJ = abort.o \ setbuf.o \ setvbuf.o \ clearerr.o \ + fwrite.o \ + fread.o \ fputc.o \ fputs.o \ fseek.o \ @@ -62,6 +81,7 @@ COBJ = abort.o \ rand.o \ raise.o \ malloc.o \ + calloc.o \ OBJS = $(COBJ) $(SYSOBJ) TARGET = $(PROJECTDIR)/lib/libc.a diff --git a/src/libc/arch/amd64/linux/.gitignore b/src/libc/arch/amd64/linux/.gitignore @@ -6,3 +6,4 @@ _lseek.s _open.s _read.s _write.s +_brk.s diff --git a/src/libc/arch/arm64/linux/syscall.lst b/src/libc/arch/arm64/linux/syscall.lst @@ -7,3 +7,4 @@ 172 _getpid 129 _kill 62 _lseek +214 brk diff --git a/src/libc/calloc.c b/src/libc/calloc.c @@ -0,0 +1,18 @@ +#include <stdlib.h> +#include <string.h> +#undef calloc + +void * +calloc(size_t nmemb, size_t size) +{ + size_t nbytes; + void *mem; + + if (!nmemb || !size || nmemb > (size_t)-1/size) + return NULL; + + nbytes = nmemb * size; + if ((mem = malloc(nbytes)) == NULL) + return NULL; + return memset(mem, 0, nbytes); +} diff --git a/src/libc/fread.c b/src/libc/fread.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#undef fread + +size_t +fread(void * restrict ptr, size_t size, size_t nmemb, + FILE * restrict fp) +{ + unsigned char *bp = ptr; + size_t n, i; + int c; + + if (size == 0) + return 0; + + for (n = 0; n < nmemb; n++) { + i = size; + do { + if ((c = getc(fp)) == EOF) + return n; + *bp++ = c; + } while (--i); + } + + return n; +} diff --git a/src/libc/fwrite.c b/src/libc/fwrite.c @@ -0,0 +1,24 @@ +#include <stdio.h> +#undef fwrite + +size_t +fwrite(const void * restrict ptr, size_t size, size_t nmemb, + FILE * restrict fp) +{ + const unsigned char *bp = ptr; + size_t n, i; + + if (size == 0) + return 0; + + for (n = 0; n < nmemb; n++) { + i = size; + do + putc(*bp++, fp); + while (--i); + if (ferror(fp)) + break; + } + + return n; +} diff --git a/src/libc/malloc.c b/src/libc/malloc.c @@ -1,37 +1,159 @@ #include <errno.h> #include <stdint.h> #include <stdlib.h> -#include <stdio.h> #include <string.h> -static int inuse[FOPEN_MAX]; -static char buffers[FOPEN_MAX][BUFSIZ]; +#include "malloc.h" +#include "syscall.h" +#define MAXADDR ((char *)-1) +#define ERRADDR ((char *)-1) + +extern char end[]; +static Header base = { .h.next = &base }; +static Header *freep = &base; + +/* + * Run over the free list looking for the nearest previous + * block. There are two possible results: end of the list + * or an intermediary block. + */ void * -malloc(size_t siz) +_prevchunk(Header *hp) { - int i; - - if (siz == BUFSIZ) { - for (i = 0; i < FOPEN_MAX && inuse[i]; i++) - ; - if (i != FOPEN_MAX) { - inuse[i] = 1; - return buffers[i]; - } - } + Header *p; - errno = ENOMEM; - return NULL; + for (p = freep; ;p = p->h.next) { + /* hp between p and p->h.next? */ + if (p < hp && hp < p->h.next) + break; + /* p before hp and hp at the end of list? */ + if (p->h.next <= p && (hp < p->h.next || hp > p)) + break; + } + return p; } +/* + * Get the previous block and try to merge + * with next and previous blocks + */ void -free(void *bp) +free(void *mem) +{ + Header *hp, *prev; + + if (!mem) + return; + + hp = (Header *) mem - 1; + prev = _prevchunk(hp); + + /* join to next */ + if (hp + hp->h.size == prev->h.next) { + hp->h.size += prev->h.next->h.size; + hp->h.next = prev->h.next->h.next; + } else { + hp->h.next = prev->h.next; + } + + /* join to previous */ + if (prev + prev->h.size == hp) { + prev->h.size += hp->h.size; + prev->h.next = hp->h.next; + } else { + prev->h.next = hp; + } + + freep = prev; +} + +static void * +sbrk(uintptr_t inc) +{ + char *new, *old; + void *p; + static void *heap; + + if (!heap) + heap = _brk(0); + old = heap; + if (old >= MAXADDR - inc) + return ERRADDR; + new = old + inc; + p = _brk(new); + if (p == old || p < 0) + return ERRADDR; + heap = new; + + return old; +} + +static Header * +morecore(size_t nunits) { - int i; + char *rawmem; + Header *hp; + + if (nunits < NALLOC) + nunits = NALLOC; + + rawmem = sbrk(nunits * sizeof(Header)); + if (rawmem == ERRADDR) + return NULL; + + hp = (Header*)rawmem; + hp->h.size = nunits; + + /* integrate new memory into the list */ + free(hp + 1); + + return freep; +} - for (i = 0; i < FOPEN_MAX && buffers[i] != bp; i++) - ; - if (i < FOPEN_MAX) - inuse[i] = 0; +/* + * Run over the list of free blocks trying to find a block + * big enough for nbytes. If the block fit perfectly with + * the required size then we only have to unlink + * the block. Otherwise we have to split the block and + * return the right part. If we run over the full list + * without a fit then we have to require more memory + * + * ______________________________________ + * ___________./______________________________________\_____ + * ...| in | | | in | |.....| in | | | |.... + * ...| use | | | use | |.....| use | | | |.... + * ___|______|___|.____|_____|._|_____|______|._|.___|.|____ + * \__/ \_________/ \_____________/ \/ \__/ + */ +void * +malloc(size_t nbytes) +{ + Header *cur, *prev; + size_t nunits; + + /* 1 unit for header plus enough units to fit nbytes */ + nunits = (nbytes+sizeof(Header)-1) / sizeof(Header) + 1; + + for (prev = freep; ; prev = cur) { + cur = prev->h.next; + if (cur->h.size >= nunits) { + if (cur->h.size == nunits) { + prev->h.next = cur->h.next; + } else { + cur->h.size -= nunits; + cur += cur->h.size; + cur->h.size = nunits; + } + freep = prev; + return cur + 1; + } + + if (cur == freep) { + if ((cur = morecore(nunits)) == NULL) { + errno = ENOMEM; + return NULL; + } + } + } } diff --git a/src/libc/malloc.h b/src/libc/malloc.h @@ -0,0 +1,16 @@ +#include <stdlib.h> + +/* minimum amount of required units */ +#define NALLOC 10000 + +typedef union header Header; +union header { + struct hdr { + Header *next; + size_t size; + } h; + /* most restrictive type fixes the union size for alignment */ + _ALIGNTYPE most; +}; + +extern void *_prevchunk(Header *hp); diff --git a/src/libc/strcspn.c b/src/libc/strcspn.c @@ -8,7 +8,7 @@ strcspn(const char *s1, const char *s2) const unsigned char *accept = s2; unsigned ch; size_t n; - char buf[__NUMCHARS]; + char buf[256]; memset(buf, 0, sizeof(buf)); while (ch = *accept++) diff --git a/src/libc/strftime.c b/src/libc/strftime.c @@ -1,246 +0,0 @@ -#include <time.h> -#include <string.h> -#include "libc.h" -#undef strftime - -static char *days[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", -}; - -static char *months[] = { - "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" -}; - -static char *am_pm[] = {"AM", "PM"}; - -static size_t -sval(char *s, size_t siz, char **strs, int abrev, int idx, int max) -{ - char *str; - size_t len; - - if (idx < 0 && idx >= max) - goto wrong; - - str = strs[idx]; - len = (!abrev) ? strlen(str) : 3; - if (len > siz) - goto wrong; - - memcpy(s, str, len); - return len; - -wrong: - *s = '?'; - return 1; -} - -static size_t -dval(char *s, size_t siz, int prec, int fill, int val) -{ - char *t; - int n; - static char digits[] = "0123456789"; - - if (prec > siz || val < 0) { - *s = '?'; - return 1; - } - - n = prec; - do { - s[--n] = digits[val % 10]; - val /= 10; - } while (n > 0 && val > 0); - - while (n > 0) - s[--n] = fill; - - return prec; -} - -static size_t -timezone(char *s, size_t prec, const struct tm * restrict tm) -{ - long off = tm->tm_gmtoff; - - if (prec < 5) { - *s = '?'; - return 1; - } - - if (off >= 0) { - *s++ = '+'; - } else { - *s++ = '-'; - off = -off; - } - - dval(s, 2, 2, '0', off / 3600); - dval(s, 2, 2, '0', (off % 3600) / 60); - - return 5; -} - -size_t -strftime(char * restrict s, size_t siz, - const char * restrict fmt, - const struct tm * restrict tm) -{ - int ch, abrev, val, fill, width; - size_t n, inc; - char *tfmt; - - for (n = siz-1; (ch = *fmt++) && n > 0; s += inc, n -= inc) { - if (ch != '%') { - *s = ch; - inc = 1; - continue; - } - - abrev = 0; - fill = '0'; - width = 2; - - switch (*fmt++) { - case 'Z': - if (!tm->tm_zone) - break; - inc = sval(s, n, &tm->tm_zone, 0, 0, 1); - break; - case 'a': - abrev = 1; - case 'A': - inc = sval(s, n, days, abrev, tm->tm_wday, 7); - break; - case 'h': - case 'b': - abrev = 1; - case 'B': - inc = sval(s, n, months, abrev, tm->tm_mon, 12); - break; - case 'p': - inc = sval(s, n, am_pm, 0, tm->tm_hour > 12, 2); - break; - case 'c': - tfmt = "%a %b %e %T %Y"; - goto recursive; - case 'D': - tfmt = "%m/%d/%y"; - goto recursive; - case 'F': - tfmt = "%Y-%m-%d"; - goto recursive; - case 'R': - tfmt = "%H:%M"; - goto recursive; - case 'X': - case 'T': - tfmt = "%H:%M:%S"; - goto recursive; - case 'r': - tfmt = "%I:%M:%S %p"; - goto recursive; - case 'x': - tfmt = "%m/%d/%y"; - goto recursive; - recursive: - inc = strftime(s, n+1, tfmt, tm) - 1; - break; - case 'n': - val = '\n'; - goto character; - case 't': - val = '\t'; - goto character; - case '%': - val = '%'; - character: - *s = val; - inc = 1; - break; - case 'e': - fill = ' '; - val = tm->tm_mday; - goto number; - case 'd': - val = tm->tm_mday; - goto number; - case 'V': - case 'g': - case 'G': - /* TODO */ - break; - case 'C': - val = tm->tm_year / 100; - goto number; - case 'H': - val = tm->tm_hour; - goto number; - case 'I': - val = tm->tm_hour; - if (val == 0) - val = 12; - if (val > 12) - val -= 12; - goto number; - case 'j': - width = 3; - val = tm->tm_yday+1; - goto number; - case 'm': - val = tm->tm_mon+1; - goto number; - case 'M': - val = tm->tm_min; - goto number; - case 'S': - val = tm->tm_sec; - goto number; - case 'u': - width = 1; - val = tm->tm_wday+1; - goto number; - case 'U': - val = tm->tm_yday / 7; - if (_newyear(tm->tm_year) == SAT) - val++; - goto number; - case 'W': - val = tm->tm_yday / 7; - if (_newyear(tm->tm_year) == MON) - val++; - goto number; - case 'w': - width = 1; - val = tm->tm_wday; - goto number; - case 'y': - val = tm->tm_year%100; - goto number; - case 'Y': - width = 4; - val = 1900 + tm->tm_year; - number: - inc = dval(s, n, width, fill, val); - break; - case 'z': - inc = timezone(s, n, tm); - break; - case 'E': - case 'O': - if (*fmt != '\0') - fmt += 2;; - case '\0': - inc = 0; - --fmt; - break; - } - } - *s = '\0'; - - return siz - n; -} diff --git a/src/libc/strpbrk.c b/src/libc/strpbrk.c @@ -7,7 +7,7 @@ strpbrk(const char *s1, const char *s2) const unsigned char *s = s1; const unsigned char *accept = s2; unsigned ch; - char buf[__NUMCHARS]; + char buf[256]; memset(buf, 0, sizeof(buf)); while (ch = *accept++) diff --git a/src/libc/strspn.c b/src/libc/strspn.c @@ -8,7 +8,7 @@ strspn(const char *s1, const char *s2) const unsigned char *accept = s2; unsigned ch; size_t n; - char buf[__NUMCHARS]; + char buf[256]; memset(buf, 0, sizeof(buf)); while (ch = *accept++)