From 57fc1e90b76b35e77b76c48f248b3777a430902a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 25 Oct 1995 15:49:27 +0000 Subject: [PATCH] * emultempl/aix.em: Add support for various AIX linker options, for AIX import and export files, and for AIX shared objects. * scripttempl/aix.sc: Add .pad. Put .ds just before the TOC. --- ld/emultempl/aix.em | 665 ++++++++++++++++++++++++++++++++++++++++++++++++++ ld/scripttempl/aix.sc | 50 ++++ 2 files changed, 715 insertions(+) create mode 100644 ld/emultempl/aix.em create mode 100644 ld/scripttempl/aix.sc diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em new file mode 100644 index 0000000..256c24f --- /dev/null +++ b/ld/emultempl/aix.em @@ -0,0 +1,665 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +cat >e${EMULATION_NAME}.c < + AIX support by Ian Lance Taylor + +This file is part of GLD, the Gnu Linker. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "bfd.h" +#include "sysdep.h" +#include "libiberty.h" +#include "getopt.h" +#include "bfdlink.h" + +#include + +#include "ld.h" +#include "ldmain.h" +#include "ldemul.h" +#include "ldfile.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" + +static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); +static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **)); +static void gld${EMULATION_NAME}_before_allocation PARAMS ((void)); +static void gld${EMULATION_NAME}_read_file PARAMS ((const char *, boolean)); +static void gld${EMULATION_NAME}_free PARAMS ((PTR)); +static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); + +/* The file alignment required for each section. */ +static unsigned long file_align; + +/* The maximum size the stack is permitted to grow. This is stored in + the a.out header. */ +static unsigned long maxstack; + +/* The maximum data size. This is stored in the a.out header. */ +static unsigned long maxdata; + +/* Whether to perform garbage collection. */ +static int gc = 1; + +/* The module type to use. */ +static unsigned short modtype = ('1' << 8) | 'L'; + +/* Whether the .text section must be read-only (i.e., no relocs + permitted). */ +static int textro; + +/* Structure used to hold import or export file list. */ + +struct filelist +{ + struct filelist *next; + const char *name; +}; + +/* List of import files. */ +struct filelist *import_files; + +/* List of export files. */ +struct filelist *export_files; + +static void +gld${EMULATION_NAME}_before_parse() +{ +#ifndef TARGET_ /* I.e., if not generic. */ + ldfile_output_architecture = bfd_arch_${ARCH}; +#endif /* not TARGET_ */ +} + +/* Handle AIX specific options. */ + +static int +gld${EMULATION_NAME}_parse_args (argc, argv) + int argc; + char **argv; +{ + int prevoptind = optind; + int prevopterr = opterr; + int longind; + int optc; + long val; + char *end; + +#define OPTION_IGNORE (300) +#define OPTION_AUTOIMP (OPTION_IGNORE + 1) +#define OPTION_ERNOTOK (OPTION_AUTOIMP + 1) +#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_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) + + static struct option longopts[] = { + {"basis", no_argument, NULL, OPTION_IGNORE}, + {"bautoimp", no_argument, NULL, OPTION_AUTOIMP}, + {"bcomprld", no_argument, NULL, OPTION_IGNORE}, + {"bcrld", no_argument, NULL, OPTION_IGNORE}, + {"bcror31", no_argument, NULL, OPTION_IGNORE}, + {"bD", required_argument, NULL, OPTION_MAXDATA}, + {"bE", required_argument, NULL, OPTION_EXPORT}, + {"bernotok", no_argument, NULL, OPTION_ERNOTOK}, + {"berok", no_argument, NULL, OPTION_EROK}, + {"berrmsg", no_argument, NULL, OPTION_IGNORE}, + {"bexport", required_argument, NULL, OPTION_EXPORT}, + {"bf", no_argument, NULL, OPTION_ERNOTOK}, + {"bgc", no_argument, &gc, 1}, + {"bh", required_argument, NULL, OPTION_IGNORE}, + {"bhalt", required_argument, NULL, OPTION_IGNORE}, + {"bI", required_argument, NULL, OPTION_IMPORT}, + {"bimport", required_argument, NULL, OPTION_IMPORT}, + {"bmaxdata", required_argument, NULL, OPTION_MAXDATA}, + {"bmaxstack", required_argument, NULL, OPTION_MAXSTACK}, + {"bM", required_argument, NULL, OPTION_MODTYPE}, + {"bmodtype", required_argument, NULL, OPTION_MODTYPE}, + {"bnoautoimp", no_argument, NULL, OPTION_NOAUTOIMP}, + {"bnodelcsect", no_argument, NULL, OPTION_IGNORE}, + {"bnogc", no_argument, &gc, 0}, + {"bnso", no_argument, NULL, OPTION_NOAUTOIMP}, + {"bnostrcmpct", no_argument, NULL, OPTION_NOSTRCMPCT}, + {"bnotextro", no_argument, &textro, 0}, + {"bnro", no_argument, &textro, 0}, + {"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}, + {NULL, no_argument, NULL, 0} + }; + + /* Options supported by the AIX linker which we do not support: -f, + -S, -v, -Z, -bbindcmds, -bbinder, -bbindopts, -bcalls, -bcaps, + -bcror15, -bdebugopt, -bdbg, -bdelcsect, -bex?, -bfilelist, -bfl, + -bgcbypass, -bglink, -binsert, -bi, -bloadmap, -bl, -bmap, -bnl, + -bnobind, -bnocomprld, -bnocrld, -bnoerrmsg, -bnoglink, + -bnoloadmap, -bnl, -bnoobjreorder, -bnoquiet, -bnoreorder, + -bnotypchk, -bnox, -bquiet, -bR, -brename, -breorder, -btypchk, + -bx, -bX, -bxref. */ + + /* If the first 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) + { + char *s; + + for (s = argv[optind]; *s != '\0'; s++) + { + if (*s == ':') + { + *s = '='; + break; + } + } + } + + opterr = 0; + optc = getopt_long_only (argc, argv, "-D:H:KT:z", longopts, &longind); + opterr = prevopterr; + + switch (optc) + { + default: + optind = prevoptind; + return 0; + + case 'D': + val = strtol (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -D number %s\n", optarg); + else if (val != -1) + lang_section_start (".data", exp_intop (val)); + break; + + case 'H': + val = strtoul (optarg, &end, 0); + if (*end != '\0' + || (val & (val - 1)) != 0) + einfo ("%P: warning: ignoring invalid -H number %s\n", optarg); + else + file_align = val; + break; + + case 'K': + case 'z': + /* FIXME: This should use the page size for the target system. */ + file_align = 4096; + break; + + case 'T': + /* On AIX this is the same as GNU ld -Ttext. When we see -T + number, we assume the AIX option is intended. Otherwise, we + assume the usual GNU ld -T option is intended. We can't just + ignore the AIX option, because gcc passes it to the linker. */ + val = strtoul (optarg, &end, 0); + if (*end != '\0') + { + optind = prevoptind; + return 0; + } + lang_section_start (".text", exp_intop (val)); + break; + + case OPTION_IGNORE: + break; + + case OPTION_AUTOIMP: + link_info.static_link = false; + break; + + case OPTION_ERNOTOK: + force_make_executable = false; + break; + + case OPTION_EROK: + force_make_executable = true; + break; + + case OPTION_EXPORT: + case OPTION_IMPORT: + { + struct filelist *n; + struct filelist **flpp; + + n = (struct filelist *) xmalloc (sizeof (struct filelist)); + n->next = NULL; + n->name = optarg; + if (optc == OPTION_EXPORT) + flpp = &export_files; + else + flpp = &import_files; + while (*flpp != NULL) + flpp = &(*flpp)->next; + *flpp = n; + } + break; + + case OPTION_MAXDATA: + val = strtoul (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -bmaxdata number %s\n", + optarg); + else + maxdata = val; + break; + + case OPTION_MAXSTACK: + val = strtoul (optarg, &end, 0); + if (*end != '\0') + einfo ("%P: warning: ignoring invalid -bmaxstack number %s\n", + optarg); + else + maxstack = val; + break; + + case OPTION_MODTYPE: + if (*optarg == 'S') + { + link_info.shared = true; + ++optarg; + } + if (*optarg == '\0' || optarg[1] == '\0') + einfo ("%P: warning: ignoring invalid module type %s\n", optarg); + else + modtype = (*optarg << 8) | optarg[1]; + break; + + case OPTION_NOAUTOIMP: + link_info.static_link = true; + break; + + case OPTION_NOSTRCMPCT: + config.traditional_format = true; + break; + + case OPTION_STRCMPCT: + config.traditional_format = false; + break; + } + + return 1; +} + +/* This is called after the sections have been attached to output + sections, but before any sizes or addresses have been set. */ + +static void +gld${EMULATION_NAME}_before_allocation () +{ + struct filelist *fl; + char *libpath; + + /* Handle the import and export files, if any. */ + for (fl = import_files; fl != NULL; fl = fl->next) + gld${EMULATION_NAME}_read_file (fl->name, true); + for (fl = export_files; fl != NULL; fl = fl->next) + gld${EMULATION_NAME}_read_file (fl->name, false); + + /* We need to build LIBPATH from the -L arguments. If any -rpath + arguments were used, though, we use -rpath instead, as a GNU + extension. */ + if (command_line.rpath != NULL) + libpath = command_line.rpath; + else if (search_head == NULL) + libpath = (char *) ""; + else + { + size_t len; + search_dirs_type *search; + + len = strlen (search_head->name); + libpath = xmalloc (len + 1); + strcpy (libpath, search_head->name); + for (search = search_head->next; search != NULL; search = search->next) + { + size_t nlen; + + nlen = strlen (search->name); + libpath = xrealloc (libpath, len + nlen + 2); + libpath[len] = ':'; + strcpy (libpath + len + 1, search->name); + len += nlen + 1; + } + } + + /* Let the XCOFF backend set up the .loader section. */ + if (! bfd_xcoff_size_dynamic_sections (output_bfd, &link_info, libpath, + entry_symbol, file_align, + maxstack, maxdata, + gc ? true : false, + modtype, + textro ? true : false)) + einfo ("%P%F: failed to set dynamic section sizes: %E\n"); +} + +/* Read an import or export file. */ + +static void +gld${EMULATION_NAME}_read_file (filename, import) + const char *filename; + boolean import; +{ + struct obstack *o; + FILE *f; + int lineno; + int c; + boolean keep; + const char *imppath; + const char *impfile; + const char *impmember; + + o = (struct obstack *) xmalloc (sizeof (struct obstack)); + obstack_specify_allocation (o, 0, 0, xmalloc, gld${EMULATION_NAME}_free); + + f = fopen (filename, "r"); + if (f == NULL) + { + bfd_set_error (bfd_error_system_call); + einfo ("%F%s: %E\n", filename); + } + + keep = false; + + imppath = NULL; + impfile = NULL; + impmember = NULL; + + lineno = 0; + while ((c = getc (f)) != EOF) + { + char *s; + char *symname; + boolean syscall; + bfd_vma address; + struct bfd_link_hash_entry *h; + + if (c != '\n') + { + obstack_1grow (o, c); + continue; + } + + obstack_1grow (o, '\0'); + ++lineno; + + s = (char *) obstack_base (o); + while (isspace ((unsigned char) *s)) + ++s; + if (*s == '\0' + || *s == '*' + || (*s == '#' && s[1] == ' ') + || (! import && *s == '#' && s[1] == '!')) + { + obstack_free (o, obstack_base (o)); + continue; + } + + if (*s == '#' && s[1] == '!') + { + s += 2; + while (isspace ((unsigned char) *s)) + ++s; + if (*s == '\0') + { + imppath = NULL; + impfile = NULL; + impmember = NULL; + obstack_free (o, obstack_base (o)); + } + else if (*s == '(') + einfo ("%F%s%d: #! ([member]) is not supported in import files", + filename, lineno); + else + { + char cs; + char *file; + + (void) obstack_finish (o); + keep = true; + imppath = s; + impfile = NULL; + while (! isspace ((unsigned char) *s) && *s != '(' && *s != '\0') + { + if (*s == '/') + file = s + 1; + ++s; + } + if (file != NULL) + { + file[-1] = '\0'; + impfile = file; + if (imppath == file - 1) + imppath = "/"; + } + else + { + impfile = imppath; + imppath = ""; + } + cs = *s; + *s = '\0'; + while (isspace ((unsigned char) cs)) + { + ++s; + cs = *s; + } + if (cs != '(') + { + impmember = ""; + if (cs != '\0') + einfo ("%s:%d: warning: syntax error in import file\n", + filename, lineno); + } + else + { + ++s; + impmember = s; + while (*s != ')' && *s != '\0') + ++s; + if (*s == ')') + *s = '\0'; + else + einfo ("%s:%d: warning: syntax error in import file\n", + filename, lineno); + } + } + + continue; + } + + /* This is a symbol to be imported or exported. */ + symname = s; + syscall = false; + address = (bfd_vma) -1; + + while (! isspace ((unsigned char) *s) && *s != '\0') + ++s; + if (*s != '\0') + { + char *se; + + *s++ = '\0'; + + while (isspace ((unsigned char) *s)) + ++s; + + se = s; + while (! isspace ((unsigned char) *se) && *se != '\0') + ++se; + if (*se != '\0') + { + *se++ = '\0'; + while (isspace ((unsigned char) *se)) + ++se; + if (*se != '\0') + einfo ("%s%d: warning: syntax error in import/export file\n", + filename, lineno); + } + + if (strcasecmp (s, "svc") == 0 + || strcasecmp (s, "syscall") == 0) + syscall = true; + else + { + char *end; + + address = strtoul (s, &end, 0); + if (*end != '\0') + einfo ("%s:%d: warning: syntax error in import/export file\n", + filename, lineno); + } + } + + 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 (! 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); + } + 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); + } + + obstack_free (o, obstack_base (o)); + } + + if (obstack_object_size (o) > 0) + { + einfo ("%s:%d: warning: ignoring unterminated last line\n", + filename, lineno); + obstack_free (o, obstack_base (o)); + } + + if (! keep) + { + obstack_free (o, NULL); + free (o); + } +} + +/* This routine saves us from worrying about declaring free. */ + +static void +gld${EMULATION_NAME}_free (p) + PTR p; +{ + free (p); +} + +static char * +gld${EMULATION_NAME}_get_script(isfile) + 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 ${srcdir}/emultempl/stringify.sed" + +cat >>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocateable == true) 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 +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +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 <>e${EMULATION_NAME}.c <