coffcode.h handle_COMDAT tidy

I started down the path of attempting to fix
https://sourceware.org/pipermail/binutils/2023-April/127263.html but
decided after a while that I didn't want to mess with this code..

This patch is a just a few things that I thought worth doing, the main
one being reporting of errors up the call chain.  The while loop to
for loop change is shamelessly stolen from Oleg.

	* coffcode.h (handle_COMDAT): Return bool.  Make sec_flags a
	flagword*, and adjust to suit.  Replace while loop with for
	loop.  Check isym.n_numaux before reading aux entries.  Alloc
	coff_comdat_info and name in one call to bfd_alloc.  Remove
	goto breakloop.
	(styp_to_sec_flags): Adjust handle_COMDAT call.
This commit is contained in:
Alan Modra
2023-05-04 18:49:04 +09:30
parent 880853ed94
commit cb3f0ff479

View File

@@ -852,9 +852,9 @@ styp_to_sec_flags (bfd *abfd,
#else /* COFF_WITH_PE */ #else /* COFF_WITH_PE */
static flagword static bool
handle_COMDAT (bfd * abfd, handle_COMDAT (bfd * abfd,
flagword sec_flags, flagword *sec_flags,
void * hdr, void * hdr,
const char *name, const char *name,
asection *section) asection *section)
@@ -864,7 +864,7 @@ handle_COMDAT (bfd * abfd,
int seen_state = 0; int seen_state = 0;
char *target_name = NULL; char *target_name = NULL;
sec_flags |= SEC_LINK_ONCE; *sec_flags |= SEC_LINK_ONCE;
/* Unfortunately, the PE format stores essential information in /* Unfortunately, the PE format stores essential information in
the symbol table, of all places. We need to extract that the symbol table, of all places. We need to extract that
@@ -884,18 +884,19 @@ handle_COMDAT (bfd * abfd,
rather messy. */ rather messy. */
if (! _bfd_coff_get_external_symbols (abfd)) if (! _bfd_coff_get_external_symbols (abfd))
return sec_flags; return true;
esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd); esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd);
esymend = esym + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); esymend = esym + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd);
while (esym < esymend) for (struct internal_syment isym;
esym < esymend;
esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd))
{ {
struct internal_syment isym;
char buf[SYMNMLEN + 1]; char buf[SYMNMLEN + 1];
const char *symname; const char *symname;
bfd_coff_swap_sym_in (abfd, esym, & isym); bfd_coff_swap_sym_in (abfd, esym, &isym);
BFD_ASSERT (sizeof (internal_s->s_name) <= SYMNMLEN); BFD_ASSERT (sizeof (internal_s->s_name) <= SYMNMLEN);
@@ -933,7 +934,7 @@ handle_COMDAT (bfd * abfd,
{ {
_bfd_error_handler (_("%pB: unable to load COMDAT section name"), _bfd_error_handler (_("%pB: unable to load COMDAT section name"),
abfd); abfd);
break; return false;
} }
switch (seen_state) switch (seen_state)
@@ -968,7 +969,7 @@ handle_COMDAT (bfd * abfd,
cf PR 21781. */ cf PR 21781. */
_bfd_error_handler (_("%pB: error: unexpected symbol '%s' in COMDAT section"), _bfd_error_handler (_("%pB: error: unexpected symbol '%s' in COMDAT section"),
abfd, symname); abfd, symname);
goto breakloop; return false;
} }
/* FIXME LATER: MSVC generates section names /* FIXME LATER: MSVC generates section names
@@ -982,22 +983,8 @@ handle_COMDAT (bfd * abfd,
" does not match section name '%s'"), " does not match section name '%s'"),
abfd, symname, name); abfd, symname, name);
seen_state = 1;
/* PR 17512: file: e2cfe54f. */
if (esym + bfd_coff_symesz (abfd) >= esymend)
{
/* xgettext:c-format */
_bfd_error_handler (_("%pB: warning: no symbol for"
" section '%s' found"),
abfd, symname);
break;
}
/* This is the section symbol. */ /* This is the section symbol. */
bfd_coff_swap_aux_in (abfd, (esym + bfd_coff_symesz (abfd)), seen_state = 1;
isym.n_type, isym.n_sclass,
0, isym.n_numaux, & aux);
target_name = strchr (name, '$'); target_name = strchr (name, '$');
if (target_name != NULL) if (target_name != NULL)
{ {
@@ -1007,6 +994,24 @@ handle_COMDAT (bfd * abfd,
target_name += 1; target_name += 1;
} }
if (isym.n_numaux == 0)
aux.x_scn.x_comdat = 0;
else
{
/* PR 17512: file: e2cfe54f. */
if (esym + bfd_coff_symesz (abfd) >= esymend)
{
/* xgettext:c-format */
_bfd_error_handler (_("%pB: warning: no symbol for"
" section '%s' found"),
abfd, symname);
break;
}
bfd_coff_swap_aux_in (abfd, esym + bfd_coff_symesz (abfd),
isym.n_type, isym.n_sclass,
0, isym.n_numaux, &aux);
}
/* FIXME: Microsoft uses NODUPLICATES and /* FIXME: Microsoft uses NODUPLICATES and
ASSOCIATIVE, but gnu uses ANY and ASSOCIATIVE, but gnu uses ANY and
SAME_SIZE. Unfortunately, gnu doesn't do SAME_SIZE. Unfortunately, gnu doesn't do
@@ -1027,23 +1032,23 @@ handle_COMDAT (bfd * abfd,
{ {
case IMAGE_COMDAT_SELECT_NODUPLICATES: case IMAGE_COMDAT_SELECT_NODUPLICATES:
#ifdef STRICT_PE_FORMAT #ifdef STRICT_PE_FORMAT
sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY; *sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY;
#else #else
sec_flags &= ~SEC_LINK_ONCE; *sec_flags &= ~SEC_LINK_ONCE;
#endif #endif
break; break;
case IMAGE_COMDAT_SELECT_ANY: case IMAGE_COMDAT_SELECT_ANY:
sec_flags |= SEC_LINK_DUPLICATES_DISCARD; *sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
break; break;
case IMAGE_COMDAT_SELECT_SAME_SIZE: case IMAGE_COMDAT_SELECT_SAME_SIZE:
sec_flags |= SEC_LINK_DUPLICATES_SAME_SIZE; *sec_flags |= SEC_LINK_DUPLICATES_SAME_SIZE;
break; break;
case IMAGE_COMDAT_SELECT_EXACT_MATCH: case IMAGE_COMDAT_SELECT_EXACT_MATCH:
/* Not yet fully implemented ??? */ /* Not yet fully implemented ??? */
sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; *sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
break; break;
/* debug$S gets this case; other /* debug$S gets this case; other
@@ -1056,16 +1061,16 @@ handle_COMDAT (bfd * abfd,
case IMAGE_COMDAT_SELECT_ASSOCIATIVE: case IMAGE_COMDAT_SELECT_ASSOCIATIVE:
#ifdef STRICT_PE_FORMAT #ifdef STRICT_PE_FORMAT
/* FIXME: This is not currently implemented. */ /* FIXME: This is not currently implemented. */
sec_flags |= SEC_LINK_DUPLICATES_DISCARD; *sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
#else #else
sec_flags &= ~SEC_LINK_ONCE; *sec_flags &= ~SEC_LINK_ONCE;
#endif #endif
break; break;
default: /* 0 means "no symbol" */ default: /* 0 means "no symbol" */
/* debug$F gets this case; other /* debug$F gets this case; other
implications ??? */ implications ??? */
sec_flags |= SEC_LINK_DUPLICATES_DISCARD; *sec_flags |= SEC_LINK_DUPLICATES_DISCARD;
break; break;
} }
} }
@@ -1082,7 +1087,6 @@ handle_COMDAT (bfd * abfd,
symname + (TARGET_UNDERSCORE ? 1 : 0)) != 0) symname + (TARGET_UNDERSCORE ? 1 : 0)) != 0)
{ {
/* Not the name we're looking for */ /* Not the name we're looking for */
esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd);
continue; continue;
} }
/* Fall through. */ /* Fall through. */
@@ -1090,42 +1094,30 @@ handle_COMDAT (bfd * abfd,
/* MSVC mode: the lexically second symbol (or /* MSVC mode: the lexically second symbol (or
drop through from the above). */ drop through from the above). */
{ {
char *newname;
size_t amt;
/* This must the second symbol with the /* This must the second symbol with the
section #. It is the actual symbol name. section #. It is the actual symbol name.
Intel puts the two adjacent, but Alpha (at Intel puts the two adjacent, but Alpha (at
least) spreads them out. */ least) spreads them out. */
amt = sizeof (struct coff_comdat_info); struct coff_comdat_info *comdat;
coff_section_data (abfd, section)->comdat size_t len = strlen (symname) + 1;
= (struct coff_comdat_info *) bfd_alloc (abfd, amt);
if (coff_section_data (abfd, section)->comdat == NULL)
abort ();
coff_section_data (abfd, section)->comdat->symbol = comdat = bfd_alloc (abfd, sizeof (*comdat) + len);
(esym - esymstart) / bfd_coff_symesz (abfd); if (comdat == NULL)
return false;
amt = strlen (symname) + 1; coff_section_data (abfd, section)->comdat = comdat;
newname = (char *) bfd_alloc (abfd, amt); comdat->symbol = (esym - esymstart) / bfd_coff_symesz (abfd);
if (newname == NULL) char *newname = (char *) (comdat + 1);
abort (); comdat->name = newname;
memcpy (newname, symname, len);
strcpy (newname, symname); return true;
coff_section_data (abfd, section)->comdat->name
= newname;
} }
goto breakloop;
} }
} }
esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd);
} }
breakloop: return true;
return sec_flags;
} }
@@ -1276,7 +1268,8 @@ styp_to_sec_flags (bfd *abfd,
break; break;
case IMAGE_SCN_LNK_COMDAT: case IMAGE_SCN_LNK_COMDAT:
/* COMDAT gets very special treatment. */ /* COMDAT gets very special treatment. */
sec_flags = handle_COMDAT (abfd, sec_flags, hdr, name, section); if (!handle_COMDAT (abfd, &sec_flags, hdr, name, section))
result = false;
break; break;
default: default:
/* Silently ignore for now. */ /* Silently ignore for now. */