From: Ian Lance Taylor Date: Tue, 23 Oct 2007 05:05:48 +0000 (+0000) Subject: Add support for PT_GNU_STACK. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=943f35e2d3a61fa96012d2b306238f941847f838;p=pf3gnuchains%2Fpf3gnuchains3x.git Add support for PT_GNU_STACK. --- diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 499eda70da..119f0c74ca 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -1210,8 +1210,7 @@ Versions::get_dynobj_for_sym(const Symbol_table* symtab, // symbol table. void -Versions::record_version(const General_options* options, - const Symbol_table* symtab, +Versions::record_version(const Symbol_table* symtab, Stringpool* dynpool, const Symbol* sym) { gold_assert(!this->is_finalized_); @@ -1223,7 +1222,7 @@ Versions::record_version(const General_options* options, if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) { if (parameters->output_is_shared()) - this->add_def(options, sym, version, version_key); + this->add_def(sym, version, version_key); } else { @@ -1236,8 +1235,8 @@ Versions::record_version(const General_options* options, // We've found a symbol SYM defined in version VERSION. void -Versions::add_def(const General_options* options, const Symbol* sym, - const char* version, Stringpool::Key version_key) +Versions::add_def(const Symbol* sym, const char* version, + Stringpool::Key version_key) { Key k(version_key, 0); Version_base* const vbnull = NULL; @@ -1271,7 +1270,7 @@ Versions::add_def(const General_options* options, const Symbol* sym, // If this is the first version we are defining, first define // the base version. FIXME: Should use soname here when // creating a shared object. - Verdef* vdbase = new Verdef(options->output_file_name(), true, false, + Verdef* vdbase = new Verdef(parameters->output_file_name(), true, false, true); this->defs_.push_back(vdbase); diff --git a/gold/dynobj.h b/gold/dynobj.h index 78caaf9da3..a3d733d799 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -411,8 +411,7 @@ class Versions // SYM is going into the dynamic symbol table and has a version. // Record the appropriate version information. void - record_version(const General_options*, const Symbol_table* symtab, - Stringpool*, const Symbol* sym); + record_version(const Symbol_table* symtab, Stringpool*, const Symbol* sym); // Set the version indexes. DYNSYM_INDEX is the index we should use // for the next dynamic symbol. We add new dynamic symbols to SYMS @@ -466,8 +465,7 @@ class Versions // Handle a symbol SYM defined with version VERSION. void - add_def(const General_options*, const Symbol* sym, const char* version, - Stringpool::Key); + add_def(const Symbol* sym, const char* version, Stringpool::Key); // Add a reference to version NAME in file FILENAME. void diff --git a/gold/i386.cc b/gold/i386.cc index 26888bfffb..e36b22cdaf 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -263,6 +263,7 @@ const Target::Target_info Target_i386::i386_info = false, // has_make_symbol false, // has_resolve true, // has_code_fill + true, // is_default_stack_executable "/usr/lib/libc.so.1", // dynamic_linker 0x08048000, // default_text_segment_address 0x1000, // abi_pagesize diff --git a/gold/layout.cc b/gold/layout.cc index ae2b23f6e9..22d3b59169 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -67,7 +67,10 @@ Layout::Layout(const General_options& options) unattached_section_list_(), special_output_list_(), tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL), - eh_frame_section_(NULL), output_file_size_(-1) + eh_frame_section_(NULL), output_file_size_(-1), + input_requires_executable_stack_(false), + input_with_gnu_stack_note_(false), + input_without_gnu_stack_note_(false) { // Make space for more than enough segments for a typical file. // This is just for efficiency--it's OK if we wind up needing more. @@ -404,6 +407,27 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, return os; } +// Handle the .note.GNU-stack section at layout time. SEEN_GNU_STACK +// is whether we saw a .note.GNU-stack section in the object file. +// GNU_STACK_FLAGS is the section flags. The flags give the +// protection required for stack memory. We record this in an +// executable as a PT_GNU_STACK segment. If an object file does not +// have a .note.GNU-stack segment, we must assume that it is an old +// object. On some targets that will force an executable stack. + +void +Layout::layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags) +{ + if (!seen_gnu_stack) + this->input_without_gnu_stack_note_ = true; + else + { + this->input_with_gnu_stack_note_ = true; + if ((gnu_stack_flags & elfcpp::SHF_EXECINSTR) != 0) + this->input_requires_executable_stack_ = true; + } +} + // Create the dynamic sections which are needed before we read the // relocs. @@ -542,7 +566,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) target->finalize_sections(this); - this->create_note_section(); + this->create_gold_note(); + this->create_executable_stack_info(target); Output_segment* phdr_seg = NULL; if (!parameters->doing_static_link()) @@ -635,7 +660,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // records the version of gold used to create the binary. void -Layout::create_note_section() +Layout::create_gold_note() { if (parameters->output_is_object()) return; @@ -651,7 +676,7 @@ Layout::create_note_section() // version 2.16.91), and glibc always generates the latter for // .note.ABI-tag (as of version 1.6), so that's the one we go with // here. -#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION // this is not defined by default +#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION // This is not defined by default. const int size = parameters->get_size(); #else const int size = 32; @@ -719,6 +744,54 @@ Layout::create_note_section() os->add_output_section_data(posd); } +// Record whether the stack should be executable. This can be set +// from the command line using the -z execstack or -z noexecstack +// options. Otherwise, if any input file has a .note.GNU-stack +// section with the SHF_EXECINSTR flag set, the stack should be +// executable. Otherwise, if at least one input file a +// .note.GNU-stack section, and some input file has no .note.GNU-stack +// section, we use the target default for whether the stack should be +// executable. Otherwise, we don't generate a stack note. When +// generating a object file, we create a .note.GNU-stack section with +// the appropriate marking. When generating an executable or shared +// library, we create a PT_GNU_STACK segment. + +void +Layout::create_executable_stack_info(const Target* target) +{ + bool is_stack_executable; + if (this->options_.is_execstack_set()) + is_stack_executable = this->options_.is_stack_executable(); + else if (!this->input_with_gnu_stack_note_) + return; + else + { + if (this->input_requires_executable_stack_) + is_stack_executable = true; + else if (this->input_without_gnu_stack_note_) + is_stack_executable = target->is_default_stack_executable(); + else + is_stack_executable = false; + } + + if (parameters->output_is_object()) + { + const char* name = this->namepool_.add(".note.GNU-stack", false, NULL); + elfcpp::Elf_Xword flags = 0; + if (is_stack_executable) + flags |= elfcpp::SHF_EXECINSTR; + this->make_output_section(name, elfcpp::SHT_PROGBITS, flags); + } + else + { + int flags = elfcpp::PF_R | elfcpp::PF_W; + if (is_stack_executable) + flags |= elfcpp::PF_X; + Output_segment* oseg = new Output_segment(elfcpp::PT_GNU_STACK, flags); + this->segment_list_.push_back(oseg); + } +} + // Return whether SEG1 should be before SEG2 in the output file. This // is based entirely on the segment type and flags. When this is // called the segment addresses has normally not yet been set. @@ -1126,9 +1199,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, // FIXME: We have to tell set_dynsym_indexes whether the // -E/--export-dynamic option was used. - index = symtab->set_dynsym_indexes(&this->options_, target, index, - pdynamic_symbols, &this->dynpool_, - pversions); + index = symtab->set_dynsym_indexes(target, index, pdynamic_symbols, + &this->dynpool_, pversions); int symsize; unsigned int align; diff --git a/gold/layout.h b/gold/layout.h index 409290a6bb..19c8e09ee1 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -94,6 +94,13 @@ class Layout layout(Relobj *object, unsigned int shndx, const char* name, const elfcpp::Shdr& shdr, off_t* offset); + // Handle a GNU stack note. This is called once per input object + // file. SEEN_GNU_STACK is true if the object file has a + // .note.GNU-stack section. GNU_STACK_FLAGS is the section flags + // from that section if there was one. + void + layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags); + // Add an Output_section_data to the layout. This is used for // special sections like the GOT section. void @@ -220,7 +227,11 @@ class Layout // Create a .note section for gold. void - create_note_section(); + create_gold_note(); + + // Record whether the stack must be executable. + void + create_executable_stack_info(const Target*); // Find the first read-only PT_LOAD segment, creating one if // necessary. @@ -377,6 +388,15 @@ class Layout Output_section* eh_frame_section_; // The size of the output file. off_t output_file_size_; + // Whether we have seen an object file marked to require an + // executable stack. + bool input_requires_executable_stack_; + // Whether we have seen at least one object file with an executable + // stack marker. + bool input_with_gnu_stack_note_; + // Whether we have seen at least one object file without an + // executable stack marker. + bool input_without_gnu_stack_note_; }; // This task handles writing out data which is not part of a section diff --git a/gold/object.cc b/gold/object.cc index 64cecc8376..9e4b58d810 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -427,6 +427,11 @@ Sized_relobj::do_layout(Symbol_table* symtab, std::vector& map_sections(this->map_to_output()); map_sections.resize(shnum); + // Whether we've seen a .note.GNU-stack section. + bool seen_gnu_stack = false; + // The flags of a .note.GNU-stack section. + uint64_t gnu_stack_flags = 0; + // Keep track of which sections to omit. std::vector omit(shnum, false); @@ -451,6 +456,16 @@ Sized_relobj::do_layout(Symbol_table* symtab, omit[i] = true; } + // The .note.GNU-stack section is special. It gives the + // protection flags that this object file requires for the stack + // in memory. + if (strcmp(name, ".note.GNU-stack") == 0) + { + seen_gnu_stack = true; + gnu_stack_flags |= shdr.get_sh_flags(); + omit[i] = true; + } + bool discard = omit[i]; if (!discard) { @@ -481,6 +496,8 @@ Sized_relobj::do_layout(Symbol_table* symtab, map_sections[i].offset = offset; } + layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags); + delete sd->section_headers; sd->section_headers = NULL; delete sd->section_names; diff --git a/gold/options.cc b/gold/options.cc index 4e74dcefa8..1e4b90e1d4 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -93,11 +93,24 @@ struct options::One_option { return this->general_arg != NULL || this->dependent_arg != NULL; } }; +// We have a separate table for -z options. + +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)(); +}; + class options::Command_line_options { public: static const One_option options[]; static const int options_size; + static const One_z_option z_options[]; + static const int z_options_size; }; } // End namespace gold. @@ -394,6 +407,14 @@ options::Command_line_options::options[] = N_("Include only needed archive contents"), NULL, TWO_DASHES, &Position_dependent_options::clear_whole_archive), + + 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"), + N_("-z SUBCOMMAND"), ONE_DASH, + &General_options::handle_z_option), + SPECIAL('(', "start-group", N_("Start a library search group"), NULL, TWO_DASHES, &start_group), SPECIAL(')', "end-group", N_("End a library search group"), NULL, @@ -407,6 +428,18 @@ options::Command_line_options::options[] = const int options::Command_line_options::options_size = sizeof (options) / sizeof (options[0]); +// The -z options. + +const options::One_z_option +options::Command_line_options::z_options[] = +{ + { "execstack", &General_options::set_execstack }, + { "noexecstack", &General_options::set_noexecstack }, +}; + +const int options::Command_line_options::z_options_size = + sizeof(z_options) / sizeof(z_options[0]); + // The default values for the general options. General_options::General_options() @@ -429,7 +462,8 @@ General_options::General_options() threads_(false), thread_count_initial_(0), thread_count_middle_(0), - thread_count_final_(0) + thread_count_final_(0), + execstack_(EXECSTACK_FROM_INPUT) { } @@ -442,6 +476,28 @@ Position_dependent_options::Position_dependent_options() { } +// Handle the -z option. + +void +General_options::handle_z_option(const char* 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) + { + (this->*(z_options[i].set))(); + return; + } + } + + fprintf(stderr, _("%s: unrecognized -z subcommand: %s\n"), + program_name, arg); + ::exit(1); +} + // Add the sysroot, if any, to the search paths. void @@ -686,7 +742,7 @@ Command_line::process(int argc, char** argv) if (this->inputs_.in_group()) { - fprintf(stderr, _("%s: missing group end"), program_name); + fprintf(stderr, _("%s: missing group end\n"), program_name); this->usage(); } diff --git a/gold/options.h b/gold/options.h index f9782cc999..dad1c90180 100644 --- a/gold/options.h +++ b/gold/options.h @@ -47,6 +47,7 @@ namespace options { class Command_line_options; struct One_option; +struct One_z_option; } // End namespace gold::options. @@ -214,6 +215,15 @@ class General_options thread_count_final() const { return this->thread_count_final_; } + // -z execstack, -z noexecstack + bool + is_execstack_set() const + { return this->execstack_ != EXECSTACK_FROM_INPUT; } + + bool + is_stack_executable() const + { return this->execstack_ == EXECSTACK_YES; } + private: // Don't copy this structure. General_options(const General_options&); @@ -233,6 +243,17 @@ class General_options STRIP_DEBUG }; + // Whether to mark the stack as executable. + enum Execstack + { + // Not set on command line. + EXECSTACK_FROM_INPUT, + // Mark the stack as executable. + EXECSTACK_YES, + // Mark the stack as not executable. + EXECSTACK_NO + }; + void set_export_dynamic() { this->export_dynamic_ = true; } @@ -364,6 +385,18 @@ class General_options ignore(const char*) { } + void + set_execstack() + { this->execstack_ = EXECSTACK_YES; } + + void + set_noexecstack() + { this->execstack_ = EXECSTACK_NO; } + + // Handle the -z option. + void + handle_z_option(const char*); + // Apply any sysroot to the directory lists. void add_sysroot(); @@ -388,6 +421,7 @@ class General_options int thread_count_initial_; int thread_count_middle_; int thread_count_final_; + Execstack execstack_; }; // The current state of the position dependent options. diff --git a/gold/symtab.cc b/gold/symtab.cc index 1f120dd190..3108433799 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1294,8 +1294,7 @@ Symbol_table::get_copy_source(const Symbol* sym) const // updated dynamic symbol index. unsigned int -Symbol_table::set_dynsym_indexes(const General_options* options, - const Target* target, +Symbol_table::set_dynsym_indexes(const Target* target, unsigned int index, std::vector* syms, Stringpool* dynpool, @@ -1322,7 +1321,7 @@ Symbol_table::set_dynsym_indexes(const General_options* options, // Record any version information. if (sym->version() != NULL) - versions->record_version(options, this, dynpool, sym); + versions->record_version(this, dynpool, sym); } } diff --git a/gold/symtab.h b/gold/symtab.h index 49ceb7a032..05c8d7a85f 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -947,7 +947,7 @@ class Symbol_table // the vector. The names are stored into the Stringpool. This // returns an updated dynamic symbol index. unsigned int - set_dynsym_indexes(const General_options*, const Target*, unsigned int index, + set_dynsym_indexes(const Target*, unsigned int index, std::vector*, Stringpool*, Versions*); // Finalize the symbol table after we have set the final addresses diff --git a/gold/target.h b/gold/target.h index 3908174e38..32166d12a7 100644 --- a/gold/target.h +++ b/gold/target.h @@ -108,6 +108,14 @@ class Target common_pagesize() const { return this->pti_->common_pagesize; } + // If we see some object files with .note.GNU-stack sections, and + // some objects files without them, this returns whether we should + // consider the object files without them to imply that the stack + // should be executable. + bool + is_default_stack_executable() const + { return this->pti_->is_default_stack_executable; } + // This is called to tell the target to complete any sections it is // handling. After this all sections must have their final size. void @@ -146,6 +154,9 @@ class Target bool has_resolve; // Whether this target has a specific code fill function. bool has_code_fill; + // Whether an object file with no .note.GNU-stack sections implies + // that the stack should be executable. + bool is_default_stack_executable; // The default dynamic linker name. const char* dynamic_linker; // The default text segment address. diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc index 116c6b6a5a..8e6a48d0b4 100644 --- a/gold/testsuite/testfile.cc +++ b/gold/testsuite/testfile.cc @@ -68,6 +68,7 @@ const Target::Target_info Target_test::test_target_info = false, // has_make_symbol false, // has_resolve false, // has_code_fill + false, // is_default_stack_executable "/dummy", // dynamic_linker 0x08000000, // default_text_segment_address 0x1000, // abi_pagesize diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 0af7a16483..c520375a9d 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -263,6 +263,7 @@ const Target::Target_info Target_x86_64::x86_64_info = false, // has_make_symbol false, // has_resolve true, // has_code_fill + true, // is_default_stack_executable "/lib/ld64.so.1", // program interpreter 0x400000, // default_text_segment_address 0x1000, // abi_pagesize