libmach: Add support for segments - scc - simple c99 compiler
HTML git clone git://git.simple-cc.org/scc
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
DIR commit 9b488b2b643bb7e0cd9a8de14223184f74582c16
DIR parent 53676f73312d33d5945bc60e718fd1a5647951e5
HTML 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:
M include/bits/scc/mach.h | 16 +++++++++++++---
M src/cmd/scc-as/symbol.c | 10 ++++++----
M src/cmd/scc-strip.c | 2 +-
M src/libmach/Makefile | 4 +++-
M src/libmach/coff32/coff32loadmap.c | 19 +++++++++++--------
M src/libmach/elf/elfloadmap.c | 43 +++++++++++++++++++++++--------
M src/libmach/findsec.c | 2 +-
M src/libmach/libmach.h | 20 ++++++++++++--------
M src/libmach/newmap.c | 57 ++++++++++++++++++++-----------
D src/libmach/setmap.c | 36 -------------------------------
10 files changed, 116 insertions(+), 93 deletions(-)
---
DIR 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);
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 (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");
DIR 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:
DIR 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\
DIR 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;
DIR 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;
DIR 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;
DIR 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 */
DIR 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;
}
DIR 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;
-}