scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit 079de338d0a2d275671d12756e4349f17d1b927d
parent b66f5506b858ae66635d27988ee9d4dd7e0471e6
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:
Minclude/bits/scc/mach.h | 37++++++++++++++++++++++---------------
Msrc/cmd/scc-as/symbol.c | 10++--------
Msrc/libmach/Makefile | 1+
Msrc/libmach/coff32/coff32getsec.c | 5+++--
Msrc/libmach/coff32/coff32loadmap.c | 23++++++-----------------
Msrc/libmach/coff32/coff32write.c | 22+++++++++-------------
Asrc/libmach/copysec.c | 18++++++++++++++++++
Asrc/libmach/delmap.c | 16++++++++++++++++
Msrc/libmach/elf/elfloadmap.c | 50+++++++++++++++++++-------------------------------
Msrc/libmach/findsec.c | 4++--
Msrc/libmach/libmach.h | 17+++--------------
Asrc/libmach/mapsec.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libmach/mapseg.c | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/libmach/newmap.c | 29+++++++++++++++++++++--------
14 files changed, 235 insertions(+), 110 deletions(-)

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 *); 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"); 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\ 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; } 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; } 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; 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; +} 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); +} 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; } 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; } 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, ...); 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); +} 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; +} 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; }