commit 099548f9e14488bce21d9f894637e9a2905c3efe
parent a960beadc92a005fd0c0b38c70d95c6e5e8b2976
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Fri, 17 Jan 2025 17:38:28 +0100
libmach: Add support for long section names
This is a common extension and it makes sense to apply the
same hack that is done for ent and aux entries.
Diffstat:
5 files changed, 88 insertions(+), 31 deletions(-)
diff --git a/include/bits/scc/coff32/scnhdr.h b/include/bits/scc/coff32/scnhdr.h
@@ -2,8 +2,18 @@
#define SCNNMLEN 8
+#define s_name _s._s_name
+#define s_zeroes _s._s_s._s_zeroes
+#define s_offset _s._s_s._s_offset
+
struct scnhdr {
- char s_name[SCNNMLEN]; /* section name */
+ union {
+ char _s_name[SCNNMLEN]; /* section name */
+ struct {
+ long _s_zeroes; /* if _s_name[0-3] == 0 */
+ long _s_offset; /* offset into string table */
+ } _s_s;
+ } _s;
long s_paddr; /* physical address */
long s_vaddr; /* virtual address */
long s_size; /* section size */
diff --git a/src/libmach/coff32/coff32getsec.c b/src/libmach/coff32/coff32getsec.c
@@ -5,6 +5,15 @@
#include "../libmach.h"
#include "coff32.h"
+static char *
+secname(Coff32 *coff, SCNHDR *scn)
+{
+ if (scn->s_zeroes != 0)
+ return scn->s_name;
+
+ return &coff->strtbl[scn->s_offset];
+}
+
Section *
coff32getsec(Obj *obj, int *idx, Section *sec)
{
@@ -79,7 +88,7 @@ coff32getsec(Obj *obj, int *idx, Section *sec)
break;
}
- sec->name = scn->s_name;
+ sec->name = secname(coff, scn);
sec->index = n;
sec->size = scn->s_size;
sec->base = scn->s_vaddr;
diff --git a/src/libmach/coff32/coff32read.c b/src/libmach/coff32/coff32read.c
@@ -46,6 +46,7 @@ static void
unpack_scn(int order, unsigned char *buf, SCNHDR *scn)
{
int n;
+ char *s;
n = unpack(order,
buf,
@@ -61,6 +62,10 @@ unpack_scn(int order, unsigned char *buf, SCNHDR *scn)
&scn->s_nlnno,
&scn->s_flags);
assert(n == SCNHSZ);
+
+ s = scn->s_name;
+ if (!s[0] && !s[1] && !s[2] && !s[3])
+ unpack(order, buf, "ll", &scn->s_zeroes, &scn->s_offset);
}
static void
diff --git a/src/libmach/coff32/coff32setsec.c b/src/libmach/coff32/coff32setsec.c
@@ -8,6 +8,29 @@
#include "../libmach.h"
#include "coff32.h"
+static char *
+secname(Coff32 *coff, SCNHDR *scn, Section *sec)
+{
+ char *p;
+ unsigned long siz = strlen(sec->name);
+
+ if (siz < SCNNMLEN)
+ return strncpy(scn->s_name, sec->name, SCNNMLEN);
+
+ if (coff->strsiz > ULONG_MAX - siz - 1)
+ return NULL;
+
+ siz += coff->strsiz + 1;
+ if ((p = realloc(coff->strtbl, siz)) == NULL)
+ return NULL;
+ coff->strtbl = p;
+
+ scn->s_zeroes = 0;
+ scn->s_offset = coff->strsiz;
+ coff->strsiz += siz;
+ return strcpy(&coff->strtbl[scn->s_offset], sec->name);
+}
+
Section *
coff32setsec(Obj *obj, int *idx, Section *sec)
{
@@ -65,9 +88,11 @@ coff32setsec(Obj *obj, int *idx, Section *sec)
coff->scns = scn;
hdr->f_nscns = n + 1;
}
+
scn = &coff->scns[n];
+ if (!secname(coff, scn, sec))
+ return NULL;
- strncpy(scn->s_name, sec->name, SCNNMLEN);
scn->s_paddr = 0;
scn->s_vaddr = sec->base;
scn->s_size = sec->size;
diff --git a/src/libmach/coff32/coff32write.c b/src/libmach/coff32/coff32write.c
@@ -38,10 +38,14 @@ pack_scn(int order, unsigned char *buf, SCNHDR *scn)
{
int n;
+ if (scn->s_zeroes == 0)
+ pack(order, buf, "ll", scn->s_zeroes, scn->s_offset);
+ else
+ memcpy(buf, scn->s_name, 8);
+
n = pack(order,
- buf,
- "'8llllllssl",
- scn->s_name,
+ buf + 8,
+ "llllllssl",
scn->s_paddr,
scn->s_vaddr,
scn->s_size,
@@ -51,6 +55,7 @@ pack_scn(int order, unsigned char *buf, SCNHDR *scn)
scn->s_nrelloc,
scn->s_nlnno,
scn->s_flags);
+ n += 8;
assert(n == SCNHSZ);
}
@@ -58,7 +63,6 @@ static void
pack_ent(int order, unsigned char *buf, SYMENT *ent)
{
int n;
- char *s;
if (ent->n_zeroes == 0)
pack(order, buf, "ll", ent->n_zeroes, ent->n_offset);
@@ -66,7 +70,7 @@ pack_ent(int order, unsigned char *buf, SYMENT *ent)
memcpy(buf, ent->n_name, 8);
n = pack(order,
- buf,
+ buf + 8,
"lsscc",
ent->n_value,
ent->n_scnum,
@@ -224,28 +228,6 @@ writehdr(Obj *obj, FILE *fp)
}
static int
-writescns(Obj *obj, FILE *fp)
-{
- int i;
- SCNHDR *scn;
- FILHDR *hdr;
- struct coff32 *coff;
- unsigned char buf[SCNHSZ];
-
- coff = obj->data;
- hdr = &coff->hdr;
-
- for (i = 0; i < hdr->f_nscns; i++) {
- scn = &coff->scns[i];
- pack_scn(ORDER(obj->type), buf, scn);
- if (fwrite(buf, SCNHSZ, 1, fp) != 1)
- return 0;
- }
-
- return 1;
-}
-
-static int
allocstring(struct coff32 *coff, long off, struct strtbl *tbl)
{
char *s, *name;
@@ -269,6 +251,32 @@ allocstring(struct coff32 *coff, long off, struct strtbl *tbl)
}
static int
+writescns(Obj *obj, FILE *fp, struct strtbl *tbl)
+{
+ int i;
+ SCNHDR *scn;
+ FILHDR *hdr;
+ struct coff32 *coff;
+ unsigned char buf[SCNHSZ];
+
+ coff = obj->data;
+ hdr = &coff->hdr;
+
+ for (i = 0; i < hdr->f_nscns; i++) {
+ scn = &coff->scns[i];
+ if (scn->s_zeroes == 0) {
+ if (!allocstring(coff, scn->s_offset, tbl))
+ return 0;
+ }
+ pack_scn(ORDER(obj->type), buf, scn);
+ if (fwrite(buf, SCNHSZ, 1, fp) != 1)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
writeents(Obj *obj, FILE *fp, struct strtbl *tbl)
{
long i;
@@ -510,7 +518,7 @@ coff32write(Obj *obj, Map *map, FILE *fp)
goto err;
if (!writeaout(obj, fp))
goto err;
- if (!writescns(obj, fp))
+ if (!writescns(obj, fp, &tbl))
goto err;
if (!writedata(obj, map, fp))
goto err;