[nasm:master] output/coff: Possibility to define the associated comdat sections in any order
nasm-bot for Igor Glucksmann
33635651+igg0 at users.noreply.github.com
Mon Nov 7 17:12:20 PST 2022
Commit-ID: 27e17c913c3c95dcbfa3120073f776d430ba71ec
Gitweb: http://repo.or.cz/w/nasm.git?a=commitdiff;h=27e17c913c3c95dcbfa3120073f776d430ba71ec
Author: Igor Glucksmann <33635651+igg0 at users.noreply.github.com>
AuthorDate: Wed, 7 Apr 2021 13:58:04 +0200
Committer: Cyrill Gorcunov <gorcunov at gmail.com>
CommitDate: Fri, 17 Dec 2021 23:45:39 +0300
output/coff: Possibility to define the associated comdat sections in any order
Signed-off-by: "Glücksmann, Igor" <igor.glucksmann at avast.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at gmail.com>
---
output/outcoff.c | 152 +++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 114 insertions(+), 38 deletions(-)
diff --git a/output/outcoff.c b/output/outcoff.c
index a8159ba7..e505fe60 100644
--- a/output/outcoff.c
+++ b/output/outcoff.c
@@ -186,6 +186,8 @@ static void coff_write_relocs(struct coff_Section *);
static void coff_write_symbols(void);
static void coff_defcomdatname(char *name, int32_t segment);
+#define COMDAT_PLACEHOLDER_NAME ".tmpcmdt"
+
static void coff_win32_init(void)
{
win32 = true;
@@ -288,6 +290,31 @@ int coff_make_section(char *name, uint32_t flags)
return coff_nsects - 1;
}
+/*
+ * Update the name and flags of an existing section
+ */
+static void coff_update_section(int section, char *name, uint32_t flags)
+{
+ struct coff_Section *s = coff_sects[section];
+ size_t namelen = strlen(name);
+
+ if (namelen > 8) {
+ if (win32 || win64) {
+ s->namepos = strslen + 4;
+ saa_wbytes(coff_strs, name, namelen + 1);
+ strslen += namelen + 1;
+ } else {
+ namelen = 8;
+ }
+ }
+
+ nasm_free(s->name);
+ s->name = nasm_malloc(namelen + 1);
+ strncpy(s->name, name, namelen);
+ s->name[namelen] = '\0';
+ s->flags = flags;
+}
+
/*
* Convert an alignment value to the corresponding flags.
* An alignment value of 0 means no flags should be set.
@@ -306,12 +333,38 @@ static inline unsigned int coff_alignment(uint32_t flags)
return (1U << ((flags & IMAGE_SCN_ALIGN_MASK) >> 20)) >> 1;
}
+/*
+ * Get the default section flags (based on section name)
+ */
+static uint32_t coff_section_flags(char *name, uint32_t flags)
+{
+ if (!flags) {
+ flags = TEXT_FLAGS;
+
+ if (!strcmp(name, ".data")) {
+ flags = DATA_FLAGS;
+ } else if (!strcmp(name, ".rdata")) {
+ flags = RDATA_FLAGS;
+ } else if (!strcmp(name, ".bss")) {
+ flags = BSS_FLAGS;
+ } else if (win64) {
+ if (!strcmp(name, ".pdata"))
+ flags = PDATA_FLAGS;
+ else if (!strcmp(name, ".xdata"))
+ flags = XDATA_FLAGS;
+ }
+ }
+
+ return flags;
+}
+
static int32_t coff_section_names(char *name, int *bits)
{
char *p, *comdat_name;
uint32_t flags, align_flags;
int i, j;
int8_t comdat_selection;
+ int32_t comdat_associated;
/*
* Set default bits.
@@ -336,7 +389,7 @@ static int32_t coff_section_names(char *name, int *bits)
name[8] = '\0';
}
}
- flags = align_flags = comdat_selection = 0;
+ flags = align_flags = comdat_selection = comdat_associated = 0;
comdat_name = NULL;
while (*p && nasm_isspace(*p))
@@ -400,7 +453,7 @@ static int32_t coff_section_names(char *name, int *bits)
comdat_selection = strtoul(q + 7, &q, 10);
if (!comdat_selection)
nasm_nonfatal("invalid argument to `comdat'");
- else if (*q != ':')
+ else if (*q != ':' || q[1] == '\0')
nasm_nonfatal("missing name in `comdat'");
else {
comdat_name = q + 1;
@@ -429,49 +482,62 @@ static int32_t coff_section_names(char *name, int *bits)
}
}
}
- if (i == coff_nsects) {
- if (!flags) {
- flags = TEXT_FLAGS;
-
- if (!strcmp(name, ".data")) {
- flags = DATA_FLAGS;
- } else if (!strcmp(name, ".rdata")) {
- flags = RDATA_FLAGS;
- } else if (!strcmp(name, ".bss")) {
- flags = BSS_FLAGS;
- } else if (win64) {
- if (!strcmp(name, ".pdata"))
- flags = PDATA_FLAGS;
- else if (!strcmp(name, ".xdata"))
- flags = XDATA_FLAGS;
- }
+ else if (comdat_name && coff_sects[i]->comdat_name &&
+ !coff_sects[i]->comdat_selection &&
+ !strcmp(comdat_name, coff_sects[i]->comdat_name) &&
+ comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ /*
+ * This seems to be a "placeholder section" we've created before
+ * to be the associate of a previous comdat section.
+ * We'll just update the name and flags with the real ones now.
+ */
+ flags = coff_section_flags(name, flags);
+ coff_update_section(i, name, flags | IMAGE_SCN_LNK_COMDAT);
+ coff_sects[i]->comdat_selection = comdat_selection;
+ break;
}
- if (comdat_name)
- flags |= IMAGE_SCN_LNK_COMDAT;
-
- i = coff_make_section(name, flags);
- coff_sects[i]->align_flags = align_flags;
+ if (i == coff_nsects) {
+ flags = coff_section_flags(name, flags);
if (comdat_name) {
- coff_sects[i]->comdat_selection = comdat_selection;
+ flags |= IMAGE_SCN_LNK_COMDAT;
- coff_sects[i]->comdat_name = strdup(comdat_name);
if (comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
/*
- * Find a previous section with given comdat name
+ * Find an existing section with given comdat name
*/
- for (j = 0; j < coff_nsects - 1; j++)
+ for (j = 0; j < coff_nsects; 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;
+
+ if (j == coff_nsects) {
+ /*
+ * The associated section doesn't exist (yet)
+ * Even though the specs don't enforce a particular order,
+ * VS (2019) linker doesn't accept .obj files where the
+ * target section is a later one (than the one with sel==5)
+ *
+ * So let's insert another section now (a placeholder),
+ * hoping it will be turned into the target section later.
+ */
+ j = coff_make_section(COMDAT_PLACEHOLDER_NAME, TEXT_FLAGS);
+ coff_sects[j]->comdat_name = nasm_strdup(comdat_name);
}
- else
- nasm_nonfatal("unknown `comdat' associative");
+
+ comdat_associated = j + 1;
}
}
+
+ 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_associated = comdat_associated;
+ coff_sects[i]->comdat_name = nasm_strdup(comdat_name);
+ }
} else {
if (flags) {
if (comdat_name)
@@ -1000,15 +1066,25 @@ static void coff_write(void)
}
/*
- * Check if all comdat sections have their comdat symbol
- * If not, define it
+ * Check all comdat sections
*/
- 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);
+ for (i = 0; i < coff_nsects; i++)
+ if (coff_sects[i]->comdat_name) {
+ if (!coff_sects[i]->comdat_symbol &&
+ coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ /*
+ * This section doesn't have its comdat symbol defined; do it
+ */
+ coff_defcomdatname(coff_sects[i]->comdat_name, coff_sects[i]->index);
+ }
+ if (!coff_sects[i]->comdat_selection) {
+ /*
+ * This is a placeholder section that wasn't properly defined
+ */
+ nasm_nonfatal("`comdat' associate with symbol `%s` wasn't defined",
+ coff_sects[i]->comdat_name);
+ }
}
- }
/*
* Work out how big the file will get.
More information about the Nasm-commits
mailing list