X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Foptions.cc;h=6ab2fe9dba48a5bbbaa2b38dab272b59df7012bf;hb=4fb3aee212ad7ebb51327a61db1066303084d515;hp=ff9bd41c195904d8245ec40a1805bc64cd3e864f;hpb=3b2935444fe89c883ffe7964b69556f3580ee1ef;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/options.cc b/gold/options.cc index ff9bd41c19..6ab2fe9dba 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -1,6 +1,6 @@ // options.c -- handle command line options for gold -// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -22,8 +22,10 @@ #include "gold.h" +#include #include #include +#include #include #include #include @@ -47,12 +49,17 @@ Position_dependent_options::default_options_; namespace options { +// This flag is TRUE if we should register the command-line options as they +// are constructed. It is set after construction of the options within +// class Position_dependent_options. +static bool ready_to_register = false; + // This global variable is set up as General_options is constructed. static std::vector registered_options; // These are set up at the same time -- the variables that accept one // dash, two, or require -z. A single variable may be in more than -// one of thes data structures. +// one of these data structures. typedef Unordered_map Option_map; static Option_map* long_options = NULL; static One_option* short_options[128]; @@ -60,6 +67,9 @@ static One_option* short_options[128]; void One_option::register_option() { + if (!ready_to_register) + return; + registered_options.push_back(this); // We can't make long_options a static Option_map because we can't @@ -75,7 +85,10 @@ One_option::register_option() const int shortname_as_int = static_cast(this->shortname); gold_assert(shortname_as_int >= 0 && shortname_as_int < 128); if (this->shortname != '\0') - short_options[shortname_as_int] = this; + { + gold_assert(short_options[shortname_as_int] == NULL); + short_options[shortname_as_int] = this; + } } void @@ -182,7 +195,17 @@ parse_uint(const char* option_name, const char* arg, int* retval) } void -parse_uint64(const char* option_name, const char* arg, uint64_t *retval) +parse_int(const char* option_name, const char* arg, int* retval) +{ + char* endptr; + *retval = strtol(arg, &endptr, 0); + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value (expected an integer): %s"), + option_name, arg); +} + +void +parse_uint64(const char* option_name, const char* arg, uint64_t* retval) { char* endptr; *retval = strtoull(arg, &endptr, 0); @@ -265,14 +288,18 @@ General_options::parse_help(const char*, const char*, Command_line*) void General_options::parse_version(const char* opt, const char*, Command_line*) { - gold::print_version(opt[0] == '-' && opt[1] == 'v'); - ::exit(EXIT_SUCCESS); + bool print_short = (opt[0] == '-' && opt[1] == 'v'); + gold::print_version(print_short); + this->printed_version_ = true; + if (!print_short) + ::exit(EXIT_SUCCESS); } void General_options::parse_V(const char*, const char*, Command_line*) { gold::print_version(true); + this->printed_version_ = true; printf(_(" Supported targets:\n")); std::vector supported_names; gold::supported_target_names(&supported_names); @@ -289,11 +316,75 @@ General_options::parse_defsym(const char*, const char* arg, cmdline->script_options().define_symbol(arg); } +void +General_options::parse_incremental(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_AUTO; +} + +void +General_options::parse_no_incremental(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_OFF; +} + +void +General_options::parse_incremental_full(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_FULL; +} + +void +General_options::parse_incremental_update(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_UPDATE; +} + +void +General_options::parse_incremental_changed(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_disposition_ = INCREMENTAL_CHANGED; +} + +void +General_options::parse_incremental_unchanged(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_disposition_ = INCREMENTAL_UNCHANGED; +} + +void +General_options::parse_incremental_unknown(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_disposition_ = INCREMENTAL_CHECK; +} + void General_options::parse_library(const char*, const char* arg, Command_line* cmdline) { - Input_file_argument file(arg, true, "", false, *this); + Input_file_argument::Input_file_type type; + const char* name; + if (arg[0] == ':') + { + type = Input_file_argument::INPUT_FILE_TYPE_SEARCHED_FILE; + name = arg + 1; + } + else + { + type = Input_file_argument::INPUT_FILE_TYPE_LIBRARY; + name = arg; + } + Input_file_argument file(name, type, "", false, *this); cmdline->inputs().add_file(file); } @@ -330,10 +421,68 @@ void General_options::parse_just_symbols(const char*, const char* arg, Command_line* cmdline) { - Input_file_argument file(arg, false, "", true, *this); + Input_file_argument file(arg, Input_file_argument::INPUT_FILE_TYPE_FILE, + "", true, *this); cmdline->inputs().add_file(file); } +// Handle --section-start. + +void +General_options::parse_section_start(const char*, const char* arg, + Command_line*) +{ + const char* eq = strchr(arg, '='); + if (eq == NULL) + { + gold_error(_("invalid argument to --section-start; " + "must be SECTION=ADDRESS")); + return; + } + + std::string section_name(arg, eq - arg); + + ++eq; + const char* val_start = eq; + if (eq[0] == '0' && (eq[1] == 'x' || eq[1] == 'X')) + eq += 2; + if (*eq == '\0') + { + gold_error(_("--section-start address missing")); + return; + } + uint64_t addr = 0; + hex_init(); + for (; *eq != '\0'; ++eq) + { + if (!hex_p(*eq)) + { + gold_error(_("--section-start argument %s is not a valid hex number"), + val_start); + return; + } + addr <<= 4; + addr += hex_value(*eq); + } + + this->section_starts_[section_name] = addr; +} + +// Look up a --section-start value. + +bool +General_options::section_start(const char* secname, uint64_t* paddr) const +{ + if (this->section_starts_.empty()) + return false; + std::map::const_iterator p = + this->section_starts_.find(secname); + if (p == this->section_starts_.end()) + return false; + *paddr = p->second; + return true; +} + void General_options::parse_static(const char*, const char*, Command_line*) { @@ -378,27 +527,82 @@ General_options::parse_end_group(const char*, const char*, cmdline->inputs().end_group(); } -} // End namespace gold. - -namespace +void +General_options::parse_start_lib(const char*, const char*, + Command_line* cmdline) { + cmdline->inputs().start_lib(cmdline->position_dependent_options()); +} void -usage() +General_options::parse_end_lib(const char*, const char*, + Command_line* cmdline) { - fprintf(stderr, - _("%s: use the --help option for usage information\n"), - gold::program_name); - ::exit(EXIT_FAILURE); + cmdline->inputs().end_lib(); } +// The function add_excluded_libs() in ld/ldlang.c of GNU ld breaks up a list +// of names separated by commas or colons and puts them in a linked list. +// We implement the same parsing of names here but store names in an unordered +// map to speed up searching of names. + void -usage(const char* msg, const char *opt) +General_options::parse_exclude_libs(const char*, const char* arg, + Command_line*) { - fprintf(stderr, - _("%s: %s: %s\n"), - gold::program_name, opt, msg); - usage(); + const char* p = arg; + + while (*p != '\0') + { + size_t length = strcspn(p, ",:"); + this->excluded_libs_.insert(std::string(p, length)); + p += (p[length] ? length + 1 : length); + } +} + +// The checking logic is based on the function check_excluded_libs() in +// ld/ldlang.c of GNU ld but our implementation is different because we use +// an unordered map instead of a linked list, which is what GNU ld uses. GNU +// ld searches sequentially in the excluded libs list. For a given archive, +// a match is found if the archive's name matches exactly one of the list +// entry or if the archive's name is of the form FOO.a and FOO matches exactly +// one of the list entry. An entry "ALL" in the list is considered as a +// wild-card and matches any given name. + +bool +General_options::check_excluded_libs(const std::string &name) const +{ + Unordered_set::const_iterator p; + + // Exit early for the most common case. + if (excluded_libs_.empty()) + return false; + + // If we see "ALL", all archives are excluded from automatic export. + p = excluded_libs_.find(std::string("ALL")); + if (p != excluded_libs_.end()) + return true; + + // First strip off any directories in name. + const char* basename = lbasename(name.c_str()); + + // Try finding an exact match. + p = excluded_libs_.find(std::string(basename)); + if (p != excluded_libs_.end()) + return true; + + // Try matching NAME without ".a" at the end. + size_t length = strlen(basename); + if ((length >= 2) + && (basename[length - 2] == '.') + && (basename[length - 1] == 'a')) + { + p = excluded_libs_.find(std::string(basename, length - 2)); + if (p != excluded_libs_.end()) + return true; + } + + return false; } // Recognize input and output target names. The GNU linker accepts @@ -408,8 +612,8 @@ usage(const char* msg, const char *opt) // "elf". Non-ELF targets would be "srec", "symbolsrec", "tekhex", // "binary", "ihex". -gold::General_options::Object_format -string_to_object_format(const char* arg) +General_options::Object_format +General_options::string_to_object_format(const char* arg) { if (strncmp(arg, "elf", 3) == 0) return gold::General_options::OBJECT_FORMAT_ELF; @@ -424,10 +628,59 @@ string_to_object_format(const char* arg) } } +void +General_options::parse_fix_v4bx(const char*, const char*, + Command_line*) +{ + this->fix_v4bx_ = FIX_V4BX_REPLACE; +} + +void +General_options::parse_fix_v4bx_interworking(const char*, const char*, + Command_line*) +{ + this->fix_v4bx_ = FIX_V4BX_INTERWORKING; +} + +void +General_options::parse_EB(const char*, const char*, Command_line*) +{ + this->endianness_ = ENDIANNESS_BIG; +} + +void +General_options::parse_EL(const char*, const char*, Command_line*) +{ + this->endianness_ = ENDIANNESS_LITTLE; +} + +} // End namespace gold. + +namespace +{ + +void +usage() +{ + fprintf(stderr, + _("%s: use the --help option for usage information\n"), + gold::program_name); + ::exit(EXIT_FAILURE); +} + +void +usage(const char* msg, const char* opt) +{ + fprintf(stderr, + _("%s: %s: %s\n"), + gold::program_name, opt, msg); + usage(); +} + // If the default sysroot is relocatable, try relocating it based on // the prefix FROM. -char* +static char* get_relative_sysroot(const char* from) { char* path = make_relative_prefix(gold::program_name, from, @@ -448,7 +701,7 @@ get_relative_sysroot(const char* from) // get_relative_sysroot, which is a small memory leak, but is // necessary since we store this pointer directly in General_options. -const char* +static const char* get_default_sysroot() { const char* sysroot = TARGET_SYSTEM_ROOT; @@ -563,7 +816,7 @@ parse_short_option(int argc, const char** argv, int pos_in_argv_i, // We handle -z as a special case. static gold::options::One_option dash_z("", gold::options::DASH_Z, - 'z', "", "-z", "Z-OPTION", false, + 'z', "", NULL, "Z-OPTION", false, NULL); gold::options::One_option* retval = NULL; if (this_argv[pos_in_argv_i] == 'z') @@ -620,21 +873,36 @@ namespace gold { General_options::General_options() - : execstack_status_(General_options::EXECSTACK_FROM_INPUT), static_(false), - do_demangle_(false), plugins_() + : printed_version_(false), + execstack_status_(EXECSTACK_FROM_INPUT), + icf_status_(ICF_NONE), + static_(false), + do_demangle_(false), + plugins_(NULL), + dynamic_list_(), + incremental_mode_(INCREMENTAL_OFF), + incremental_disposition_(INCREMENTAL_CHECK), + implicit_incremental_(false), + excluded_libs_(), + symbols_to_retain_(), + section_starts_(), + fix_v4bx_(FIX_V4BX_NONE), + endianness_(ENDIANNESS_NOT_SET) { + // Turn off option registration once construction is complete. + gold::options::ready_to_register = false; } General_options::Object_format General_options::format_enum() const { - return string_to_object_format(this->format()); + return General_options::string_to_object_format(this->format()); } General_options::Object_format General_options::oformat_enum() const { - return string_to_object_format(this->oformat()); + return General_options::string_to_object_format(this->oformat()); } // Add the sysroot, if any, to the search paths. @@ -659,6 +927,26 @@ General_options::add_sysroot() free(canonical_sysroot); } +// Return whether FILENAME is in a system directory. + +bool +General_options::is_in_system_directory(const std::string& filename) const +{ + for (Dir_list::const_iterator p = this->library_path_.value.begin(); + p != this->library_path_.value.end(); + ++p) + { + // We use a straight string comparison rather than calling + // FILENAME_CMP because we are only interested in the cases + // where we found the file in a system directory, which means + // that we used the directory name as a prefix for a -L search. + if (p->is_system_directory() + && filename.compare(0, p->name().size(), p->name()) == 0) + return true; + } + return false; +} + // Add a plugin to the list of plugins. void @@ -725,6 +1013,15 @@ General_options::finalize() else if (this->noexecstack()) this->set_execstack_status(EXECSTACK_NO); + // icf_status_ is a three-state variable; update it based on the + // value of this->icf(). + if (strcmp(this->icf(), "none") == 0) + this->set_icf_status(ICF_NONE); + else if (strcmp(this->icf(), "safe") == 0) + this->set_icf_status(ICF_SAFE); + else + this->set_icf_status(ICF_ALL); + // Handle the optional argument for --demangle. if (this->user_set_demangle()) { @@ -806,7 +1103,7 @@ General_options::finalize() } while (next_pos != std::string::npos); } - else + else if (!this->nostdlib()) { // Even if they don't specify it, we add -L /lib and -L /usr/lib. // FIXME: We should only do this when configured in native mode. @@ -814,6 +1111,25 @@ General_options::finalize() this->add_to_library_path_with_sysroot("/usr/lib"); } + // Parse the contents of -retain-symbols-file into a set. + if (this->retain_symbols_file()) + { + std::ifstream in; + in.open(this->retain_symbols_file()); + if (!in) + gold_fatal(_("unable to open -retain-symbols-file file %s: %s"), + this->retain_symbols_file(), strerror(errno)); + std::string line; + std::getline(in, line); // this chops off the trailing \n, if any + while (in) + { + if (!line.empty() && line[line.length() - 1] == '\r') // Windows + line.resize(line.length() - 1); + this->symbols_to_retain_.insert(line); + std::getline(in, line); + } + } + if (this->shared() && !this->user_set_allow_shlib_undefined()) this->set_allow_shlib_undefined(true); @@ -824,13 +1140,24 @@ General_options::finalize() // Now that we've normalized the options, check for contradictory ones. if (this->shared() && this->is_static()) gold_fatal(_("-shared and -static are incompatible")); + if (this->shared() && this->pie()) + gold_fatal(_("-shared and -pie are incompatible")); if (this->shared() && this->relocatable()) gold_fatal(_("-shared and -r are incompatible")); + if (this->pie() && this->relocatable()) + gold_fatal(_("-pie and -r are incompatible")); + + // TODO: implement support for -retain-symbols-file with -r, if needed. + if (this->relocatable() && this->retain_symbols_file()) + gold_fatal(_("-retain-symbols-file does not yet work with -r")); if (this->oformat_enum() != General_options::OBJECT_FORMAT_ELF - && (this->shared() || this->relocatable())) - gold_fatal(_("binary output format not compatible with -shared or -r")); + && (this->shared() + || this->pie() + || this->relocatable())) + gold_fatal(_("binary output format not compatible " + "with -shared or -pie or -r")); if (this->user_set_hash_bucket_empty_fraction() && (this->hash_bucket_empty_fraction() < 0.0 @@ -839,6 +1166,10 @@ General_options::finalize() "[0.0, 1.0)"), this->hash_bucket_empty_fraction()); + if (this->implicit_incremental_ && this->incremental_mode_ == INCREMENTAL_OFF) + gold_fatal(_("Options --incremental-changed, --incremental-unchanged, " + "--incremental-unknown require the use of --incremental")); + // FIXME: we can/should be doing a lot more sanity checking here. } @@ -886,14 +1217,20 @@ Search_directory::add_sysroot(const char* sysroot, void Input_arguments::add_file(const Input_file_argument& file) { - if (!this->in_group_) - this->input_argument_list_.push_back(Input_argument(file)); - else + if (this->in_group_) { gold_assert(!this->input_argument_list_.empty()); gold_assert(this->input_argument_list_.back().is_group()); this->input_argument_list_.back().group()->add_file(file); } + else if (this->in_lib_) + { + gold_assert(!this->input_argument_list_.empty()); + gold_assert(this->input_argument_list_.back().is_lib()); + this->input_argument_list_.back().lib()->add_file(file); + } + else + this->input_argument_list_.push_back(Input_argument(file)); } // Start a group. @@ -903,6 +1240,8 @@ Input_arguments::start_group() { if (this->in_group_) gold_fatal(_("May not nest groups")); + if (this->in_lib_) + gold_fatal(_("may not nest groups in libraries")); Input_file_group* group = new Input_file_group(); this->input_argument_list_.push_back(Input_argument(group)); this->in_group_ = true; @@ -918,12 +1257,43 @@ Input_arguments::end_group() this->in_group_ = false; } +// Start a lib. + +void +Input_arguments::start_lib(const Position_dependent_options& options) +{ + if (this->in_lib_) + gold_fatal(_("may not nest libraries")); + if (this->in_group_) + gold_fatal(_("may not nest libraries in groups")); + Input_file_lib* lib = new Input_file_lib(options); + this->input_argument_list_.push_back(Input_argument(lib)); + this->in_lib_ = true; +} + +// End a lib. + +void +Input_arguments::end_lib() +{ + if (!this->in_lib_) + gold_fatal(_("lib end without lib start")); + this->in_lib_ = false; +} + // Command_line options. Command_line::Command_line() { } +// Pre_options is the hook that sets the ready_to_register flag. + +Command_line::Pre_options::Pre_options() +{ + gold::options::ready_to_register = true; +} + // Process the command line options. For process_one_option, i is the // index of argv to process next, and must be an option (that is, // start with a dash). The return value is the index of the next @@ -987,8 +1357,9 @@ Command_line::process(int argc, const char** argv) this->position_options_.copy_from_options(this->options()); if (no_more_options || argv[i][0] != '-') { - Input_file_argument file(argv[i], false, "", false, - this->position_options_); + Input_file_argument file(argv[i], + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, this->position_options_); this->inputs_.add_file(file); ++i; } @@ -1006,4 +1377,15 @@ Command_line::process(int argc, const char** argv) this->options_.finalize(); } +// Finalize the version script options and return them. + +const Version_script_info& +Command_line::version_script() +{ + this->options_.finalize_dynamic_list(); + Version_script_info* vsi = this->script_options_.version_script_info(); + vsi->finalize(); + return *vsi; +} + } // End namespace gold.