From cd72c291808dbf72aad1603f3c60cd72de62c8f8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 26 Feb 2008 22:10:32 +0000 Subject: [PATCH] From Craig Silverstein: implement -z max-page-size and -z common-page-size. --- gold/i386.cc | 4 ++-- gold/options.cc | 56 ++++++++++++++++++++++++++++++++++++---------- gold/options.h | 30 +++++++++++++++++++++++++ gold/parameters.cc | 6 ++++- gold/parameters.h | 19 ++++++++++++++++ gold/target.h | 17 ++++++++++++-- gold/x86_64.cc | 4 ++-- 7 files changed, 117 insertions(+), 19 deletions(-) diff --git a/gold/i386.cc b/gold/i386.cc index 8bd3f32bb24..0655f137276 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -366,8 +366,8 @@ const Target::Target_info Target_i386::i386_info = true, // is_default_stack_executable "/usr/lib/libc.so.1", // dynamic_linker 0x08048000, // default_text_segment_address - 0x1000, // abi_pagesize - 0x1000 // common_pagesize + 0x1000, // abi_pagesize (overridable by -z max-page-size) + 0x1000 // common_pagesize (overridable by -z common-page-size) }; // Get the GOT section, creating it if necessary. diff --git a/gold/options.cc b/gold/options.cc index c5f1edf9782..8b607afe827 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -109,8 +109,13 @@ struct options::One_z_option // The name of the option. const char* name; - // The member function in General_options called to record it. - void (General_options::*set)(bool); + // The member function in General_options called to record an option + // which does not take an argument. + void (General_options::*set_noarg)(bool); + + // The member function in General_options called to record an option + // which does take an argument. + void (General_options::*set_arg)(const char*); }; // We have a separate table for --debug options. @@ -593,7 +598,9 @@ options::Command_line_options::options[] = GENERAL_ARG('z', NULL, N_("Subcommands as follows:\n\ -z execstack Mark output as requiring executable stack\n\ - -z noexecstack Mark output as not requiring executable stack"), + -z noexecstack Mark output as not requiring executable stack\n\ + -z max-page-size=SIZE Set maximum page size to SIZE\n\ + -z common-page-size=SIZE Set common page size to SIZE"), N_("-z SUBCOMMAND"), ONE_DASH, &General_options::handle_z_option), @@ -618,8 +625,10 @@ const int options::Command_line_options::options_size = const options::One_z_option options::Command_line_options::z_options[] = { - { "execstack", &General_options::set_execstack }, - { "noexecstack", &General_options::set_noexecstack }, + { "execstack", &General_options::set_execstack, NULL }, + { "noexecstack", &General_options::set_noexecstack, NULL }, + { "max-page-size", NULL, &General_options::set_max_page_size }, + { "common-page-size", NULL, &General_options::set_common_page_size } }; const int options::Command_line_options::z_options_size = @@ -670,6 +679,8 @@ General_options::General_options(Script_options* script_options) thread_count_middle_(0), thread_count_final_(0), execstack_(EXECSTACK_FROM_INPUT), + max_page_size_(0), + common_page_size_(0), debug_(0), script_options_(script_options) { @@ -731,21 +742,42 @@ General_options::default_target() const void General_options::handle_z_option(const char* arg) { + // ARG may be a word, like "noexec", or it may be an option in its + // own right, like "max-page-size=SIZE". + const char* argarg = strchr(arg, '='); // the argument to the -z argument + int arglen; + if (argarg) + { + arglen = argarg - arg; + argarg++; + } + else + arglen = strlen(arg); + const int z_options_size = options::Command_line_options::z_options_size; const gold::options::One_z_option* z_options = gold::options::Command_line_options::z_options; for (int i = 0; i < z_options_size; ++i) { - if (strcmp(arg, z_options[i].name) == 0) + if (memcmp(arg, z_options[i].name, arglen) == 0 + && z_options[i].name[arglen] == '\0') { - (this->*(z_options[i].set))(true); - return; - } + if (z_options[i].set_noarg && argarg) + gold::gold_fatal(_("-z subcommand does not take an argument: %s\n"), + z_options[i].name); + else if (z_options[i].set_arg && !argarg) + gold::gold_fatal(_("-z subcommand requires an argument: %s\n"), + z_options[i].name); + else if (z_options[i].set_arg) + (this->*(z_options[i].set_arg))(argarg); + else + (this->*(z_options[i].set_noarg))(true); + return; + } } - fprintf(stderr, _("%s: unrecognized -z subcommand: %s\n"), - program_name, arg); - ::exit(EXIT_FAILURE); + gold::gold_fatal(_("%s: unrecognized -z subcommand: %s\n"), + program_name, arg); } // Handle the --debug option. diff --git a/gold/options.h b/gold/options.h index 593256042fb..d7dc06cd2e1 100644 --- a/gold/options.h +++ b/gold/options.h @@ -319,6 +319,16 @@ class General_options is_stack_executable() const { return this->execstack_ == EXECSTACK_YES; } + // -z max-page-size + uint64_t + max_page_size() const + { return this->max_page_size_; } + + // -z common-page-size + uint64_t + common_page_size() const + { return this->common_page_size_; } + // --debug unsigned int debug() const @@ -576,6 +586,24 @@ class General_options set_noexecstack(bool) { this->execstack_ = EXECSTACK_NO; } + void + set_max_page_size(const char* arg) + { + char* endptr; + this->max_page_size_ = strtoull(arg, &endptr, 0); + if (*endptr != '\0' || this->max_page_size_ == 0) + gold_fatal(_("invalid max-page-size: %s"), arg); + } + + void + set_common_page_size(const char* arg) + { + char* endptr; + this->common_page_size_ = strtoull(arg, &endptr, 0); + if (*endptr != '\0' || this->common_page_size_ == 0) + gold_fatal(_("invalid common-page-size: %s"), arg); + } + void set_debug(unsigned int flags) { this->debug_ = flags; } @@ -622,6 +650,8 @@ class General_options int thread_count_middle_; int thread_count_final_; Execstack execstack_; + uint64_t max_page_size_; + uint64_t common_page_size_; unsigned int debug_; // Some options can also be set from linker scripts. Those are // stored here. diff --git a/gold/parameters.cc b/gold/parameters.cc index 5723b807dd0..a53908ffc7c 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -38,7 +38,8 @@ Parameters::Parameters(Errors* errors) symbolic_(false), demangle_(false), detect_odr_violations_(false), optimization_level_(0), export_dynamic_(false), debug_(0), is_doing_static_link_valid_(false), doing_static_link_(false), - is_target_valid_(false), target_(NULL) + is_target_valid_(false), target_(NULL), size_(0), is_big_endian_(false), + max_page_size_(0), common_page_size_(0) { } @@ -74,6 +75,9 @@ Parameters::set_from_options(const General_options* options) else this->strip_ = STRIP_NONE; + this->max_page_size_ = options->max_page_size(); + this->common_page_size_ = options->common_page_size(); + this->options_valid_ = true; } diff --git a/gold/parameters.h b/gold/parameters.h index 3bf6c5030b0..136fd35b845 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -230,6 +230,22 @@ class Parameters return this->is_big_endian_; } + // The maximum page size + uint64_t + max_page_size() const + { + gold_assert(this->is_target_valid_); + return this->max_page_size_; + } + + // The common page size + uint64_t + common_page_size() const + { + gold_assert(this->is_target_valid_); + return this->common_page_size_; + } + // Set values recorded from options. void set_from_options(const General_options*); @@ -313,6 +329,9 @@ class Parameters int size_; // Whether the output file is big endian. bool is_big_endian_; + // The maximum page size and common page size + int max_page_size_; + int common_page_size_; }; // This is a global variable. diff --git a/gold/target.h b/gold/target.h index c05c821ad2a..fa18fc7a356 100644 --- a/gold/target.h +++ b/gold/target.h @@ -34,6 +34,7 @@ #define GOLD_TARGET_H #include "elfcpp.h" +#include "parameters.h" namespace gold { @@ -103,12 +104,24 @@ class Target // Return the ABI specified page size. uint64_t abi_pagesize() const - { return this->pti_->abi_pagesize; } + { + if (parameters->max_page_size() > 0) + return parameters->max_page_size(); + else + return this->pti_->abi_pagesize; + } // Return the common page size used on actual systems. uint64_t common_pagesize() const - { return this->pti_->common_pagesize; } + { + if (parameters->common_page_size() > 0) + return std::min(parameters->common_page_size(), + this->abi_pagesize()); + else + return std::min(this->pti_->common_pagesize, + this->abi_pagesize()); + } // If we see some object files with .note.GNU-stack sections, and // some objects files without them, this returns whether we should diff --git a/gold/x86_64.cc b/gold/x86_64.cc index c65031e9cdc..882398f487a 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -360,8 +360,8 @@ const Target::Target_info Target_x86_64::x86_64_info = true, // is_default_stack_executable "/lib/ld64.so.1", // program interpreter 0x400000, // default_text_segment_address - 0x1000, // abi_pagesize - 0x1000 // common_pagesize + 0x1000, // abi_pagesize (overridable by -z max-page-size) + 0x1000 // common_pagesize (overridable by -z common-page-size) }; // Get the GOT section, creating it if necessary. -- 2.30.2