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:
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;
}