[nasm:master] output/coff: Support for COMDAT sections
nasm-bot for Igor Glucksmann
33635651+igg0 at users.noreply.github.com
Mon Nov 7 17:12:20 PST 2022
Commit-ID: ed2c609976826ce087731b15d70eef2ff64d7a1a
Gitweb: http://repo.or.cz/w/nasm.git?a=commitdiff;h=ed2c609976826ce087731b15d70eef2ff64d7a1a
Author: Igor Glucksmann <33635651+igg0 at users.noreply.github.com>
AuthorDate: Wed, 31 Mar 2021 15:23:11 +0200
Committer: Cyrill Gorcunov <gorcunov at gmail.com>
CommitDate: Fri, 17 Dec 2021 23:45:25 +0300
output/coff: Support for COMDAT sections
Signed-off-by: "Glücksmann, Igor" <igor.glucksmann at avast.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at gmail.com>
---
Makefile.in | 2 +-
Mkfiles/msvc.mak | 2 +-
Mkfiles/openwcom.mak | 2 +-
include/hashtbl.h | 2 +
rdoff/hash.c => nasmlib/crc32.c | 29 +++----
output/outcoff.c | 168 +++++++++++++++++++++++++++++++++++-----
output/pecoff.h | 7 ++
7 files changed, 171 insertions(+), 41 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 3b4b595c..3b36b6f0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -108,7 +108,7 @@ LIBOBJ_NW = stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
\
nasmlib/ver.$(O) \
nasmlib/alloc.$(O) nasmlib/asprintf.$(O) nasmlib/errfile.$(O) \
- nasmlib/crc64.$(O) nasmlib/md5c.$(O) \
+ nasmlib/crc32.$(O) nasmlib/crc64.$(O) nasmlib/md5c.$(O) \
nasmlib/string.$(O) nasmlib/nctype.$(O) \
nasmlib/file.$(O) nasmlib/mmap.$(O) nasmlib/ilog2.$(O) \
nasmlib/realpath.$(O) nasmlib/path.$(O) \
diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak
index 4d51bcf8..0b8308f2 100644
--- a/Mkfiles/msvc.mak
+++ b/Mkfiles/msvc.mak
@@ -72,7 +72,7 @@ LIBOBJ_NW = stdlib\snprintf.$(O) stdlib\vsnprintf.$(O) stdlib\strlcpy.$(O) \
\
nasmlib\ver.$(O) \
nasmlib\alloc.$(O) nasmlib\asprintf.$(O) nasmlib\errfile.$(O) \
- nasmlib\crc64.$(O) nasmlib\md5c.$(O) \
+ nasmlib\crc32.$(O) nasmlib\crc64.$(O) nasmlib\md5c.$(O) \
nasmlib\string.$(O) nasmlib\nctype.$(O) \
nasmlib\file.$(O) nasmlib\mmap.$(O) nasmlib\ilog2.$(O) \
nasmlib\realpath.$(O) nasmlib\path.$(O) \
diff --git a/Mkfiles/openwcom.mak b/Mkfiles/openwcom.mak
index 3c5ca235..219a48e9 100644
--- a/Mkfiles/openwcom.mak
+++ b/Mkfiles/openwcom.mak
@@ -61,7 +61,7 @@ LIBOBJ_NW = stdlib\snprintf.$(O) stdlib\vsnprintf.$(O) stdlib\strlcpy.$(O) &
&
nasmlib\ver.$(O) &
nasmlib\alloc.$(O) nasmlib\asprintf.$(O) nasmlib\errfile.$(O) &
- nasmlib\crc64.$(O) nasmlib\md5c.$(O) &
+ nasmlib\crc32.$(O) nasmlib\crc64.$(O) nasmlib\md5c.$(O) &
nasmlib\string.$(O) nasmlib\nctype.$(O) &
nasmlib\file.$(O) nasmlib\mmap.$(O) nasmlib\ilog2.$(O) &
nasmlib\realpath.$(O) nasmlib\path.$(O) &
diff --git a/include/hashtbl.h b/include/hashtbl.h
index e84d5061..9ea94dcb 100644
--- a/include/hashtbl.h
+++ b/include/hashtbl.h
@@ -79,6 +79,8 @@ static inline uint64_t crc64_byte(uint64_t crc, uint8_t v)
return crc64_tab[(uint8_t)(v ^ crc)] ^ (crc >> 8);
}
+uint32_t crc32b(uint32_t crc, const void *data, size_t len);
+
void **hash_find(struct hash_table *head, const char *string,
struct hash_insert *insert);
void **hash_findb(struct hash_table *head, const void *key, size_t keylen,
diff --git a/rdoff/hash.c b/nasmlib/crc32.c
similarity index 91%
copy from rdoff/hash.c
copy to nasmlib/crc32.c
index f2afad0f..40b914ef 100644
--- a/rdoff/hash.c
+++ b/nasmlib/crc32.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2021 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -31,17 +31,10 @@
*
* ----------------------------------------------------------------------- */
-/*
- * hash.h Routines to calculate a CRC32 hash value
- *
- * These routines donated to the NASM effort by Graeme Defty.
- */
-
#include "compiler.h"
+#include "hashtbl.h"
-#include "hash.h"
-
-const uint32_t consttab[] = {
+const uint32_t crc32_tab[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
@@ -108,15 +101,15 @@ const uint32_t consttab[] = {
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
-uint32_t hash(const char *name)
+uint32_t crc32b(uint32_t crc, const void *data, size_t len)
{
- register const char *n;
- register uint32_t hashval = 0xffffffff;
+ register const uint8_t *p = data;
+ register uint32_t hashval = crc;
- for (n = name; *n; n++)
- hashval = (hashval >> 8) ^ consttab[(hashval ^ *n) & 0xff];
-
- hashval ^= 0xffffffff;
+ while (len--)
+ {
+ hashval = (hashval >> 8) ^ crc32_tab[(hashval ^ *p++) & 0xff];
+ }
return hashval;
-}
+};
diff --git a/output/outcoff.c b/output/outcoff.c
index 58fa0249..a8159ba7 100644
--- a/output/outcoff.c
+++ b/output/outcoff.c
@@ -184,6 +184,7 @@ static void coff_write(void);
static void coff_section_header(char *, int32_t, int32_t, int32_t, int32_t, int32_t, int, int32_t);
static void coff_write_relocs(struct coff_Section *);
static void coff_write_symbols(void);
+static void coff_defcomdatname(char *name, int32_t segment);
static void coff_win32_init(void)
{
@@ -238,6 +239,7 @@ static void coff_cleanup(void)
nasm_free(r);
}
nasm_free(coff_sects[i]->name);
+ nasm_free(coff_sects[i]->comdat_name);
nasm_free(coff_sects[i]);
}
nasm_free(coff_sects);
@@ -306,9 +308,10 @@ static inline unsigned int coff_alignment(uint32_t flags)
static int32_t coff_section_names(char *name, int *bits)
{
- char *p;
+ char *p, *comdat_name;
uint32_t flags, align_flags;
- int i;
+ int i, j;
+ int8_t comdat_selection;
/*
* Set default bits.
@@ -333,7 +336,8 @@ static int32_t coff_section_names(char *name, int *bits)
name[8] = '\0';
}
}
- flags = align_flags = 0;
+ flags = align_flags = comdat_selection = 0;
+ comdat_name = NULL;
while (*p && nasm_isspace(*p))
p++;
@@ -386,12 +390,45 @@ static int32_t coff_section_names(char *name, int *bits)
align_flags = coff_sectalign_flags(align);
}
}
+ } else if (!nasm_strnicmp(q, "comdat=", 7)) {
+ /*
+ * Expected format: comdat=num:name]
+ * where
+ * num is a number: one of the IMAGE_COMDAT_SELECT_* constants
+ * name is a string: the "COMDAT name"
+ */
+ comdat_selection = strtoul(q + 7, &q, 10);
+ if (!comdat_selection)
+ nasm_nonfatal("invalid argument to `comdat'");
+ else if (*q != ':')
+ nasm_nonfatal("missing name in `comdat'");
+ else {
+ comdat_name = q + 1;
+ }
}
}
for (i = 0; i < coff_nsects; i++)
- if (!strcmp(name, coff_sects[i]->name))
- break;
+ if (!strcmp(name, coff_sects[i]->name)) {
+ if (!comdat_name && !coff_sects[i]->comdat_name)
+ break;
+ else if (comdat_name && coff_sects[i]->comdat_name &&
+ !strcmp(comdat_name, coff_sects[i]->comdat_name)) {
+ /*
+ * For COMDAT, it makes sense to have multiple sections with
+ * the same name (different comdat name though)
+ */
+ if ((coff_sects[i]->comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE &&
+ comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) ||
+ (coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE &&
+ comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE)) {
+ /*
+ * Let's also allow an associative/other pair with the same name
+ */
+ break;
+ }
+ }
+ }
if (i == coff_nsects) {
if (!flags) {
flags = TEXT_FLAGS;
@@ -409,10 +446,37 @@ static int32_t coff_section_names(char *name, int *bits)
flags = XDATA_FLAGS;
}
}
+
+ if (comdat_name)
+ flags |= IMAGE_SCN_LNK_COMDAT;
+
i = coff_make_section(name, flags);
coff_sects[i]->align_flags = align_flags;
+
+ if (comdat_name) {
+ coff_sects[i]->comdat_selection = comdat_selection;
+
+ coff_sects[i]->comdat_name = strdup(comdat_name);
+ if (comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ /*
+ * Find a previous section with given comdat name
+ */
+ for (j = 0; j < coff_nsects - 1; j++)
+ if (coff_sects[j]->comdat_name &&
+ !strcmp(coff_sects[j]->comdat_name, comdat_name))
+ break;
+ if (j < coff_nsects - 1) {
+ coff_sects[i]->comdat_associated = j + 1;
+ }
+ else
+ nasm_nonfatal("unknown `comdat' associative");
+ }
+ }
} else {
if (flags) {
+ if (comdat_name)
+ flags |= IMAGE_SCN_LNK_COMDAT;
+
/* Warn if non-alignment flags differ */
if (((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK) &&
coff_sects[i]->pass_last_seen == pass_count()) {
@@ -428,6 +492,14 @@ static int32_t coff_section_names(char *name, int *bits)
if (align_flags > coff_sects[i]->align_flags) {
coff_sects[i]->align_flags = align_flags;
}
+
+ if (comdat_name) {
+ if ((coff_sects[i]->comdat_selection != comdat_selection) &&
+ coff_sects[i]->pass_last_seen == pass_count()) {
+ nasm_warn(WARN_OTHER, "comdat selection changed on"
+ " redeclaration of name `%s'", comdat_name);
+ }
+ }
}
coff_sects[i]->pass_last_seen = pass_count();
@@ -437,7 +509,7 @@ static int32_t coff_section_names(char *name, int *bits)
static void coff_deflabel(char *name, int32_t segment, int64_t offset,
int is_global, char *special)
{
- int pos = strslen + 4;
+ int pos, section;
struct coff_Symbol *sym;
if (special)
@@ -450,6 +522,32 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset,
return;
}
+ if (segment == NO_SEG)
+ section = -1; /* absolute symbol */
+ else {
+ int i;
+ section = 0;
+ for (i = 0; i < coff_nsects; i++)
+ if (segment == coff_sects[i]->index) {
+ section = i + 1;
+
+ if (coff_sects[i]->comdat_name && !coff_sects[i]->comdat_symbol) {
+ /*
+ * The "comdat symbol" must be the first one in symbol table
+ * So we'll insert/define it - before defining the other one
+ */
+ coff_sects[i]->comdat_symbol = 1;
+
+ if (coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE &&
+ 0 != strcmp(coff_sects[i]->comdat_name, name)) {
+ coff_defcomdatname(coff_sects[i]->comdat_name, segment);
+ }
+ }
+ break;
+ }
+ }
+
+ pos = strslen + 4;
if (strlen(name) > 8) {
size_t nlen = strlen(name)+1;
saa_wbytes(coff_strs, name, nlen);
@@ -465,19 +563,9 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset,
strcpy(sym->name, name);
sym->is_global = !!is_global;
sym->type = 0; /* Default to T_NULL (no type) */
- if (segment == NO_SEG)
- sym->section = -1; /* absolute symbol */
- else {
- int i;
- sym->section = 0;
- for (i = 0; i < coff_nsects; i++)
- if (segment == coff_sects[i]->index) {
- sym->section = i + 1;
- break;
- }
- if (!sym->section)
- sym->is_global = true;
- }
+ sym->section = section;
+ if (!sym->section)
+ sym->is_global = true;
if (is_global == 2)
sym->value = offset;
else
@@ -740,6 +828,11 @@ static void BuildExportTable(STRING **rvp)
*rvp = NULL;
}
+static void coff_defcomdatname(char *name, int32_t segment)
+{
+ coff_deflabel(name, segment, 0, 1, NULL);
+}
+
static enum directive_result
coff_directives(enum directive directive, char *value)
{
@@ -906,6 +999,17 @@ static void coff_write(void)
coff_deflabel("@feat.00", NO_SEG, 1, 0, NULL);
}
+ /*
+ * Check if all comdat sections have their comdat symbol
+ * If not, define it
+ */
+ for (i = 0; i < coff_nsects; i++) {
+ if (coff_sects[i]->comdat_name && !coff_sects[i]->comdat_symbol &&
+ coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ coff_defcomdatname(coff_sects[i]->comdat_name, coff_sects[i]->index);
+ }
+ }
+
/*
* Work out how big the file will get.
* Calculate the start of the `real' symbols at the same time.
@@ -961,6 +1065,22 @@ static void coff_write(void)
if (coff_sects[i]->data) {
saa_fpwrite(coff_sects[i]->data, ofile);
coff_write_relocs(coff_sects[i]);
+
+ if (coff_sects[i]->flags & IMAGE_SCN_LNK_COMDAT) {
+ /*
+ * Checksum the section data
+ */
+ uint32_t checksum = 0;
+ const char *data;
+ size_t len;
+
+ saa_rewind(coff_sects[i]->data);
+ while (len = coff_sects[i]->data->datalen,
+ (data = saa_rbytes(coff_sects[i]->data, &len)) != NULL)
+ checksum = crc32b(checksum, data, len);
+
+ coff_sects[i]->checksum = checksum;
+ }
}
/*
@@ -1091,7 +1211,15 @@ static void coff_write_symbols(void)
coff_symbol(coff_sects[i]->name, 0L, 0L, i + 1, 0, 3, 1);
fwriteint32_t(coff_sects[i]->len, ofile);
fwriteint16_t(coff_sects[i]->nrelocs,ofile);
- nasm_write(filename, 12, ofile);
+ if (coff_sects[i]->flags & IMAGE_SCN_LNK_COMDAT) {
+ fwriteint16_t(0, ofile);
+ fwriteint32_t(coff_sects[i]->checksum, ofile);
+ fwriteint16_t(coff_sects[i]->comdat_associated, ofile);
+ fputc(coff_sects[i]->comdat_selection, ofile);
+ nasm_write(filename, 3, ofile);
+ }
+ else
+ nasm_write(filename, 12, ofile);
}
/*
diff --git a/output/pecoff.h b/output/pecoff.h
index efecd0f9..b99bed09 100644
--- a/output/pecoff.h
+++ b/output/pecoff.h
@@ -487,6 +487,13 @@ struct coff_Section {
int32_t namepos; /* Offset of name into the strings table */
int32_t pos, relpos;
int64_t pass_last_seen;
+
+ /* comdat-related members */
+ char *comdat_name;
+ uint32_t checksum; /* set only for comdat sections */
+ int8_t comdat_selection;
+ int8_t comdat_symbol; /* is the "comdat name" in symbol table? */
+ int32_t comdat_associated; /* associated section for selection==5 */
};
struct coff_Reloc {
More information about the Nasm-commits
mailing list