libmach: Rewrite the mapping functions - scc - simple c99 compiler
 (HTM) git clone git://git.simple-cc.org/scc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 079de338d0a2d275671d12756e4349f17d1b927d
 (DIR) parent b66f5506b858ae66635d27988ee9d4dd7e0471e6
 (HTM) Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
       Date:   Wed, 19 Feb 2025 18:16:32 +0100
       
       libmach: Rewrite the mapping functions
       
       The support for elf requires to include the segment to section
       mapping, and it requires a deep rewrite of the mapping functions
       and how we build the map.
       
       Diffstat:
         M include/bits/scc/mach.h             |      37 ++++++++++++++++++-------------
         M src/cmd/scc-as/symbol.c             |      10 ++--------
         M src/libmach/Makefile                |       1 +
         M src/libmach/coff32/coff32getsec.c   |       5 +++--
         M src/libmach/coff32/coff32loadmap.c  |      23 ++++++-----------------
         M src/libmach/coff32/coff32write.c    |      22 +++++++++-------------
         A src/libmach/copysec.c               |      18 ++++++++++++++++++
         A src/libmach/delmap.c                |      16 ++++++++++++++++
         M src/libmach/elf/elfloadmap.c        |      50 ++++++++++++-------------------
         M src/libmach/findsec.c               |       4 ++--
         M src/libmach/libmach.h               |      17 +++--------------
         A src/libmach/mapsec.c                |      72 +++++++++++++++++++++++++++++++
         A src/libmach/mapseg.c                |      41 +++++++++++++++++++++++++++++++
         M src/libmach/newmap.c                |      29 +++++++++++++++++++++--------
       
       14 files changed, 235 insertions(+), 110 deletions(-)
       ---
 (DIR) diff --git a/include/bits/scc/mach.h b/include/bits/scc/mach.h
       @@ -93,6 +93,26 @@ struct section {
                char type;
        };
        
       +#ifdef stdin
       +struct mapsec {
       +        Section sec;
       +        int used;
       +        int loaded;
       +        FILE *fp;
       +        long fsiz;
       +
       +        int nchild;
       +        struct mapsec **child;
       +};
       +#endif
       +
       +struct map {
       +        int nsec, nseg;
       +        struct mapsec *sec;
       +        struct mapsec *seg;
       +};
       +
       +
        /**
         * @stype: Used internally by libmach
         * @dtype: Coff debug type
       @@ -122,21 +142,8 @@ extern int writeobj(Obj *, Map *, FILE *);
        
        extern Map *loadmap(Obj *, FILE *);
        
       -extern int mapsec(Map *,
       -                  char *,
       -                  FILE *,
       -                  unsigned long long,
       -                  unsigned long long,
       -                  long,
       -                  long);
       -
       -extern int mapseg(Map *,
       -                  char *,
       -                  FILE *,
       -                  unsigned long long,
       -                  unsigned long long,
       -                  long,
       -                  long);
       +extern int mapsec(Map *, Section *, FILE *, long);
       +extern int mapseg(Map *, Section *, FILE *, long);
        
        extern int setindex(int, long, char **, long *, FILE *);
        extern int getindex(int, long *, char ***, long **, FILE *);
 (DIR) diff --git a/src/cmd/scc-as/symbol.c b/src/cmd/scc-as/symbol.c
       @@ -315,7 +315,7 @@ newsec(Symbol *sym, char *attr)
                lsym = (struct lsymbol *) sym;
                lsym->sec = sec;
        
       -        if (mapsec(map, sym->name, NULL, 0, 0, 0, 0) < 0) {
       +        if (mapsec(map, sec, NULL, 0) < 0) {
                        fprintf(stderr,
                               "as: error allocating section mapping '%s'\n",
                                sym->name);
       @@ -406,13 +406,7 @@ cleansecs(void)
                                continue;
        
                        lsec->fp = tmpfile();
       -                r = mapsec(map,
       -                           sec->name,
       -                           lsec->fp,
       -                           sec->base,
       -                           sec->base + sec->size,
       -                           sec->size,
       -                       0);
       +                r = mapsec(map, sec, lsec->fp, sec->size);
        
                        if (!lsec->fp || r < 0) {
                                perror("as: creating section mapping");
 (DIR) diff --git a/src/libmach/Makefile b/src/libmach/Makefile
       @@ -12,6 +12,7 @@ TARGET = libmach.a
        OBJS =\
                archive.o\
                armember.o\
       +        copysec.o\
                delmap.o\
                delobj.o\
                findsec.o\
 (DIR) diff --git a/src/libmach/coff32/coff32getsec.c b/src/libmach/coff32/coff32getsec.c
       @@ -83,12 +83,13 @@ coff32getsec(Obj *obj, int *idx, Section *sec)
                sec->name = coff32str(coff, scn);
                sec->index = n;
                sec->size = scn->s_size;
       -        sec->base = scn->s_vaddr;
       -        sec->load = scn->s_paddr;
       +        sec->load = scn->s_vaddr;
       +        sec->base = scn->s_paddr;
                sec->offset = scn->s_scnptr;
                sec->type = type;
                sec->flags = sflags;
                sec->align = 4;
       +        sec->fill = 0;
        
                return sec;
        }
 (DIR) diff --git a/src/libmach/coff32/coff32loadmap.c b/src/libmach/coff32/coff32loadmap.c
       @@ -9,10 +9,8 @@
        Map *
        coff32loadmap(Obj *obj, FILE *fp)
        {
       -        int nsec;
       -        unsigned long o, s;
       -        unsigned long long b, e;
       -
       +        int i, nsec;
       +        Section sec;
                Map *map;
                FILE *src;
                SCNHDR *scn;
       @@ -23,20 +21,11 @@ coff32loadmap(Obj *obj, FILE *fp)
                if ((map = newmap(nsec, 0)) == NULL)
                        return NULL;
        
       -        for (scn = coff->scns; nsec--; ++scn) {
       -                b = scn->s_paddr;
       -                e = b + scn->s_size;
       -
       -                if (scn->s_scnptr != 0) {
       -                        s = scn->s_size;
       -                        o = obj->pos + scn->s_scnptr;
       -                        src = fp;
       -                } else {
       -                        s = o = 0;
       -                        src = NULL;
       -                }
       +        for (i = 0; getsec(obj, &i, &sec); ++i) {
       +                sec.offset += obj->pos;
       +                src = ((sec.flags & SALLOC) != 0) ? fp : NULL;
        
       -                if (mapsec(map, scn->s_name, src, b, e, s, o) < 0)
       +                if (mapsec(map, &sec, src, sec.size) < 0)
                                return NULL;
                }
        
 (DIR) diff --git a/src/libmach/coff32/coff32write.c b/src/libmach/coff32/coff32write.c
       @@ -441,29 +441,25 @@ writelines(Obj *obj, FILE *fp)
        static int
        writedata(Obj *obj, Map *map, FILE *fp)
        {
       -        int id;
       -        long nsec;
       -        unsigned long long n;
       +        long n;
       +        int id, nsec;
       +        Mapsec *msec;
       +        Section *sec;
                struct coff32 *coff = obj->data;
                FILHDR *hdr = &coff->hdr;
                SCNHDR *scn;
       -        Mapsec *sec;
        
                nsec = hdr->f_nscns;
                for (scn = coff->scns; nsec--; scn++) {
                        if ((id = findsec(map, scn->s_name)) < 0)
                                continue;
       -                sec = &map->sec[id];
       -                if (!sec->fp)
       +                msec = &map->sec[id];
       +                sec = &msec->sec;
       +                if (!msec->fp)
                                continue;
        
       -                fseek(sec->fp, sec->offset, SEEK_SET);
       -
       -                for (n = sec->end - sec->begin; n > 0; n--)
       -                        putc(getc(sec->fp), fp);
       -
       -                if (ferror(sec->fp))
       -                        return 0;
       +                if (copysec(msec, fp) < 0)
       +                        return -1;
                }
        
                return 1;
 (DIR) diff --git a/src/libmach/copysec.c b/src/libmach/copysec.c
       @@ -0,0 +1,18 @@
       +#include <stdio.h>
       +
       +#include <scc/mach.h>
       +
       +#include "libmach.h"
       +
       +int
       +copysec(Mapsec *msec, FILE *fp)
       +{
       +        long n;
       +        Section *sec = &msec->sec;
       +
       +        fseek(msec->fp, sec->offset, SEEK_SET);
       +        for (n = msec->fsiz; n != 0; n--)
       +                putc(getc(msec->fp), fp);
       +
       +        return ferror(msec->fp) ? -1 : 0;
       +}
 (DIR) diff --git a/src/libmach/delmap.c b/src/libmach/delmap.c
       @@ -0,0 +1,16 @@
       +#include <limits.h>
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <string.h>
       +
       +#include <scc/mach.h>
       +
       +#include "libmach.h"
       +
       +void
       +delmap(Map *map)
       +{
       +        free(map->seg);
       +        free(map->sec);
       +        free(map);
       +}
 (DIR) diff --git a/src/libmach/elf/elfloadmap.c b/src/libmach/elf/elfloadmap.c
       @@ -1,4 +1,5 @@
        #include <stdio.h>
       +#include <string.h>
        
        #include <scc/mach.h>
        #include <scc/elf.h>
       @@ -9,13 +10,11 @@
        Map *
        elfloadmap(Obj *obj, FILE *fp)
        {
       +        int i;
                int nsec, nseg;
       -        unsigned long o, s;
       -        unsigned long long b, e;
       -
                Map *map;
       +        Section sec;
                FILE *src;
       -        Elfsec *shdr;
                Elf *elf = obj->data;
                Elfhdr *hdr = &elf->hdr;
                Elfphdr *phdr;
       @@ -25,37 +24,26 @@ elfloadmap(Obj *obj, FILE *fp)
                if ((map = newmap(nsec, nseg)) == NULL)
                        return NULL;
        
       -        for (shdr = elf->secs; nsec-- > 0; ++shdr) {
       -                b = shdr->addr;
       -                e = b + shdr->size;
       -
       -                if (shdr->offset != 0) {
       -                        s = shdr->size;
       -                        o = obj->pos + shdr->offset;
       -                        src = fp;
       -                } else {
       -                        s = o = 0;
       -                        src = NULL;
       -                }
       -
       -                if (mapsec(map, shdr->name, src, b, e, s, o) < 0)
       +        memset(&sec, 0, sizeof(sec));
       +        for (i = 0; i < nseg; ++i) {
       +                phdr = &elf->phdr[i];
       +                sec.name = NULL;
       +                sec.load = phdr->vaddr;
       +                sec.base = phdr->paddr;
       +                sec.offset = obj->pos + phdr->offset;
       +                sec.align = phdr->align;
       +                sec.size = phdr->memsz;
       +                sec.index = i;
       +
       +                if (mapseg(map, &sec, fp, phdr->filesz) < 0)
                                return NULL;
                }
        
       -        for (phdr = elf->phdr; nseg-- > 0; ++phdr) {
       -                b = phdr->vaddr;
       -                e = b + phdr->memsz;
       -
       -                if (phdr->offset != 0) {
       -                        s = phdr->filesz;
       -                        o = obj->pos + phdr->offset;
       -                        src = fp;
       -                } else {
       -                        s = o = 0;
       -                        src = NULL;
       -                }
       +        for (i = 0; getsec(obj, &i, &sec); ++i) {
       +                sec.offset += obj->pos;
       +                src = ((sec.flags & SALLOC) != 0) ? fp : NULL;
        
       -                if (mapseg(map, NULL, src, b, e, s, o) < 0)
       +                if (mapsec(map, &sec, src, sec.size) < 0)
                                return NULL;
                }
        
 (DIR) diff --git a/src/libmach/findsec.c b/src/libmach/findsec.c
       @@ -9,10 +9,10 @@ int
        findsec(Map *map, char *name)
        {
                int i;
       -        struct mapsec *sec;
       +        Mapsec *sec;
        
                for (i = 0; i < map->nsec; i++) {
       -                char *s = map->sec[i].name;
       +                char *s = map->sec[i].sec.name;
                        if (s && strcmp(s, name) == 0)
                                return i;
                }
 (DIR) diff --git a/src/libmach/libmach.h b/src/libmach/libmach.h
       @@ -1,17 +1,6 @@
       -struct mapsec {
       -        char *name;
       -        FILE *fp;
       -        unsigned long long begin;
       -        unsigned long long end;
       -        long fsiz;
       -        long offset;
       -};
       -
       -struct map {
       -        int nsec, nseg;
       -        struct mapsec *sec;
       -        struct mapsec *seg;
       -};
       +#ifdef stdin
       +extern int copysec(Mapsec *, FILE *);
       +#endif
        
        /* common functions */
        extern int pack(int order, unsigned char *dst, char *fmt, ...);
 (DIR) diff --git a/src/libmach/mapsec.c b/src/libmach/mapsec.c
       @@ -0,0 +1,72 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +
       +#include <scc/mach.h>
       +
       +#include "libmach.h"
       +
       +static int
       +matchseg(Map *map, Mapsec *msec, FILE *fp)
       +{
       +        unsigned long long o, e, mo, me;
       +        Section *seg;
       +        Mapsec *mseg, **v;
       +
       +        mo = msec->sec.load;
       +        me =  mo + msec->sec.size;
       +
       +        if ((msec->sec.flags & SLOAD) == 0)
       +                return 0;
       +
       +        for (mseg = map->seg; mseg < &map->seg[map->nseg]; ++mseg) {
       +                if (mseg->fp != fp)
       +                        continue;
       +                o = mseg->sec.load;
       +                e = o + mseg->sec.size;
       +                if (mo >= o && me <= e) {
       +                        v = realloc(mseg->child, sizeof(Mapsec *) * (mseg->nchild+1));
       +                        if (!v)
       +                                return -1;
       +                        mseg->child = v;
       +                        v[mseg->nchild++] = msec;
       +                }
       +        }
       +
       +        return 0;
       +}
       +
       +int
       +mapsec(Map *map, Section *sec, FILE *fp, long fsiz)
       +{
       +        int n;
       +        char *s;
       +        Mapsec *msec, *mp;
       +
       +        mp = NULL;
       +        n = map->nsec;
       +        for (msec = map->sec; n--; msec++) {
       +                s = msec->sec.name;
       +                if (s && !strcmp(s, sec->name))
       +                        goto found;
       +                if (!mp && !msec->used)
       +                        mp = msec;
       +        }
       +
       +        if (mp) {
       +                msec = mp;
       +                goto found;
       +        }
       +
       +        if ((map = remap(map, map->nsec+1, map->nseg)) == NULL)
       +                return -1;
       +        msec = &map->sec[map->nsec-1];
       +
       +found:
       +        msec->used = 1;
       +        msec->sec = *sec;
       +        msec->fp = fp,
       +        msec->fsiz = fsiz;
       +
       +        return matchseg(map, msec, fp);
       +}
 (DIR) diff --git a/src/libmach/mapseg.c b/src/libmach/mapseg.c
       @@ -0,0 +1,41 @@
       +#include <stdio.h>
       +#include <string.h>
       +
       +#include <scc/mach.h>
       +
       +#include "libmach.h"
       +
       +int
       +mapseg(Map *map, Section *seg, FILE *fp, long fsiz)
       +{
       +        int n;
       +        char *s;
       +        Mapsec *mseg, *mp;
       +
       +        mp = NULL;
       +        n = map->nseg;
       +        for (mseg = map->seg; n--; mseg++) {
       +                s = mseg->sec.name;
       +                if (mseg->used && s && !strcmp(s, seg->name))
       +                        goto found;
       +                if (!mp && !mseg->used)
       +                        mp = mseg;
       +        }
       +
       +        if (mp) {
       +                mseg = mp;
       +                goto found;
       +        }
       +
       +        if ((map = remap(map, map->nsec+1, map->nseg)) == NULL)
       +                return -1;
       +        mseg = &map->sec[map->nsec-1];
       +
       +found:
       +        mseg->sec = *seg;
       +        mseg->used = 1;
       +        mseg->fp = fp,
       +        mseg->fsiz = fsiz;
       +
       +        return 0;
       +}
 (DIR) diff --git a/src/libmach/newmap.c b/src/libmach/newmap.c
       @@ -11,29 +11,41 @@
        Map *
        remap(Map *map, int nsec, int nseg)
        {
       +        int n;
                struct mapsec *sec, *seg;
        
                if (nseg > SIZE_MAX/sizeof(*sec) || nseg > SIZE_MAX/sizeof(*seg))
                        return NULL;
        
       +        n = nseg - map->nseg;
                if (nseg == 0) {
                        free(map->seg);
                        seg = NULL;
       +        } else if (n == 0) {
       +                seg = map->seg;
                } else {
                        seg = realloc(map->seg, nseg * sizeof(*seg));
                        if (!seg)
                                return NULL;
       +                if (n > 0) {
       +                        memset(&seg[map->nseg], 0, n * sizeof(*seg));
       +                }
                }
                map->seg = seg;
                map->nseg = nseg;
        
       +        n = nsec - map->nsec;
                if (nsec == 0) {
                        free(map->seg);
                        sec = NULL;
       +        } else if (n == 0) {
       +                sec = map->sec;
                } else {
       -                sec = realloc(map->seg, nsec * sizeof(*sec));
       +                sec = realloc(map->sec, nsec * sizeof(*sec));
                        if (!sec)
                                return NULL;
       +                if (n > 0)
       +                        memset(&sec[map->nsec], 0, n * sizeof(*sec));
                }
                map->sec = sec;
                map->nsec = nsec;
       @@ -45,17 +57,18 @@ Map *
        newmap(int nsec, int nseg)
        {
                Map m, *map;
       -        struct mapsec *sec, *seg;
        
                if (!remap(memset(&m, 0, sizeof(Map)), nsec, nseg))
       -                return NULL;
       +                goto err;
        
       -        if ((map = malloc(sizeof(*map))) == NULL) {
       -                free(m.sec);
       -                free(m.seg);
       -                return NULL;
       -        }
       +        if ((map = malloc(sizeof(*map))) == NULL)
       +                goto err;
        
                *map = m;
                return map;
       +
       +err:
       +        free(m.sec);
       +        free(m.seg);
       +        return NULL;
        }