Add support for PT_GNU_STACK.

This commit is contained in:
Ian Lance Taylor 2007-10-23 05:05:48 +00:00
parent 5cab600649
commit 35cdfc9a87
13 changed files with 233 additions and 24 deletions

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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();
}

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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