/* Copyright (C) 2001-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. Red Hat elfutils 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; version 2 of the License. Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. Red Hat elfutils is an included package of the Open Invention Network. An included package of the Open Invention Network is a package for which Open Invention Network licensees cross-license their patents. No patent license is granted, either expressly or impliedly, by designation as an included package. Should you wish to participate in the Open Invention Network licensing program, please visit www.openinventionnetwork.com . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ld.h" #include "list.h" /* Name and version of program. */ static void print_version (FILE *stream, struct argp_state *state); ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the various options. */ enum { ARGP_whole_archive = 300, ARGP_no_whole_archive, ARGP_static, ARGP_dynamic, ARGP_pagesize, ARGP_rpath_link, ARGP_runpath, ARGP_runpath_link, ARGP_version_script, ARGP_gc_sections, ARGP_no_gc_sections, ARGP_no_undefined, ARGP_conserve, ARGP_as_needed, ARGP_no_as_needed, ARGP_eh_frame_hdr, ARGP_hash_style, ARGP_build_id, #if YYDEBUG ARGP_yydebug, #endif }; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { { NULL, 0, NULL, 0, N_("Input File Control:"), 0 }, { "whole-archive", ARGP_whole_archive, NULL, 0, N_("Include whole archives in the output from now on."), 0 }, { "no-whole-archive", ARGP_no_whole_archive, NULL, 0, N_("Stop including the whole archives in the output."), 0 }, { NULL, 'l', N_("FILE"), OPTION_HIDDEN, NULL, 0 }, { "start-group", '(', NULL, 0, N_("Start a group."), 0 }, { "end-group", ')', NULL, 0, N_("End a group."), 0 }, { NULL, 'L', N_("PATH"), 0, N_("Add PATH to list of directories files are searched in."), 0 }, { "as-needed", ARGP_as_needed, NULL, 0, N_("Only set DT_NEEDED for following dynamic libs if actually used"), 0 }, { "no-as-needed", ARGP_no_as_needed, NULL, 0, N_("Always set DT_NEEDED for following dynamic libs"), 0 }, { "rpath-link", ARGP_rpath_link, "PATH", OPTION_HIDDEN, NULL, 0 }, { NULL, 'i', NULL, 0, N_("Ignore LD_LIBRARY_PATH environment variable."), 0 }, { NULL, 0, NULL, 0, N_("Output File Control:"), 0 }, { "output", 'o', N_("FILE"), 0, N_("Place output in FILE."), 0 }, { NULL, 'z', "KEYWORD", OPTION_HIDDEN, NULL, 0 }, { "-z nodefaultlib", '\0', NULL, OPTION_DOC, N_("Object is marked to not use default search path at runtime."), 0 }, { "-z allextract", '\0', NULL, OPTION_DOC, N_("Same as --whole-archive."), 0 }, { "-z defaultextract", '\0', NULL, OPTION_DOC, N_("\ Default rules of extracting from archive; weak references are not enough."), 0 }, { "-z weakextract", '\0', NULL, OPTION_DOC, N_("Weak references cause extraction from archive."), 0 }, { "-z muldefs", '\0', NULL, OPTION_DOC, N_("Allow multiple definitions; first is used."), 0 }, { "-z defs | nodefs", '\0', NULL, OPTION_DOC, N_("Disallow/allow undefined symbols in DSOs."), 0 }, { "no-undefined", ARGP_no_undefined, NULL, OPTION_HIDDEN, NULL, 0 }, { "-z origin", '\0', NULL, OPTION_DOC, N_("Object requires immediate handling of $ORIGIN."), 0 }, { "-z now", '\0', NULL, OPTION_DOC, N_("Relocation will not be processed lazily."), 0 }, { "-z nodelete", '\0', NULL, OPTION_DOC, N_("Object cannot be unloaded at runtime."), 0 }, { "-z initfirst", '\0', NULL, OPTION_DOC, N_("Mark object to be initialized first."), 0 }, { "-z lazyload | nolazyload", '\0', NULL, OPTION_DOC, N_("Enable/disable lazy-loading flag for following dependencies."), 0 }, { "-z nodlopen", '\0', NULL, OPTION_DOC, N_("Mark object as not loadable with 'dlopen'."), 0 }, { "-z ignore | record", '\0', NULL, OPTION_DOC, N_("Ignore/record dependencies on unused DSOs."), 0 }, { "-z systemlibrary", '\0', NULL, OPTION_DOC, N_("Generated DSO will be a system library."), 0 }, { "entry", 'e', N_("ADDRESS"), 0, N_("Set entry point address."), 0 }, { "static", ARGP_static, NULL, OPTION_HIDDEN, NULL, 0 }, { "-B static", ARGP_static, NULL, OPTION_DOC, N_("Do not link against shared libraries."), 0 }, { "dynamic", ARGP_dynamic, NULL, OPTION_HIDDEN, NULL, 0 }, { "-B dynamic", ARGP_dynamic, NULL, OPTION_DOC, N_("Prefer linking against shared libraries."), 0 }, { "export-dynamic", 'E', NULL, 0, N_("Export all dynamic symbols."), 0 }, { "strip-all", 's', NULL, 0, N_("Strip all symbols."), 0 }, { "strip-debug", 'S', NULL, 0, N_("Strip debugging symbols."), 0 }, { "pagesize", ARGP_pagesize, "SIZE", 0, N_("Assume pagesize for the target system to be SIZE."), 0 }, { "rpath", 'R', "PATH", OPTION_HIDDEN, NULL, 0 }, { "runpath", ARGP_runpath, "PATH", 0, N_("Set runtime DSO search path."), 0 }, { "runpath-link", ARGP_runpath_link, "PATH", 0, N_("Set link time DSO search path."), 0 }, { "shared", 'G', NULL, 0, N_("Generate dynamic shared object."), 0 }, { NULL, 'r', NULL, 0L, N_("Generate relocatable object."), 0 }, { NULL, 'B', "KEYWORD", OPTION_HIDDEN, "", 0 }, { "-B local", 'B', NULL, OPTION_DOC, N_("Causes symbol not assigned to a version be reduced to local."), 0 }, { "gc-sections", ARGP_gc_sections, NULL, 0, N_("Remove unused sections."), 0 }, { "no-gc-sections", ARGP_no_gc_sections, NULL, 0, N_("Don't remove unused sections."), 0 }, { "soname", 'h', "NAME", 0, N_("Set soname of shared object."), 0 }, { "dynamic-linker", 'I', "NAME", 0, N_("Set the dynamic linker name."), 0 }, { NULL, 'Q', "YN", OPTION_HIDDEN, NULL, 0 }, { "-Q y | n", 'Q', NULL, OPTION_DOC, N_("Add/suppress addition indentifying link-editor to .comment section."), 0 }, { "eh-frame-hdr", ARGP_eh_frame_hdr, NULL, 0, N_("Create .eh_frame_hdr section"), 0 }, { "hash-style", ARGP_hash_style, "STYLE", 0, N_("Set hash style to sysv, gnu or both."), 0 }, { "build-id", ARGP_build_id, "STYLE", OPTION_ARG_OPTIONAL, N_("Generate build ID note (md5, sha1 (default), uuid)."), 0 }, { NULL, 0, NULL, 0, N_("Linker Operation Control:"), 0 }, { "verbose", 'v', NULL, 0, N_("Verbose messages."), 0 }, { "trace", 't', NULL, 0, N_("Trace file opens."), 0 }, { "conserve-memory", ARGP_conserve, NULL, 0, N_("Trade speed for less memory usage"), 0 }, { NULL, 'O', N_("LEVEL"), OPTION_ARG_OPTIONAL, N_("Set optimization level to LEVEL."), 0 }, { NULL, 'c', N_("FILE"), 0, N_("Use linker script in FILE."), 0 }, #if YYDEBUG { "yydebug", ARGP_yydebug, NULL, 0, N_("Select to get parser debug information"), 0 }, #endif { "version-script", ARGP_version_script, "FILE", 0, N_("Read version information from FILE."), 0 }, { "emulation", 'm', "NAME", 0, N_("Set emulation to NAME."), 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; /* Short description of program. */ static const char doc[] = N_("Combine object and archive files."); /* Strings for arguments in help texts. */ static const char args_doc[] = N_("[FILE]..."); /* Prototype for option handler. */ static void replace_args (int argc, char *argv[]); static error_t parse_opt_1st (int key, char *arg, struct argp_state *state); static error_t parse_opt_2nd (int key, char *arg, struct argp_state *state); /* Data structure to communicate with argp functions. */ static struct argp argp_1st = { options, parse_opt_1st, args_doc, doc, NULL, NULL, NULL }; static struct argp argp_2nd = { options, parse_opt_2nd, args_doc, doc, NULL, NULL, NULL }; /* Linker state. This contains all global information. */ struct ld_state ld_state; /* List of the input files. */ static struct file_list { const char *name; struct file_list *next; } *input_file_list; /* If nonzero be verbose. */ int verbose; /* If nonzero, trade speed for less memory/address space usage. */ int conserve_memory; /* The emulation name to use. */ static const char *emulation; /* Keep track of the nesting level. Even though we don't handle nested groups we still keep track to improve the error messages. */ static int group_level; /* The last file we processed. */ static struct usedfiles *last_file; /* The default linker script. */ /* XXX We'll do this a bit different in the real solution. */ static const char *linker_script = SRCDIR "/elf32-i386.script"; /* Nonzero if an error occurred while loading the input files. */ static int error_loading; /* Intermediate storage for the LD_LIBRARY_PATH information from the environment. */ static char *ld_library_path1; /* Flag used to communicate with the scanner. */ int ld_scan_version_script; /* Name of the input file. */ const char *ldin_fname; /* Define by parser if required. */ extern int lddebug; /* Prototypes for local functions. */ static void parse_z_option (const char *arg); static void parse_z_option_2 (const char *arg); static void parse_B_option (const char *arg); static void parse_B_option_2 (const char *arg); static void determine_output_format (void); static void load_needed (void); static void collect_sections (void); static void add_rxxpath (struct pathelement **pathp, const char *str); static void gen_rxxpath_data (void); static void read_version_script (const char *fname); static void create_lscript_symbols (void); static void create_special_section_symbol (struct symbol **symp, const char *name); int main (int argc, char *argv[]) { int remaining; int err; #ifndef NDEBUG /* Enable memory debugging. */ mtrace (); #endif /* Sanity check. We always want to use the LFS functionality. */ if (sizeof (off_t) != sizeof (off64_t)) abort (); /* We use no threads here which can interfere with handling a stream. */ __fsetlocking (stdin, FSETLOCKING_BYCALLER); __fsetlocking (stdout, FSETLOCKING_BYCALLER); __fsetlocking (stderr, FSETLOCKING_BYCALLER); /* Set locale. */ setlocale (LC_ALL, ""); /* Make sure the message catalog can be found. */ bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); /* Initialize the message catalog. */ textdomain (PACKAGE_TARNAME); /* Before we start tell the ELF library which version we are using. */ elf_version (EV_CURRENT); /* The user can use the LD_LIBRARY_PATH environment variable to add additional lookup directories. */ ld_library_path1 = getenv ("LD_LIBRARY_PATH"); /* Initialize the memory handling. */ #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free obstack_init (&ld_state.smem); /* Recognize old-style parameters for compatibility. */ replace_args (argc, argv); /* One quick pass over the parameters which allows us to scan for options with global effect which influence the rest of the processing. */ argp_parse (&argp_1st, argc, argv, ARGP_IN_ORDER, &remaining, NULL); /* We need at least one input file. */ if (input_file_list == NULL) { error (0, 0, gettext ("At least one input file needed")); argp_help (&argp_1st, stderr, ARGP_HELP_SEE, "ld"); exit (EXIT_FAILURE); } /* Determine which ELF backend to use. */ determine_output_format (); /* If no hash style was specific default to the oldand slow SysV method. */ if (unlikely (ld_state.hash_style == hash_style_none)) ld_state.hash_style = hash_style_sysv; /* Prepare state. */ err = ld_prepare_state (emulation); if (err != 0) error (EXIT_FAILURE, 0, gettext ("error while preparing linking")); /* XXX Read the linker script now. Since we later will have the linker script built in we don't go into trouble to make sure we handle GROUP statements in the script. This simply must not happen. */ ldin = fopen (linker_script, "r"); if (ldin == NULL) error (EXIT_FAILURE, errno, gettext ("cannot open linker script '%s'"), linker_script); /* No need for locking. */ __fsetlocking (ldin, FSETLOCKING_BYCALLER); ld_state.srcfiles = NULL; ldlineno = 1; ld_scan_version_script = 0; ldin_fname = linker_script; if (ldparse () != 0) /* Something went wrong during parsing. */ exit (EXIT_FAILURE); fclose (ldin); /* We now might have a list of directories to look for libraries in named by the linker script. Put them in a different list so that they are searched after all paths given by the user on the command line. */ ld_state.default_paths = ld_state.paths; ld_state.paths = ld_state.tailpaths = NULL; /* Get runpath/rpath information in usable form. */ gen_rxxpath_data (); /* Parse and process arguments for real. */ argp_parse (&argp_2nd, argc, argv, ARGP_IN_ORDER, &remaining, NULL); /* All options should have been processed by the argp parser. */ assert (remaining == argc); /* Process the last file. */ while (last_file != NULL) /* Try to open the file. */ error_loading |= FILE_PROCESS (-1, last_file, &ld_state, &last_file); /* Stop if there has been a problem while reading the input files. */ if (error_loading) exit (error_loading); /* See whether all opened -( were closed. */ if (group_level > 0) { error (0, 0, gettext ("-( without matching -)")); argp_help (&argp_1st, stderr, ARGP_HELP_SEE, "ld"); exit (EXIT_FAILURE); } /* When we create a relocatable file we don't have to look for the DT_NEEDED DSOs and we also don't test for undefined symbols. */ if (ld_state.file_type != relocatable_file_type) { /* At this point we have loaded all the direct dependencies. What remains to be done is find the indirect dependencies. These are DSOs which are referenced by the DT_NEEDED entries in the DSOs which are direct dependencies. We have to transitively find and load all these dependencies. */ load_needed (); /* At this point all object files and DSOs are read. If there are still undefined symbols left they might have to be synthesized from the linker script. */ create_lscript_symbols (); /* Now that we have loaded all the object files we can determine whether we have any non-weak unresolved references left. If there are any we stop. If the user used the '-z nodefs' option and we are creating a DSO don't perform the tests. */ if (FLAG_UNRESOLVED (&ld_state) != 0) exit (1); } /* Collect information about the relocations which will be carried forward into the output. We have to do this here and now since we need to know which sections have to be created. */ if (ld_state.file_type != relocatable_file_type) { void *p ; struct scnhead *h; p = NULL; while ((h = ld_section_tab_iterate (&ld_state.section_tab, &p)) != NULL) if (h->type == SHT_REL || h->type == SHT_RELA) { struct scninfo *runp = h->last; do { /* If we are processing the relocations determine how many will be in the output file. Also determine how many GOT entries are needed. */ COUNT_RELOCATIONS (&ld_state, runp); ld_state.relsize_total += runp->relsize; } while ((runp = runp->next) != h->last); } } /* Not part of the gABI, but part of every psABI: the symbols for the GOT section. Add the symbol if necessary. */ if (ld_state.need_got) create_special_section_symbol (&ld_state.got_symbol, "_GLOBAL_OFFSET_TABLE_"); /* Similarly for the _DYNAMIC symbol which points to the dynamic section. */ if (dynamically_linked_p ()) create_special_section_symbol (&ld_state.dyn_symbol, "_DYNAMIC"); /* We are ready to start working on the output file. Not all information has been gather or created yet. This will be done as we go. Open the file now. */ if (OPEN_OUTFILE (&ld_state, EM_NONE, ELFCLASSNONE, ELFDATANONE) != 0) exit (1); /* Create the sections which are generated by the linker and are not present in the input file. The output file must already have been opened since we need the ELF descriptor to deduce type sizes. */ GENERATE_SECTIONS (&ld_state); /* At this point we have read all the files and know all the sections which have to be linked into the application. We do now create an array listing all the sections. We will than pass this array to a system specific function which can reorder it at will. The functions can also merge sections if this is what is wanted. */ collect_sections (); /* Create the output sections now. This may requires sorting them first. */ CREATE_SECTIONS (&ld_state); /* Create the output file data. Appropriate code for the selected output file type is called. */ if (CREATE_OUTFILE (&ld_state) != 0) exit (1); /* Finalize the output file, write the data out. */ err |= FINALIZE (&ld_state); /* Return with an non-zero exit status also if any error message has been printed. */ return err | (error_message_count != 0); } static void replace_args (int argc, char *argv[]) { static const struct { const char *from; const char *to; } args[] = { { "-export-dynamic", "--export-dynamic" }, { "-dynamic-linker", "--dynamic-linker" }, { "-static", "--static" }, }; const size_t nargs = sizeof (args) / sizeof (args[0]); for (int i = 1; i < argc; ++i) if (argv[i][0] == '-' && islower (argv[i][1]) && argv[i][2] != '\0') for (size_t j = 0; j < nargs; ++j) if (strcmp (argv[i], args[j].from) == 0) { argv[i] = (char *) args[j].to; break; } } static int valid_hexarg (const char *arg) { if (strncasecmp (arg, "0x", 2) != 0) return 0; arg += 2; do { if (isxdigit (arg[0]) && isxdigit (arg[1])) { arg += 2; if (arg[0] == '-' || arg[0] == ':') ++arg; } else return 0; } while (*arg != '\0'); return 1; } /* Quick scan of the parameter list for options with global effect. */ static error_t parse_opt_1st (int key, char *arg, struct argp_state *state __attribute__ ((unused))) { switch (key) { case 'B': parse_B_option (arg); break; case 'c': linker_script = arg; break; case 'E': ld_state.export_all_dynamic = true; break; case 'G': if (ld_state.file_type != no_file_type) error (EXIT_FAILURE, 0, gettext ("only one option of -G and -r is allowed")); ld_state.file_type = dso_file_type; /* If we generate a DSO we have to export all symbols. */ ld_state.export_all_dynamic = true; break; case 'h': ld_state.soname = arg; break; case 'i': /* Discard the LD_LIBRARY_PATH value we found. */ ld_library_path1 = NULL; break; case 'I': ld_state.interp = arg; break; case 'm': if (emulation != NULL) error (EXIT_FAILURE, 0, gettext ("more than one '-m' parameter")); emulation = arg; break; case 'Q': if (arg[1] == '\0' && (arg[0] == 'y' || arg[0] == 'Y')) ld_state.add_ld_comment = true; else if (arg[1] == '\0' && (arg[0] == 'n' || arg[0] == 'N')) ld_state.add_ld_comment = true; else error (EXIT_FAILURE, 0, gettext ("unknown option `-%c %s'"), 'Q', arg); break; case 'r': if (ld_state.file_type != no_file_type) error (EXIT_FAILURE, 0, gettext ("only one option of -G and -r is allowed")); ld_state.file_type = relocatable_file_type; break; case 'S': ld_state.strip = strip_debug; break; case 't': ld_state.trace_files = true; break; case 'v': verbose = 1; break; case 'z': /* The SysV linker used 'z' to pass various flags to the linker. We follow this. See 'parse_z_option' for the options we recognize. */ parse_z_option (arg); break; case ARGP_pagesize: { char *endp; ld_state.pagesize = strtoul (arg, &endp, 0); if (*endp != '\0') { if (endp[1] == '\0' && tolower (*endp) == 'k') ld_state.pagesize *= 1024; else if (endp[1] == '\0' && tolower (*endp) == 'm') ld_state.pagesize *= 1024 * 1024; else { error (0, 0, gettext ("invalid page size value '%s': ignored"), arg); ld_state.pagesize = 0; } } } break; case 'R': add_rxxpath (&ld_state.rpath, arg); break; case ARGP_rpath_link: add_rxxpath (&ld_state.rpath_link, arg); break; case ARGP_runpath: add_rxxpath (&ld_state.runpath, arg); break; case ARGP_runpath_link: add_rxxpath (&ld_state.runpath_link, arg); break; case ARGP_gc_sections: case ARGP_no_gc_sections: ld_state.gc_sections = key == ARGP_gc_sections; break; case ARGP_eh_frame_hdr: ld_state.eh_frame_hdr = true; break; case ARGP_hash_style: if (strcmp (arg, "gnu") == 0) ld_state.hash_style = hash_style_gnu; else if (strcmp (arg, "both") == 0) ld_state.hash_style = hash_style_gnu | hash_style_sysv; else if (strcmp (arg, "sysv") == 0) ld_state.hash_style = hash_style_sysv; else error (EXIT_FAILURE, 0, gettext ("invalid hash style '%s'"), arg); break; case ARGP_build_id: if (arg == NULL) ld_state.build_id = "sha1"; else if (strcmp (arg, "uuid") != 0 && strcmp (arg, "md5") != 0 && strcmp (arg, "sha1") != 0 && !valid_hexarg (arg)) error (EXIT_FAILURE, 0, gettext ("invalid build-ID style '%s'"), arg); else ld_state.build_id = arg; break; case 's': if (arg == NULL) { if (ld_state.strip == strip_all) ld_state.strip = strip_everything; else ld_state.strip = strip_all; break; } /* FALLTHROUGH */ case 'e': case 'o': case 'O': case ARGP_whole_archive: case ARGP_no_whole_archive: case ARGP_as_needed: case ARGP_no_as_needed: case 'L': case '(': case ')': case 'l': case ARGP_static: case ARGP_dynamic: case ARGP_version_script: /* We'll handle these in the second pass. */ break; case ARGP_KEY_ARG: { struct file_list *newp; newp = (struct file_list *) xmalloc (sizeof (struct file_list)); newp->name = arg; #ifndef NDEBUG newp->next = NULL; #endif CSNGL_LIST_ADD_REAR (input_file_list, newp); } break; #if YYDEBUG case ARGP_yydebug: lddebug = 1; break; #endif case ARGP_no_undefined: ld_state.nodefs = false; break; case ARGP_conserve: conserve_memory = 1; break; default: return ARGP_ERR_UNKNOWN; } return 0; } /* Handle program arguments for real. */ static error_t parse_opt_2nd (int key, char *arg, struct argp_state *state __attribute__ ((unused))) { static bool group_start_requested; static bool group_end_requested; switch (key) { case 'B': parse_B_option_2 (arg); break; case 'e': ld_state.entry = arg; break; case 'o': if (ld_state.outfname != NULL) { error (0, 0, gettext ("More than one output file name given.")); see_help: argp_help (&argp_2nd, stderr, ARGP_HELP_SEE, "ld"); exit (EXIT_FAILURE); } ld_state.outfname = arg; break; case 'O': if (arg == NULL) ld_state.optlevel = 1; else { char *endp; unsigned long int level = strtoul (arg, &endp, 10); if (*endp != '\0') { error (0, 0, gettext ("Invalid optimization level `%s'"), arg); goto see_help; } ld_state.optlevel = level; } break; case ARGP_whole_archive: ld_state.extract_rule = allextract; break; case ARGP_no_whole_archive: ld_state.extract_rule = defaultextract; break; case ARGP_as_needed: ld_state.as_needed = true; break; case ARGP_no_as_needed: ld_state.as_needed = false; break; case ARGP_static: case ARGP_dynamic: /* Enable/disable use for DSOs. */ ld_state.statically = key == ARGP_static; break; case 'z': /* The SysV linker used 'z' to pass various flags to the linker. We follow this. See 'parse_z_option' for the options we recognize. */ parse_z_option_2 (arg); break; case ARGP_version_script: read_version_script (arg); break; case 'L': /* Add a new search directory. */ ld_new_searchdir (arg); break; case '(': /* Start a link group. We have to be able to determine the object file which is named next. Do this by remembering a pointer to the pointer which will point to the next object. */ if (verbose && (group_start_requested || !group_end_requested)) error (0, 0, gettext ("nested -( -) groups are not allowed")); /* Increment the nesting level. */ ++group_level; /* Record group start. */ group_start_requested = true; group_end_requested = false; break; case ')': /* End a link group. If there is no group open this is clearly a bug. If there is a group open insert a back reference pointer in the record for the last object of the group. If there is no new object or just one don't do anything. */ if (!group_end_requested) { if (group_level == 0) { error (0, 0, gettext ("-) without matching -(")); goto see_help; } } else last_file->group_end = true; if (group_level > 0) --group_level; break; case 'l': case ARGP_KEY_ARG: { while (last_file != NULL) /* Try to open the file. */ error_loading |= FILE_PROCESS (-1, last_file, &ld_state, &last_file); last_file = ld_new_inputfile (arg, key == 'l' ? archive_file_type : relocatable_file_type); if (group_start_requested) { last_file->group_start = true; group_start_requested = false; group_end_requested = true; } } break; default: /* We can catch all other options here. They either have already been handled or, if the parameter was not correct, the error has been reported. */ break; } return 0; } /* Load all the DSOs named as dependencies in other DSOs we already loaded. */ static void load_needed (void) { struct usedfiles *first; struct usedfiles *runp; /* XXX There is one problem here: do we allow references from regular object files to be satisfied by these implicit dependencies? The old linker allows this and several libraries depend on this. Solaris' linker does not allow this; it provides the user with a comprehensive error message explaining the situation. XXX IMO the old ld behavior is correct since this is also how the dynamic linker will work. It will look for unresolved references in all loaded DSOs. XXX Should we add an option to get Solaris compatibility? */ if (ld_state.needed == NULL) return; runp = first = ld_state.needed->next; do { struct usedfiles *ignore; struct usedfiles *next = runp->next; int err; err = FILE_PROCESS (-1, runp, &ld_state, &ignore); if (err != 0) /* Something went wrong. */ exit (err); runp = next; } while (runp != first); } /* Print the version information. */ static void print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) { fprintf (stream, "ld (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); fprintf (stream, gettext ("\ Copyright (C) %s Red Hat, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ "), "2009"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } /* There are a lot of -z options, parse them here. Some of them have to be parsed in the first pass, others must be handled in the second pass. */ static void parse_z_option (const char *arg) { if (strcmp (arg, "nodefaultlib") == 0 /* This is only meaningful if we create a DSO. */ && ld_state.file_type == dso_file_type) ld_state.dt_flags_1 |= DF_1_NODEFLIB; else if (strcmp (arg, "muldefs") == 0) ld_state.muldefs = true; else if (strcmp (arg, "nodefs") == 0) ld_state.nodefs = true; else if (strcmp (arg, "defs") == 0) ld_state.nodefs = false; else if (strcmp (arg, "now") == 0) /* We could also set the DF_1_NOW flag in DT_FLAGS_1 but this isn't necessary. */ ld_state.dt_flags |= DF_BIND_NOW; else if (strcmp (arg, "origin") == 0) /* We could also set the DF_1_ORIGIN flag in DT_FLAGS_1 but this isn't necessary. */ ld_state.dt_flags |= DF_ORIGIN; else if (strcmp (arg, "nodelete") == 0 /* This is only meaningful if we create a DSO. */ && ld_state.file_type == dso_file_type) ld_state.dt_flags_1 |= DF_1_NODELETE; else if (strcmp (arg, "initfirst") == 0) ld_state.dt_flags_1 |= DF_1_INITFIRST; else if (strcmp (arg, "nodlopen") == 0 /* This is only meaningful if we create a DSO. */ && ld_state.file_type == dso_file_type) ld_state.dt_flags_1 |= DF_1_NOOPEN; else if (strcmp (arg, "systemlibrary") == 0) ld_state.is_system_library = true; else if (strcmp (arg, "execstack") == 0) ld_state.execstack = execstack_true; else if (strcmp (arg, "noexecstack") == 0) ld_state.execstack = execstack_false_force; else if (strcmp (arg, "allextract") != 0 && strcmp (arg, "defaultextract") != 0 && strcmp (arg, "weakextract") != 0 && strcmp (arg, "lazyload") != 0 && strcmp (arg, "nolazyload") != 0 && strcmp (arg, "ignore") != 0 && strcmp (arg, "record") != 0) error (0, 0, gettext ("unknown option `-%c %s'"), 'z', arg); } static void parse_z_option_2 (const char *arg) { if (strcmp (arg, "allextract") == 0) ld_state.extract_rule = allextract; else if (strcmp (arg, "defaultextract") == 0) ld_state.extract_rule = defaultextract; else if (strcmp (arg, "weakextract") == 0) ld_state.extract_rule = weakextract; else if (strcmp (arg, "lazyload") == 0) ld_state.lazyload = true; else if (strcmp (arg, "nolazyload") == 0) ld_state.lazyload = false; else if (strcmp (arg, "ignore") == 0) ld_state.as_needed = true; else if (strcmp (arg, "record") == 0) ld_state.as_needed = false; } /* There are a lot of -B options, parse them here. */ static void parse_B_option (const char *arg) { if (strcmp (arg, "local") == 0) ld_state.default_bind_local = true; else if (strcmp (arg, "symbolic") != 0 && strcmp (arg, "static") != 0 && strcmp (arg, "dynamic") != 0) error (0, 0, gettext ("unknown option '-%c %s'"), 'B', arg); } /* The same functionality, but called in the second pass over the parameters. */ static void parse_B_option_2 (const char *arg) { if (strcmp (arg, "static") == 0) ld_state.statically = true; else if (strcmp (arg, "dynamic") == 0) ld_state.statically = false; else if (strcmp (arg, "symbolic") == 0 /* This is only meaningful if we create a DSO. */ && ld_state.file_type == dso_file_type) ld_state.dt_flags |= DF_SYMBOLIC; } static void determine_output_format (void) { /* First change the 'input_file_list' variable in a simple single-linked list. */ struct file_list *last = input_file_list; input_file_list = input_file_list->next; last->next = NULL; /* Determine the target configuration which we are supposed to use. The user can use the '-m' option to select one. If this is missing we are trying to load one file and determine the architecture from that. */ if (emulation != NULL) { ld_state.ebl = ebl_openbackend_emulation (emulation); assert (ld_state.ebl != NULL); } else { /* Find an ELF input file and let it determine the ELf backend. */ struct file_list *runp = input_file_list; while (runp != NULL) { int fd = open (runp->name, O_RDONLY); if (fd != -1) { int try (Elf *elf) { int result = 0; if (elf == NULL) return 0; if (elf_kind (elf) == ELF_K_ELF) { /* We have an ELF file. We now can find out what the output format should be. */ XElf_Ehdr_vardef(ehdr); /* Get the ELF header of the object. */ xelf_getehdr (elf, ehdr); if (ehdr != NULL) ld_state.ebl = ebl_openbackend_machine (ehdr->e_machine); result = 1; } else if (elf_kind (elf) == ELF_K_AR) { /* Try the archive members. This could potentially lead to wrong results if the archive contains files for more than one architecture. But this is the user's problem. */ Elf *subelf; Elf_Cmd cmd = ELF_C_READ_MMAP; while ((subelf = elf_begin (fd, cmd, elf)) != NULL) { cmd = elf_next (subelf); if (try (subelf) != 0) break; } } elf_end (elf); return result; } if (try (elf_begin (fd, ELF_C_READ_MMAP, NULL)) != 0) /* Found a file. */ break; } runp = runp->next; } if (ld_state.ebl == NULL) { error (0, 0, gettext ("\ could not find input file to determine output file format")); error (EXIT_FAILURE, 0, gettext ("\ try again with an appropriate '-m' parameter")); } } /* We don't need the list of input files anymore. The second run over the parameters will handle them. */ while (input_file_list != NULL) { struct file_list *oldp = input_file_list; input_file_list = input_file_list->next; free (oldp); } /* We also know now what kind of file we are supposed to create. If the user hasn't selected anythign we create and executable. */ if (ld_state.file_type == no_file_type) ld_state.file_type = executable_file_type; } /* Add DIR to the list of directories searched for object files and libraries. */ void ld_new_searchdir (const char *dir) { struct pathelement *newpath; newpath = (struct pathelement *) obstack_calloc (&ld_state.smem, sizeof (struct pathelement)); newpath->pname = dir; /* Enqueue the file. */ if (ld_state.tailpaths == NULL) ld_state.paths = ld_state.tailpaths = newpath->next = newpath; else { ld_state.tailpaths->next = newpath; ld_state.tailpaths = newpath; newpath->next = ld_state.paths; } } struct usedfiles * ld_new_inputfile (const char *fname, enum file_type type) { struct usedfiles *newfile = (struct usedfiles *) obstack_calloc (&ld_state.smem, sizeof (struct usedfiles)); newfile->soname = newfile->fname = newfile->rfname = fname; newfile->file_type = type; newfile->extract_rule = ld_state.extract_rule; newfile->as_needed = ld_state.as_needed; newfile->lazyload = ld_state.lazyload; newfile->status = not_opened; return newfile; } /* Create an array listing all the sections. We will than pass this array to a system specific function which can reorder it at will. The functions can also merge sections if this is what is wanted. */ static void collect_sections (void) { void *p ; struct scnhead *h; size_t cnt; /* We have that many sections. At least for now. */ ld_state.nallsections = ld_state.section_tab.filled; /* Allocate the array. We allocate one more entry than computed so far since we might need a new section for the copy relocations. */ ld_state.allsections = (struct scnhead **) obstack_alloc (&ld_state.smem, (ld_state.nallsections + 1) * sizeof (struct scnhead *)); /* Fill the array. We rely here on the hash table iterator to return the entries in the order they were added. */ cnt = 0; p = NULL; while ((h = ld_section_tab_iterate (&ld_state.section_tab, &p)) != NULL) { struct scninfo *runp; bool used = false; if (h->kind == scn_normal) { runp = h->last; do { if (h->type == SHT_REL || h->type == SHT_RELA) { if (runp->used) /* This is a relocation section. If the section it is relocating is used in the result so must the relocation section. */ runp->used = runp->fileinfo->scninfo[SCNINFO_SHDR (runp->shdr).sh_info].used; } /* Accumulate the result. */ used |= runp->used; /* Next input section. */ runp = runp->next; } while (runp != h->last); h->used = used; } ld_state.allsections[cnt++] = h; } ld_state.nusedsections = cnt; assert (cnt == ld_state.nallsections); } /* Add given path to the end of list. */ static void add_rxxpath (struct pathelement **pathp, const char *str) { struct pathelement *newp; /* The path elements can in theory be freed after we read all the files. But the amount of memory we are talking about is small and the cost of free() calls is not neglectable. */ newp = (struct pathelement *) obstack_alloc (&ld_state.smem, sizeof (*newp)); newp->pname = str; newp->exist = 0; #ifndef NDEBUG newp->next = NULL; #endif CSNGL_LIST_ADD_REAR (*pathp, newp); } /* Convert lists of possibly colon-separated directory lists into lists where each entry is for a single directory. */ static void normalize_dirlist (struct pathelement **pathp) { struct pathelement *firstp = *pathp; do { const char *pname = (*pathp)->pname; const char *colonp = strchrnul (pname, ':'); if (colonp != NULL) { struct pathelement *lastp = *pathp; struct pathelement *newp; while (1) { if (colonp == pname) lastp->pname = "."; else lastp->pname = obstack_strndup (&ld_state.smem, pname, colonp - pname); if (*colonp == '\0') break; pname = colonp + 1; newp = (struct pathelement *) obstack_alloc (&ld_state.smem, sizeof (*newp)); newp->next = lastp->next; newp->exist = 0; lastp = lastp->next = newp; colonp = strchrnul (pname, ':'); } pathp = &lastp->next; } else pathp = &(*pathp)->next; } while (*pathp != firstp); } /* Called after all parameters are parsed to bring the runpath/rpath information into a usable form. */ static void gen_rxxpath_data (void) { char *ld_library_path2; /* Convert the information in true single-linked lists for easy use. At this point we also discard the rpath information if runpath information is provided. rpath is deprecated and should not be used (or ever be invented for that matter). */ if (ld_state.rpath != NULL) { struct pathelement *endp = ld_state.rpath; ld_state.rpath = ld_state.rpath->next; endp->next = NULL; } if (ld_state.rpath_link != NULL) { struct pathelement *endp = ld_state.rpath_link; ld_state.rpath_link = ld_state.rpath_link->next; endp->next = NULL; } if (ld_state.runpath != NULL) { struct pathelement *endp = ld_state.runpath; ld_state.runpath = ld_state.runpath->next; endp->next = NULL; /* If rpath information is also available discard it. XXX Should there be a possibility to avoid this? */ while (ld_state.rpath != NULL) { struct pathelement *old = ld_state.rpath; ld_state.rpath = ld_state.rpath->next; free (old); } } if (ld_state.runpath_link != NULL) { struct pathelement *endp = ld_state.runpath_link; ld_state.runpath_link = ld_state.runpath_link->next; endp->next = NULL; /* If rpath information is also available discard it. XXX Should there be a possibility to avoid this? */ while (ld_state.rpath_link != NULL) { struct pathelement *old = ld_state.rpath_link; ld_state.rpath_link = ld_state.rpath_link->next; free (old); } /* The information in the strings in the list can actually be directory lists themselves, with entries separated by colons. Convert the list now to a list with one list entry for each directory. */ normalize_dirlist (&ld_state.runpath_link); } else if (ld_state.rpath_link != NULL) /* Same as for the runpath_link above. */ normalize_dirlist (&ld_state.rpath_link); /* As a related task, handle the LD_LIBRARY_PATH value here. First we have to possibly split the value found (if it contains a semicolon). Then we have to split the value in list of directories, i.e., split at the colons. */ if (ld_library_path1 != NULL) { ld_library_path2 = strchr (ld_library_path1, ';'); if (ld_library_path2 == NULL) { /* If no semicolon is present the directories are looked at after the -L parameters (-> ld_library_path2). */ ld_library_path2 = ld_library_path1; ld_library_path1 = NULL; } else { /* NUL terminate the first part. */ *ld_library_path2++ = '\0'; /* Convert the string value in a list. */ add_rxxpath (&ld_state.ld_library_path1, ld_library_path1); normalize_dirlist (&ld_state.ld_library_path1); } add_rxxpath (&ld_state.ld_library_path2, ld_library_path2); normalize_dirlist (&ld_state.ld_library_path2); } } static void read_version_script (const char *fname) { /* Open the file. The name is supposed to be the complete (relative or absolute) path. No search along a path will be performed. */ ldin = fopen (fname, "r"); if (ldin == NULL) error (EXIT_FAILURE, errno, gettext ("cannot read version script '%s'"), fname); /* No need for locking. */ __fsetlocking (ldin, FSETLOCKING_BYCALLER); /* Tell the parser that this is a version script. */ ld_scan_version_script = 1; ldlineno = 1; ldin_fname = fname; if (ldparse () != 0) /* Something went wrong during parsing. */ exit (EXIT_FAILURE); fclose (ldin); } static void create_lscript_symbols (void) { /* Walk through the data from the linker script and generate all the symbols which are required to be present and and those marked with PROVIDE if there is a undefined reference. */ if (ld_state.output_segments == NULL) return; struct output_segment *segment = ld_state.output_segments->next; do { struct output_rule *orule; for (orule = segment->output_rules; orule != NULL; orule = orule->next) if (orule->tag == output_assignment /* The assignments to "." (i.e., the PC) have to be ignored here. */ && strcmp (orule->val.assignment->variable, ".") != 0) { struct symbol *s = ld_state.unresolved; /* Check whether the symbol is needed. */ if (likely (s != NULL)) { struct symbol *first = s; const char *providename = orule->val.assignment->variable; /* Determine whether the provided symbol is still undefined. */ // XXX TODO Loop inside a loop. Gag! Must rewrite. */ do if (strcmp (s->name, providename) == 0) { /* Not defined but referenced. */ if (unlikely (!s->defined)) { /* Put on the list of symbols. First remove it from whatever list it currently is on. */ CDBL_LIST_DEL (ld_state.unresolved, s); --ld_state.nunresolved; goto use_it; } if (unlikely (!orule->val.assignment->provide_flag)) { /* The symbol is already defined and now again in the linker script. This is an error. */ error (0, 0, gettext ("\ duplicate definition of '%s' in linker script"), providename); goto next_rule; } } while ((s = s->next) != first); } /* If the symbol only has to be provided if it is needed, ignore it here since it is not undefined. */ if (orule->val.assignment->provide_flag) continue; /* Allocate memory for this new symbol. */ s = (struct symbol *) obstack_calloc (&ld_state.smem, sizeof (struct symbol)); /* Initialize it. */ s->name = orule->val.assignment->variable; /* Insert it into the symbol hash table. */ unsigned long int hval = elf_hash (s->name); if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, hval, s) != 0)) { /* This means the symbol is defined somewhere else. Maybe it comes from a DSO or so. Get the definition. */ free (s); struct symbol *old = ld_symbol_tab_find (&ld_state.symbol_tab, hval, s); assert (old != NULL); free (s); /* If this is a definition from the application itself this means a duplicate definition. */ if (! old->in_dso) { error (0, 0, gettext ("\ duplicate definition of '%s' in linker script"), s->name); goto next_rule; } /* We use the definition from the linker script. */ s = old; } use_it: /* The symbol is (now) defined. */ s->defined = 1; s->type = STT_NOTYPE; /* Add a reference to the symbol record. We will come across it when creating the output file. */ orule->val.assignment->sym = s; SNGL_LIST_PUSH (ld_state.lscript_syms, s); ++ld_state.nlscript_syms; next_rule: ; } segment = segment->next; } while (segment != ld_state.output_segments->next); } /* Create creation of spection section symbols representing sections in the output file. This is done for symbols like _GLOBAL_OFFSET_TABLE_ and _DYNAMIC. */ static void create_special_section_symbol (struct symbol **symp, const char *name) { if (*symp == NULL) { /* No symbol defined found yet. Create one. */ struct symbol *newsym = (struct symbol *) obstack_calloc (&ld_state.smem, sizeof (*newsym)); newsym->name = name; // XXX Should we mark the symbol hidden? They are hardly useful // used outside the current object. /* Add to the symbol table. */ if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, elf_hash (name), newsym) != 0)) abort (); *symp = newsym; } else if ((*symp)->defined) /* Cannot happen. We do use this symbol from any input file. */ abort (); (*symp)->defined = 1; (*symp)->local = 1; (*symp)->hidden = 1; (*symp)->type = STT_OBJECT; ++ld_state.nsymtab; } #include "debugpred.h"