commit 9b488b2b643bb7e0cd9a8de14223184f74582c16
parent 53676f73312d33d5945bc60e718fd1a5647951e5
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Mon, 10 Feb 2025 12:39:43 +0100
libmach: Add support for segments
ELF has the concept of segments and sections, and to be able
to manage it correctly we need a way to incorporate them to
the map abstraction, because in elf files the sections are
combined in segments, sharing the file pointer space, but
there is not any indication of what sections conform a segment.
Diffstat:
10 files changed, 116 insertions(+), 93 deletions(-)
diff --git a/include/bits/scc/mach.h b/include/bits/scc/mach.h
@@ -135,11 +135,20 @@ extern int writeobj(Obj *, Map *, FILE *);
extern Map *loadmap(Obj *, FILE *);
-extern int setmap(Map *,
+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 setindex(int, long, char **, long *, FILE *);
@@ -147,8 +156,9 @@ extern int getindex(int, long *, char ***, long **, FILE *);
#endif
-extern Map *newmap(Map *, int);
-extern Map *remap(Map *, int);
+extern Map *newmap(int, int);
+extern Map *remap(Map *, int, int);
+extern void delmap(Map *);
extern int objtype(char *);
extern Obj *newobj(int);
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 (setmap(map, sym->name, NULL, 0, 0, 0) < 0) {
+ if (mapsec(map, sym->name, NULL, 0, 0, 0, 0) < 0) {
fprintf(stderr,
"as: error allocating section mapping '%s'\n",
sym->name);
@@ -382,7 +382,7 @@ ibinfmt(void)
exit(EXIT_FAILURE);
}
- if ((map = newmap(NULL, 4)) == NULL) {
+ if ((map = newmap(4, 0)) == NULL) {
perror("as");
exit(EXIT_FAILURE);
}
@@ -406,11 +406,13 @@ cleansecs(void)
continue;
lsec->fp = tmpfile();
- r = setmap(map,
+ r = mapsec(map,
sec->name,
lsec->fp,
sec->base,
- sec->size, 0);
+ sec->base + sec->size,
+ sec->size,
+ 0);
if (!lsec->fp || r < 0) {
perror("as: creating section mapping");
diff --git a/src/cmd/scc-strip.c b/src/cmd/scc-strip.c
@@ -94,7 +94,7 @@ err5:
err4:
remove(tmpname);
err3:
- free(map);
+ delmap(map);
err2:
delobj(obj);
err1:
diff --git a/src/libmach/Makefile b/src/libmach/Makefile
@@ -12,6 +12,7 @@ TARGET = libmach.a
OBJS =\
archive.o\
armember.o\
+ delmap.o\
delobj.o\
findsec.o\
getindex.o\
@@ -28,7 +29,8 @@ OBJS =\
readobj.o\
rebase.o\
setindex.o\
- setmap.o\
+ mapsec.o\
+ mapseg.o\
setsec.o\
setsym.o\
strip.o\
diff --git a/src/libmach/coff32/coff32loadmap.c b/src/libmach/coff32/coff32loadmap.c
@@ -9,32 +9,35 @@
Map *
coff32loadmap(Obj *obj, FILE *fp)
{
- long i;
+ int nsec;
+ unsigned long o, s;
+ unsigned long long b, e;
+
Map *map;
- long nsec;
FILE *src;
SCNHDR *scn;
struct coff32 *coff = obj->data;
FILHDR *hdr = &coff->hdr;
nsec = hdr->f_nscns;
- if ((map = newmap(NULL, nsec)) == NULL)
+ if ((map = newmap(nsec, 0)) == NULL)
return NULL;
for (scn = coff->scns; nsec--; ++scn) {
- unsigned long o;
- unsigned long long b = scn->s_paddr;
- unsigned long long e = b + scn->s_size;
+ 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 {
- o = 0;
+ s = o = 0;
src = NULL;
}
- setmap(map, scn->s_name, src, b, e, o);
+ if (mapsec(map, scn->s_name, src, b, e, s, o) < 0)
+ return NULL;
}
return map;
diff --git a/src/libmach/elf/elfloadmap.c b/src/libmach/elf/elfloadmap.c
@@ -9,33 +9,54 @@
Map *
elfloadmap(Obj *obj, FILE *fp)
{
- long i;
+ int nsec, nseg;
+ unsigned long o, s;
+ unsigned long long b, e;
+
Map *map;
- char *name;
- long nsec;
FILE *src;
Elfsec *shdr;
Elf *elf = obj->data;
Elfhdr *hdr = &elf->hdr;
+ Elfphdr *phdr;
- nsec = hdr->shnum;
- if ((map = newmap(NULL, nsec)) == NULL)
+ nseg = hdr->phnum;
+ nsec = elf->nsec;
+ if ((map = newmap(nsec, nseg)) == NULL)
return NULL;
- for (shdr = elf->secs; nsec--; ++shdr) {
- unsigned long o;
- unsigned long long b = shdr->addralign;
- unsigned long long e = b + shdr->size;
+ 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 {
- o = 0;
+ s = o = 0;
+ src = NULL;
+ }
+
+ if (mapsec(map, shdr->name, src, b, e, s, o) < 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;
}
- setmap(map, name, src, b, e, o);
+ if (mapseg(map, NULL, src, b, e, s, o) < 0)
+ return NULL;
}
return map;
diff --git a/src/libmach/findsec.c b/src/libmach/findsec.c
@@ -11,7 +11,7 @@ findsec(Map *map, char *name)
int i;
struct mapsec *sec;
- for (i = 0; i < map->n; i++) {
+ for (i = 0; i < map->nsec; i++) {
char *s = map->sec[i].name;
if (s && strcmp(s, name) == 0)
return i;
diff --git a/src/libmach/libmach.h b/src/libmach/libmach.h
@@ -1,12 +1,16 @@
+struct mapsec {
+ char *name;
+ FILE *fp;
+ unsigned long long begin;
+ unsigned long long end;
+ long fsiz;
+ long offset;
+};
+
struct map {
- int n;
- struct mapsec {
- char *name;
- FILE *fp;
- unsigned long long begin;
- unsigned long long end;
- long offset;
- } sec[];
+ int nsec, nseg;
+ struct mapsec *sec;
+ struct mapsec *seg;
};
/* common functions */
diff --git a/src/libmach/newmap.c b/src/libmach/newmap.c
@@ -1,4 +1,4 @@
-#include <errno.h>
+#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
@@ -9,36 +9,53 @@
#include "libmach.h"
Map *
-remap(Map *map, int n)
+remap(Map *map, int nsec, int nseg)
{
- size_t vsiz;
+ struct mapsec *sec, *seg;
- if (n > SIZE_MAX/sizeof(struct mapsec))
- goto out_range;
- vsiz = n * sizeof(struct mapsec);
- if (vsiz > SIZE_MAX - sizeof(*map))
- goto out_range;
- vsiz += sizeof(*map);
-
- if ((map = realloc(map, vsiz)) == NULL)
+ if (nseg > SIZE_MAX/sizeof(*sec) || nseg > SIZE_MAX/sizeof(*seg))
return NULL;
- map->n = n;
- return map;
+ if (nseg == 0) {
+ free(map->seg);
+ seg = NULL;
+ } else {
+ seg = realloc(map->seg, nseg * sizeof(*seg));
+ if (!seg)
+ return NULL;
+ }
+ map->seg = seg;
+ map->nseg = nseg;
+
+ if (nsec == 0) {
+ free(map->seg);
+ sec = NULL;
+ } else {
+ sec = realloc(map->seg, nsec * sizeof(*sec));
+ if (!sec)
+ return NULL;
+ }
+ map->sec = sec;
+ map->nsec = nsec;
return map;
-
-out_range:
- errno = ERANGE;
- return NULL;
}
Map *
-newmap(Map *map, int n)
+newmap(int nsec, int nseg)
{
- if ((map = remap(map, n)) == NULL)
+ Map m, *map;
+ struct mapsec *sec, *seg;
+
+ if (!remap(memset(&m, 0, sizeof(Map)), nsec, nseg))
+ return NULL;
+
+ if ((map = malloc(sizeof(*map))) == NULL) {
+ free(m.sec);
+ free(m.seg);
return NULL;
- memset(map->sec, 0, n * sizeof(struct mapsec));
+ }
+ *map = m;
return map;
}
diff --git a/src/libmach/setmap.c b/src/libmach/setmap.c
@@ -1,36 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-
-#include <scc/mach.h>
-
-#include "libmach.h"
-
-int
-setmap(Map *map,
- char *name,
- FILE *fp,
- unsigned long long begin,
- unsigned long long end,
- long off)
-{
- int n;
- Mapsec *sec;
-
- n = map->n;
- for (sec = map->sec; n--; sec++) {
- if (!sec->name || !strcmp(sec->name, name))
- goto found;
- }
-
- if ((map = remap(map, map->n+1 )) == NULL)
- return -1;
- sec = &map->sec[map->n-1];
-
-found:
- sec->name = name;
- sec->fp = fp,
- sec->begin = begin;
- sec->end = end;
- sec->offset = off;
- return 0;
-}