Improve selection of output format

This commit is contained in:
Nick Clifton 1999-07-19 14:57:03 +00:00
parent c3c89269f8
commit e50d80767c
2 changed files with 247 additions and 35 deletions

View File

@ -1,3 +1,22 @@
1999-07-17 Nick Clifton <nickc@cygnus.com>
* ldlang.c (get_target): New function: Return true iff the
given target is the target being sought.
(stricpy): New function: Like strcpy but convert to lower
case as well.
(strcut): New function: Like strstr but remove the located
substring as well.
(name_compare): New function: Compute a compatability rating
for two target names.
(winner): New variable: Best target found by
closest_target_match() so far.
(closest_target_match): New function: Find the target which is
the closest match to the original target.
(get_first_input_target): New function: Find the target format
of the first of the linker's input file.
(open_output): Be more clever about deciding the output target
format.
1999-07-16 Jakub Jelinek <jj@ultra.linux.cz>
* emulparams/elf64_sparc.sh: Add 64-bit directories to native LIB_PATH.

View File

@ -151,6 +151,13 @@ static void walk_wild_section
static void walk_wild_file
PARAMS ((lang_wild_statement_type *, const char *,
lang_input_statement_type *, callback_t, void *));
static int get_target PARAMS ((const bfd_target *, void *));
static void stricpy PARAMS ((char *, char *));
static void strcut PARAMS ((char *, char *));
static int name_compare PARAMS ((char *, char *));
static int closest_target_match PARAMS ((const bfd_target *, void *));
static char * get_first_input_target PARAMS ((void));
/* EXPORTS */
lang_output_section_statement_type *abs_output_section;
@ -294,23 +301,17 @@ walk_wild (s, section, file, callback, data)
callback_t callback;
void *data;
{
lang_input_statement_type *f;
if (file == (char *) NULL)
{
/* Perform the iteration over all files in the list. */
for (f = (lang_input_statement_type *) file_chain.head;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
walk_wild_file (s, section, f, callback, data);
}
}
else if (wildcardp (file))
{
for (f = (lang_input_statement_type *) file_chain.head;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
if (fnmatch (file, f->filename, FNM_FILE_NAME) == 0)
walk_wild_file (s, section, f, callback, data);
@ -318,6 +319,8 @@ walk_wild (s, section, file, callback, data)
}
else
{
lang_input_statement_type *f;
/* Perform the iteration over a single file. */
f = lookup_name (file);
walk_wild_file (s, section, f, callback, data);
@ -1449,29 +1452,234 @@ wild (s, section, file, target, output)
}
}
/* Return true iff target is the sought target. */
static int
get_target (target, data)
const bfd_target * target;
void * data;
{
const char * sought = (const char *) data;
return strcmp (target->name, sought) == 0;
}
/* Like strcpy() but convert to lower case as well. */
static void
stricpy (dest, src)
char * dest;
char * src;
{
char c;
while ((c = * src ++) != 0)
{
if (isupper ((unsigned char) c))
c = tolower (c);
* dest ++ = c;
}
* dest = 0;
}
/* Remove the first occurance of needle (if any) in haystack
from haystack. */
static void
strcut (haystack, needle)
char * haystack;
char * needle;
{
haystack = strstr (haystack, needle);
if (haystack)
{
char * src;
for (src = haystack + strlen (needle); * src;)
* haystack ++ = * src ++;
* haystack = 0;
}
}
/* Compare two target format name strings.
Return a value indicating how "similar" they are. */
static int
name_compare (first, second)
char * first;
char * second;
{
char * copy1;
char * copy2;
int result;
copy1 = xmalloc (strlen (first) + 1);
copy2 = xmalloc (strlen (second) + 1);
/* Convert the names to lower case. */
stricpy (copy1, first);
stricpy (copy2, second);
/* Remove and endian strings from the name. */
strcut (copy1, "big");
strcut (copy1, "little");
strcut (copy2, "big");
strcut (copy2, "little");
/* Return a value based on how many characters match,
starting from the beginning. If both strings are
the same then return 10 * their length. */
for (result = 0; copy1 [result] == copy2 [result]; result ++)
if (copy1 [result] == 0)
{
result *= 10;
break;
}
free (copy1);
free (copy2);
return result;
}
/* Set by closest_target_match() below. */
static const bfd_target * winner;
/* Scan all the valid bfd targets looking for one that has the endianness
requirement that was specified on the command line, and is the nearest
match to the original output target. */
static int
closest_target_match (target, data)
const bfd_target * target;
void * data;
{
const bfd_target * original = (const bfd_target *) data;
if (command_line.endian == ENDIAN_BIG && target->byteorder != BFD_ENDIAN_BIG)
return 0;
if (command_line.endian == ENDIAN_LITTLE && target->byteorder != BFD_ENDIAN_LITTLE)
return 0;
/* Must be the same flavour. */
if (target->flavour != original->flavour)
return 0;
/* If we have not found a potential winner yet, then record this one. */
if (winner == NULL)
{
winner = target;
return 0;
}
/* Oh dear, we now have two potential candidates for a successful match.
Compare their names and choose the better one. */
if (name_compare (target->name, original->name) > name_compare (winner->name, original->name))
winner = target;
/* Keep on searching until wqe have checked them all. */
return 0;
}
/* Return the BFD target format of the first input file. */
static char *
get_first_input_target ()
{
char * target = NULL;
LANG_FOR_EACH_INPUT_STATEMENT (s)
{
if (s->header.type == lang_input_statement_enum
&& s->real)
{
ldfile_open_file (s);
if (s->the_bfd != NULL
&& bfd_check_format (s->the_bfd, bfd_object))
{
target = bfd_get_target (s->the_bfd);
if (target != NULL)
break;
}
}
}
return target;
}
/* Open the output file. */
static bfd *
open_output (name)
const char *name;
const char * name;
{
bfd *output;
bfd * output;
/* Has the user told us which output format to use ? */
if (output_target == (char *) NULL)
{
if (current_target != (char *) NULL)
/* No - has the current target been set to something other than the default ? */
if (current_target != default_target)
output_target = current_target;
/* No - can we determine the format of the first input file ? */
else
output_target = default_target;
{
output_target = get_first_input_target ();
/* Failed - use the default output target. */
if (output_target == NULL)
output_target = default_target;
}
}
/* Has the user requested a particular endianness on the command line ? */
if (command_line.endian != ENDIAN_UNSET)
{
const bfd_target * target;
int desired_endian;
/* Get the chosen target. */
target = bfd_search_for_target (get_target, (void *) output_target);
if (command_line.endian == ENDIAN_BIG)
desired_endian = BFD_ENDIAN_BIG;
else
desired_endian = BFD_ENDIAN_LITTLE;
/* See if the target has the wrong endianness. This should not happen
if the linker script has provided big and little endian alternatives,
but some scrips don't do this. */
if (target->byteorder != desired_endian)
{
/* If it does, then see if the target provides
an alternative with the correct endianness. */
if (target->alternative_target != NULL
&& (target->alternative_target->byteorder == desired_endian))
output_target = target->alternative_target->name;
else
{
/* Try to find a target as similar as possible to the default
target, but which has the desired endian characteristic. */
(void) bfd_search_for_target (closest_target_match, (void *) target);
/* Oh dear - we could not find any targets that satisfy our requirements. */
if (winner == NULL)
einfo (_("%P: warning: could not find any targets that match endianness requirement\n"));
else
output_target = winner->name;
}
}
}
output = bfd_openw (name, output_target);
if (output == (bfd *) NULL)
{
if (bfd_get_error () == bfd_error_invalid_target)
{
einfo (_("%P%F: target %s not found\n"), output_target);
}
einfo (_("%P%F: target %s not found\n"), output_target);
einfo (_("%P%F: cannot open output file %s: %E\n"), name);
}
@ -1494,9 +1702,6 @@ open_output (name)
return output;
}
static void
ldlang_open_output (statement)
lang_statement_union_type * statement;
@ -1573,7 +1778,7 @@ open_input_bfds (s, force)
current_target = s->target_statement.target;
break;
case lang_input_statement_enum:
if (s->input_statement.real == true)
if (s->input_statement.real)
{
lang_statement_list_type add;
@ -3211,11 +3416,7 @@ into the statement tree.
static void
lang_place_orphans ()
{
lang_input_statement_type *file;
for (file = (lang_input_statement_type *) file_chain.head;
file != (lang_input_statement_type *) NULL;
file = (lang_input_statement_type *) file->next)
LANG_FOR_EACH_INPUT_STATEMENT (file)
{
asection *s;
@ -3340,11 +3541,7 @@ void
lang_for_each_file (func)
void (*func) PARAMS ((lang_input_statement_type *));
{
lang_input_statement_type *f;
for (f = (lang_input_statement_type *) file_chain.head;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
func (f);
}
@ -3358,13 +3555,9 @@ void
lang_for_each_input_section (func)
void (*func) PARAMS ((bfd * ab, asection * as));
{
lang_input_statement_type *f;
for (f = (lang_input_statement_type *) file_chain.head;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
asection *s;
asection * s;
for (s = f->the_bfd->sections;
s != (asection *) NULL;