@@ -186,6 +186,8 @@ static void coff_write_relocs(struct coff_Section *);
186186static void coff_write_symbols (void );
187187static void coff_defcomdatname (char * name , int32_t segment );
188188
189+ #define COMDAT_PLACEHOLDER_NAME ".tmpcmdt"
190+
189191static 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+
309361static 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