ld: pe: Make archive member file extension comparisons case insensitive when cross compiling too

On Windows, filename_cmp is case insensitive, but when cross compiling
with libraries that may contain members with uppercase file names, we
should keep those comparisons case insensitive when running the build
tools on other OSes too.

Also make the check for .def consistent with the other ones, fixing
out of bounds reads if file names are shorter than 4 characters.
This commit is contained in:
Martin Storsjö 2021-09-27 11:20:24 +03:00
parent a37854f916
commit b53b12c8e8
2 changed files with 44 additions and 10 deletions

View File

@ -534,6 +534,23 @@ gld${EMULATION_NAME}_list_options (FILE *file)
fprintf (file, _(" --build-id[=STYLE] Generate build ID\n"));
}
/* A case insensitive comparison, regardless of the host platform, used for
comparing file extensions. */
static int
fileext_cmp (const char *s1, const char *s2)
{
for (;;)
{
int c1 = TOLOWER (*s1++);
int c2 = *s2++; /* Assumed to be lower case from the caller. */
if (c1 != c2)
return (c1 - c2);
if (c1 == '\0')
return 0;
}
}
static void
set_pe_name (char *name, long val)
@ -1666,7 +1683,7 @@ gld${EMULATION_NAME}_after_open (void)
extension, and use that for the remainder of the
comparisons. */
pnt = strrchr (bfd_get_filename (is3->the_bfd), '.');
if (pnt != NULL && filename_cmp (pnt, ".dll") == 0)
if (pnt != NULL && fileext_cmp (pnt + 1, "dll") == 0)
break;
}
@ -1683,7 +1700,7 @@ gld${EMULATION_NAME}_after_open (void)
/* Skip static members, ie anything with a .obj
extension. */
pnt = strrchr (bfd_get_filename (is2->the_bfd), '.');
if (pnt != NULL && filename_cmp (pnt, ".obj") == 0)
if (pnt != NULL && fileext_cmp (pnt + 1, "obj") == 0)
continue;
if (filename_cmp (bfd_get_filename (is3->the_bfd),
@ -1701,7 +1718,7 @@ gld${EMULATION_NAME}_after_open (void)
then leave the filename alone. */
pnt = strrchr (bfd_get_filename (is->the_bfd), '.');
if (is_ms_arch && (filename_cmp (pnt, ".dll") == 0))
if (is_ms_arch && pnt != NULL && (fileext_cmp (pnt + 1, "dll") == 0))
{
int idata2 = 0, reloc_count=0;
asection *sec;
@ -1855,9 +1872,9 @@ static bool
gld${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED)
{
#ifdef DLL_SUPPORT
const char *ext = entry->filename + strlen (entry->filename) - 4;
const char *ext = strrchr (entry->filename, '.');
if (filename_cmp (ext, ".def") == 0 || filename_cmp (ext, ".DEF") == 0)
if (ext != NULL && fileext_cmp (ext + 1, "def") == 0)
{
pe_def_file = def_file_parse (entry->filename, pe_def_file);

View File

@ -181,6 +181,23 @@ static int is_underscoring (void)
return pep_leading_underscore;
}
/* A case insensitive comparison, regardless of the host platform, used for
comparing file extensions. */
static int
fileext_cmp (const char *s1, const char *s2)
{
for (;;)
{
int c1 = TOLOWER (*s1++);
int c2 = *s2++; /* Assumed to be lower case from the caller. */
if (c1 != c2)
return (c1 - c2);
if (c1 == '\0')
return 0;
}
}
static void
gld${EMULATION_NAME}_before_parse (void)
@ -1630,7 +1647,7 @@ gld${EMULATION_NAME}_after_open (void)
extension, and use that for the remainder of the
comparisons. */
pnt = strrchr (bfd_get_filename (is3->the_bfd), '.');
if (pnt != NULL && filename_cmp (pnt, ".dll") == 0)
if (pnt != NULL && fileext_cmp (pnt + 1, "dll") == 0)
break;
}
@ -1647,7 +1664,7 @@ gld${EMULATION_NAME}_after_open (void)
/* Skip static members, ie anything with a .obj
extension. */
pnt = strrchr (bfd_get_filename (is2->the_bfd), '.');
if (pnt != NULL && filename_cmp (pnt, ".obj") == 0)
if (pnt != NULL && fileext_cmp (pnt + 1, "obj") == 0)
continue;
if (filename_cmp (bfd_get_filename (is3->the_bfd),
@ -1665,7 +1682,7 @@ gld${EMULATION_NAME}_after_open (void)
then leave the filename alone. */
pnt = strrchr (bfd_get_filename (is->the_bfd), '.');
if (is_ms_arch && (filename_cmp (pnt, ".dll") == 0))
if (is_ms_arch && pnt != NULL && (fileext_cmp (pnt + 1, "dll") == 0))
{
int idata2 = 0, reloc_count=0;
asection *sec;
@ -1725,9 +1742,9 @@ static bool
gld${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED)
{
#ifdef DLL_SUPPORT
const char *ext = entry->filename + strlen (entry->filename) - 4;
const char *ext = strrchr (entry->filename, '.');
if (filename_cmp (ext, ".def") == 0 || filename_cmp (ext, ".DEF") == 0)
if (ext != NULL && fileext_cmp (ext + 1, "def") == 0)
{
pep_def_file = def_file_parse (entry->filename, pep_def_file);