mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-10-19 22:03:57 +08:00
Improve selection of output format
This commit is contained in:
19
ld/ChangeLog
19
ld/ChangeLog
@ -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>
|
1999-07-16 Jakub Jelinek <jj@ultra.linux.cz>
|
||||||
|
|
||||||
* emulparams/elf64_sparc.sh: Add 64-bit directories to native LIB_PATH.
|
* emulparams/elf64_sparc.sh: Add 64-bit directories to native LIB_PATH.
|
||||||
|
253
ld/ldlang.c
253
ld/ldlang.c
@ -152,6 +152,13 @@ static void walk_wild_file
|
|||||||
PARAMS ((lang_wild_statement_type *, const char *,
|
PARAMS ((lang_wild_statement_type *, const char *,
|
||||||
lang_input_statement_type *, callback_t, void *));
|
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 */
|
/* EXPORTS */
|
||||||
lang_output_section_statement_type *abs_output_section;
|
lang_output_section_statement_type *abs_output_section;
|
||||||
lang_statement_list_type *stat_ptr = &statement_list;
|
lang_statement_list_type *stat_ptr = &statement_list;
|
||||||
@ -294,23 +301,17 @@ walk_wild (s, section, file, callback, data)
|
|||||||
callback_t callback;
|
callback_t callback;
|
||||||
void *data;
|
void *data;
|
||||||
{
|
{
|
||||||
lang_input_statement_type *f;
|
|
||||||
|
|
||||||
if (file == (char *) NULL)
|
if (file == (char *) NULL)
|
||||||
{
|
{
|
||||||
/* Perform the iteration over all files in the list. */
|
/* Perform the iteration over all files in the list. */
|
||||||
for (f = (lang_input_statement_type *) file_chain.head;
|
LANG_FOR_EACH_INPUT_STATEMENT (f)
|
||||||
f != (lang_input_statement_type *) NULL;
|
|
||||||
f = (lang_input_statement_type *) f->next)
|
|
||||||
{
|
{
|
||||||
walk_wild_file (s, section, f, callback, data);
|
walk_wild_file (s, section, f, callback, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (wildcardp (file))
|
else if (wildcardp (file))
|
||||||
{
|
{
|
||||||
for (f = (lang_input_statement_type *) file_chain.head;
|
LANG_FOR_EACH_INPUT_STATEMENT (f)
|
||||||
f != (lang_input_statement_type *) NULL;
|
|
||||||
f = (lang_input_statement_type *) f->next)
|
|
||||||
{
|
{
|
||||||
if (fnmatch (file, f->filename, FNM_FILE_NAME) == 0)
|
if (fnmatch (file, f->filename, FNM_FILE_NAME) == 0)
|
||||||
walk_wild_file (s, section, f, callback, data);
|
walk_wild_file (s, section, f, callback, data);
|
||||||
@ -318,6 +319,8 @@ walk_wild (s, section, file, callback, data)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
lang_input_statement_type *f;
|
||||||
|
|
||||||
/* Perform the iteration over a single file. */
|
/* Perform the iteration over a single file. */
|
||||||
f = lookup_name (file);
|
f = lookup_name (file);
|
||||||
walk_wild_file (s, section, f, callback, data);
|
walk_wild_file (s, section, f, callback, data);
|
||||||
@ -1449,6 +1452,162 @@ 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. */
|
/* Open the output file. */
|
||||||
|
|
||||||
static bfd *
|
static bfd *
|
||||||
@ -1457,21 +1616,70 @@ open_output (name)
|
|||||||
{
|
{
|
||||||
bfd * output;
|
bfd * output;
|
||||||
|
|
||||||
|
/* Has the user told us which output format to use ? */
|
||||||
if (output_target == (char *) NULL)
|
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;
|
output_target = current_target;
|
||||||
|
|
||||||
|
/* No - can we determine the format of the first input file ? */
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
output_target = get_first_input_target ();
|
||||||
|
|
||||||
|
/* Failed - use the default output target. */
|
||||||
|
if (output_target == NULL)
|
||||||
output_target = default_target;
|
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);
|
output = bfd_openw (name, output_target);
|
||||||
|
|
||||||
if (output == (bfd *) NULL)
|
if (output == (bfd *) NULL)
|
||||||
{
|
{
|
||||||
if (bfd_get_error () == bfd_error_invalid_target)
|
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);
|
einfo (_("%P%F: cannot open output file %s: %E\n"), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1494,9 +1702,6 @@ open_output (name)
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ldlang_open_output (statement)
|
ldlang_open_output (statement)
|
||||||
lang_statement_union_type * statement;
|
lang_statement_union_type * statement;
|
||||||
@ -1573,7 +1778,7 @@ open_input_bfds (s, force)
|
|||||||
current_target = s->target_statement.target;
|
current_target = s->target_statement.target;
|
||||||
break;
|
break;
|
||||||
case lang_input_statement_enum:
|
case lang_input_statement_enum:
|
||||||
if (s->input_statement.real == true)
|
if (s->input_statement.real)
|
||||||
{
|
{
|
||||||
lang_statement_list_type add;
|
lang_statement_list_type add;
|
||||||
|
|
||||||
@ -3211,11 +3416,7 @@ into the statement tree.
|
|||||||
static void
|
static void
|
||||||
lang_place_orphans ()
|
lang_place_orphans ()
|
||||||
{
|
{
|
||||||
lang_input_statement_type *file;
|
LANG_FOR_EACH_INPUT_STATEMENT (file)
|
||||||
|
|
||||||
for (file = (lang_input_statement_type *) file_chain.head;
|
|
||||||
file != (lang_input_statement_type *) NULL;
|
|
||||||
file = (lang_input_statement_type *) file->next)
|
|
||||||
{
|
{
|
||||||
asection *s;
|
asection *s;
|
||||||
|
|
||||||
@ -3340,11 +3541,7 @@ void
|
|||||||
lang_for_each_file (func)
|
lang_for_each_file (func)
|
||||||
void (*func) PARAMS ((lang_input_statement_type *));
|
void (*func) PARAMS ((lang_input_statement_type *));
|
||||||
{
|
{
|
||||||
lang_input_statement_type *f;
|
LANG_FOR_EACH_INPUT_STATEMENT (f)
|
||||||
|
|
||||||
for (f = (lang_input_statement_type *) file_chain.head;
|
|
||||||
f != (lang_input_statement_type *) NULL;
|
|
||||||
f = (lang_input_statement_type *) f->next)
|
|
||||||
{
|
{
|
||||||
func (f);
|
func (f);
|
||||||
}
|
}
|
||||||
@ -3358,11 +3555,7 @@ void
|
|||||||
lang_for_each_input_section (func)
|
lang_for_each_input_section (func)
|
||||||
void (*func) PARAMS ((bfd * ab, asection * as));
|
void (*func) PARAMS ((bfd * ab, asection * as));
|
||||||
{
|
{
|
||||||
lang_input_statement_type *f;
|
LANG_FOR_EACH_INPUT_STATEMENT (f)
|
||||||
|
|
||||||
for (f = (lang_input_statement_type *) file_chain.head;
|
|
||||||
f != (lang_input_statement_type *) NULL;
|
|
||||||
f = (lang_input_statement_type *) f->next)
|
|
||||||
{
|
{
|
||||||
asection * s;
|
asection * s;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user