X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Femultempl%2Faix.em;h=8b386ba8f8ef50ce4355dc20cbdc6c23b61c4568;hb=c553bb910d30224f6d5e1e10a67a839093e97fa0;hp=08c79b20f6afdf46c10ec4c54b8f92f1560a55fe;hpb=c7c8b500b95493a83123895210e0a56074d34c14;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em index 08c79b20f6..8b386ba8f8 100644 --- a/ld/emultempl/aix.em +++ b/ld/emultempl/aix.em @@ -1,12 +1,19 @@ # This shell script emits a C file. -*- C -*- # It does some substitutions. +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi cat >e${EMULATION_NAME}.c < AIX support by Ian Lance Taylor + AIX 64 bit support by Tom Rix This file is part of GLD, the Gnu Linker. @@ -29,25 +36,45 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "libiberty.h" +#include "safe-ctype.h" #include "getopt.h" +#include "obstack.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" +#include "ldfile.h" +#include "ldemul.h" +#include "ldctor.h" +#include "ldgram.h" + +#include "coff/internal.h" +#include "coff/xcoff.h" +#include "libcoff.h" +#include "libxcoff.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}_after_open PARAMS ((void)); +static char *gld${EMULATION_NAME}_choose_target 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 void gld${EMULATION_NAME}_find_relocs +PARAMS ((lang_statement_union_type *)); +static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *)); static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); +static boolean gld${EMULATION_NAME}_unrecognized_file + PARAMS ((lang_input_statement_type *)); +static void gld${EMULATION_NAME}_create_output_section_statements + PARAMS ((void)); +static void gld${EMULATION_NAME}_set_output_arch PARAMS ((void)); + +static int is_syscall PARAMS ((char *, unsigned int *)); +static int change_symbol_mode PARAMS ((char *)); /* The file alignment required for each section. */ static unsigned long file_align; @@ -69,7 +96,10 @@ static unsigned short modtype = ('1' << 8) | 'L'; permitted). */ static int textro; -/* Structure used to hold import or export file list. */ +/* Whether to implement Unix like linker semantics. */ +static int unix_ld; + +/* Structure used to hold import file list. */ struct filelist { @@ -78,17 +108,63 @@ struct filelist }; /* List of import files. */ -struct filelist *import_files; +static struct filelist *import_files; + +/* List of export symbols read from the export files. */ + +struct export_symbol_list +{ + struct export_symbol_list *next; + const char *name; +}; + +static struct export_symbol_list *export_symbols; -/* List of export files. */ -struct filelist *export_files; +/* Maintains the 32 or 64 bit mode state of import file */ +static unsigned int symbol_mode = 0x04; + +/* Which symbol modes are valid */ +static unsigned int symbol_mode_mask = 0x0d; + +/* Whether this is a 64 bit link */ +static int is_64bit = 0; + +/* Which syscalls from import file are valid */ +static unsigned int syscall_mask = 0x77; + +/* fake file for -binitfini support */ +static lang_input_statement_type *initfini_file; + +/* Whether to do run time linking + -brtl enables, -bnortl and -bnortllib disable. */ +static int rtld; + +/* Explicit command line library path, -blibpath */ +static char *command_line_blibpath = NULL; + +/* This routine is called before anything else is done. */ static void -gld${EMULATION_NAME}_before_parse() +gld${EMULATION_NAME}_before_parse () { -#ifndef TARGET_ /* I.e., if not generic. */ - ldfile_output_architecture = bfd_arch_${ARCH}; -#endif /* not TARGET_ */ + const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}"); + if (arch) + { + ldfile_output_architecture = arch->arch; + ldfile_output_machine = arch->mach; + ldfile_output_machine_name = arch->printable_name; + } + else + ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`; + + config.has_shared = true; + + /* The link_info.[init|fini]_functions are initialized in ld/lexsup.c. + Override them here so we can use the link_info.init_function as a + state flag that lets the backend know that -binitfini has been done. */ + + link_info.init_function = NULL; + link_info.fini_function = NULL; } /* Handle AIX specific options. */ @@ -100,25 +176,47 @@ gld${EMULATION_NAME}_parse_args (argc, argv) { int prevoptind = optind; int prevopterr = opterr; + int indx; int longind; int optc; - long val; + bfd_signed_vma 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[] = { + enum + { + OPTION_IGNORE = 300, + OPTION_AUTOIMP, + OPTION_ERNOTOK, + OPTION_EROK, + OPTION_EXPORT, + OPTION_IMPORT, + OPTION_INITFINI, + OPTION_LOADMAP, + OPTION_MAXDATA, + OPTION_MAXSTACK, + OPTION_MODTYPE, + OPTION_NOAUTOIMP, + OPTION_NOSTRCMPCT, + OPTION_PD, + OPTION_PT, + OPTION_STRCMPCT, + OPTION_UNIX, + OPTION_32, + OPTION_64, + OPTION_LIBPATH, + OPTION_NOLIBPATH, + }; + + /* -binitfini has special handling in the linker backend. The native linker + uses the arguemnts to generate a table of init and fini functions for + the executable. The important use for this option is to support aix 4.2+ + c++ constructors and destructors. This is tied into gcc via collect2.c. + + The function table is accessed by the runtime linker/loader by checking if + the first symbol in the loader symbol table is __rtinit. The gnu linker + generates this symbol and makes it the first loader symbol. */ + + static const struct option longopts[] = { {"basis", no_argument, NULL, OPTION_IGNORE}, {"bautoimp", no_argument, NULL, OPTION_AUTOIMP}, {"bcomprld", no_argument, NULL, OPTION_IGNORE}, @@ -136,23 +234,37 @@ gld${EMULATION_NAME}_parse_args (argc, argv) {"bhalt", required_argument, NULL, OPTION_IGNORE}, {"bI", required_argument, NULL, OPTION_IMPORT}, {"bimport", required_argument, NULL, OPTION_IMPORT}, + {"binitfini", required_argument, NULL, OPTION_INITFINI}, + {"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}, {"bmodtype", required_argument, NULL, OPTION_MODTYPE}, {"bnoautoimp", no_argument, NULL, OPTION_NOAUTOIMP}, {"bnodelcsect", no_argument, NULL, OPTION_IGNORE}, + {"bnoentry", 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}, + {"bpD", required_argument, NULL, OPTION_PD}, + {"bpT", required_argument, NULL, OPTION_PT}, {"bro", no_argument, &textro, 1}, + {"brtl", no_argument, &rtld, 1}, + {"bnortl", no_argument, &rtld, 0}, + {"bnortllib", no_argument, &rtld, 0}, {"bS", required_argument, NULL, OPTION_MAXSTACK}, {"bso", no_argument, NULL, OPTION_AUTOIMP}, {"bstrcmpct", no_argument, NULL, OPTION_STRCMPCT}, {"btextro", no_argument, &textro, 1}, + {"b32", no_argument, NULL, OPTION_32}, + {"b64", no_argument, NULL, OPTION_64}, {"static", no_argument, NULL, OPTION_NOAUTOIMP}, + {"unix", no_argument, NULL, OPTION_UNIX}, + {"blibpath", required_argument, NULL, OPTION_LIBPATH}, + {"bnolibpath", required_argument, NULL, OPTION_NOLIBPATH}, {NULL, no_argument, NULL, 0} }; @@ -165,14 +277,18 @@ gld${EMULATION_NAME}_parse_args (argc, argv) -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 == ':') { @@ -182,12 +298,18 @@ gld${EMULATION_NAME}_parse_args (argc, argv) } } + + /* We add s and u so to the short options list so that -s and -u on + the command line do not match -static and -unix. */ + opterr = 0; - optc = getopt_long_only (argc, argv, "-D:H:KT:z", longopts, &longind); + optc = getopt_long_only (argc, argv, "-D:H:KT:zsu", longopts, &longind); opterr = prevopterr; switch (optc) { + case 's': + case 'u': default: optind = prevoptind; return 0; @@ -197,7 +319,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) break; case 'D': - val = strtol (optarg, &end, 0); + val = strtoll (optarg, &end, 0); if (*end != '\0') einfo ("%P: warning: ignoring invalid -D number %s\n", optarg); else if (val != -1) @@ -206,8 +328,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) case 'H': val = strtoul (optarg, &end, 0); - if (*end != '\0' - || (val & (val - 1)) != 0) + if (*end != '\0' || (val & (val - 1)) != 0) einfo ("%P: warning: ignoring invalid -H number %s\n", optarg); else file_align = val; @@ -221,10 +342,10 @@ gld${EMULATION_NAME}_parse_args (argc, argv) 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); + 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 = strtoull (optarg, &end, 0); if (*end != '\0') { optind = prevoptind; @@ -236,6 +357,43 @@ gld${EMULATION_NAME}_parse_args (argc, argv) case OPTION_IGNORE: break; + case OPTION_INITFINI: + { + /* + * The aix linker init fini has the format : + * + * -binitfini:[ Initial][:Termination][:Priority] + * + * it allows the Termination and Priority to be optional. + * + * Since we support only one init/fini pair, we ignore the Priority. + * + * Define the special symbol __rtinit. + * + * strtok does not correctly handle the case of -binitfini::fini: so + * do it by hand + */ + char *t, *i, *f; + + i = t = optarg; + while (*t && ':' != *t) + t++; + if (*t) + *t++ = 0; + + if (0 != strlen (i)) + link_info.init_function = i; + + f = t; + while (*t && ':' != *t) + t++; + *t = 0; + + if (0 != strlen (f)) + link_info.fini_function = f; + } + break; + case OPTION_AUTOIMP: link_info.static_link = false; break; @@ -249,6 +407,9 @@ gld${EMULATION_NAME}_parse_args (argc, argv) break; case OPTION_EXPORT: + gld${EMULATION_NAME}_read_file (optarg, false); + break; + case OPTION_IMPORT: { struct filelist *n; @@ -257,27 +418,27 @@ gld${EMULATION_NAME}_parse_args (argc, argv) 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); + val = strtoull (optarg, &end, 0); if (*end != '\0') - einfo ("%P: warning: ignoring invalid -bmaxdata number %s\n", - optarg); + einfo ("%P: warning: ignoring invalid -bmaxdata number %s\n", optarg); else maxdata = val; break; case OPTION_MAXSTACK: - val = strtoul (optarg, &end, 0); + val = strtoull (optarg, &end, 0); if (*end != '\0') einfo ("%P: warning: ignoring invalid -bmaxstack number %s\n", optarg); @@ -302,17 +463,170 @@ gld${EMULATION_NAME}_parse_args (argc, argv) break; case OPTION_NOSTRCMPCT: - config.traditional_format = true; + link_info.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 = strtoull (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 (31)), + exp_intop (~(bfd_vma) 31)); + 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 = strtoull (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 (31)), + exp_intop (~(bfd_vma) 31)); + lang_section_start (".text", t); + } break; case OPTION_STRCMPCT: - config.traditional_format = false; + link_info.traditional_format = false; + break; + + case OPTION_UNIX: + unix_ld = true; + break; + + case OPTION_32: + is_64bit = 0; + syscall_mask = 0x77; + symbol_mode_mask = 0x0d; break; + + case OPTION_64: + is_64bit = 1; + syscall_mask = 0xcc; + symbol_mode_mask = 0x0e; + break; + + case OPTION_LIBPATH: + command_line_blibpath = optarg; + break; + + case OPTION_NOLIBPATH: + command_line_blibpath = NULL; + break; + } return 1; } +/* This is called when an input file can not be recognized as a BFD + object or an archive. If the file starts with #!, we must treat it + as an import file. This is for AIX compatibility. */ + +static boolean +gld${EMULATION_NAME}_unrecognized_file (entry) + lang_input_statement_type *entry; +{ + FILE *e; + boolean ret; + + e = fopen (entry->filename, FOPEN_RT); + if (e == NULL) + return false; + + ret = false; + + if (getc (e) == '#' && getc (e) == '!') + { + struct filelist *n; + struct filelist **flpp; + + n = (struct filelist *) xmalloc (sizeof (struct filelist)); + n->next = NULL; + n->name = entry->filename; + flpp = &import_files; + while (*flpp != NULL) + flpp = &(*flpp)->next; + *flpp = n; + + ret = true; + entry->loaded = true; + } + + fclose (e); + + return ret; +} + +/* This is called after the input files have been opened. */ + +static void +gld${EMULATION_NAME}_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. Of course, we only want to do this if we are + producing an XCOFF output file. */ + r = link_info.relocateable; + if (strstr (bfd_get_target (output_bfd), "xcoff") != NULL) + 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. */ @@ -320,18 +634,38 @@ static void gld${EMULATION_NAME}_before_allocation () { struct filelist *fl; + struct export_symbol_list *el; char *libpath; + asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS]; + int i; /* 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); + for (el = export_symbols; el != NULL; el = el->next) + { + struct bfd_link_hash_entry *h; - /* 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) + 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)) + 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 (gld${EMULATION_NAME}_find_relocs); + + /* Precedence of LIBPATH + -blibpath: native support always first + -rpath: gnu extension + -L build from command line -L's */ + if (command_line_blibpath != NULL) + libpath = command_line_blibpath; + else if (command_line.rpath != NULL) libpath = command_line.rpath; else if (search_head == NULL) libpath = (char *) ""; @@ -356,16 +690,251 @@ gld${EMULATION_NAME}_before_allocation () } /* 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)) + if (!bfd_xcoff_size_dynamic_sections + (output_bfd, &link_info, libpath, entry_symbol.name, file_align, + maxstack, maxdata, gc && !unix_ld ? true : false, + modtype, textro ? true : false, unix_ld, special_sections, + rtld ? true : false)) 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 < XCOFF_NUMBER_OF_SPECIAL_SECTIONS; 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)->header.next) + { + if ((*pls)->header.type == lang_input_section_enum + && (*pls)->input_section.section == sec) + { + is = (lang_input_section_type *) * pls; + *pls = (*pls)->header.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)->header.next) + { + + if ((*pwls)->header.type == lang_input_section_enum + && (*pwls)->input_section.section == sec) + { + is = (lang_input_section_type *) * pwls; + *pwls = (*pwls)->header.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 XCOFF_SPECIAL_SECTION_TEXT: + /* _text */ + oname = ".text"; + start = true; + break; + + case XCOFF_SPECIAL_SECTION_ETEXT: + /* _etext */ + oname = ".text"; + start = false; + break; + + case XCOFF_SPECIAL_SECTION_DATA: + /* _data */ + oname = ".data"; + start = true; + break; + + case XCOFF_SPECIAL_SECTION_EDATA: + /* _edata */ + oname = ".data"; + start = false; + break; + + case XCOFF_SPECIAL_SECTION_END: + case XCOFF_SPECIAL_SECTION_END2: + /* _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); + } + } +} + +static char * +gld${EMULATION_NAME}_choose_target (argc, argv) + int argc; + char **argv; +{ + int i, j, jmax; + static char *from_outside; + static char *from_inside; + static char *argv_to_target[][2] = { + {NULL, "${OUTPUT_FORMAT}"}, + {"-b32", "${OUTPUT_FORMAT_32BIT}"}, + {"-b64", "${OUTPUT_FORMAT_64BIT}"}, + }; + + jmax = 3; + + from_outside = getenv (TARGET_ENVIRON); + if (from_outside != (char *) NULL) + return from_outside; + + /* Set to default. */ + from_inside = argv_to_target[0][1]; + for (i = 1; i < argc; i++) + { + for (j = 1; j < jmax; j++) + { + if (0 == strcmp (argv[i], argv_to_target[j][0])) + from_inside = argv_to_target[j][1]; + } + } + + return from_inside; } -/* Read an import or export file. */ +/* Returns + 1 : state changed + 0 : no change */ +static int +change_symbol_mode (input) + char *input; +{ + char *symbol_mode_string[] = { + "# 32", /* 0x01 */ + "# 64", /* 0x02 */ + "# no32", /* 0x04 */ + "# no64", /* 0x08 */ + NULL, + }; + + unsigned int bit; + char *string; + + for (bit = 0;; bit++) + { + string = symbol_mode_string[bit]; + if (string == NULL) + return 0; + + if (0 == strcmp (input, string)) + { + symbol_mode = (1 << bit); + return 1; + } + } + /* should not be here */ + return 0; +} + +/* Returns + 1 : yes + 0 : ignore + -1 : error, try something else */ +static int +is_syscall (input, flag) + char *input; + unsigned int *flag; +{ + unsigned int bit; + char *string; + + struct sc { + char *syscall_string; + unsigned int flag; + } s [] = { + { "svc" /* 0x01 */, XCOFF_SYSCALL32 }, + { "svc32" /* 0x02 */, XCOFF_SYSCALL32 }, + { "svc3264" /* 0x04 */, XCOFF_SYSCALL32 | XCOFF_SYSCALL64 }, + { "svc64" /* 0x08 */, XCOFF_SYSCALL64 }, + { "syscall" /* 0x10 */, XCOFF_SYSCALL32 }, + { "syscall32" /* 0x20 */, XCOFF_SYSCALL32 }, + { "syscall3264" /* 0x40 */, XCOFF_SYSCALL32 | XCOFF_SYSCALL64 }, + { "syscall64" /* 0x80 */, XCOFF_SYSCALL64 }, + { NULL, 0 }, + }; + + *flag = 0; + + for (bit = 0;; bit++) + { + string = s[bit].syscall_string; + if (string == NULL) + return -1; + + if (0 == strcmp (input, string)) + { + if (1 << bit & syscall_mask) + { + *flag = s[bit].flag; + return 1; + } + else + { + return 0; + } + } + } + /* should not be here */ + return -1; +} + +/* 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 gld${EMULATION_NAME}_read_file (filename, import) @@ -384,7 +953,7 @@ gld${EMULATION_NAME}_read_file (filename, import) o = (struct obstack *) xmalloc (sizeof (struct obstack)); obstack_specify_allocation (o, 0, 0, xmalloc, gld${EMULATION_NAME}_free); - f = fopen (filename, "r"); + f = fopen (filename, FOPEN_RT); if (f == NULL) { bfd_set_error (bfd_error_system_call); @@ -398,11 +967,19 @@ gld${EMULATION_NAME}_read_file (filename, import) impmember = NULL; lineno = 0; + + /* Default to 32 and 64 bit mode + symbols at top of /lib/syscalls.exp do not have a mode modifier and they + are not repeated, assume 64 bit routines also want to use them. + See the routine change_symbol_mode for more information. */ + + symbol_mode = 0x04; + while ((c = getc (f)) != EOF) { char *s; char *symname; - boolean syscall; + unsigned int syscall_flag = 0; bfd_vma address; struct bfd_link_hash_entry *h; @@ -416,12 +993,13 @@ gld${EMULATION_NAME}_read_file (filename, import) ++lineno; s = (char *) obstack_base (o); - while (isspace ((unsigned char) *s)) + while (ISSPACE (*s)) ++s; if (*s == '\0' || *s == '*' + || change_symbol_mode (s) || (*s == '#' && s[1] == ' ') - || (! import && *s == '#' && s[1] == '!')) + || (!import && *s == '#' && s[1] == '!')) { obstack_free (o, obstack_base (o)); continue; @@ -430,7 +1008,7 @@ gld${EMULATION_NAME}_read_file (filename, import) if (*s == '#' && s[1] == '!') { s += 2; - while (isspace ((unsigned char) *s)) + while (ISSPACE (*s)) ++s; if (*s == '\0') { @@ -440,7 +1018,7 @@ gld${EMULATION_NAME}_read_file (filename, import) obstack_free (o, obstack_base (o)); } else if (*s == '(') - einfo ("%F%s%d: #! ([member]) is not supported in import files", + einfo ("%F%s%d: #! ([member]) is not supported in import files\n", filename, lineno); else { @@ -450,8 +1028,8 @@ gld${EMULATION_NAME}_read_file (filename, import) (void) obstack_finish (o); keep = true; imppath = s; - impfile = NULL; - while (! isspace ((unsigned char) *s) && *s != '(' && *s != '\0') + file = NULL; + while (!ISSPACE (*s) && *s != '(' && *s != '\0') { if (*s == '/') file = s + 1; @@ -471,7 +1049,7 @@ gld${EMULATION_NAME}_read_file (filename, import) } cs = *s; *s = '\0'; - while (isspace ((unsigned char) cs)) + while (ISSPACE (cs)) { ++s; cs = *s; @@ -500,72 +1078,88 @@ gld${EMULATION_NAME}_read_file (filename, import) 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') + if (symbol_mode & symbol_mode_mask) { - char *se; - - *s++ = '\0'; + /* This is a symbol to be imported or exported. */ + symname = s; + syscall_flag = 0; + address = (bfd_vma) -1; - while (isspace ((unsigned char) *s)) + while (!ISSPACE (*s) && *s != '\0') ++s; - - se = s; - while (! isspace ((unsigned char) *se) && *se != '\0') - ++se; - if (*se != '\0') + if (*s != '\0') { - *se++ = '\0'; - while (isspace ((unsigned char) *se)) + char *se; + + *s++ = '\0'; + + while (ISSPACE (*s)) + ++s; + + se = s; + while (!ISSPACE (*se) && *se != '\0') ++se; if (*se != '\0') - einfo ("%s%d: warning: syntax error in import/export file\n", - filename, lineno); + { + *se++ = '\0'; + while (ISSPACE (*se)) + ++se; + if (*se != '\0') + einfo ("%s%d: warning: syntax error in import/export file\n", + filename, lineno); + } + + if (s != se) + { + int status; + char *end; + + status = is_syscall (s, &syscall_flag); + + if (0 > status) + { + /* not a system call, check for address */ + address = strtoul (s, &end, 0); + if (*end != '\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; + if (!import) + { + 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 = xstrdup (symname); + export_symbols = n; + } 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. */ + } + else + { + if (!bfd_xcoff_import_symbol (output_bfd, &link_info, h, + address, imppath, impfile, + impmember, syscall_flag)) + einfo ("%X%s:%d: failed to import 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. */ - 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)); } @@ -576,7 +1170,7 @@ gld${EMULATION_NAME}_read_file (filename, import) obstack_free (o, obstack_base (o)); } - if (! keep) + if (!keep) { obstack_free (o, NULL); free (o); @@ -592,8 +1186,78 @@ gld${EMULATION_NAME}_free (p) 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 +gld${EMULATION_NAME}_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) + gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); +} + +/* Look through an expression for an assignment statement. */ + +static void +gld${EMULATION_NAME}_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); + } + 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 char * -gld${EMULATION_NAME}_get_script(isfile) +gld${EMULATION_NAME}_get_script (isfile) int *isfile; EOF @@ -602,31 +1266,31 @@ then # Scripts compiled in. # sed commands to quote an ld script as a C string. -sc="-f ${srcdir}/emultempl/stringify.sed" +sc="-f ${srcdir}/emultempl/ostring.sed" cat >>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xu >> 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 +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 <the_bfd = bfd_create ("initfini", output_bfd); + if (initfini_file->the_bfd == NULL + || ! bfd_set_arch_mach (initfini_file->the_bfd, + bfd_get_arch (output_bfd), + bfd_get_mach (output_bfd))) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + + /* Call backend to fill in the rest */ + if (false == bfd_xcoff_link_generate_rtinit (initfini_file->the_bfd, + link_info.init_function, + link_info.fini_function, + rtld)) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + + /* __rtld defined in /lib/librtl.a */ + if (true == rtld) + lang_add_input_file ("rtl", lang_input_file_is_l_enum, NULL); + } +} + +static void +gld${EMULATION_NAME}_set_output_arch () +{ + bfd_set_arch_mach (output_bfd, + bfd_xcoff_architecture (output_bfd), + bfd_xcoff_machine (output_bfd)); + + ldfile_output_architecture = bfd_get_arch (output_bfd); + ldfile_output_machine = bfd_get_mach (output_bfd); + ldfile_output_machine_name = bfd_printable_name (output_bfd); +} + +struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { gld${EMULATION_NAME}_before_parse, syslib_default, hll_default, after_parse_default, - after_open_default, + gld${EMULATION_NAME}_after_open, after_allocation_default, - set_output_arch_default, - ldemul_default_target, + gld${EMULATION_NAME}_set_output_arch, + gld${EMULATION_NAME}_choose_target, gld${EMULATION_NAME}_before_allocation, gld${EMULATION_NAME}_get_script, "${EMULATION_NAME}", "${OUTPUT_FORMAT}", - 0, /* finish */ - 0, /* create_output_section_statements */ - 0, /* open_dynamic_archive */ - 0, /* place_orphan */ - 0, /* set_symbols */ + 0, /* finish */ + gld${EMULATION_NAME}_create_output_section_statements, + 0, /* open_dynamic_archive */ + 0, /* place_orphan */ + 0, /* set_symbols */ gld${EMULATION_NAME}_parse_args, + gld${EMULATION_NAME}_unrecognized_file, + NULL, /* list_options */ + NULL, /* recognized_file */ + NULL, /* find potential_libraries */ + NULL /* new_vers_pattern */ }; EOF