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:
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++)