aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/dynobj.cc11
-rw-r--r--gold/dynobj.h6
-rw-r--r--gold/i386.cc1
-rw-r--r--gold/layout.cc86
-rw-r--r--gold/layout.h22
-rw-r--r--gold/object.cc17
-rw-r--r--gold/options.cc60
-rw-r--r--gold/options.h34
-rw-r--r--gold/symtab.cc5
-rw-r--r--gold/symtab.h2
-rw-r--r--gold/target.h11
-rw-r--r--gold/testsuite/testfile.cc1
-rw-r--r--gold/x86_64.cc1
13 files changed, 233 insertions, 24 deletions
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
index 499eda7..119f0c7 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 78caaf9..a3d733d 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 26888bf..e36b22c 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 ae2b23f..22d3b59 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 409290a..19c8e09 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<size, big_endian>& 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 64cecc8..9e4b58d 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -427,6 +427,11 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
std::vector<Map_to_output>& 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<bool> omit(shnum, false);
@@ -451,6 +456,16 @@ Sized_relobj<size, big_endian>::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<size, big_endian>::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 4e74dce..1e4b90e 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 f9782cc..dad1c90 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 1f120dd..3108433 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<Symbol*>* 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 49ceb7a..05c8d7a 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<Symbol*>*, Stringpool*, Versions*);
// Finalize the symbol table after we have set the final addresses
diff --git a/gold/target.h b/gold/target.h
index 3908174..32166d1 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 116c6b6..8e6a48d 100644
--- a/gold/testsuite/testfile.cc
+++ b/gold/testsuite/testfile.cc
@@ -68,6 +68,7 @@ const Target::Target_info Target_test<size, big_endian>::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 0af7a16..c520375 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