mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-08 18:28:33 +00:00
Add support for PT_GNU_STACK.
This commit is contained in:
parent
5cab600649
commit
35cdfc9a87
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user