Skip to content

Commit 27e17c9

Browse files
igg0cyrillos
authored andcommitted
output/coff: Possibility to define the associated comdat sections in any order
Signed-off-by: "Glücksmann, Igor" <igor.glucksmann@avast.com> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
1 parent ed2c609 commit 27e17c9

File tree

1 file changed

+114
-38
lines changed

1 file changed

+114
-38
lines changed

output/outcoff.c

Lines changed: 114 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ static void coff_write_relocs(struct coff_Section *);
186186
static void coff_write_symbols(void);
187187
static void coff_defcomdatname(char *name, int32_t segment);
188188

189+
#define COMDAT_PLACEHOLDER_NAME ".tmpcmdt"
190+
189191
static void coff_win32_init(void)
190192
{
191193
win32 = true;
@@ -288,6 +290,31 @@ int coff_make_section(char *name, uint32_t flags)
288290
return coff_nsects - 1;
289291
}
290292

293+
/*
294+
* Update the name and flags of an existing section
295+
*/
296+
static void coff_update_section(int section, char *name, uint32_t flags)
297+
{
298+
struct coff_Section *s = coff_sects[section];
299+
size_t namelen = strlen(name);
300+
301+
if (namelen > 8) {
302+
if (win32 || win64) {
303+
s->namepos = strslen + 4;
304+
saa_wbytes(coff_strs, name, namelen + 1);
305+
strslen += namelen + 1;
306+
} else {
307+
namelen = 8;
308+
}
309+
}
310+
311+
nasm_free(s->name);
312+
s->name = nasm_malloc(namelen + 1);
313+
strncpy(s->name, name, namelen);
314+
s->name[namelen] = '\0';
315+
s->flags = flags;
316+
}
317+
291318
/*
292319
* Convert an alignment value to the corresponding flags.
293320
* An alignment value of 0 means no flags should be set.
@@ -306,12 +333,38 @@ static inline unsigned int coff_alignment(uint32_t flags)
306333
return (1U << ((flags & IMAGE_SCN_ALIGN_MASK) >> 20)) >> 1;
307334
}
308335

336+
/*
337+
* Get the default section flags (based on section name)
338+
*/
339+
static uint32_t coff_section_flags(char *name, uint32_t flags)
340+
{
341+
if (!flags) {
342+
flags = TEXT_FLAGS;
343+
344+
if (!strcmp(name, ".data")) {
345+
flags = DATA_FLAGS;
346+
} else if (!strcmp(name, ".rdata")) {
347+
flags = RDATA_FLAGS;
348+
} else if (!strcmp(name, ".bss")) {
349+
flags = BSS_FLAGS;
350+
} else if (win64) {
351+
if (!strcmp(name, ".pdata"))
352+
flags = PDATA_FLAGS;
353+
else if (!strcmp(name, ".xdata"))
354+
flags = XDATA_FLAGS;
355+
}
356+
}
357+
358+
return flags;
359+
}
360+
309361
static int32_t coff_section_names(char *name, int *bits)
310362
{
311363
char *p, *comdat_name;
312364
uint32_t flags, align_flags;
313365
int i, j;
314366
int8_t comdat_selection;
367+
int32_t comdat_associated;
315368

316369
/*
317370
* Set default bits.
@@ -336,7 +389,7 @@ static int32_t coff_section_names(char *name, int *bits)
336389
name[8] = '\0';
337390
}
338391
}
339-
flags = align_flags = comdat_selection = 0;
392+
flags = align_flags = comdat_selection = comdat_associated = 0;
340393
comdat_name = NULL;
341394

342395
while (*p && nasm_isspace(*p))
@@ -400,7 +453,7 @@ static int32_t coff_section_names(char *name, int *bits)
400453
comdat_selection = strtoul(q + 7, &q, 10);
401454
if (!comdat_selection)
402455
nasm_nonfatal("invalid argument to `comdat'");
403-
else if (*q != ':')
456+
else if (*q != ':' || q[1] == '\0')
404457
nasm_nonfatal("missing name in `comdat'");
405458
else {
406459
comdat_name = q + 1;
@@ -429,49 +482,62 @@ static int32_t coff_section_names(char *name, int *bits)
429482
}
430483
}
431484
}
432-
if (i == coff_nsects) {
433-
if (!flags) {
434-
flags = TEXT_FLAGS;
435-
436-
if (!strcmp(name, ".data")) {
437-
flags = DATA_FLAGS;
438-
} else if (!strcmp(name, ".rdata")) {
439-
flags = RDATA_FLAGS;
440-
} else if (!strcmp(name, ".bss")) {
441-
flags = BSS_FLAGS;
442-
} else if (win64) {
443-
if (!strcmp(name, ".pdata"))
444-
flags = PDATA_FLAGS;
445-
else if (!strcmp(name, ".xdata"))
446-
flags = XDATA_FLAGS;
447-
}
485+
else if (comdat_name && coff_sects[i]->comdat_name &&
486+
!coff_sects[i]->comdat_selection &&
487+
!strcmp(comdat_name, coff_sects[i]->comdat_name) &&
488+
comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
489+
/*
490+
* This seems to be a "placeholder section" we've created before
491+
* to be the associate of a previous comdat section.
492+
* We'll just update the name and flags with the real ones now.
493+
*/
494+
flags = coff_section_flags(name, flags);
495+
coff_update_section(i, name, flags | IMAGE_SCN_LNK_COMDAT);
496+
coff_sects[i]->comdat_selection = comdat_selection;
497+
break;
448498
}
449499

450-
if (comdat_name)
451-
flags |= IMAGE_SCN_LNK_COMDAT;
452-
453-
i = coff_make_section(name, flags);
454-
coff_sects[i]->align_flags = align_flags;
500+
if (i == coff_nsects) {
501+
flags = coff_section_flags(name, flags);
455502

456503
if (comdat_name) {
457-
coff_sects[i]->comdat_selection = comdat_selection;
504+
flags |= IMAGE_SCN_LNK_COMDAT;
458505

459-
coff_sects[i]->comdat_name = strdup(comdat_name);
460506
if (comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
461507
/*
462-
* Find a previous section with given comdat name
508+
* Find an existing section with given comdat name
463509
*/
464-
for (j = 0; j < coff_nsects - 1; j++)
510+
for (j = 0; j < coff_nsects; j++)
465511
if (coff_sects[j]->comdat_name &&
466512
!strcmp(coff_sects[j]->comdat_name, comdat_name))
467513
break;
468-
if (j < coff_nsects - 1) {
469-
coff_sects[i]->comdat_associated = j + 1;
514+
515+
if (j == coff_nsects) {
516+
/*
517+
* The associated section doesn't exist (yet)
518+
* Even though the specs don't enforce a particular order,
519+
* VS (2019) linker doesn't accept .obj files where the
520+
* target section is a later one (than the one with sel==5)
521+
*
522+
* So let's insert another section now (a placeholder),
523+
* hoping it will be turned into the target section later.
524+
*/
525+
j = coff_make_section(COMDAT_PLACEHOLDER_NAME, TEXT_FLAGS);
526+
coff_sects[j]->comdat_name = nasm_strdup(comdat_name);
470527
}
471-
else
472-
nasm_nonfatal("unknown `comdat' associative");
528+
529+
comdat_associated = j + 1;
473530
}
474531
}
532+
533+
i = coff_make_section(name, flags);
534+
coff_sects[i]->align_flags = align_flags;
535+
536+
if (comdat_name) {
537+
coff_sects[i]->comdat_selection = comdat_selection;
538+
coff_sects[i]->comdat_associated = comdat_associated;
539+
coff_sects[i]->comdat_name = nasm_strdup(comdat_name);
540+
}
475541
} else {
476542
if (flags) {
477543
if (comdat_name)
@@ -1000,15 +1066,25 @@ static void coff_write(void)
10001066
}
10011067

10021068
/*
1003-
* Check if all comdat sections have their comdat symbol
1004-
* If not, define it
1069+
* Check all comdat sections
10051070
*/
1006-
for (i = 0; i < coff_nsects; i++) {
1007-
if (coff_sects[i]->comdat_name && !coff_sects[i]->comdat_symbol &&
1008-
coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
1009-
coff_defcomdatname(coff_sects[i]->comdat_name, coff_sects[i]->index);
1071+
for (i = 0; i < coff_nsects; i++)
1072+
if (coff_sects[i]->comdat_name) {
1073+
if (!coff_sects[i]->comdat_symbol &&
1074+
coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
1075+
/*
1076+
* This section doesn't have its comdat symbol defined; do it
1077+
*/
1078+
coff_defcomdatname(coff_sects[i]->comdat_name, coff_sects[i]->index);
1079+
}
1080+
if (!coff_sects[i]->comdat_selection) {
1081+
/*
1082+
* This is a placeholder section that wasn't properly defined
1083+
*/
1084+
nasm_nonfatal("`comdat' associate with symbol `%s` wasn't defined",
1085+
coff_sects[i]->comdat_name);
1086+
}
10101087
}
1011-
}
10121088

10131089
/*
10141090
* Work out how big the file will get.

0 commit comments

Comments
 (0)