#include "bfd.h"
#include "sysdep.h"
+
+#include <ctype.h>
+
#include "bfdlink.h"
#include "ld.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldlang.h"
+#include "ldgram.h"
static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
+static boolean gld${EMULATION_NAME}_open_dynamic_archive
+ PARAMS ((const char *, lang_input_statement_type *));
static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
static void gld${EMULATION_NAME}_find_statement_assignment
PARAMS ((lang_statement_union_type *));
static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
+static boolean gld${EMULATION_NAME}_place_orphan
+ PARAMS ((lang_input_statement_type *, asection *));
+static void gld${EMULATION_NAME}_place_section
+ PARAMS ((lang_statement_union_type *));
static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
static void
gld${EMULATION_NAME}_before_parse()
{
ldfile_output_architecture = bfd_arch_${ARCH};
- config.dynamic_link = true;
+ config.dynamic_link = ${DYNAMIC_LINK-true};
+}
+
+/* Try to open a dynamic archive. This is where we know that ELF
+ dynamic libraries have an extension of .so. */
+
+static boolean
+gld${EMULATION_NAME}_open_dynamic_archive (arch, entry)
+ const char *arch;
+ lang_input_statement_type *entry;
+{
+ const char *filename;
+
+ filename = entry->filename;
+
+ if (! ldfile_open_file_search (arch, entry, "lib", ".so"))
+ return false;
+
+ /* We have found a dynamic object to include in the link. The ELF
+ backend linker will create a DT_NEEDED entry in the .dynamic
+ section naming this file. If this file includes a DT_SONAME
+ entry, it will be used. Otherwise, the ELF linker will just use
+ the name of the file. For an archive found by searching, like
+ this one, the DT_NEEDED entry should consist of just the name of
+ the file, without the path information used to find it. Note
+ that we only need to do this if we have a dynamic object; an
+ archive will never be referenced by a DT_NEEDED entry.
+
+ FIXME: This approach--using bfd_elf_set_dt_needed_name--is not
+ very pretty. I haven't been able to think of anything that is
+ pretty, though. */
+ if (bfd_check_format (entry->the_bfd, bfd_object)
+ && (entry->the_bfd->flags & DYNAMIC) != 0)
+ {
+ char *needed_name;
+
+ ASSERT (entry->is_archive && entry->search_dirs_flag);
+ needed_name = (char *) xmalloc (strlen (filename)
+ + strlen (arch)
+ + sizeof "lib.so");
+ sprintf (needed_name, "lib%s%s.so", filename, arch);
+ bfd_elf_set_dt_needed_name (entry->the_bfd, needed_name);
+ }
+
+ return true;
}
/* This is called after the sections have been attached to output
/* Let the ELF backend work out the sizes of any sections required
by dynamic linking. */
- if (! bfd_elf32_size_dynamic_sections (output_bfd, &link_info,
+ if (! bfd_elf32_size_dynamic_sections (output_bfd,
+ command_line.soname,
+ command_line.rpath,
+ command_line.export_dynamic,
+ &link_info,
&sinterp))
einfo ("%P%F: failed to set dynamic section sizes: %E\n");
}
}
+/* Place an orphan section. We use this to put random SHF_ALLOC
+ sections in the right segment. */
+
+static asection *hold_section;
+static lang_output_section_statement_type *hold_use;
+static lang_output_section_statement_type *hold_text;
+static lang_output_section_statement_type *hold_data;
+static lang_output_section_statement_type *hold_bss;
+
+/*ARGSUSED*/
+static boolean
+gld${EMULATION_NAME}_place_orphan (file, s)
+ lang_input_statement_type *file;
+ asection *s;
+{
+ lang_output_section_statement_type *place;
+ asection *snew, **pps;
+ lang_statement_list_type *old;
+ lang_statement_list_type add;
+ etree_type *address;
+ const char *secname, *ps;
+ lang_output_section_statement_type *os;
+
+ if ((s->flags & SEC_ALLOC) == 0)
+ return false;
+
+ /* Look through the script to see where to place this section. */
+ hold_section = s;
+ hold_use = NULL;
+ lang_for_each_statement (gld${EMULATION_NAME}_place_section);
+
+ if (hold_use != NULL)
+ {
+ /* We have already placed a section with this name. */
+ wild_doit (&hold_use->children, s, hold_use, file);
+ return true;
+ }
+
+ /* Decide which segment the section should go in based on the
+ section flags. */
+ place = NULL;
+ if ((s->flags & SEC_HAS_CONTENTS) == 0
+ && hold_bss != NULL)
+ place = hold_bss;
+ else if ((s->flags & SEC_READONLY) == 0
+ && hold_data != NULL)
+ place = hold_data;
+ else if ((s->flags & SEC_READONLY) != 0
+ && hold_text != NULL)
+ place = hold_text;
+ if (place == NULL)
+ return false;
+
+ secname = bfd_get_section_name (s->owner, s);
+
+ /* Create the section in the output file, and put it in the right
+ place. This shuffling to make the output file look neater, and
+ also means that the BFD backend does not have to sort the
+ sections in order by address. */
+ snew = bfd_make_section (output_bfd, secname);
+ if (snew == NULL)
+ einfo ("%P%F: output format %s cannot represent section called %s\n",
+ output_bfd->xvec->name, secname);
+ for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
+ ;
+ *pps = snew->next;
+ snew->next = place->bfd_section->next;
+ place->bfd_section->next = snew;
+
+ /* Start building a list of statements for this section. */
+ old = stat_ptr;
+ stat_ptr = &add;
+ lang_list_init (stat_ptr);
+
+ /* If the name of the section is representable in C, then create
+ symbols to mark the start and the end of the section. */
+ for (ps = secname; *ps != '\0'; ps++)
+ if (! isalnum (*ps) && *ps != '_')
+ break;
+ if (*ps == '\0' && config.build_constructors)
+ {
+ char *symname;
+
+ symname = (char *) xmalloc (ps - secname + sizeof "__start_");
+ sprintf (symname, "__start_%s", secname);
+ lang_add_assignment (exp_assop ('=', symname,
+ exp_nameop (NAME, ".")));
+ }
+
+ if (! link_info.relocateable)
+ address = NULL;
+ else
+ address = exp_intop ((bfd_vma) 0);
+
+ lang_enter_output_section_statement (secname, address, 0,
+ (bfd_vma) 0,
+ (etree_type *) NULL,
+ (etree_type *) NULL,
+ (etree_type *) NULL);
+
+ os = lang_output_section_statement_lookup (secname);
+ wild_doit (&os->children, s, os, file);
+
+ lang_leave_output_section_statement ((bfd_vma) 0, "*default*");
+ stat_ptr = &add;
+
+ if (*ps == '\0' && config.build_constructors)
+ {
+ char *symname;
+
+ symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
+ sprintf (symname, "__stop_%s", secname);
+ lang_add_assignment (exp_assop ('=', symname,
+ exp_nameop (NAME, ".")));
+ }
+
+ /* Now stick the new statement list right after PLACE. */
+ *add.tail = place->header.next;
+ place->header.next = add.head;
+
+ stat_ptr = old;
+
+ return true;
+}
+
+static void
+gld${EMULATION_NAME}_place_section (s)
+ lang_statement_union_type *s;
+{
+ lang_output_section_statement_type *os;
+
+ if (s->header.type != lang_output_section_statement_enum)
+ return;
+
+ os = &s->output_section_statement;
+
+ if (strcmp (os->name, hold_section->name) == 0)
+ hold_use = os;
+
+ if (strcmp (os->name, ".text") == 0)
+ hold_text = os;
+ else if (strcmp (os->name, ".data") == 0)
+ hold_data = os;
+ else if (strcmp (os->name, ".bss") == 0)
+ hold_bss = os;
+}
+
static char *
gld${EMULATION_NAME}_get_script(isfile)
int *isfile;
return `sed "$sc" ldscripts/${EMULATION_NAME}.xbn`;
else if (!config.magic_demand_paged)
return `sed "$sc" ldscripts/${EMULATION_NAME}.xn`;
+ else if (link_info.shared)
+ return `sed "$sc" ldscripts/${EMULATION_NAME}.xs`;
else
return `sed "$sc" ldscripts/${EMULATION_NAME}.x`;
}
return "ldscripts/${EMULATION_NAME}.xbn";
else if (!config.magic_demand_paged)
return "ldscripts/${EMULATION_NAME}.xn";
+ else if (link_info.shared)
+ return "ldscripts/${EMULATION_NAME}.xs";
else
return "ldscripts/${EMULATION_NAME}.x";
}
gld${EMULATION_NAME}_before_allocation,
gld${EMULATION_NAME}_get_script,
"${EMULATION_NAME}",
- "${OUTPUT_FORMAT}"
+ "${OUTPUT_FORMAT}",
+ NULL,
+ NULL,
+ gld${EMULATION_NAME}_open_dynamic_archive,
+ gld${EMULATION_NAME}_place_orphan
};
EOF