#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "safe-ctype.h"
#include "ld.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldlang.h"
#include "ldfile.h"
#include "ldmain.h"
#include <ldgram.h>
#include "ldlex.h"
#include "ldemul.h"
#include "libiberty.h"
#include "filenames.h"
const char * ldfile_input_filename;
bfd_boolean ldfile_assumed_script = FALSE;
const char * ldfile_output_machine_name = "";
unsigned long ldfile_output_machine;
enum bfd_architecture ldfile_output_architecture;
search_dirs_type * search_head;
#ifdef VMS
char * slash = "";
#else
#if defined (_WIN32) && ! defined (__CYGWIN32__)
char * slash = "\\";
#else
char * slash = "/";
#endif
#endif
typedef struct search_arch
{
char *name;
struct search_arch *next;
} search_arch_type;
static search_dirs_type **search_tail_ptr = &search_head;
static search_arch_type *search_arch_head;
static search_arch_type **search_arch_tail_ptr = &search_arch_head;
static bfd_boolean
is_sysrooted_pathname (const char *name, bfd_boolean notsame)
{
char * realname = ld_canon_sysroot ? lrealpath (name) : NULL;
int len;
bfd_boolean result;
if (! realname)
return FALSE;
len = strlen (realname);
if (((! notsame && len == ld_canon_sysroot_len)
|| (len >= ld_canon_sysroot_len
&& IS_DIR_SEPARATOR (realname[ld_canon_sysroot_len])
&& (realname[ld_canon_sysroot_len] = '\0') == '\0'))
&& FILENAME_CMP (ld_canon_sysroot, realname) == 0)
result = TRUE;
else
result = FALSE;
if (realname)
free (realname);
return result;
}
void
ldfile_add_library_path (const char *name, bfd_boolean cmdline)
{
search_dirs_type *new;
if (!cmdline && config.only_cmd_line_lib_dirs)
return;
new = xmalloc (sizeof (search_dirs_type));
new->next = NULL;
new->cmdline = cmdline;
*search_tail_ptr = new;
search_tail_ptr = &new->next;
if (name[0] == '=')
{
new->name = concat (ld_sysroot, name + 1, NULL);
new->sysrooted = TRUE;
}
else
{
new->name = xstrdup (name);
new->sysrooted = is_sysrooted_pathname (name, FALSE);
}
}
bfd_boolean
ldfile_try_open_bfd (const char *attempt,
lang_input_statement_type *entry)
{
entry->the_bfd = bfd_openr (attempt, entry->target);
if (trace_file_tries)
{
if (entry->the_bfd == NULL)
info_msg (_("attempt to open %s failed\n"), attempt);
else
info_msg (_("attempt to open %s succeeded\n"), attempt);
}
if (entry->the_bfd == NULL)
{
if (bfd_get_error () == bfd_error_invalid_target)
einfo (_("%F%P: invalid BFD target `%s'\n"), entry->target);
return FALSE;
}
if (entry->search_dirs_flag || !entry->dynamic)
{
bfd *check;
if (bfd_check_format (entry->the_bfd, bfd_archive))
check = bfd_openr_next_archived_file (entry->the_bfd, NULL);
else
check = entry->the_bfd;
if (check != NULL)
{
if (! bfd_check_format (check, bfd_object))
{
if (check == entry->the_bfd
&& entry->search_dirs_flag
&& bfd_get_error () == bfd_error_file_not_recognized
&& ! ldemul_unrecognized_file (entry))
{
int token, skip = 0;
char *arg, *arg1, *arg2, *arg3;
extern FILE *yyin;
ldfile_open_command_file (attempt);
ldfile_assumed_script = TRUE;
parser_input = input_selected;
ldlex_both ();
token = INPUT_SCRIPT;
while (token != 0)
{
switch (token)
{
case OUTPUT_FORMAT:
if ((token = yylex ()) != '(')
continue;
if ((token = yylex ()) != NAME)
continue;
arg1 = yylval.name;
arg2 = NULL;
arg3 = NULL;
token = yylex ();
if (token == ',')
{
if ((token = yylex ()) != NAME)
{
free (arg1);
continue;
}
arg2 = yylval.name;
if ((token = yylex ()) != ','
|| (token = yylex ()) != NAME)
{
free (arg1);
free (arg2);
continue;
}
arg3 = yylval.name;
token = yylex ();
}
if (token == ')')
{
switch (command_line.endian)
{
default:
case ENDIAN_UNSET:
arg = arg1; break;
case ENDIAN_BIG:
arg = arg2 ? arg2 : arg1; break;
case ENDIAN_LITTLE:
arg = arg3 ? arg3 : arg1; break;
}
if (strcmp (arg, lang_get_output_target ()) != 0)
skip = 1;
}
free (arg1);
if (arg2) free (arg2);
if (arg3) free (arg3);
break;
case NAME:
case LNAME:
case VERS_IDENTIFIER:
case VERS_TAG:
free (yylval.name);
break;
case INT:
if (yylval.bigint.str)
free (yylval.bigint.str);
break;
}
token = yylex ();
}
ldlex_popstate ();
ldfile_assumed_script = FALSE;
fclose (yyin);
yyin = NULL;
if (skip)
{
einfo (_("%P: skipping incompatible %s when searching for %s\n"),
attempt, entry->local_sym_name);
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
return FALSE;
}
}
return TRUE;
}
if (!entry->dynamic && (entry->the_bfd->flags & DYNAMIC) != 0)
{
einfo (_("%F%P: attempted static link of dynamic object `%s'\n"),
attempt);
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
return FALSE;
}
if (entry->search_dirs_flag
&& !bfd_arch_get_compatible (check, output_bfd,
command_line.accept_unknown_input_arch)
&& ! (bfd_get_flavour (check) == bfd_target_xcoff_flavour
&& bfd_get_flavour (output_bfd) == bfd_target_xcoff_flavour
&& bfd_check_format (entry->the_bfd, bfd_archive)))
{
einfo (_("%P: skipping incompatible %s when searching for %s\n"),
attempt, entry->local_sym_name);
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
return FALSE;
}
}
}
return TRUE;
}
bfd_boolean
ldfile_open_file_search (const char *arch,
lang_input_statement_type *entry,
const char *lib,
const char *suffix)
{
search_dirs_type *search;
if (! entry->is_archive)
{
if (entry->sysrooted && IS_ABSOLUTE_PATH (entry->filename))
{
char *name = concat (ld_sysroot, entry->filename,
(const char *) NULL);
if (ldfile_try_open_bfd (name, entry))
{
entry->filename = name;
return TRUE;
}
free (name);
}
else if (ldfile_try_open_bfd (entry->filename, entry))
{
entry->sysrooted = IS_ABSOLUTE_PATH (entry->filename)
&& is_sysrooted_pathname (entry->filename, TRUE);
return TRUE;
}
if (IS_ABSOLUTE_PATH (entry->filename))
return FALSE;
}
for (search = search_head; search != NULL; search = search->next)
{
char *string;
if (entry->dynamic && ! link_info.relocatable)
{
if (ldemul_open_dynamic_archive (arch, search, entry))
{
entry->sysrooted = search->sysrooted;
return TRUE;
}
}
string = xmalloc (strlen (search->name)
+ strlen (slash)
+ strlen (lib)
+ strlen (entry->filename)
+ strlen (arch)
+ strlen (suffix)
+ 1);
if (entry->is_archive)
sprintf (string, "%s%s%s%s%s%s", search->name, slash,
lib, entry->filename, arch, suffix);
else
sprintf (string, "%s%s%s", search->name, slash, entry->filename);
if (ldfile_try_open_bfd (string, entry))
{
entry->filename = string;
entry->sysrooted = search->sysrooted;
return TRUE;
}
free (string);
}
return FALSE;
}
void
ldfile_open_file (lang_input_statement_type *entry)
{
if (entry->the_bfd != NULL)
return;
if (! entry->search_dirs_flag)
{
if (ldfile_try_open_bfd (entry->filename, entry))
return;
if (strcmp (entry->filename, entry->local_sym_name) != 0)
einfo (_("%F%P: %s (%s): No such file: %E\n"),
entry->filename, entry->local_sym_name);
else
einfo (_("%F%P: %s: No such file: %E\n"), entry->local_sym_name);
}
else
{
search_arch_type *arch;
bfd_boolean found = FALSE;
for (arch = search_arch_head; arch != NULL; arch = arch->next)
{
found = ldfile_open_file_search (arch->name, entry, "lib", ".a");
if (found)
break;
#ifdef VMS
found = ldfile_open_file_search (arch->name, entry, ":lib", ".a");
if (found)
break;
#endif
found = ldemul_find_potential_libraries (arch->name, entry);
if (found)
break;
}
if (found)
entry->search_dirs_flag = FALSE;
else if (entry->sysrooted
&& ld_sysroot
&& IS_ABSOLUTE_PATH (entry->local_sym_name))
einfo (_("%F%P: cannot find %s inside %s\n"),
entry->local_sym_name, ld_sysroot);
else
einfo (_("%F%P: cannot find %s\n"), entry->local_sym_name);
}
}
static FILE *
try_open (const char *name, const char *exten)
{
FILE *result;
char buff[1000];
result = fopen (name, "r");
if (trace_file_tries)
{
if (result == NULL)
info_msg (_("cannot find script file %s\n"), name);
else
info_msg (_("opened script file %s\n"), name);
}
if (result != NULL)
return result;
if (*exten)
{
sprintf (buff, "%s%s", name, exten);
result = fopen (buff, "r");
if (trace_file_tries)
{
if (result == NULL)
info_msg (_("cannot find script file %s\n"), buff);
else
info_msg (_("opened script file %s\n"), buff);
}
}
return result;
}
FILE *
ldfile_find_command_file (const char *name, const char *extend)
{
search_dirs_type *search;
FILE *result;
char buffer[1000];
result = try_open (name, "");
if (result == NULL)
{
for (search = search_head; search != NULL; search = search->next)
{
sprintf (buffer, "%s%s%s", search->name, slash, name);
result = try_open (buffer, extend);
if (result)
break;
}
}
return result;
}
void
ldfile_open_command_file (const char *name)
{
FILE *ldlex_input_stack;
ldlex_input_stack = ldfile_find_command_file (name, "");
if (ldlex_input_stack == NULL)
{
bfd_set_error (bfd_error_system_call);
einfo (_("%P%F: cannot open linker script file %s: %E\n"), name);
}
lex_push_file (ldlex_input_stack, name);
ldfile_input_filename = name;
lineno = 1;
saved_script_handle = ldlex_input_stack;
}
void
ldfile_add_arch (const char *in_name)
{
char *name = xstrdup (in_name);
search_arch_type *new = xmalloc (sizeof (search_arch_type));
ldfile_output_machine_name = in_name;
new->name = name;
new->next = NULL;
while (*name)
{
*name = TOLOWER (*name);
name++;
}
*search_arch_tail_ptr = new;
search_arch_tail_ptr = &new->next;
}
void
ldfile_set_output_arch (const char *string, enum bfd_architecture defarch)
{
const bfd_arch_info_type *arch = bfd_scan_arch (string);
if (arch)
{
ldfile_output_architecture = arch->arch;
ldfile_output_machine = arch->mach;
ldfile_output_machine_name = arch->printable_name;
}
else if (defarch != bfd_arch_unknown)
ldfile_output_architecture = defarch;
else
einfo (_("%P%F: cannot represent machine `%s'\n"), string);
}