Browse Source

feat(gblibc): realloc

greatbridf 2 years ago
parent
commit
64c1db8727
5 changed files with 57 additions and 24 deletions
  1. 1 0
      gblibc/include/stdlib.h
  2. 5 0
      gblibc/private-include/priv-vars.h
  3. 6 1
      gblibc/src/init.c
  4. 1 3
      gblibc/src/stdio.c
  5. 44 20
      gblibc/src/stdlib.c

+ 1 - 0
gblibc/include/stdlib.h

@@ -12,6 +12,7 @@ int atoi(const char* str);
 void __attribute__((noreturn)) exit(int status);
 void __attribute__((noreturn)) exit(int status);
 
 
 void* malloc(size_t size);
 void* malloc(size_t size);
+void* realloc(void* ptr, size_t newsize);
 void free(void* ptr);
 void free(void* ptr);
 
 
 typedef int (*comparator_t)(const void* a, const void* b);
 typedef int (*comparator_t)(const void* a, const void* b);

+ 5 - 0
gblibc/private-include/priv-vars.h

@@ -8,6 +8,11 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+struct mem {
+    uint32_t sz;
+    uint32_t flag;
+};
+
 #define FILE_READ (1 << 0)
 #define FILE_READ (1 << 0)
 #define FILE_WRITE (1 << 1)
 #define FILE_WRITE (1 << 1)
 #define FILE_ERROR (1 << 2)
 #define FILE_ERROR (1 << 2)

+ 6 - 1
gblibc/src/init.c

@@ -26,9 +26,14 @@ size_t* __environ_size_location(void)
 void __init_gblibc(int argc, char** argv, char** envp)
 void __init_gblibc(int argc, char** argv, char** envp)
 {
 {
     (void)argc, (void)argv;
     (void)argc, (void)argv;
-    // initialize program break position
+    // initialize program break position and heap
     start_brk = curr_brk = (void*)syscall1(SYS_brk, (uint32_t)NULL);
     start_brk = curr_brk = (void*)syscall1(SYS_brk, (uint32_t)NULL);
 
 
+    sbrk(128 * 1024);
+    struct mem* first = start_brk;
+    first->sz = 0;
+    first->flag = 0;
+
     // save environ vector
     // save environ vector
     environ_size = 4;
     environ_size = 4;
     environ = malloc(environ_size * sizeof(char*));
     environ = malloc(environ_size * sizeof(char*));

+ 1 - 3
gblibc/src/stdio.c

@@ -819,15 +819,13 @@ int vasprintf(char** strp, const char* fmt, va_list args)
     char* buf = NULL;
     char* buf = NULL;
 
 
     do {
     do {
-        buf = malloc(sz *= 2);
+        buf = realloc(buf, sz *= 2);
         if (!buf)
         if (!buf)
             return -1;
             return -1;
         
         
         n = vsnprintf(buf, sz, fmt, args);
         n = vsnprintf(buf, sz, fmt, args);
         if (sz > n)
         if (sz > n)
             break;
             break;
-
-        free(buf);
     } while (1);
     } while (1);
     
     
     *strp = buf;
     *strp = buf;

+ 44 - 20
gblibc/src/stdlib.c

@@ -26,18 +26,6 @@ void __attribute__((noreturn)) exit(int status)
 
 
 #define MINIMUM_ALLOCATION_SIZE (8)
 #define MINIMUM_ALLOCATION_SIZE (8)
 #define MEM_ALLOCATED (1)
 #define MEM_ALLOCATED (1)
-struct mem {
-    uint32_t sz;
-    uint32_t flag;
-};
-
-static inline void _init_heap(void)
-{
-    sbrk(128 * 1024);
-    struct mem* first = start_brk;
-    first->sz = 0;
-    first->flag = 0;
-}
 
 
 static inline int _is_end(struct mem* p)
 static inline int _is_end(struct mem* p)
 {
 {
@@ -90,11 +78,19 @@ static inline void _union(struct mem* p)
     }
     }
 }
 }
 
 
-void* malloc(size_t size)
+static inline void _cut_block(struct mem* p, size_t mem_size, size_t block_size)
 {
 {
-    if (curr_brk == start_brk)
-        _init_heap();
+    if (block_size >= mem_size + sizeof(struct mem) + MINIMUM_ALLOCATION_SIZE) {
+        p->sz = mem_size;
+
+        struct mem* next = _next(p, mem_size);
+        next->flag = 0;
+        next->sz = block_size - mem_size - sizeof(struct mem);
+    }
+}
 
 
+void* malloc(size_t size)
+{
     if (size < MINIMUM_ALLOCATION_SIZE)
     if (size < MINIMUM_ALLOCATION_SIZE)
         size = MINIMUM_ALLOCATION_SIZE;
         size = MINIMUM_ALLOCATION_SIZE;
 
 
@@ -124,16 +120,44 @@ void* malloc(size_t size)
     }
     }
 
 
     p->flag |= MEM_ALLOCATED;
     p->flag |= MEM_ALLOCATED;
+    _cut_block(p, size, sz);
+
+    return _next(p, 0);
+}
+
+void* realloc(void* ptr, size_t newsize)
+{
+    if (!ptr)
+        return malloc(newsize);
 
 
-    if (sz >= size + sizeof(struct mem) + MINIMUM_ALLOCATION_SIZE) {
-        p->sz = size;
+    struct mem* p = ptr - sizeof(struct mem);
+    size_t oldsize = p->sz;
+
+    _union(p);
+    if (_is_end(p)) {
+        if (_size(p) < newsize + sizeof(struct mem))
+            sbrk(_max(128 * 1024, newsize + sizeof(struct mem)));
 
 
-        struct mem* next = _next(p, size);
+        p->sz = newsize;
+        struct mem* next = _next(p, newsize);
         next->flag = 0;
         next->flag = 0;
-        next->sz = sz - size - sizeof(struct mem);
+        next->sz = 0;
+
+        return ptr;
     }
     }
 
 
-    return _next(p, 0);
+    if (p->sz >= newsize) {
+        _cut_block(p, newsize, p->sz);
+        return ptr;
+    }
+
+    void* newptr = malloc(newsize);
+    if (!newptr)
+        return NULL;
+    
+    memcpy(newptr, ptr, oldsize);
+    free(ptr);
+    return newptr;
 }
 }
 
 
 void free(void* ptr)
 void free(void* ptr)