# This shell script emits a C file. -*- C -*-
# It does some substitutions.
# This file is now misnamed, because it supports both 32 bit and 64 bit
# ELF emulations.
test -z "${ELFSIZE}" && ELFSIZE=32
if [ -z "$MACHINE" ]; then
OUTPUT_ARCH=${ARCH}
else
OUTPUT_ARCH=${ARCH}:${MACHINE}
fi
cat >e${EMULATION_NAME}.c <<EOF
#define TARGET_IS_${EMULATION_NAME}
#include "bfd.h"
#include "sysdep.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "getopt.h"
#include "bfdlink.h"
#include "ld.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldlang.h"
#include "ldfile.h"
#include "ldemul.h"
#include <ldgram.h>
#include "elf/common.h"
static void gld${EMULATION_NAME}_before_parse (void);
static void gld${EMULATION_NAME}_after_open (void);
static void gld${EMULATION_NAME}_before_allocation (void);
static bfd_boolean gld${EMULATION_NAME}_place_orphan
(lang_input_statement_type *file, asection *s);
static void gld${EMULATION_NAME}_finish (void);
EOF
# Import any needed special functions and/or overrides.
#
if test -n "$EXTRA_EM_FILE" ; then
. ${srcdir}/emultempl/${EXTRA_EM_FILE}.em
fi
# Functions in this file can be overridden by setting the LDEMUL_* shell
# variables. If the name of the overriding function is the same as is
# defined in this file, then don't output this file's version.
# If a different overriding name is given then output the standard function
# as presumably it is called from the overriding function.
#
if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_before_parse (void)
{
ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.* config.dynamic_link = ${DYNAMIC_LINK-TRUE};
config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
}
EOF
fi
if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then
cat >>e${EMULATION_NAME}.c <<EOF
static bfd_boolean
gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
{
if (!entry->as_needed
|| (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0)
return FALSE;
bfd_elf_set_dyn_lib_class (entry->the_bfd, DYN_AS_NEEDED);
return FALSE;
}
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
static struct bfd_link_needed_list *global_needed;
static struct stat global_stat;
static bfd_boolean global_found;
static struct bfd_link_needed_list *global_vercheck_needed;
static bfd_boolean global_vercheck_failed;
static void
gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s)
{
const char *soname;
struct bfd_link_needed_list *l;
if (global_vercheck_failed)
return;
if (s->the_bfd == NULL
|| (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
return;
soname = bfd_elf_get_dt_soname (s->the_bfd);
if (soname == NULL)
soname = lbasename (bfd_get_filename (s->the_bfd));
for (l = global_vercheck_needed; l != NULL; l = l->next)
{
const char *suffix;
if (strcmp (soname, l->name) == 0)
{
continue;
}
if (strchr (l->name, '/') != NULL)
continue;
suffix = strstr (l->name, ".so.");
if (suffix == NULL)
continue;
suffix += sizeof ".so." - 1;
if (strncmp (soname, l->name, suffix - l->name) == 0)
{
global_vercheck_failed = TRUE;
return;
}
}
}
static void
gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s)
{
struct stat st;
const char *suffix;
const char *soname;
if (global_found)
return;
if (s->the_bfd == NULL)
return;
if (bfd_stat (s->the_bfd, &st) != 0)
{
einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
return;
}
if (st.st_dev == global_stat.st_dev
&& st.st_ino == global_stat.st_ino)
{
global_found = TRUE;
return;
}
if (strchr (global_needed->name, '/') != NULL)
return;
suffix = strstr (global_needed->name, ".so.");
if (suffix == NULL)
return;
suffix += sizeof ".so." - 1;
soname = bfd_elf_get_dt_soname (s->the_bfd);
if (soname == NULL)
soname = lbasename (s->filename);
if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0)
einfo ("%P: warning: %s, needed by %B, may conflict with %s\n",
global_needed->name, global_needed->by, soname);
}
static bfd_boolean
gld${EMULATION_NAME}_try_needed (const char *name, int force)
{
bfd *abfd;
const char *soname;
abfd = bfd_openr (name, bfd_get_target (output_bfd));
if (abfd == NULL)
return FALSE;
if (! bfd_check_format (abfd, bfd_object))
{
bfd_close (abfd);
return FALSE;
}
if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
{
bfd_close (abfd);
return FALSE;
}
if (abfd->xvec != output_bfd->xvec)
{
bfd_close (abfd);
return FALSE;
}
if (! force)
{
struct bfd_link_needed_list *needed;
if (! bfd_elf_get_bfd_needed_list (abfd, &needed))
einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd);
if (needed != NULL)
{
global_vercheck_needed = needed;
global_vercheck_failed = FALSE;
lang_for_each_input_file (gld${EMULATION_NAME}_vercheck);
if (global_vercheck_failed)
{
bfd_close (abfd);
return FALSE;
}
EOF
case ${target} in
*-*-linux-gnu*)
cat >>e${EMULATION_NAME}.c <<EOF
{
struct bfd_link_needed_list *l;
for (l = needed; l != NULL; l = l->next)
if (strncmp (l->name, "libc.so", 7) == 0)
break;
if (l == NULL)
{
bfd_close (abfd);
return FALSE;
}
}
EOF
;;
esac
cat >>e${EMULATION_NAME}.c <<EOF
}
}
if (bfd_stat (abfd, &global_stat) != 0)
einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);
soname = lbasename (abfd->filename);
if (trace_file_tries)
info_msg (_("found %s at %s\n"), soname, name);
global_found = FALSE;
lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed);
if (global_found)
{
return TRUE;
}
bfd_elf_set_dt_needed_name (abfd, soname);
bfd_elf_set_dyn_lib_class (abfd, DYN_DT_NEEDED);
if (! bfd_link_add_symbols (abfd, &link_info))
einfo ("%F%B: could not read symbols: %E\n", abfd);
return TRUE;
}
static bfd_boolean
gld${EMULATION_NAME}_search_needed (const char *path, const char *name, int force)
{
const char *s;
size_t len;
if (name[0] == '/')
return gld${EMULATION_NAME}_try_needed (name, force);
if (path == NULL || *path == '\0')
return FALSE;
len = strlen (name);
while (1)
{
char *filename, *sset;
s = strchr (path, ':');
if (s == NULL)
s = path + strlen (path);
filename = (char *) xmalloc (s - path + len + 2);
if (s == path)
sset = filename;
else
{
memcpy (filename, path, s - path);
filename[s - path] = '/';
sset = filename + (s - path) + 1;
}
strcpy (sset, name);
if (gld${EMULATION_NAME}_try_needed (filename, force))
return TRUE;
free (filename);
if (*s == '\0')
break;
path = s + 1;
}
return FALSE;
}
EOF
if [ "x${USE_LIBPATH}" = xyes ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
static char *
gld${EMULATION_NAME}_add_sysroot (const char *path)
{
int len, colons, i;
char *ret, *p;
len = strlen (path);
colons = 0;
i = 0;
while (path[i])
if (path[i++] == ':')
colons++;
if (path[i])
colons++;
len = len + (colons + 1) * strlen (ld_sysroot);
ret = xmalloc (len + 1);
strcpy (ret, ld_sysroot);
p = ret + strlen (ret);
i = 0;
while (path[i])
if (path[i] == ':')
{
*p++ = path[i++];
strcpy (p, ld_sysroot);
p = p + strlen (p);
}
else
*p++ = path[i++];
*p = 0;
return ret;
}
EOF
case ${target} in
*-*-linux-gnu*)
cat >>e${EMULATION_NAME}.c <<EOF
static bfd_boolean
gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force)
{
static bfd_boolean initialized;
static char *ld_so_conf;
if (! initialized)
{
FILE *f;
char *tmppath;
tmppath = concat (ld_sysroot, "/etc/ld.so.conf", NULL);
f = fopen (tmppath, FOPEN_RT);
free (tmppath);
if (f != NULL)
{
char *b;
size_t len, alloc;
int c;
len = 0;
alloc = 100;
b = (char *) xmalloc (alloc);
while ((c = getc (f)) != EOF)
{
if (len + 1 >= alloc)
{
alloc *= 2;
b = (char *) xrealloc (b, alloc);
}
if (c != ':'
&& c != ' '
&& c != '\t'
&& c != '\n'
&& c != ',')
{
b[len] = c;
++len;
}
else
{
if (len > 0 && b[len - 1] != ':')
{
b[len] = ':';
++len;
}
}
}
if (len > 0 && b[len - 1] == ':')
--len;
if (len > 0)
b[len] = '\0';
else
{
free (b);
b = NULL;
}
fclose (f);
if (b)
{
char *d = gld${EMULATION_NAME}_add_sysroot (b);
free (b);
b = d;
}
ld_so_conf = b;
}
initialized = TRUE;
}
if (ld_so_conf == NULL)
return FALSE;
return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
}
EOF
# Linux
;;
esac
fi
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s)
{
if (global_found)
return;
if (s->filename != NULL)
{
const char *f;
if (strcmp (s->filename, global_needed->name) == 0)
{
global_found = TRUE;
return;
}
if (s->search_dirs_flag)
{
f = strrchr (s->filename, '/');
if (f != NULL
&& strcmp (f + 1, global_needed->name) == 0)
{
global_found = TRUE;
return;
}
}
}
if (s->the_bfd != NULL)
{
const char *soname;
soname = bfd_elf_get_dt_soname (s->the_bfd);
if (soname != NULL
&& strcmp (soname, global_needed->name) == 0)
{
global_found = TRUE;
return;
}
}
}
EOF
if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_after_open (void)
{
struct bfd_link_needed_list *needed, *l;
if (link_info.relocatable || !link_info.executable)
return;
needed = bfd_elf_get_needed_list (output_bfd, &link_info);
for (l = needed; l != NULL; l = l->next)
{
struct bfd_link_needed_list *ll;
int force;
for (ll = needed; ll != l; ll = ll->next)
if (strcmp (ll->name, l->name) == 0)
break;
if (ll != l)
continue;
global_needed = l;
global_found = FALSE;
lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
if (global_found)
continue;
if (trace_file_tries)
info_msg (_("%s needed by %B\n"), l->name, l->by);
for (force = 0; force < 2; force++)
{
size_t len;
search_dirs_type *search;
EOF
if [ "x${USE_LIBPATH}" = xyes ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
const char *lib_path;
struct bfd_link_needed_list *rp;
int found;
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
l->name, force))
break;
EOF
if [ "x${USE_LIBPATH}" = xyes ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
l->name, force))
break;
EOF
fi
if [ "x${NATIVE}" = xyes ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
if (command_line.rpath_link == NULL
&& command_line.rpath == NULL)
{
lib_path = (const char *) getenv ("LD_RUN_PATH");
if (gld${EMULATION_NAME}_search_needed (lib_path, l->name,
force))
break;
}
lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
break;
EOF
fi
if [ "x${USE_LIBPATH}" = xyes ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
found = 0;
rp = bfd_elf_get_runpath_list (output_bfd, &link_info);
for (; !found && rp != NULL; rp = rp->next)
{
char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name);
found = (rp->by == l->by
&& gld${EMULATION_NAME}_search_needed (tmpname,
l->name,
force));
free (tmpname);
}
if (found)
break;
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
len = strlen (l->name);
for (search = search_head; search != NULL; search = search->next)
{
char *filename;
if (search->cmdline)
continue;
filename = (char *) xmalloc (strlen (search->name) + len + 2);
sprintf (filename, "%s/%s", search->name, l->name);
if (gld${EMULATION_NAME}_try_needed (filename, force))
break;
free (filename);
}
if (search != NULL)
break;
EOF
if [ "x${USE_LIBPATH}" = xyes ] ; then
case ${target} in
*-*-linux-gnu*)
cat >>e${EMULATION_NAME}.c <<EOF
if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
break;
EOF
# Linux
;;
esac
fi
cat >>e${EMULATION_NAME}.c <<EOF
}
if (force < 2)
continue;
einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n",
l->name, l->by);
}
}
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp)
{
struct bfd_link_hash_entry *h;
switch (exp->type.node_class)
{
case etree_provide:
h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst,
FALSE, FALSE, FALSE);
if (h == NULL)
break;
case etree_assign:
if (strcmp (exp->assign.dst, ".") != 0)
{
if (! (bfd_elf_record_link_assignment
(output_bfd, &link_info, exp->assign.dst,
exp->type.node_class == etree_provide ? TRUE : FALSE)))
einfo ("%P%F: failed to record assignment to %s: %E\n",
exp->assign.dst);
}
gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src);
break;
case etree_binary:
gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs);
gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs);
break;
case etree_trinary:
gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond);
gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs);
gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs);
break;
case etree_unary:
gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child);
break;
default:
break;
}
}
static void
gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s)
{
if (s->header.type == lang_assignment_statement_enum)
gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
}
EOF
if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then
if test x"${ELF_INTERPRETER_NAME+set}" = xset; then
ELF_INTERPRETER_SET_DEFAULT="
if (sinterp != NULL)
{
sinterp->contents = ${ELF_INTERPRETER_NAME};
sinterp->size = strlen (sinterp->contents) + 1;
}
"
else
ELF_INTERPRETER_SET_DEFAULT=
fi
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_before_allocation (void)
{
const char *rpath;
asection *sinterp;
if (link_info.hash->type == bfd_link_elf_hash_table)
_bfd_elf_tls_setup (output_bfd, &link_info);
lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
rpath = command_line.rpath;
if (rpath == NULL)
rpath = (const char *) getenv ("LD_RUN_PATH");
if (! (bfd_elf_size_dynamic_sections
(output_bfd, command_line.soname, rpath,
command_line.filter_shlib,
(const char * const *) command_line.auxiliary_filters,
&link_info, &sinterp, lang_elf_version_info)))
einfo ("%P%F: failed to set dynamic section sizes: %E\n");
${ELF_INTERPRETER_SET_DEFAULT}
if (command_line.interpreter != NULL
&& sinterp != NULL)
{
sinterp->contents = (bfd_byte *) command_line.interpreter;
sinterp->size = strlen (command_line.interpreter) + 1;
}
{
LANG_FOR_EACH_INPUT_STATEMENT (is)
{
asection *s;
bfd_size_type sz;
bfd_size_type prefix_len;
char *msg;
bfd_boolean ret;
const char * gnu_warning_prefix = _("warning: ");
if (is->just_syms_flag)
continue;
s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
if (s == NULL)
continue;
sz = s->size;
prefix_len = strlen (gnu_warning_prefix);
msg = xmalloc ((size_t) (prefix_len + sz + 1));
strcpy (msg, gnu_warning_prefix);
if (! bfd_get_section_contents (is->the_bfd, s, msg + prefix_len,
(file_ptr) 0, sz))
einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n",
is->the_bfd);
msg[prefix_len + sz] = '\0';
ret = link_info.callbacks->warning (&link_info, msg,
(const char *) NULL,
is->the_bfd, (asection *) NULL,
(bfd_vma) 0);
ASSERT (ret);
free (msg);
s->size = 0;
}
}
}
EOF
fi
if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then
cat >>e${EMULATION_NAME}.c <<EOF
static bfd_boolean
gld${EMULATION_NAME}_open_dynamic_archive
(const char *arch, search_dirs_type *search, lang_input_statement_type *entry)
{
const char *filename;
char *string;
if (! entry->is_archive)
return FALSE;
filename = entry->filename;
string = (char *) xmalloc (strlen (search->name)
+ strlen (filename)
+ strlen (arch)
#ifdef EXTRA_SHLIB_EXTENSION
+ strlen (EXTRA_SHLIB_EXTENSION)
#endif
+ sizeof "/lib.so");
sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
#ifdef EXTRA_SHLIB_EXTENSION
if (! ldfile_try_open_bfd (string, entry))
sprintf (string, "%s/lib%s%s%s", search->name,
filename, arch, EXTRA_SHLIB_EXTENSION);
#endif
if (! ldfile_try_open_bfd (string, entry))
{
free (string);
return FALSE;
}
entry->filename = string;
if (bfd_check_format (entry->the_bfd, bfd_object)
&& (entry->the_bfd->flags & DYNAMIC) != 0)
{
ASSERT (entry->is_archive && entry->search_dirs_flag);
filename = lbasename (entry->filename);
bfd_elf_set_dt_needed_name (entry->the_bfd, filename);
}
return TRUE;
}
EOF
fi
if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
cat >>e${EMULATION_NAME}.c <<EOF
static lang_output_section_statement_type *
output_rel_find (asection *sec, int isdyn)
{
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
lang_output_section_statement_type *last = NULL;
lang_output_section_statement_type *last_alloc = NULL;
lang_output_section_statement_type *last_rel = NULL;
lang_output_section_statement_type *last_rel_alloc = NULL;
int rela = sec->name[4] == 'a';
for (u = lang_output_section_statement.head; u; u = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup->constraint != -1
&& strncmp (".rel", lookup->name, 4) == 0)
{
int lookrela = lookup->name[4] == 'a';
if (isdyn)
break;
if (strcmp (".plt", lookup->name + 4 + lookrela) == 0)
break;
if (rela == lookrela || last_rel == NULL)
last_rel = lookup;
if ((rela == lookrela || last_rel_alloc == NULL)
&& lookup->bfd_section != NULL
&& (lookup->bfd_section->flags & SEC_ALLOC) != 0)
last_rel_alloc = lookup;
}
last = lookup;
if (lookup->bfd_section != NULL
&& (lookup->bfd_section->flags & SEC_ALLOC) != 0)
last_alloc = lookup;
}
if (last_rel_alloc)
return last_rel_alloc;
if (last_rel)
return last_rel;
if (last_alloc)
return last_alloc;
return last;
}
static asection *
output_prev_sec_find (lang_output_section_statement_type *os)
{
asection *s = (asection *) NULL;
lang_statement_union_type *u;
lang_output_section_statement_type *lookup;
for (u = lang_output_section_statement.head;
u != (lang_statement_union_type *) NULL;
u = lookup->next)
{
lookup = &u->output_section_statement;
if (lookup == os)
return s;
if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
s = lookup->bfd_section;
}
return NULL;
}
struct orphan_save {
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
lang_statement_union_type **os_tail;
};
static bfd_boolean
gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
{
static struct orphan_save hold_text;
static struct orphan_save hold_rodata;
static struct orphan_save hold_data;
static struct orphan_save hold_bss;
static struct orphan_save hold_rel;
static struct orphan_save hold_interp;
static struct orphan_save hold_sdata;
static int count = 1;
struct orphan_save *place;
lang_statement_list_type *old;
lang_statement_list_type add;
etree_type *address;
const char *secname;
const char *ps = NULL;
lang_output_section_statement_type *os;
lang_statement_union_type **os_tail;
etree_type *load_base;
int isdyn = 0;
secname = bfd_get_section_name (s->owner, s);
if (! link_info.relocatable
&& link_info.combreloc
&& (s->flags & SEC_ALLOC)
&& strncmp (secname, ".rel", 4) == 0)
{
if (secname[4] == 'a')
secname = ".rela.dyn";
else
secname = ".rel.dyn";
isdyn = 1;
}
if (isdyn || (!config.unique_orphan_sections && !unique_section_p (s)))
{
os = lang_output_section_find (secname);
if (os != NULL
&& (os->bfd_section == NULL
|| ((s->flags ^ os->bfd_section->flags)
& (SEC_LOAD | SEC_ALLOC)) == 0))
{
lang_add_section (&os->children, s, os, file);
return TRUE;
}
}
if (hold_text.os == NULL)
hold_text.os = lang_output_section_find (".text");
if (link_info.executable
&& ! link_info.relocatable
&& strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
&& hold_text.os != NULL)
{
lang_add_section (&hold_text.os->children, s, hold_text.os, file);
return TRUE;
}
#define HAVE_SECTION(hold, name) \
(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
place = NULL;
if ((s->flags & SEC_ALLOC) == 0)
;
else if ((s->flags & SEC_LOAD) != 0
&& strncmp (secname, ".note", 5) == 0
&& HAVE_SECTION (hold_interp, ".interp"))
place = &hold_interp;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
&& HAVE_SECTION (hold_bss, ".bss"))
place = &hold_bss;
else if ((s->flags & SEC_SMALL_DATA) != 0
&& HAVE_SECTION (hold_sdata, ".sdata"))
place = &hold_sdata;
else if ((s->flags & SEC_READONLY) == 0
&& HAVE_SECTION (hold_data, ".data"))
place = &hold_data;
else if (strncmp (secname, ".rel", 4) == 0
&& (s->flags & SEC_LOAD) != 0
&& (hold_rel.os != NULL
|| (hold_rel.os = output_rel_find (s, isdyn)) != NULL))
place = &hold_rel;
else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
&& HAVE_SECTION (hold_rodata, ".rodata"))
place = &hold_rodata;
else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
&& hold_text.os != NULL)
place = &hold_text;
#undef HAVE_SECTION
if (bfd_get_section_by_name (output_bfd, secname) != NULL)
{
secname = bfd_get_unique_section_name (output_bfd, secname, &count);
if (secname == NULL)
einfo ("%F%P: place_orphan failed: %E\n");
}
old = stat_ptr;
if (place != NULL)
{
stat_ptr = &add;
lang_list_init (stat_ptr);
}
if (config.build_constructors)
{
for (ps = secname; *ps != '\0'; ps++)
if (! ISALNUM (*ps) && *ps != '_')
break;
if (*ps == '\0')
{
char *symname;
etree_type *e_align;
symname = (char *) xmalloc (ps - secname + sizeof "__start_");
sprintf (symname, "__start_%s", secname);
e_align = exp_unop (ALIGN_K,
exp_intop ((bfd_vma) 1 << s->alignment_power));
lang_add_assignment (exp_assop ('=', symname, e_align));
}
}
address = NULL;
if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop ((bfd_vma) 0);
load_base = NULL;
if (place != NULL && place->os->load_base != NULL)
{
etree_type *lma_from_vma;
lma_from_vma = exp_binop ('-', place->os->load_base,
exp_nameop (ADDR, place->os->name));
load_base = exp_binop ('+', lma_from_vma,
exp_nameop (ADDR, secname));
}
os_tail = lang_output_section_statement.tail;
os = lang_enter_output_section_statement (secname, address, 0,
(etree_type *) NULL,
(etree_type *) NULL,
load_base, 0);
lang_add_section (&os->children, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, NULL);
if (config.build_constructors && *ps == '\0')
{
char *symname;
if (place != NULL)
stat_ptr = &add;
symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
sprintf (symname, "__stop_%s", secname);
lang_add_assignment (exp_assop ('=', symname,
exp_nameop (NAME, ".")));
}
stat_ptr = old;
if (place != NULL && os->bfd_section != NULL)
{
asection *snew, **pps;
snew = os->bfd_section;
if (place->section == NULL)
{
asection *bfd_section = place->os->bfd_section;
if (bfd_section == NULL)
bfd_section = output_prev_sec_find (place->os);
if (bfd_section != NULL && bfd_section != snew)
place->section = &bfd_section->next;
}
if (place->section != NULL)
{
for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
;
bfd_section_list_remove (output_bfd, pps);
bfd_section_list_insert (output_bfd, place->section, snew);
}
place->section = &snew->next;
if (add.head != NULL)
{
lang_statement_union_type *newly_added_os;
if (place->stmt == NULL)
{
*add.tail = place->os->header.next;
place->os->header.next = add.head;
place->os_tail = &place->os->next;
}
else
{
*add.tail = *place->stmt;
*place->stmt = add.head;
}
if (*old->tail == add.head)
old->tail = add.tail;
place->stmt = add.tail;
newly_added_os = *os_tail;
*os_tail = NULL;
newly_added_os->output_section_statement.next = *place->os_tail;
*place->os_tail = newly_added_os;
place->os_tail = &newly_added_os->output_section_statement.next;
if (*os_tail == NULL)
lang_output_section_statement.tail = os_tail;
}
}
return TRUE;
}
EOF
fi
if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_finish (void)
{
if (bfd_elf_discard_info (output_bfd, &link_info))
{
lang_reset_memory_regions ();
lang_size_sections (stat_ptr->head, abs_output_section,
&stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE);
ldemul_after_allocation ();
lang_do_assignments (stat_ptr->head, abs_output_section,
(fill_type *) 0, (bfd_vma) 0);
}
}
EOF
fi
if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
cat >>e${EMULATION_NAME}.c <<EOF
static char *
gld${EMULATION_NAME}_get_script (int *isfile)
EOF
if test -n "$COMPILE_IN"
then
# Scripts compiled in.
# sed commands to quote an ld script as a C string.
sc="-f stringify.sed"
cat >>e${EMULATION_NAME}.c <<EOF
{
*isfile = 0;
if (link_info.relocatable && config.build_constructors)
return
EOF
sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else
echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
fi
if test -n "$GENERATE_PIE_SCRIPT" ; then
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c
fi
echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c
fi
if test -n "$GENERATE_SHLIB_SCRIPT" ; then
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
fi
echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
fi
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
fi
echo ' ; else return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
echo '; }' >> e${EMULATION_NAME}.c
else
# Scripts read from the filesystem.
cat >>e${EMULATION_NAME}.c <<EOF
{
*isfile = 1;
if (link_info.relocatable && config.build_constructors)
return "ldscripts/${EMULATION_NAME}.xu";
else if (link_info.relocatable)
return "ldscripts/${EMULATION_NAME}.xr";
else if (!config.text_read_only)
return "ldscripts/${EMULATION_NAME}.xbn";
EOF
if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then :
else
cat >>e${EMULATION_NAME}.c <<EOF
else if (!config.magic_demand_paged)
return "ldscripts/${EMULATION_NAME}.xn";
EOF
fi
if test -n "$GENERATE_PIE_SCRIPT" ; then
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
cat >>e${EMULATION_NAME}.c <<EOF
else if (link_info.pie && link_info.combreloc
&& link_info.relro && (link_info.flags & DT_BIND_NOW))
return "ldscripts/${EMULATION_NAME}.xdw";
else if (link_info.pie && link_info.combreloc)
return "ldscripts/${EMULATION_NAME}.xdc";
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
else if (link_info.pie)
return "ldscripts/${EMULATION_NAME}.xd";
EOF
fi
if test -n "$GENERATE_SHLIB_SCRIPT" ; then
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
cat >>e${EMULATION_NAME}.c <<EOF
else if (link_info.shared && link_info.combreloc
&& link_info.relro && (link_info.flags & DT_BIND_NOW))
return "ldscripts/${EMULATION_NAME}.xsw";
else if (link_info.shared && link_info.combreloc)
return "ldscripts/${EMULATION_NAME}.xsc";
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
else if (link_info.shared)
return "ldscripts/${EMULATION_NAME}.xs";
EOF
fi
if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
cat >>e${EMULATION_NAME}.c <<EOF
else if (link_info.combreloc && link_info.relro
&& (link_info.flags & DT_BIND_NOW))
return "ldscripts/${EMULATION_NAME}.xw";
else if (link_info.combreloc)
return "ldscripts/${EMULATION_NAME}.xc";
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
else
return "ldscripts/${EMULATION_NAME}.x";
}
EOF
fi
fi
if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then
if test -n "$PARSE_AND_LIST_PROLOGUE" ; then
cat >>e${EMULATION_NAME}.c <<EOF
$PARSE_AND_LIST_PROLOGUE
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
#define OPTION_DISABLE_NEW_DTAGS (400)
#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1)
#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1)
static void
gld${EMULATION_NAME}_add_options
(int ns, char **shortopts, int nl, struct option **longopts,
int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
{
static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:";
static const struct option xtra_long[] = {
EOF
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
cat >>e${EMULATION_NAME}.c <<EOF
{"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
{"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
{"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
{"Bgroup", no_argument, NULL, OPTION_GROUP},
EOF
fi
if test -n "$PARSE_AND_LIST_LONGOPTS" ; then
cat >>e${EMULATION_NAME}.c <<EOF
$PARSE_AND_LIST_LONGOPTS
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
{NULL, no_argument, NULL, 0}
};
*shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short));
memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short));
*longopts = (struct option *)
xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
}
static bfd_boolean
gld${EMULATION_NAME}_handle_option (int optc)
{
switch (optc)
{
default:
return FALSE;
EOF
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
cat >>e${EMULATION_NAME}.c <<EOF
case OPTION_DISABLE_NEW_DTAGS:
link_info.new_dtags = FALSE;
break;
case OPTION_ENABLE_NEW_DTAGS:
link_info.new_dtags = TRUE;
break;
case OPTION_EH_FRAME_HDR:
link_info.eh_frame_hdr = TRUE;
break;
case OPTION_GROUP:
link_info.flags_1 |= (bfd_vma) DF_1_GROUP;
link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR;
break;
case 'z':
if (strcmp (optarg, "initfirst") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
else if (strcmp (optarg, "interpose") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE;
else if (strcmp (optarg, "loadfltr") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR;
else if (strcmp (optarg, "nodefaultlib") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB;
else if (strcmp (optarg, "nodelete") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_NODELETE;
else if (strcmp (optarg, "nodlopen") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN;
else if (strcmp (optarg, "nodump") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_NODUMP;
else if (strcmp (optarg, "now") == 0)
{
link_info.flags |= (bfd_vma) DF_BIND_NOW;
link_info.flags_1 |= (bfd_vma) DF_1_NOW;
}
else if (strcmp (optarg, "origin") == 0)
{
link_info.flags |= (bfd_vma) DF_ORIGIN;
link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
}
else if (strcmp (optarg, "defs") == 0)
link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
else if (strcmp (optarg, "muldefs") == 0)
link_info.allow_multiple_definition = TRUE;
else if (strcmp (optarg, "combreloc") == 0)
link_info.combreloc = TRUE;
else if (strcmp (optarg, "nocombreloc") == 0)
link_info.combreloc = FALSE;
else if (strcmp (optarg, "nocopyreloc") == 0)
link_info.nocopyreloc = TRUE;
else if (strcmp (optarg, "execstack") == 0)
{
link_info.execstack = TRUE;
link_info.noexecstack = FALSE;
}
else if (strcmp (optarg, "noexecstack") == 0)
{
link_info.noexecstack = TRUE;
link_info.execstack = FALSE;
}
else if (strcmp (optarg, "relro") == 0)
link_info.relro = TRUE;
else if (strcmp (optarg, "norelro") == 0)
link_info.relro = FALSE;
break;
EOF
fi
if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then
cat >>e${EMULATION_NAME}.c <<EOF
$PARSE_AND_LIST_ARGS_CASES
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
}
return TRUE;
}
EOF
if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_list_options (FILE * file)
{
EOF
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
cat >>e${EMULATION_NAME}.c <<EOF
fprintf (file, _(" -Bgroup\t\tSelects group name lookup rules for DSO\n"));
fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n"));
fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n"));
fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
fprintf (file, _(" -z defs\t\tReport unresolved symbols in object files.\n"));
fprintf (file, _(" -z execstack\t\tMark executable as requiring executable stack\n"));
fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at runtime\n"));
fprintf (file, _(" -z interpose\t\tMark object to interpose all DSOs but executable\n"));
fprintf (file, _(" -z loadfltr\t\tMark object requiring immediate process\n"));
fprintf (file, _(" -z muldefs\t\tAllow multiple definitions\n"));
fprintf (file, _(" -z nocombreloc\tDon't merge dynamic relocs into one section\n"));
fprintf (file, _(" -z nocopyreloc\tDon't create copy relocs\n"));
fprintf (file, _(" -z nodefaultlib\tMark object not to use default search paths\n"));
fprintf (file, _(" -z nodelete\t\tMark DSO non-deletable at runtime\n"));
fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n"));
fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n"));
fprintf (file, _(" -z noexecstack\tMark executable as not requiring executable stack\n"));
fprintf (file, _(" -z norelro\t\tDon't create RELRO program header\n"));
fprintf (file, _(" -z now\t\tMark object non-lazy runtime binding\n"));
fprintf (file, _(" -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t at runtime\n"));
fprintf (file, _(" -z relro\t\tCreate RELRO program header\n"));
fprintf (file, _(" -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
EOF
fi
if test -n "$PARSE_AND_LIST_OPTIONS" ; then
cat >>e${EMULATION_NAME}.c <<EOF
$PARSE_AND_LIST_OPTIONS
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
}
EOF
if test -n "$PARSE_AND_LIST_EPILOGUE" ; then
cat >>e${EMULATION_NAME}.c <<EOF
$PARSE_AND_LIST_EPILOGUE
EOF
fi
fi
else
cat >>e${EMULATION_NAME}.c <<EOF
#define gld${EMULATION_NAME}_add_options NULL
#define gld${EMULATION_NAME}_handle_option NULL
EOF
if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
cat >>e${EMULATION_NAME}.c <<EOF
#define gld${EMULATION_NAME}_list_options NULL
EOF
fi
fi
cat >>e${EMULATION_NAME}.c <<EOF
struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
{
${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
${LDEMUL_SYSLIB-syslib_default},
${LDEMUL_HLL-hll_default},
${LDEMUL_AFTER_PARSE-after_parse_default},
${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open},
${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation},
${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
"${EMULATION_NAME}",
"${OUTPUT_FORMAT}",
${LDEMUL_FINISH-gld${EMULATION_NAME}_finish},
${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive},
${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
${LDEMUL_SET_SYMBOLS-NULL},
${LDEMUL_PARSE_ARGS-NULL},
gld${EMULATION_NAME}_add_options,
gld${EMULATION_NAME}_handle_option,
${LDEMUL_UNRECOGNIZED_FILE-NULL},
${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
${LDEMUL_NEW_VERS_PATTERN-NULL}
};
EOF