#include "ldmisc.h"
#include "ldexp.h"
#include "ldlang.h"
+#include "ldctor.h"
+#include "ldgram.h"
static void gldppcmacos_before_parse PARAMS ((void));
static int gldppcmacos_parse_args PARAMS ((int, char **));
+static void gldppcmacos_after_open PARAMS ((void));
static void gldppcmacos_before_allocation PARAMS ((void));
static void gldppcmacos_read_file PARAMS ((const char *, boolean));
static void gldppcmacos_free PARAMS ((PTR));
+static void gldppcmacos_find_relocs
+ PARAMS ((lang_statement_union_type *));
+static void gldppcmacos_find_exp_assignment PARAMS ((etree_type *));
static char *gldppcmacos_get_script PARAMS ((int *isfile));
/* The file alignment required for each section. */
permitted). */
static int textro;
-/* Structure used to hold import or export file list. */
+/* Structure used to hold import file list. */
struct filelist
{
};
/* List of import files. */
-struct filelist *import_files;
+static struct filelist *import_files;
-/* List of export files. */
-struct filelist *export_files;
+/* List of export symbols read from the export files. */
+
+struct export_symbol_list
+{
+ struct export_symbol_list *next;
+ const char *name;
+ boolean syscall;
+};
+
+static struct export_symbol_list *export_symbols;
+
+/* This routine is called before anything else is done. */
static void
gldppcmacos_before_parse()
{
int prevoptind = optind;
int prevopterr = opterr;
+ int indx;
int longind;
int optc;
long val;
#define OPTION_EROK (OPTION_ERNOTOK + 1)
#define OPTION_EXPORT (OPTION_EROK + 1)
#define OPTION_IMPORT (OPTION_EXPORT + 1)
-#define OPTION_MAXDATA (OPTION_IMPORT + 1)
+#define OPTION_LOADMAP (OPTION_IMPORT + 1)
+#define OPTION_MAXDATA (OPTION_LOADMAP + 1)
#define OPTION_MAXSTACK (OPTION_MAXDATA + 1)
#define OPTION_MODTYPE (OPTION_MAXSTACK + 1)
#define OPTION_NOAUTOIMP (OPTION_MODTYPE + 1)
#define OPTION_NOSTRCMPCT (OPTION_NOAUTOIMP + 1)
-#define OPTION_STRCMPCT (OPTION_NOSTRCMPCT + 1)
+#define OPTION_PD (OPTION_NOSTRCMPCT + 1)
+#define OPTION_PT (OPTION_PD + 1)
+#define OPTION_STRCMPCT (OPTION_PT + 1)
static struct option longopts[] = {
{"basis", no_argument, NULL, OPTION_IGNORE},
{"bhalt", required_argument, NULL, OPTION_IGNORE},
{"bI", required_argument, NULL, OPTION_IMPORT},
{"bimport", required_argument, NULL, OPTION_IMPORT},
+ {"bl", required_argument, NULL, OPTION_LOADMAP},
+ {"bloadmap", required_argument, NULL, OPTION_LOADMAP},
{"bmaxdata", required_argument, NULL, OPTION_MAXDATA},
{"bmaxstack", required_argument, NULL, OPTION_MAXSTACK},
{"bM", required_argument, NULL, OPTION_MODTYPE},
{"bnostrcmpct", no_argument, NULL, OPTION_NOSTRCMPCT},
{"bnotextro", no_argument, &textro, 0},
{"bnro", no_argument, &textro, 0},
+ {"bpD", required_argument, NULL, OPTION_PD},
+ {"bpT", required_argument, NULL, OPTION_PT},
{"bro", no_argument, &textro, 1},
{"bS", required_argument, NULL, OPTION_MAXSTACK},
{"bso", no_argument, NULL, OPTION_AUTOIMP},
{"bstrcmpct", no_argument, NULL, OPTION_STRCMPCT},
{"btextro", no_argument, &textro, 1},
+ {"static", no_argument, NULL, OPTION_NOAUTOIMP},
{NULL, no_argument, NULL, 0}
};
-bnotypchk, -bnox, -bquiet, -bR, -brename, -breorder, -btypchk,
-bx, -bX, -bxref. */
- /* If the first option starts with -b, change the first : to an =.
+ /* If the current option starts with -b, change the first : to an =.
The AIX linker uses : to separate the option from the argument;
changing it to = lets us treat it as a getopt option. */
- if (optind < argc && strncmp (argv[optind], "-b", 2) == 0)
+ indx = optind;
+ if (indx == 0)
+ indx = 1;
+ if (indx < argc && strncmp (argv[indx], "-b", 2) == 0)
{
char *s;
- for (s = argv[optind]; *s != '\0'; s++)
+ for (s = argv[indx]; *s != '\0'; s++)
{
if (*s == ':')
{
break;
case OPTION_EXPORT:
+ gldppcmacos_read_file (optarg, false);
+ break;
+
case OPTION_IMPORT:
{
struct filelist *n;
n = (struct filelist *) xmalloc (sizeof (struct filelist));
n->next = NULL;
n->name = optarg;
- if (optc == OPTION_EXPORT)
- flpp = &export_files;
- else
- flpp = &import_files;
+ flpp = &import_files;
while (*flpp != NULL)
flpp = &(*flpp)->next;
*flpp = n;
}
break;
+ case OPTION_LOADMAP:
+ config.map_filename = optarg;
+ break;
+
case OPTION_MAXDATA:
val = strtoul (optarg, &end, 0);
if (*end != '\0')
config.traditional_format = true;
break;
+ case OPTION_PD:
+ /* This sets the page that the .data section is supposed to
+ start on. The offset within the page should still be the
+ offset within the file, so we need to build an appropriate
+ expression. */
+ val = strtoul (optarg, &end, 0);
+ if (*end != '\0')
+ einfo ("%P: warning: ignoring invalid -pD number %s\n", optarg);
+ else
+ {
+ etree_type *t;
+
+ t = exp_binop ('+',
+ exp_intop (val),
+ exp_binop ('&',
+ exp_nameop (NAME, "."),
+ exp_intop (0xfff)));
+ t = exp_binop ('&',
+ exp_binop ('+', t, exp_intop (7)),
+ exp_intop (~ (bfd_vma) 7));
+ lang_section_start (".data", t);
+ }
+ break;
+
+ case OPTION_PT:
+ /* This set the page that the .text section is supposed to start
+ on. The offset within the page should still be the offset
+ within the file. */
+ val = strtoul (optarg, &end, 0);
+ if (*end != '\0')
+ einfo ("%P: warning: ignoring invalid -pT number %s\n", optarg);
+ else
+ {
+ etree_type *t;
+
+ t = exp_binop ('+',
+ exp_intop (val),
+ exp_nameop (SIZEOF_HEADERS, NULL));
+ t = exp_binop ('&',
+ exp_binop ('+', t, exp_intop (7)),
+ exp_intop (~ (bfd_vma) 7));
+ lang_section_start (".text", t);
+ }
+ break;
+
case OPTION_STRCMPCT:
config.traditional_format = false;
break;
return 1;
}
+/* This is called after the input files have been opened. */
+
+static void
+gldppcmacos_after_open ()
+{
+ boolean r;
+ struct set_info *p;
+
+ /* Call ldctor_build_sets, after pretending that this is a
+ relocateable link. We do this because AIX requires relocation
+ entries for all references to symbols, even in a final
+ executable. */
+ r = link_info.relocateable;
+ link_info.relocateable = true;
+ ldctor_build_sets ();
+ link_info.relocateable = r;
+
+ /* For each set, record the size, so that the XCOFF backend can
+ output the correct csect length. */
+ for (p = sets; p != (struct set_info *) NULL; p = p->next)
+ {
+ bfd_size_type size;
+
+ /* If the symbol is defined, we may have been invoked from
+ collect, and the sets may already have been built, so we do
+ not do anything. */
+ if (p->h->type == bfd_link_hash_defined
+ || p->h->type == bfd_link_hash_defweak)
+ continue;
+
+ if (p->reloc != BFD_RELOC_CTOR)
+ {
+ /* Handle this if we need to. */
+ abort ();
+ }
+
+ size = (p->count + 2) * 4;
+ if (! bfd_xcoff_link_record_set (output_bfd, &link_info, p->h, size))
+ einfo ("%F%P: bfd_xcoff_link_record_set failed: %E\n");
+ }
+}
+
/* This is called after the sections have been attached to output
sections, but before any sizes or addresses have been set. */
gldppcmacos_before_allocation ()
{
struct filelist *fl;
+ struct export_symbol_list *el;
char *libpath;
+ asection *special_sections[6];
+ int i;
/* Handle the import and export files, if any. */
for (fl = import_files; fl != NULL; fl = fl->next)
gldppcmacos_read_file (fl->name, true);
- for (fl = export_files; fl != NULL; fl = fl->next)
- gldppcmacos_read_file (fl->name, false);
+ for (el = export_symbols; el != NULL; el = el->next)
+ {
+ struct bfd_link_hash_entry *h;
+
+ h = bfd_link_hash_lookup (link_info.hash, el->name, false, false, false);
+ if (h == NULL)
+ einfo ("%P%F: bfd_link_hash_lookup of export symbol failed: %E\n");
+ if (! bfd_xcoff_export_symbol (output_bfd, &link_info, h, el->syscall))
+ einfo ("%P%F: bfd_xcoff_export_symbol failed: %E\n");
+ }
+
+ /* Track down all relocations called for by the linker script (these
+ are typically constructor/destructor entries created by
+ CONSTRUCTORS) and let the backend know it will need to create
+ .loader relocs for them. */
+ lang_for_each_statement (gldppcmacos_find_relocs);
/* We need to build LIBPATH from the -L arguments. If any -rpath
arguments were used, though, we use -rpath instead, as a GNU
maxstack, maxdata,
gc ? true : false,
modtype,
- textro ? true : false))
+ textro ? true : false,
+ special_sections))
einfo ("%P%F: failed to set dynamic section sizes: %E\n");
+
+ /* Look through the special sections, and put them in the right
+ place in the link ordering. This is especially magic. */
+ for (i = 0; i < 6; i++)
+ {
+ asection *sec;
+ lang_output_section_statement_type *os;
+ lang_statement_union_type **pls;
+ lang_input_section_type *is;
+ const char *oname;
+ boolean start;
+
+ sec = special_sections[i];
+ if (sec == NULL)
+ continue;
+
+ /* Remove this section from the list of the output section.
+ This assumes we know what the script looks like. */
+ is = NULL;
+ os = lang_output_section_find (sec->output_section->name);
+ if (os == NULL)
+ einfo ("%P%F: can't find output section %s\n",
+ sec->output_section->name);
+ for (pls = &os->children.head; *pls != NULL; pls = &(*pls)->next)
+ {
+ if ((*pls)->header.type == lang_input_section_enum
+ && (*pls)->input_section.section == sec)
+ {
+ is = (lang_input_section_type *) *pls;
+ *pls = (*pls)->next;
+ break;
+ }
+ if ((*pls)->header.type == lang_wild_statement_enum)
+ {
+ lang_statement_union_type **pwls;
+
+ for (pwls = &(*pls)->wild_statement.children.head;
+ *pwls != NULL;
+ pwls = &(*pwls)->next)
+ {
+ if ((*pwls)->header.type == lang_input_section_enum
+ && (*pwls)->input_section.section == sec)
+ {
+ is = (lang_input_section_type *) *pwls;
+ *pwls = (*pwls)->next;
+ break;
+ }
+ }
+ if (is != NULL)
+ break;
+ }
+ }
+
+ if (is == NULL)
+ einfo ("%P%F: can't find %s in output section\n",
+ bfd_get_section_name (sec->owner, sec));
+
+ /* Now figure out where the section should go. */
+ switch (i)
+ {
+ default: /* to avoid warnings */
+ case 0:
+ /* _text */
+ oname = ".text";
+ start = true;
+ break;
+ case 1:
+ /* _etext */
+ oname = ".text";
+ start = false;
+ break;
+ case 2:
+ /* _data */
+ oname = ".data";
+ start = true;
+ break;
+ case 3:
+ /* _edata */
+ oname = ".data";
+ start = false;
+ break;
+ case 4:
+ case 5:
+ /* _end and end */
+ oname = ".bss";
+ start = false;
+ break;
+ }
+
+ os = lang_output_section_find (oname);
+
+ if (start)
+ {
+ is->header.next = os->children.head;
+ os->children.head = (lang_statement_union_type *) is;
+ }
+ else
+ {
+ is->header.next = NULL;
+ lang_statement_append (&os->children,
+ (lang_statement_union_type *) is,
+ &is->header.next);
+ }
+ }
}
-/* Read an import or export file. */
+/* Read an import or export file. For an import file, this is called
+ by the before_allocation emulation routine. For an export file,
+ this is called by the parse_args emulation routine. */
static void
gldppcmacos_read_file (filename, import)
}
}
- h = bfd_link_hash_lookup (link_info.hash, symname, false, false, true);
- if (h == NULL || h->type == bfd_link_hash_new)
- {
- /* We can just ignore attempts to import an unreferenced
- symbol. */
- if (! import)
- einfo ("%X%s:%d: attempt to export undefined symbol %s\n",
- filename, lineno, symname);
- }
- else if (import)
+ if (! import)
{
- if (! bfd_xcoff_import_symbol (output_bfd, &link_info, h, address,
- imppath, impfile, impmember))
- einfo ("%X%s:%d: failed to import symbol %s: %E\n",
- filename, lineno, symname);
+ struct export_symbol_list *n;
+
+ ldlang_add_undef (symname);
+ n = ((struct export_symbol_list *)
+ xmalloc (sizeof (struct export_symbol_list)));
+ n->next = export_symbols;
+ n->name = buystring (symname);
+ n->syscall = syscall;
+ export_symbols = n;
}
else
{
- if (! bfd_xcoff_export_symbol (output_bfd, &link_info, h, syscall))
- einfo ("%X%s:%d: failed to export symbol %s: %E\n",
- filename, lineno, symname);
+ h = bfd_link_hash_lookup (link_info.hash, symname, false, false,
+ true);
+ if (h == NULL || h->type == bfd_link_hash_new)
+ {
+ /* We can just ignore attempts to import an unreferenced
+ symbol. */
+ }
+ else
+ {
+ if (! bfd_xcoff_import_symbol (output_bfd, &link_info, h,
+ address, imppath, impfile,
+ impmember))
+ einfo ("%X%s:%d: failed to import symbol %s: %E\n",
+ filename, lineno, symname);
+ }
}
obstack_free (o, obstack_base (o));
free (p);
}
+/* This is called by the before_allocation routine via
+ lang_for_each_statement. It looks for relocations and assignments
+ to symbols. */
+
+static void
+gldppcmacos_find_relocs (s)
+ lang_statement_union_type *s;
+{
+ if (s->header.type == lang_reloc_statement_enum)
+ {
+ lang_reloc_statement_type *rs;
+
+ rs = &s->reloc_statement;
+ if (rs->name == NULL)
+ einfo ("%F%P: only relocations against symbols are permitted\n");
+ if (! bfd_xcoff_link_count_reloc (output_bfd, &link_info, rs->name))
+ einfo ("%F%P: bfd_xcoff_link_count_reloc failed: %E\n");
+ }
+
+ if (s->header.type == lang_assignment_statement_enum)
+ gldppcmacos_find_exp_assignment (s->assignment_statement.exp);
+}
+
+/* Look through an expression for an assignment statement. */
+
+static void
+gldppcmacos_find_exp_assignment (exp)
+ 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;
+ /* Fall through. */
+ case etree_assign:
+ if (strcmp (exp->assign.dst, ".") != 0)
+ {
+ if (! bfd_xcoff_record_link_assignment (output_bfd, &link_info,
+ exp->assign.dst))
+ einfo ("%P%F: failed to record assignment to %s: %E\n",
+ exp->assign.dst);
+ }
+ gldppcmacos_find_exp_assignment (exp->assign.src);
+ break;
+
+ case etree_binary:
+ gldppcmacos_find_exp_assignment (exp->binary.lhs);
+ gldppcmacos_find_exp_assignment (exp->binary.rhs);
+ break;
+
+ case etree_trinary:
+ gldppcmacos_find_exp_assignment (exp->trinary.cond);
+ gldppcmacos_find_exp_assignment (exp->trinary.lhs);
+ gldppcmacos_find_exp_assignment (exp->trinary.rhs);
+ break;
+
+ case etree_unary:
+ gldppcmacos_find_exp_assignment (exp->unary.child);
+ break;
+
+ default:
+ break;
+ }
+}
+
static char *
gldppcmacos_get_script(isfile)
int *isfile;
*(.rw)\n\
*(.sv)\n\
*(.ua)\n\
+ . = ALIGN(4);\n\
+ CONSTRUCTORS\n\
*(.ds)\n\
*(.tc0)\n\
*(.tc)\n\
*(.rw)\n\
*(.sv)\n\
*(.ua)\n\
+ . = ALIGN(4);\n\
*(.ds)\n\
*(.tc0)\n\
*(.tc)\n\
*(.rw)\n\
*(.sv)\n\
*(.ua)\n\
+ . = ALIGN(4);\n\
+ CONSTRUCTORS\n\
*(.ds)\n\
*(.tc0)\n\
*(.tc)\n\
*(.rw)\n\
*(.sv)\n\
*(.ua)\n\
+ . = ALIGN(4);\n\
+ CONSTRUCTORS\n\
*(.ds)\n\
*(.tc0)\n\
*(.tc)\n\
*(.rw)\n\
*(.sv)\n\
*(.ua)\n\
+ . = ALIGN(4);\n\
+ CONSTRUCTORS\n\
*(.ds)\n\
*(.tc0)\n\
*(.tc)\n\
syslib_default,
hll_default,
after_parse_default,
- after_open_default,
+ gldppcmacos_after_open,
after_allocation_default,
set_output_arch_default,
ldemul_default_target,