mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:54:41 +08:00
* options.h (class General_options): Define
split_stack_adjust_size parameter. * object.h (class Object): Add uses_split_stack_ and has_no_split_stack_ fields. Add uses_split_stack and has_no_split_stack accessor functions. Declare handle_split_stack_section. (class Reloc_symbol_changes): Define. (class Sized_relobj): Define Function_offsets. Declare split_stack_adjust, split_stack_adjust_reltype, and find_functions. * object.cc (Object::handle_split_stack_section): New function. (Sized_relobj::do_layout): Call handle_split_stack_section. * dynobj.cc (Sized_dynobj::do_layout): Call handle_split_stack_section. * reloc.cc (Sized_relobj::relocate_sections): Call split_stack_adjust for executable sections in split_stack objects. Pass reloc_map to relocate_section. (Sized_relobj::split_stack_adjust): New function. (Sized_relobj::split_stack_adjust_reltype): New function. (Sized_relobj::find_functions): New function. * target-reloc.h: Include "object.h". (relocate_section): Add reloc_symbol_changes parameter. Change all callers. * target.h (class Target): Add calls_non_split method. Declare do_calls_non_split virtual method. Declare match_view and set_view_to_nop. * target.cc: Include "elfcpp.h". (Target::do_calls_non_split): New function. (Target::match_view): New function. (Target::set_view_to_nop): New function. * gold.cc (queue_middle_tasks): Give an error if mixing split-stack and non-split-stack objects with -r. * i386.cc (Target_i386::relocate_section): Add reloc_symbol_changes parameter. (Target_i386::do_calls_non_split): New function. * x86_64.cc (Target_x86_64::relocate_section): Add reloc_symbol_changes parameter. (Target_x86_64::do_calls_non_split): New function. * arm.cc (Target_arm::relocate_section): Add reloc_symbol_changes parameter. * powerpc.cc (Target_powerpc::relocate_section): Add reloc_symbol_changes parameter. * sparc.cc (Target_sparc::relocate_section): Add reloc_symbol_changes parameter. * configure.ac: Call AM_CONDITIONAL for the default target. * configure: Rebuild. * testsuite/Makefile.am (TEST_AS): New variable. (check_SCRIPTS): Add split_i386.sh and split_x86_64.sh. (check_DATA): Add split_i386 and split_x86_64 files. (SPLIT_DEFSYMS): Define. (split_i386_[1234n].o): New targets. (split_i386_[124]): New targets. (split_i386_[1234r].stdout): New targets. (split_x86_64_[1234n].o): New targets. (split_x86_64_[124]): New targets. (split_x86_64_[1234r].stdout): New targets. (MOSTLYCLEANFILES): Add new executables. * testsuite/split_i386.sh: New file. * testsuite/split_x86_64.sh: New file. * testsuite/split_i386_1.s: New file. * testsuite/split_i386_2.s: New file. * testsuite/split_i386_3.s: New file. * testsuite/split_i386_4.s: New file. * testsuite/split_i386_n.s: New file. * testsuite/split_x86_64_1.s: New file. * testsuite/split_x86_64_2.s: New file. * testsuite/split_x86_64_3.s: New file. * testsuite/split_x86_64_4.s: New file. * testsuite/split_x86_64_n.s: New file. * testsuite/testfile.cc (Target_test): Update relocation_section function. * testsuite/Makefile.in: Rebuild.
This commit is contained in:
parent
5aafa1cc49
commit
364c7fa5c9
@ -1,3 +1,78 @@
|
||||
2009-10-06 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* options.h (class General_options): Define
|
||||
split_stack_adjust_size parameter.
|
||||
* object.h (class Object): Add uses_split_stack_ and
|
||||
has_no_split_stack_ fields. Add uses_split_stack and
|
||||
has_no_split_stack accessor functions. Declare
|
||||
handle_split_stack_section.
|
||||
(class Reloc_symbol_changes): Define.
|
||||
(class Sized_relobj): Define Function_offsets. Declare
|
||||
split_stack_adjust, split_stack_adjust_reltype, and
|
||||
find_functions.
|
||||
* object.cc (Object::handle_split_stack_section): New function.
|
||||
(Sized_relobj::do_layout): Call handle_split_stack_section.
|
||||
* dynobj.cc (Sized_dynobj::do_layout): Call
|
||||
handle_split_stack_section.
|
||||
* reloc.cc (Sized_relobj::relocate_sections): Call
|
||||
split_stack_adjust for executable sections in split_stack
|
||||
objects. Pass reloc_map to relocate_section.
|
||||
(Sized_relobj::split_stack_adjust): New function.
|
||||
(Sized_relobj::split_stack_adjust_reltype): New function.
|
||||
(Sized_relobj::find_functions): New function.
|
||||
* target-reloc.h: Include "object.h".
|
||||
(relocate_section): Add reloc_symbol_changes parameter. Change
|
||||
all callers.
|
||||
* target.h (class Target): Add calls_non_split method. Declare
|
||||
do_calls_non_split virtual method. Declare match_view and
|
||||
set_view_to_nop.
|
||||
* target.cc: Include "elfcpp.h".
|
||||
(Target::do_calls_non_split): New function.
|
||||
(Target::match_view): New function.
|
||||
(Target::set_view_to_nop): New function.
|
||||
* gold.cc (queue_middle_tasks): Give an error if mixing
|
||||
split-stack and non-split-stack objects with -r.
|
||||
* i386.cc (Target_i386::relocate_section): Add
|
||||
reloc_symbol_changes parameter.
|
||||
(Target_i386::do_calls_non_split): New function.
|
||||
* x86_64.cc (Target_x86_64::relocate_section): Add
|
||||
reloc_symbol_changes parameter.
|
||||
(Target_x86_64::do_calls_non_split): New function.
|
||||
* arm.cc (Target_arm::relocate_section): Add reloc_symbol_changes
|
||||
parameter.
|
||||
* powerpc.cc (Target_powerpc::relocate_section): Add
|
||||
reloc_symbol_changes parameter.
|
||||
* sparc.cc (Target_sparc::relocate_section): Add
|
||||
reloc_symbol_changes parameter.
|
||||
* configure.ac: Call AM_CONDITIONAL for the default target.
|
||||
* configure: Rebuild.
|
||||
* testsuite/Makefile.am (TEST_AS): New variable.
|
||||
(check_SCRIPTS): Add split_i386.sh and split_x86_64.sh.
|
||||
(check_DATA): Add split_i386 and split_x86_64 files.
|
||||
(SPLIT_DEFSYMS): Define.
|
||||
(split_i386_[1234n].o): New targets.
|
||||
(split_i386_[124]): New targets.
|
||||
(split_i386_[1234r].stdout): New targets.
|
||||
(split_x86_64_[1234n].o): New targets.
|
||||
(split_x86_64_[124]): New targets.
|
||||
(split_x86_64_[1234r].stdout): New targets.
|
||||
(MOSTLYCLEANFILES): Add new executables.
|
||||
* testsuite/split_i386.sh: New file.
|
||||
* testsuite/split_x86_64.sh: New file.
|
||||
* testsuite/split_i386_1.s: New file.
|
||||
* testsuite/split_i386_2.s: New file.
|
||||
* testsuite/split_i386_3.s: New file.
|
||||
* testsuite/split_i386_4.s: New file.
|
||||
* testsuite/split_i386_n.s: New file.
|
||||
* testsuite/split_x86_64_1.s: New file.
|
||||
* testsuite/split_x86_64_2.s: New file.
|
||||
* testsuite/split_x86_64_3.s: New file.
|
||||
* testsuite/split_x86_64_4.s: New file.
|
||||
* testsuite/split_x86_64_n.s: New file.
|
||||
* testsuite/testfile.cc (Target_test): Update relocation_section
|
||||
function.
|
||||
* testsuite/Makefile.in: Rebuild.
|
||||
|
||||
2009-10-06 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* i386.cc (class Target_i386::Relocate): Add ldo_addrs_ field.
|
||||
|
@ -205,7 +205,8 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes*);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
@ -1792,7 +1793,8 @@ Target_arm<big_endian>::relocate_section(
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
section_size_type view_size)
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes* reloc_symbol_changes)
|
||||
{
|
||||
typedef typename Target_arm<big_endian>::Relocate Arm_relocate;
|
||||
gold_assert(sh_type == elfcpp::SHT_REL);
|
||||
@ -1807,7 +1809,8 @@ Target_arm<big_endian>::relocate_section(
|
||||
needs_special_offset_handling,
|
||||
view,
|
||||
address,
|
||||
view_size);
|
||||
view_size,
|
||||
reloc_symbol_changes);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
|
71
gold/configure
vendored
71
gold/configure
vendored
@ -668,6 +668,16 @@ LDFLAGS
|
||||
CFLAGS
|
||||
CC
|
||||
TARGETOBJS
|
||||
DEFAULT_TARGET_X86_64_FALSE
|
||||
DEFAULT_TARGET_X86_64_TRUE
|
||||
DEFAULT_TARGET_SPARC_FALSE
|
||||
DEFAULT_TARGET_SPARC_TRUE
|
||||
DEFAULT_TARGET_POWERPC_FALSE
|
||||
DEFAULT_TARGET_POWERPC_TRUE
|
||||
DEFAULT_TARGET_I386_FALSE
|
||||
DEFAULT_TARGET_I386_TRUE
|
||||
DEFAULT_TARGET_ARM_FALSE
|
||||
DEFAULT_TARGET_ARM_TRUE
|
||||
PLUGINS_FALSE
|
||||
PLUGINS_TRUE
|
||||
THREADS_FALSE
|
||||
@ -3354,6 +3364,47 @@ for targ in $target $canon_targets; do
|
||||
default_size=$targ_size
|
||||
default_big_endian=$targ_big_endian
|
||||
default_osabi=$targ_osabi
|
||||
|
||||
if test "$targ_obj" = "arm"; then
|
||||
DEFAULT_TARGET_ARM_TRUE=
|
||||
DEFAULT_TARGET_ARM_FALSE='#'
|
||||
else
|
||||
DEFAULT_TARGET_ARM_TRUE='#'
|
||||
DEFAULT_TARGET_ARM_FALSE=
|
||||
fi
|
||||
|
||||
if test "$targ_obj" = "i386"; then
|
||||
DEFAULT_TARGET_I386_TRUE=
|
||||
DEFAULT_TARGET_I386_FALSE='#'
|
||||
else
|
||||
DEFAULT_TARGET_I386_TRUE='#'
|
||||
DEFAULT_TARGET_I386_FALSE=
|
||||
fi
|
||||
|
||||
if test "$targ_obj" = "powerpc"; then
|
||||
DEFAULT_TARGET_POWERPC_TRUE=
|
||||
DEFAULT_TARGET_POWERPC_FALSE='#'
|
||||
else
|
||||
DEFAULT_TARGET_POWERPC_TRUE='#'
|
||||
DEFAULT_TARGET_POWERPC_FALSE=
|
||||
fi
|
||||
|
||||
if test "$targ_obj" = "sparc"; then
|
||||
DEFAULT_TARGET_SPARC_TRUE=
|
||||
DEFAULT_TARGET_SPARC_FALSE='#'
|
||||
else
|
||||
DEFAULT_TARGET_SPARC_TRUE='#'
|
||||
DEFAULT_TARGET_SPARC_FALSE=
|
||||
fi
|
||||
|
||||
if test "$targ_obj" = "x86_64"; then
|
||||
DEFAULT_TARGET_X86_64_TRUE=
|
||||
DEFAULT_TARGET_X86_64_FALSE='#'
|
||||
else
|
||||
DEFAULT_TARGET_X86_64_TRUE='#'
|
||||
DEFAULT_TARGET_X86_64_FALSE=
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@ -6970,6 +7021,26 @@ if test -z "${PLUGINS_TRUE}" && test -z "${PLUGINS_FALSE}"; then
|
||||
as_fn_error "conditional \"PLUGINS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${DEFAULT_TARGET_ARM_TRUE}" && test -z "${DEFAULT_TARGET_ARM_FALSE}"; then
|
||||
as_fn_error "conditional \"DEFAULT_TARGET_ARM\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${DEFAULT_TARGET_I386_TRUE}" && test -z "${DEFAULT_TARGET_I386_FALSE}"; then
|
||||
as_fn_error "conditional \"DEFAULT_TARGET_I386\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${DEFAULT_TARGET_POWERPC_TRUE}" && test -z "${DEFAULT_TARGET_POWERPC_FALSE}"; then
|
||||
as_fn_error "conditional \"DEFAULT_TARGET_POWERPC\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${DEFAULT_TARGET_SPARC_TRUE}" && test -z "${DEFAULT_TARGET_SPARC_FALSE}"; then
|
||||
as_fn_error "conditional \"DEFAULT_TARGET_SPARC\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${DEFAULT_TARGET_X86_64_TRUE}" && test -z "${DEFAULT_TARGET_X86_64_FALSE}"; then
|
||||
as_fn_error "conditional \"DEFAULT_TARGET_X86_64\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
|
||||
as_fn_error "conditional \"AMDEP\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
@ -151,6 +151,12 @@ for targ in $target $canon_targets; do
|
||||
default_size=$targ_size
|
||||
default_big_endian=$targ_big_endian
|
||||
default_osabi=$targ_osabi
|
||||
|
||||
AM_CONDITIONAL(DEFAULT_TARGET_ARM, test "$targ_obj" = "arm")
|
||||
AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386")
|
||||
AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc")
|
||||
AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc")
|
||||
AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
@ -408,7 +408,7 @@ Sized_dynobj<size, big_endian>::do_initialize_xindex()
|
||||
|
||||
// Lay out the input sections for a dynamic object. We don't want to
|
||||
// include sections from a dynamic object, so all that we actually do
|
||||
// here is check for .gnu.warning sections.
|
||||
// here is check for .gnu.warning and .note.GNU-split-stack sections.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
@ -443,6 +443,7 @@ Sized_dynobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
||||
const char* name = pnames + shdr.get_sh_name();
|
||||
|
||||
this->handle_gnu_warning_section(name, i, symtab);
|
||||
this->handle_split_stack_section(name);
|
||||
}
|
||||
|
||||
delete sd->section_headers;
|
||||
|
17
gold/gold.cc
17
gold/gold.cc
@ -408,6 +408,23 @@ queue_middle_tasks(const General_options& options,
|
||||
gold_fatal(_("cannot use non-ELF output format with dynamic object %s"),
|
||||
(*input_objects->dynobj_begin())->name().c_str());
|
||||
|
||||
if (parameters->options().relocatable())
|
||||
{
|
||||
Input_objects::Relobj_iterator p = input_objects->relobj_begin();
|
||||
if (p != input_objects->relobj_end())
|
||||
{
|
||||
bool uses_split_stack = (*p)->uses_split_stack();
|
||||
for (++p; p != input_objects->relobj_end(); ++p)
|
||||
{
|
||||
if ((*p)->uses_split_stack() != uses_split_stack)
|
||||
gold_fatal(_("cannot mix split-stack '%s' and "
|
||||
"non-split-stack '%s' when using -r"),
|
||||
(*input_objects->relobj_begin())->name().c_str(),
|
||||
(*p)->name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_debugging_enabled(DEBUG_SCRIPT))
|
||||
layout->script_options()->print(stderr);
|
||||
|
||||
|
73
gold/i386.cc
73
gold/i386.cc
@ -113,7 +113,8 @@ class Target_i386 : public Target_freebsd<32, false>
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes*);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
@ -168,6 +169,13 @@ class Target_i386 : public Target_freebsd<32, false>
|
||||
return Target::do_is_local_label_name(name);
|
||||
}
|
||||
|
||||
// Adjust -fstack-split code which calls non-stack-split code.
|
||||
void
|
||||
do_calls_non_split(Relobj* object, unsigned int shndx,
|
||||
section_offset_type fnoffset, section_size_type fnsize,
|
||||
unsigned char* view, section_size_type view_size,
|
||||
std::string* from, std::string* to) const;
|
||||
|
||||
// Return the size of the GOT section.
|
||||
section_size_type
|
||||
got_size()
|
||||
@ -2465,7 +2473,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
section_size_type view_size)
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes* reloc_symbol_changes)
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_REL);
|
||||
|
||||
@ -2479,7 +2488,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
|
||||
needs_special_offset_handling,
|
||||
view,
|
||||
address,
|
||||
view_size);
|
||||
view_size,
|
||||
reloc_symbol_changes);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
@ -2699,6 +2709,63 @@ Target_i386::do_code_fill(section_size_type length) const
|
||||
return std::string(nops[length], length);
|
||||
}
|
||||
|
||||
// FNOFFSET in section SHNDX in OBJECT is the start of a function
|
||||
// compiled with -fstack-split. The function calls non-stack-split
|
||||
// code. We have to change the function so that it always ensures
|
||||
// that it has enough stack space to run some random function.
|
||||
|
||||
void
|
||||
Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
|
||||
section_offset_type fnoffset,
|
||||
section_size_type fnsize,
|
||||
unsigned char* view,
|
||||
section_size_type view_size,
|
||||
std::string* from,
|
||||
std::string* to) const
|
||||
{
|
||||
// The function starts with a comparison of the stack pointer and a
|
||||
// field in the TCB. This is followed by a jump.
|
||||
|
||||
// cmp %gs:NN,%esp
|
||||
if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3)
|
||||
&& fnsize > 7)
|
||||
{
|
||||
// We will call __morestack if the carry flag is set after this
|
||||
// comparison. We turn the comparison into an stc instruction
|
||||
// and some nops.
|
||||
view[fnoffset] = '\xf9';
|
||||
this->set_view_to_nop(view, view_size, fnoffset + 1, 6);
|
||||
}
|
||||
// lea NN(%esp),%ecx
|
||||
else if (this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3)
|
||||
&& fnsize > 7)
|
||||
{
|
||||
// This is loading an offset from the stack pointer for a
|
||||
// comparison. The offset is negative, so we decrease the
|
||||
// offset by the amount of space we need for the stack. This
|
||||
// means we will avoid calling __morestack if there happens to
|
||||
// be plenty of space on the stack already.
|
||||
unsigned char* pval = view + fnoffset + 3;
|
||||
uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
|
||||
val -= parameters->options().split_stack_adjust_size();
|
||||
elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!object->has_no_split_stack())
|
||||
object->error(_("failed to match split-stack sequence at "
|
||||
"section %u offset %0zx"),
|
||||
shndx, fnoffset);
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to change the function so that it calls
|
||||
// __morestack_non_split instead of __morestack. The former will
|
||||
// allocate additional stack space.
|
||||
*from = "__morestack";
|
||||
*to = "__morestack_non_split";
|
||||
}
|
||||
|
||||
// The selector for i386 object files.
|
||||
|
||||
class Target_selector_i386 : public Target_selector_freebsd
|
||||
|
@ -231,6 +231,25 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
|
||||
return false;
|
||||
}
|
||||
|
||||
// If NAME is the name of the special section which indicates that
|
||||
// this object was compiled with -fstack-split, mark it accordingly.
|
||||
|
||||
bool
|
||||
Object::handle_split_stack_section(const char* name)
|
||||
{
|
||||
if (strcmp(name, ".note.GNU-split-stack") == 0)
|
||||
{
|
||||
this->uses_split_stack_ = true;
|
||||
return true;
|
||||
}
|
||||
if (strcmp(name, ".note.GNU-no-split-stack") == 0)
|
||||
{
|
||||
this->has_no_split_stack_ = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Class Relobj
|
||||
|
||||
// To copy the symbols data read from the file to a local data structure.
|
||||
@ -1109,6 +1128,16 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
||||
omit[i] = true;
|
||||
}
|
||||
|
||||
// The .note.GNU-split-stack section is also special. It
|
||||
// indicates that the object was compiled with
|
||||
// -fsplit-stack.
|
||||
if (this->handle_split_stack_section(name))
|
||||
{
|
||||
if (!parameters->options().relocatable()
|
||||
&& !parameters->options().shared())
|
||||
omit[i] = true;
|
||||
}
|
||||
|
||||
bool discard = omit[i];
|
||||
if (!discard)
|
||||
{
|
||||
|
@ -195,7 +195,8 @@ class Object
|
||||
Object(const std::string& name, Input_file* input_file, bool is_dynamic,
|
||||
off_t offset = 0)
|
||||
: name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
|
||||
is_dynamic_(is_dynamic), xindex_(NULL), no_export_(false)
|
||||
is_dynamic_(is_dynamic), uses_split_stack_(false),
|
||||
has_no_split_stack_(false), xindex_(NULL), no_export_(false)
|
||||
{ input_file->file().add_object(); }
|
||||
|
||||
virtual ~Object()
|
||||
@ -216,6 +217,17 @@ class Object
|
||||
is_dynamic() const
|
||||
{ return this->is_dynamic_; }
|
||||
|
||||
// Return whether this object was compiled with -fsplit-stack.
|
||||
bool
|
||||
uses_split_stack() const
|
||||
{ return this->uses_split_stack_; }
|
||||
|
||||
// Return whether this object contains any functions compiled with
|
||||
// the no_split_stack attribute.
|
||||
bool
|
||||
has_no_split_stack() const
|
||||
{ return this->has_no_split_stack_; }
|
||||
|
||||
// Returns NULL for Objects that are not plugin objects. This method
|
||||
// is overridden in the Pluginobj class.
|
||||
Pluginobj*
|
||||
@ -556,6 +568,12 @@ class Object
|
||||
handle_gnu_warning_section(const char* name, unsigned int shndx,
|
||||
Symbol_table*);
|
||||
|
||||
// If NAME is the name of the special section which indicates that
|
||||
// this object was compiled with -fstack-split, mark it accordingly,
|
||||
// and return true. Otherwise return false.
|
||||
bool
|
||||
handle_split_stack_section(const char* name);
|
||||
|
||||
private:
|
||||
// This class may not be copied.
|
||||
Object(const Object&);
|
||||
@ -572,6 +590,11 @@ class Object
|
||||
unsigned int shnum_;
|
||||
// Whether this is a dynamic object.
|
||||
bool is_dynamic_;
|
||||
// Whether this object was compiled with -fsplit-stack.
|
||||
bool uses_split_stack_;
|
||||
// Whether this object contains any functions compiled with the
|
||||
// no_split_stack attribute.
|
||||
bool has_no_split_stack_;
|
||||
// Many sections for objects with more than SHN_LORESERVE sections.
|
||||
Xindex* xindex_;
|
||||
// True if exclude this object from automatic symbol export.
|
||||
@ -1252,6 +1275,30 @@ class Got_offset_list
|
||||
Got_offset_list* got_next_;
|
||||
};
|
||||
|
||||
// This type is used to modify relocations for -fsplit-stack. It is
|
||||
// indexed by relocation index, and means that the relocation at that
|
||||
// index should use the symbol from the vector, rather than the one
|
||||
// indicated by the relocation.
|
||||
|
||||
class Reloc_symbol_changes
|
||||
{
|
||||
public:
|
||||
Reloc_symbol_changes(size_t count)
|
||||
: vec_(count, NULL)
|
||||
{ }
|
||||
|
||||
void
|
||||
set(size_t i, Symbol* sym)
|
||||
{ this->vec_[i] = sym; }
|
||||
|
||||
const Symbol*
|
||||
operator[](size_t i) const
|
||||
{ return this->vec_[i]; }
|
||||
|
||||
private:
|
||||
std::vector<Symbol*> vec_;
|
||||
};
|
||||
|
||||
// A regular object file. This is size and endian specific.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -1671,6 +1718,30 @@ class Sized_relobj : public Relobj
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size);
|
||||
|
||||
// A type shared by split_stack_adjust_reltype and find_functions.
|
||||
typedef std::map<section_offset_type, section_size_type> Function_offsets;
|
||||
|
||||
// Check for -fsplit-stack routines calling non-split-stack routines.
|
||||
void
|
||||
split_stack_adjust(const Symbol_table*, const unsigned char* pshdrs,
|
||||
unsigned int sh_type, unsigned int shndx,
|
||||
const unsigned char* prelocs, size_t reloc_count,
|
||||
unsigned char* view, section_size_type view_size,
|
||||
Reloc_symbol_changes** reloc_map);
|
||||
|
||||
template<int sh_type>
|
||||
void
|
||||
split_stack_adjust_reltype(const Symbol_table*, const unsigned char* pshdrs,
|
||||
unsigned int shndx, const unsigned char* prelocs,
|
||||
size_t reloc_count, unsigned char* view,
|
||||
section_size_type view_size,
|
||||
Reloc_symbol_changes** reloc_map);
|
||||
|
||||
// Find all functions in a section.
|
||||
void
|
||||
find_functions(const unsigned char* pshdrs, unsigned int shndx,
|
||||
Function_offsets*);
|
||||
|
||||
// Initialize input to output maps for section symbols in merged
|
||||
// sections.
|
||||
void
|
||||
|
@ -812,6 +812,10 @@ class General_options
|
||||
DEFINE_bool(Bshareable, options::ONE_DASH, '\0', false,
|
||||
N_("Generate shared library"), NULL);
|
||||
|
||||
DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
|
||||
N_("Stack size when -fsplit-stack function calls non-split"),
|
||||
N_("SIZE"));
|
||||
|
||||
// This is not actually special in any way, but I need to give it
|
||||
// a non-standard accessor-function name because 'static' is a keyword.
|
||||
DEFINE_special(static, options::ONE_DASH, '\0',
|
||||
|
@ -110,7 +110,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes*);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
@ -1854,7 +1855,8 @@ Target_powerpc<size, big_endian>::relocate_section(
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr address,
|
||||
section_size_type view_size)
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes* reloc_symbol_changes)
|
||||
{
|
||||
typedef Target_powerpc<size, big_endian> Powerpc;
|
||||
typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
|
||||
@ -1871,7 +1873,8 @@ Target_powerpc<size, big_endian>::relocate_section(
|
||||
needs_special_offset_handling,
|
||||
view,
|
||||
address,
|
||||
view_size);
|
||||
view_size,
|
||||
reloc_symbol_changes);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
|
283
gold/reloc.cc
283
gold/reloc.cc
@ -888,39 +888,36 @@ Sized_relobj<size, big_endian>::relocate_sections(
|
||||
|
||||
relinfo.reloc_shndx = i;
|
||||
relinfo.data_shndx = index;
|
||||
unsigned char* view = (*pviews)[index].view;
|
||||
Address address = (*pviews)[index].address;
|
||||
section_size_type view_size = (*pviews)[index].view_size;
|
||||
|
||||
Reloc_symbol_changes* reloc_map = NULL;
|
||||
if (this->uses_split_stack() && output_offset != invalid_address)
|
||||
{
|
||||
typename This::Shdr data_shdr(pshdrs + index * This::shdr_size);
|
||||
if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
|
||||
this->split_stack_adjust(symtab, pshdrs, sh_type, index,
|
||||
prelocs, reloc_count, view, view_size,
|
||||
&reloc_map);
|
||||
}
|
||||
|
||||
if (!parameters->options().relocatable())
|
||||
{
|
||||
target->relocate_section(&relinfo,
|
||||
sh_type,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
os,
|
||||
target->relocate_section(&relinfo, sh_type, prelocs, reloc_count, os,
|
||||
output_offset == invalid_address,
|
||||
(*pviews)[index].view,
|
||||
(*pviews)[index].address,
|
||||
(*pviews)[index].view_size);
|
||||
view, address, view_size, reloc_map);
|
||||
if (parameters->options().emit_relocs())
|
||||
this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
|
||||
os, output_offset,
|
||||
(*pviews)[index].view,
|
||||
(*pviews)[index].address,
|
||||
(*pviews)[index].view_size,
|
||||
(*pviews)[i].view,
|
||||
(*pviews)[i].view_size);
|
||||
os, output_offset, view, address, view_size,
|
||||
(*pviews)[i].view, (*pviews)[i].view_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Relocatable_relocs* rr = this->relocatable_relocs(i);
|
||||
target->relocate_for_relocatable(&relinfo,
|
||||
sh_type,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
os,
|
||||
output_offset,
|
||||
rr,
|
||||
(*pviews)[index].view,
|
||||
(*pviews)[index].address,
|
||||
(*pviews)[index].view_size,
|
||||
target->relocate_for_relocatable(&relinfo, sh_type, prelocs,
|
||||
reloc_count, os, output_offset, rr,
|
||||
view, address, view_size,
|
||||
(*pviews)[i].view,
|
||||
(*pviews)[i].view_size);
|
||||
}
|
||||
@ -1025,6 +1022,244 @@ Sized_relobj<size, big_endian>::free_input_to_output_maps()
|
||||
}
|
||||
}
|
||||
|
||||
// If an object was compiled with -fsplit-stack, this is called to
|
||||
// check whether any relocations refer to functions defined in objects
|
||||
// which were not compiled with -fsplit-stack. If they were, then we
|
||||
// need to apply some target-specific adjustments to request
|
||||
// additional stack space.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::split_stack_adjust(
|
||||
const Symbol_table* symtab,
|
||||
const unsigned char* pshdrs,
|
||||
unsigned int sh_type,
|
||||
unsigned int shndx,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
unsigned char* view,
|
||||
section_size_type view_size,
|
||||
Reloc_symbol_changes** reloc_map)
|
||||
{
|
||||
if (sh_type == elfcpp::SHT_REL)
|
||||
this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
|
||||
prelocs, reloc_count,
|
||||
view, view_size,
|
||||
reloc_map);
|
||||
else
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_RELA);
|
||||
this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
|
||||
prelocs, reloc_count,
|
||||
view, view_size,
|
||||
reloc_map);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust for -fsplit-stack, templatized on the type of the relocation
|
||||
// section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
template<int sh_type>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::split_stack_adjust_reltype(
|
||||
const Symbol_table* symtab,
|
||||
const unsigned char* pshdrs,
|
||||
unsigned int shndx,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
unsigned char* view,
|
||||
section_size_type view_size,
|
||||
Reloc_symbol_changes** reloc_map)
|
||||
{
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
|
||||
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
|
||||
|
||||
size_t local_count = this->local_symbol_count();
|
||||
|
||||
std::vector<section_offset_type> non_split_refs;
|
||||
|
||||
const unsigned char* pr = prelocs;
|
||||
for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
|
||||
{
|
||||
Reltype reloc(pr);
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
|
||||
if (r_sym < local_count)
|
||||
continue;
|
||||
|
||||
const Symbol* gsym = this->global_symbol(r_sym);
|
||||
gold_assert(gsym != NULL);
|
||||
if (gsym->is_forwarder())
|
||||
gsym = symtab->resolve_forwards(gsym);
|
||||
|
||||
// See if this relocation refers to a function defined in an
|
||||
// object compiled without -fsplit-stack. Note that we don't
|
||||
// care about the type of relocation--this means that in some
|
||||
// cases we will ask for a large stack unnecessarily, but this
|
||||
// is not fatal. FIXME: Some targets have symbols which are
|
||||
// functions but are not type STT_FUNC, e.g., STT_ARM_TFUNC.
|
||||
if (gsym->type() == elfcpp::STT_FUNC
|
||||
&& !gsym->is_undefined()
|
||||
&& gsym->source() == Symbol::FROM_OBJECT
|
||||
&& !gsym->object()->uses_split_stack())
|
||||
{
|
||||
section_offset_type offset =
|
||||
convert_to_section_size_type(reloc.get_r_offset());
|
||||
non_split_refs.push_back(offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (non_split_refs.empty())
|
||||
return;
|
||||
|
||||
// At this point, every entry in NON_SPLIT_REFS indicates a
|
||||
// relocation which refers to a function in an object compiled
|
||||
// without -fsplit-stack. We now have to convert that list into a
|
||||
// set of offsets to functions. First, we find all the functions.
|
||||
|
||||
Function_offsets function_offsets;
|
||||
this->find_functions(pshdrs, shndx, &function_offsets);
|
||||
if (function_offsets.empty())
|
||||
return;
|
||||
|
||||
// Now get a list of the function with references to non split-stack
|
||||
// code.
|
||||
|
||||
Function_offsets calls_non_split;
|
||||
for (std::vector<section_offset_type>::const_iterator p
|
||||
= non_split_refs.begin();
|
||||
p != non_split_refs.end();
|
||||
++p)
|
||||
{
|
||||
Function_offsets::const_iterator low = function_offsets.lower_bound(*p);
|
||||
if (low == function_offsets.end())
|
||||
--low;
|
||||
else if (low->first == *p)
|
||||
;
|
||||
else if (low == function_offsets.begin())
|
||||
continue;
|
||||
else
|
||||
--low;
|
||||
|
||||
calls_non_split.insert(*low);
|
||||
}
|
||||
if (calls_non_split.empty())
|
||||
return;
|
||||
|
||||
// Now we have a set of functions to adjust. The adjustments are
|
||||
// target specific. Besides changing the output section view
|
||||
// however, it likes, the target may request a relocation change
|
||||
// from one global symbol name to another.
|
||||
|
||||
for (Function_offsets::const_iterator p = calls_non_split.begin();
|
||||
p != calls_non_split.end();
|
||||
++p)
|
||||
{
|
||||
std::string from;
|
||||
std::string to;
|
||||
parameters->target().calls_non_split(this, shndx, p->first, p->second,
|
||||
view, view_size, &from, &to);
|
||||
if (!from.empty())
|
||||
{
|
||||
gold_assert(!to.empty());
|
||||
Symbol* tosym = NULL;
|
||||
|
||||
// Find relocations in the relevant function which are for
|
||||
// FROM.
|
||||
pr = prelocs;
|
||||
for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
|
||||
{
|
||||
Reltype reloc(pr);
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword r_info =
|
||||
reloc.get_r_info();
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
|
||||
if (r_sym < local_count)
|
||||
continue;
|
||||
|
||||
section_offset_type offset =
|
||||
convert_to_section_size_type(reloc.get_r_offset());
|
||||
if (offset < p->first
|
||||
|| (offset
|
||||
>= (p->first
|
||||
+ static_cast<section_offset_type>(p->second))))
|
||||
continue;
|
||||
|
||||
const Symbol* gsym = this->global_symbol(r_sym);
|
||||
if (from == gsym->name())
|
||||
{
|
||||
if (tosym == NULL)
|
||||
{
|
||||
tosym = symtab->lookup(to.c_str());
|
||||
if (tosym == NULL)
|
||||
{
|
||||
this->error(_("could not convert call "
|
||||
"to '%s' to '%s'"),
|
||||
from.c_str(), to.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*reloc_map == NULL)
|
||||
*reloc_map = new Reloc_symbol_changes(reloc_count);
|
||||
(*reloc_map)->set(i, tosym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find all the function in this object defined in section SHNDX.
|
||||
// Store their offsets in the section in FUNCTION_OFFSETS.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Sized_relobj<size, big_endian>::find_functions(
|
||||
const unsigned char* pshdrs,
|
||||
unsigned int shndx,
|
||||
Sized_relobj<size, big_endian>::Function_offsets* function_offsets)
|
||||
{
|
||||
// We need to read the symbols to find the functions. If we wanted
|
||||
// to, we could cache reading the symbols across all sections in the
|
||||
// object.
|
||||
const unsigned int symtab_shndx = this->symtab_shndx_;
|
||||
typename This::Shdr symtabshdr(pshdrs + symtab_shndx * This::shdr_size);
|
||||
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword sh_size =
|
||||
symtabshdr.get_sh_size();
|
||||
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
|
||||
sh_size, true, true);
|
||||
|
||||
const int sym_size = This::sym_size;
|
||||
const unsigned int symcount = sh_size / sym_size;
|
||||
for (unsigned int i = 0; i < symcount; ++i, psyms += sym_size)
|
||||
{
|
||||
typename elfcpp::Sym<size, big_endian> isym(psyms);
|
||||
|
||||
// FIXME: Some targets can have functions which do not have type
|
||||
// STT_FUNC, e.g., STT_ARM_TFUNC.
|
||||
if (isym.get_st_type() != elfcpp::STT_FUNC
|
||||
|| isym.get_st_size() == 0)
|
||||
continue;
|
||||
|
||||
bool is_ordinary;
|
||||
unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
|
||||
&is_ordinary);
|
||||
if (!is_ordinary || sym_shndx != shndx)
|
||||
continue;
|
||||
|
||||
section_offset_type value =
|
||||
convert_to_section_size_type(isym.get_st_value());
|
||||
section_size_type fnsize =
|
||||
convert_to_section_size_type(isym.get_st_size());
|
||||
|
||||
(*function_offsets)[value] = fnsize;
|
||||
}
|
||||
}
|
||||
|
||||
// Class Merged_symbol_value.
|
||||
|
||||
template<int size>
|
||||
|
@ -112,7 +112,8 @@ class Target_sparc : public Sized_target<size, big_endian>
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes*);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
@ -3106,7 +3107,8 @@ Target_sparc<size, big_endian>::relocate_section(
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr address,
|
||||
section_size_type view_size)
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes* reloc_symbol_changes)
|
||||
{
|
||||
typedef Target_sparc<size, big_endian> Sparc;
|
||||
typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
|
||||
@ -3123,7 +3125,8 @@ Target_sparc<size, big_endian>::relocate_section(
|
||||
needs_special_offset_handling,
|
||||
view,
|
||||
address,
|
||||
view_size);
|
||||
view_size,
|
||||
reloc_symbol_changes);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "symtab.h"
|
||||
#include "object.h"
|
||||
#include "reloc.h"
|
||||
#include "reloc-types.h"
|
||||
|
||||
@ -163,6 +164,12 @@ get_comdat_behavior(const char* name)
|
||||
// NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
|
||||
// the output section.
|
||||
|
||||
// RELOC_SYMBOL_CHANGES is used for -fsplit-stack support. If it is
|
||||
// not NULL, it is a vector indexed by relocation index. If that
|
||||
// entry is not NULL, it points to a global symbol which used as the
|
||||
// symbol for the relocation, ignoring the symbol index in the
|
||||
// relocation.
|
||||
|
||||
template<int size, bool big_endian, typename Target_type, int sh_type,
|
||||
typename Relocate>
|
||||
inline void
|
||||
@ -175,7 +182,8 @@ relocate_section(
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
|
||||
section_size_type view_size)
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes* reloc_symbol_changes)
|
||||
{
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
|
||||
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
|
||||
@ -210,7 +218,9 @@ relocate_section(
|
||||
|
||||
Symbol_value<size> symval;
|
||||
const Symbol_value<size> *psymval;
|
||||
if (r_sym < local_count)
|
||||
if (r_sym < local_count
|
||||
&& (reloc_symbol_changes == NULL
|
||||
|| (*reloc_symbol_changes)[i] == NULL))
|
||||
{
|
||||
sym = NULL;
|
||||
psymval = object->local_symbol(r_sym);
|
||||
@ -246,7 +256,7 @@ relocate_section(
|
||||
{
|
||||
if (comdat_behavior == CB_WARNING)
|
||||
gold_warning_at_location(relinfo, i, offset,
|
||||
_("Relocation refers to discarded "
|
||||
_("relocation refers to discarded "
|
||||
"comdat section"));
|
||||
symval.set_output_value(0);
|
||||
}
|
||||
@ -256,10 +266,17 @@ relocate_section(
|
||||
}
|
||||
else
|
||||
{
|
||||
const Symbol* gsym = object->global_symbol(r_sym);
|
||||
gold_assert(gsym != NULL);
|
||||
if (gsym->is_forwarder())
|
||||
gsym = relinfo->symtab->resolve_forwards(gsym);
|
||||
const Symbol* gsym;
|
||||
if (reloc_symbol_changes != NULL
|
||||
&& (*reloc_symbol_changes)[i] != NULL)
|
||||
gsym = (*reloc_symbol_changes)[i];
|
||||
else
|
||||
{
|
||||
gsym = object->global_symbol(r_sym);
|
||||
gold_assert(gsym != NULL);
|
||||
if (gsym->is_forwarder())
|
||||
gsym = relinfo->symtab->resolve_forwards(gsym);
|
||||
}
|
||||
|
||||
sym = static_cast<const Sized_symbol<size>*>(gsym);
|
||||
if (sym->has_symtab_index())
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "gold.h"
|
||||
#include "target.h"
|
||||
#include "dynobj.h"
|
||||
#include "elfcpp.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
@ -135,4 +136,50 @@ Target::do_make_elf_object(const std::string& name, Input_file* input_file,
|
||||
}
|
||||
#endif
|
||||
|
||||
// Default conversion for -fsplit-stack is to give an error.
|
||||
|
||||
void
|
||||
Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
|
||||
section_size_type, unsigned char*, section_size_type,
|
||||
std::string*, std::string*) const
|
||||
{
|
||||
static bool warned;
|
||||
if (!warned)
|
||||
{
|
||||
gold_error(_("linker does not include stack split support "
|
||||
"required by %s"),
|
||||
object->name().c_str());
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.
|
||||
|
||||
bool
|
||||
Target::match_view(const unsigned char* view, section_size_type view_size,
|
||||
section_offset_type offset, const char* bytes,
|
||||
size_t len) const
|
||||
{
|
||||
if (offset + len > view_size)
|
||||
return false;
|
||||
return memcmp(view + offset, bytes, len) == 0;
|
||||
}
|
||||
|
||||
// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
|
||||
// for LEN bytes.
|
||||
|
||||
void
|
||||
Target::set_view_to_nop(unsigned char* view, section_size_type view_size,
|
||||
section_offset_type offset, size_t len) const
|
||||
{
|
||||
gold_assert(offset >= 0 && offset + len <= view_size);
|
||||
if (!this->has_code_fill())
|
||||
memset(view + offset, 0, len);
|
||||
else
|
||||
{
|
||||
std::string fill = this->code_fill(len);
|
||||
memcpy(view + offset, fill.data(), len);
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -43,11 +43,13 @@ namespace gold
|
||||
|
||||
class General_options;
|
||||
class Object;
|
||||
class Relobj;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_relobj;
|
||||
class Relocatable_relocs;
|
||||
template<int size, bool big_endian>
|
||||
class Relocate_info;
|
||||
class Reloc_symbol_changes;
|
||||
class Symbol;
|
||||
template<int size>
|
||||
class Sized_symbol;
|
||||
@ -217,6 +219,22 @@ class Target
|
||||
is_local_label_name(const char* name) const
|
||||
{ return this->do_is_local_label_name(name); }
|
||||
|
||||
// A function starts at OFFSET in section SHNDX in OBJECT. That
|
||||
// function was compiled with -fsplit-stack, but it refers to a
|
||||
// function which was compiled without -fsplit-stack. VIEW is a
|
||||
// modifiable view of the section; VIEW_SIZE is the size of the
|
||||
// view. The target has to adjust the function so that it allocates
|
||||
// enough stack.
|
||||
void
|
||||
calls_non_split(Relobj* object, unsigned int shndx,
|
||||
section_offset_type fnoffset, section_size_type fnsize,
|
||||
unsigned char* view, section_size_type view_size,
|
||||
std::string* from, std::string* to) const
|
||||
{
|
||||
this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
|
||||
from, to);
|
||||
}
|
||||
|
||||
// Make an ELF object.
|
||||
template<int size, bool big_endian>
|
||||
Object*
|
||||
@ -244,7 +262,7 @@ class Target
|
||||
return pass < 2;
|
||||
|
||||
return this->do_relax(pass);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// This struct holds the constant information for a child class. We
|
||||
@ -331,9 +349,15 @@ class Target
|
||||
virtual bool
|
||||
do_is_local_label_name(const char*) const;
|
||||
|
||||
// Virtual function which may be overridden by the child class.
|
||||
virtual void
|
||||
do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
|
||||
section_size_type, unsigned char*, section_size_type,
|
||||
std::string*, std::string*) const;
|
||||
|
||||
// make_elf_object hooks. There are four versions of these for
|
||||
// different address sizes and endianities.
|
||||
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
// Virtual functions which may be overriden by the child class.
|
||||
virtual Object*
|
||||
@ -372,6 +396,18 @@ class Target
|
||||
do_relax(int)
|
||||
{ return false; }
|
||||
|
||||
// A function for targets to call. Return whether BYTES/LEN matches
|
||||
// VIEW/VIEW_SIZE at OFFSET.
|
||||
bool
|
||||
match_view(const unsigned char* view, section_size_type view_size,
|
||||
section_offset_type offset, const char* bytes, size_t len) const;
|
||||
|
||||
// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
|
||||
// for LEN bytes.
|
||||
void
|
||||
set_view_to_nop(unsigned char* view, section_size_type view_size,
|
||||
section_offset_type offset, size_t len) const;
|
||||
|
||||
private:
|
||||
// The implementations of the four do_make_elf_object virtual functions are
|
||||
// almost identical except for their sizes and endianity. We use a template.
|
||||
@ -478,7 +514,8 @@ class Sized_target : public Target
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
|
||||
section_size_type view_size) = 0;
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes*) = 0;
|
||||
|
||||
// Scan the relocs during a relocatable link. The parameters are
|
||||
// like scan_relocs, with an additional Relocatable_relocs
|
||||
|
@ -25,6 +25,7 @@ TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
|
||||
TEST_STRIP = $(top_builddir)/../binutils/strip-new
|
||||
TEST_AR = $(top_builddir)/../binutils/ar
|
||||
TEST_NM = $(top_builddir)/../binutils/nm-new
|
||||
TEST_AS = $(top_builddir)/../gas/as-new
|
||||
|
||||
if PLUGINS
|
||||
LIBDL = -ldl
|
||||
@ -1182,3 +1183,79 @@ permission_test: basic_test.o gcctestdir/ld
|
||||
|
||||
endif GCC
|
||||
endif NATIVE_LINKER
|
||||
|
||||
# These tests work with cross linkers.
|
||||
|
||||
if DEFAULT_TARGET_I386
|
||||
|
||||
check_SCRIPTS += split_i386.sh
|
||||
check_DATA += split_i386_1.stdout split_i386_2.stdout \
|
||||
split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
|
||||
SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
|
||||
split_i386_1.o: split_i386_1.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_i386_2.o: split_i386_2.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_i386_3.o: split_i386_3.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_i386_4.o: split_i386_4.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_i386_n.o: split_i386_n.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
|
||||
split_i386_1.stdout: split_i386_1
|
||||
$(TEST_OBJDUMP) -d $< > $@
|
||||
split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
|
||||
split_i386_2.stdout: split_i386_2
|
||||
$(TEST_OBJDUMP) -d $< > $@
|
||||
split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
|
||||
split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
|
||||
split_i386_4.stdout: split_i386_4
|
||||
$(TEST_OBJDUMP) -d $< > $@
|
||||
split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
|
||||
../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
|
||||
MOSTLYCLEANFILES += split_i386_1 split_i386_2 split_i386_3 \
|
||||
split_i386_4 split_i386_r
|
||||
|
||||
endif DEFAULT_TARGET_I386
|
||||
|
||||
if DEFAULT_TARGET_X86_64
|
||||
|
||||
check_SCRIPTS += split_x86_64.sh
|
||||
check_DATA += split_x86_64_1.stdout split_x86_64_2.stdout \
|
||||
split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
|
||||
SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
|
||||
split_x86_64_1.o: split_x86_64_1.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_x86_64_2.o: split_x86_64_2.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_x86_64_3.o: split_x86_64_3.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_x86_64_4.o: split_x86_64_4.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_x86_64_n.o: split_x86_64_n.s
|
||||
$(TEST_AS) -o $@ $<
|
||||
split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
|
||||
split_x86_64_1.stdout: split_x86_64_1
|
||||
$(TEST_OBJDUMP) -d $< > $@
|
||||
split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
|
||||
split_x86_64_2.stdout: split_x86_64_2
|
||||
$(TEST_OBJDUMP) -d $< > $@
|
||||
split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
|
||||
split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
|
||||
../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
|
||||
split_x86_64_4.stdout: split_x86_64_4
|
||||
$(TEST_OBJDUMP) -d $< > $@
|
||||
split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
|
||||
../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
|
||||
MOSTLYCLEANFILES += split_x86_64_1 split_x86_64_2 split_x86_64_3 \
|
||||
split_x86_64_4 split_x86_64_r
|
||||
|
||||
endif DEFAULT_TARGET_X86_64
|
||||
|
@ -378,6 +378,22 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
|
||||
# Test that if the output file already exists and is empty,
|
||||
# it will get execute permission.
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_31 = permission_test
|
||||
|
||||
# These tests work with cross linkers.
|
||||
@DEFAULT_TARGET_I386_TRUE@am__append_32 = split_i386.sh
|
||||
@DEFAULT_TARGET_I386_TRUE@am__append_33 = split_i386_1.stdout split_i386_2.stdout \
|
||||
@DEFAULT_TARGET_I386_TRUE@ split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
|
||||
|
||||
@DEFAULT_TARGET_I386_TRUE@am__append_34 = split_i386_1 split_i386_2 split_i386_3 \
|
||||
@DEFAULT_TARGET_I386_TRUE@ split_i386_4 split_i386_r
|
||||
|
||||
@DEFAULT_TARGET_X86_64_TRUE@am__append_35 = split_x86_64.sh
|
||||
@DEFAULT_TARGET_X86_64_TRUE@am__append_36 = split_x86_64_1.stdout split_x86_64_2.stdout \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
|
||||
|
||||
@DEFAULT_TARGET_X86_64_TRUE@am__append_37 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ split_x86_64_4 split_x86_64_r
|
||||
|
||||
subdir = testsuite
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
@ -1389,6 +1405,7 @@ TEST_CXXFILT = $(top_builddir)/../binutils/cxxfilt
|
||||
TEST_STRIP = $(top_builddir)/../binutils/strip-new
|
||||
TEST_AR = $(top_builddir)/../binutils/ar
|
||||
TEST_NM = $(top_builddir)/../binutils/nm-new
|
||||
TEST_AS = $(top_builddir)/../gas/as-new
|
||||
@PLUGINS_TRUE@LIBDL = -ldl
|
||||
@THREADS_TRUE@THREADSLIB = -lpthread
|
||||
@OMP_SUPPORT_TRUE@TLS_TEST_C_CFLAGS = -fopenmp
|
||||
@ -1399,13 +1416,15 @@ TEST_NM = $(top_builddir)/../binutils/nm-new
|
||||
# the right choice for files 'make' builds that people rebuild.
|
||||
MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_3) \
|
||||
$(am__append_8) $(am__append_17) $(am__append_25) \
|
||||
$(am__append_29)
|
||||
$(am__append_29) $(am__append_34) $(am__append_37)
|
||||
|
||||
# We will add to these later, for each individual test. Note
|
||||
# that we add each test under check_SCRIPTS or check_PROGRAMS;
|
||||
# the TESTS variable is automatically populated from these.
|
||||
check_SCRIPTS = $(am__append_1) $(am__append_23) $(am__append_27)
|
||||
check_DATA = $(am__append_2) $(am__append_24) $(am__append_28)
|
||||
check_SCRIPTS = $(am__append_1) $(am__append_23) $(am__append_27) \
|
||||
$(am__append_32) $(am__append_35)
|
||||
check_DATA = $(am__append_2) $(am__append_24) $(am__append_28) \
|
||||
$(am__append_33) $(am__append_36)
|
||||
BUILT_SOURCES = $(am__append_16)
|
||||
TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
|
||||
|
||||
@ -1749,6 +1768,8 @@ binary_unittest_SOURCES = binary_unittest.cc
|
||||
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_CFLAGS = -mcmodel=medium
|
||||
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_DEPENDENCIES = gcctestdir/ld
|
||||
@GCC_TRUE@@MCMODEL_MEDIUM_TRUE@@NATIVE_LINKER_TRUE@large_LDFLAGS = -Bgcctestdir/
|
||||
@DEFAULT_TARGET_I386_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
|
||||
@DEFAULT_TARGET_X86_64_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
|
||||
all: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-am
|
||||
|
||||
@ -2979,6 +3000,58 @@ uninstall-am:
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ touch $@; \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod 600 $@; \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_1.o: split_i386_1.s
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_2.o: split_i386_2.s
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_3.o: split_i386_3.s
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_4.o: split_i386_4.s
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_n.o: split_i386_n.s
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
|
||||
@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_1.stdout: split_i386_1
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_OBJDUMP) -d $< > $@
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
|
||||
@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_2.stdout: split_i386_2
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_OBJDUMP) -d $< > $@
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
|
||||
@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
|
||||
@DEFAULT_TARGET_I386_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_4.stdout: split_i386_4
|
||||
@DEFAULT_TARGET_I386_TRUE@ $(TEST_OBJDUMP) -d $< > $@
|
||||
@DEFAULT_TARGET_I386_TRUE@split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
|
||||
@DEFAULT_TARGET_I386_TRUE@ ../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1.o: split_x86_64_1.s
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2.o: split_x86_64_2.s
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_3.o: split_x86_64_3.s
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4.o: split_x86_64_4.s
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_n.o: split_x86_64_n.s
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $<
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_1.stdout: split_x86_64_1
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJDUMP) -d $< > $@
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_2.stdout: split_x86_64_2
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJDUMP) -d $< > $@
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_4.stdout: split_x86_64_4
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_OBJDUMP) -d $< > $@
|
||||
@DEFAULT_TARGET_X86_64_TRUE@split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
|
||||
@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
|
54
gold/testsuite/split_i386.sh
Executable file
54
gold/testsuite/split_i386.sh
Executable file
@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
# split_i386.sh -- test -fstack-split for i386
|
||||
|
||||
# Copyright 2009 Free Software Foundation, Inc.
|
||||
# Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
match()
|
||||
{
|
||||
if ! egrep "$1" "$2" >/dev/null 2>&1; then
|
||||
echo 1>&2 "could not find '$1' in $2"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
nomatch()
|
||||
{
|
||||
if egrep "$1" "$2" >/dev/null 2>&1; then
|
||||
echo 1>&2 "found unexpected '$1' in $2"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
match 'cmp.*+%gs:[^,]*,%esp' split_i386_1.stdout
|
||||
match 'call.*__morestack>?$' split_i386_1.stdout
|
||||
match 'lea.*-0x200\(%esp\),' split_i386_1.stdout
|
||||
|
||||
match 'stc' split_i386_2.stdout
|
||||
match 'call.*__morestack_non_split>?$' split_i386_2.stdout
|
||||
nomatch 'call.*__morestack>?$' split_i386_2.stdout
|
||||
match 'lea.*-0x4200\(%esp\),' split_i386_2.stdout
|
||||
|
||||
match 'failed to match' split_i386_3.stdout
|
||||
|
||||
match 'call.*__morestack>?$' split_i386_4.stdout
|
||||
|
||||
match 'cannot mix' split_i386_r.stdout
|
33
gold/testsuite/split_i386_1.s
Normal file
33
gold/testsuite/split_i386_1.s
Normal file
@ -0,0 +1,33 @@
|
||||
# split_i386_1.s: i386 specific test case for -fsplit-stack.
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
cmp %gs:0x30,%esp
|
||||
jae 1f
|
||||
call __morestack
|
||||
ret
|
||||
1:
|
||||
call fn2
|
||||
ret
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.global fn2
|
||||
.type fn2,@function
|
||||
fn2:
|
||||
lea -0x200(%esp),%ecx
|
||||
cmp %gs:0x30,%ecx
|
||||
jae 1f
|
||||
call __morestack
|
||||
ret
|
||||
1:
|
||||
call fn1
|
||||
ret
|
||||
|
||||
.size fn2,. - fn2
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
33
gold/testsuite/split_i386_2.s
Normal file
33
gold/testsuite/split_i386_2.s
Normal file
@ -0,0 +1,33 @@
|
||||
# split_i386_2.s: i386 specific, -fsplit-stack calling non-split
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
cmp %gs:0x30,%esp
|
||||
jae 1f
|
||||
call __morestack
|
||||
ret
|
||||
1:
|
||||
call fn3
|
||||
ret
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.global fn2
|
||||
.type fn2,@function
|
||||
fn2:
|
||||
lea -0x200(%esp),%ecx
|
||||
cmp %gs:0x30,%ecx
|
||||
jae 1f
|
||||
call __morestack
|
||||
ret
|
||||
1:
|
||||
call fn3
|
||||
ret
|
||||
|
||||
.size fn2,. - fn2
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
22
gold/testsuite/split_i386_3.s
Normal file
22
gold/testsuite/split_i386_3.s
Normal file
@ -0,0 +1,22 @@
|
||||
# split_i386_3.s: i386 specific, adjustment failure
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
push %ebp
|
||||
mov %esp,%ebp
|
||||
cmp %gs:0x30,%esp
|
||||
jae 1f
|
||||
call __morestack
|
||||
ret
|
||||
1:
|
||||
call fn3
|
||||
leave
|
||||
ret
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
23
gold/testsuite/split_i386_4.s
Normal file
23
gold/testsuite/split_i386_4.s
Normal file
@ -0,0 +1,23 @@
|
||||
# split_i386_4.s: i386 specific, permitted adjustment failure
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
push %ebp
|
||||
mov %esp,%ebp
|
||||
cmp %gs:0x30,%esp
|
||||
jae 1f
|
||||
call __morestack
|
||||
ret
|
||||
1:
|
||||
call fn3
|
||||
leave
|
||||
ret
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
||||
.section .note.GNU-no-split-stack,"",@progbits
|
12
gold/testsuite/split_i386_n.s
Normal file
12
gold/testsuite/split_i386_n.s
Normal file
@ -0,0 +1,12 @@
|
||||
# split_i386_n.s: i386 specific, -fsplit-stack calling non-split
|
||||
|
||||
.text
|
||||
|
||||
.global fn3
|
||||
.type fn3,@function
|
||||
fn3:
|
||||
ret
|
||||
|
||||
.size fn3,. - fn3
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
54
gold/testsuite/split_x86_64.sh
Executable file
54
gold/testsuite/split_x86_64.sh
Executable file
@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
# split_x86_64.sh -- test -fstack-split for x86_64
|
||||
|
||||
# Copyright 2009 Free Software Foundation, Inc.
|
||||
# Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
match()
|
||||
{
|
||||
if ! egrep "$1" "$2" >/dev/null 2>&1; then
|
||||
echo 1>&2 "could not find '$1' in $2"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
nomatch()
|
||||
{
|
||||
if egrep "$1" "$2" >/dev/null 2>&1; then
|
||||
echo 1>&2 "found unexpected '$1' in $2"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
match 'cmp.*+%fs:[^,]*,%rsp' split_x86_64_1.stdout
|
||||
match 'callq.*__morestack>?$' split_x86_64_1.stdout
|
||||
match 'lea.*-0x200\(%rsp\),' split_x86_64_1.stdout
|
||||
|
||||
match 'stc' split_x86_64_2.stdout
|
||||
match 'callq.*__morestack_non_split>?$' split_x86_64_2.stdout
|
||||
nomatch 'callq.*__morestack>?$' split_x86_64_2.stdout
|
||||
match 'lea.*-0x4200\(%rsp\),' split_x86_64_2.stdout
|
||||
|
||||
match 'failed to match' split_x86_64_3.stdout
|
||||
|
||||
match 'callq.*__morestack>?$' split_x86_64_4.stdout
|
||||
|
||||
match 'cannot mix' split_x86_64_r.stdout
|
33
gold/testsuite/split_x86_64_1.s
Normal file
33
gold/testsuite/split_x86_64_1.s
Normal file
@ -0,0 +1,33 @@
|
||||
# split_x86_64_1.s: x86_64 specific test case for -fsplit-stack.
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
cmp %fs:0x70,%rsp
|
||||
jae 1f
|
||||
callq __morestack
|
||||
retq
|
||||
1:
|
||||
callq fn2
|
||||
retq
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.global fn2
|
||||
.type fn2,@function
|
||||
fn2:
|
||||
lea -0x200(%rsp),%r10
|
||||
cmp %fs:0x70,%r10
|
||||
jae 1f
|
||||
callq __morestack
|
||||
retq
|
||||
1:
|
||||
callq fn1
|
||||
retq
|
||||
|
||||
.size fn2,. - fn2
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
33
gold/testsuite/split_x86_64_2.s
Normal file
33
gold/testsuite/split_x86_64_2.s
Normal file
@ -0,0 +1,33 @@
|
||||
# split_x86_64_2.s: x86_64 specific, -fsplit-stack calling non-split
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
cmp %fs:0x70,%rsp
|
||||
jae 1f
|
||||
callq __morestack
|
||||
retq
|
||||
1:
|
||||
callq fn3
|
||||
retq
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.global fn2
|
||||
.type fn2,@function
|
||||
fn2:
|
||||
lea -0x200(%rsp),%r10
|
||||
cmp %fs:0x70,%r10
|
||||
jae 1f
|
||||
callq __morestack
|
||||
retq
|
||||
1:
|
||||
callq fn3
|
||||
retq
|
||||
|
||||
.size fn2,. - fn2
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
22
gold/testsuite/split_x86_64_3.s
Normal file
22
gold/testsuite/split_x86_64_3.s
Normal file
@ -0,0 +1,22 @@
|
||||
# split_x86_64_3.s: x86_64 specific, adjustment failure
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
cmp %fs:0x70,%rsp
|
||||
jae 1f
|
||||
callq __morestack
|
||||
retq
|
||||
1:
|
||||
callq fn3
|
||||
leaveq
|
||||
retq
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
23
gold/testsuite/split_x86_64_4.s
Normal file
23
gold/testsuite/split_x86_64_4.s
Normal file
@ -0,0 +1,23 @@
|
||||
# split_x86_64_4.s: x86_64 specific, permitted adjustment failure
|
||||
|
||||
.text
|
||||
|
||||
.global fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
cmp %fs:0x70,%rsp
|
||||
jae 1f
|
||||
callq __morestack
|
||||
retq
|
||||
1:
|
||||
callq fn3
|
||||
leaveq
|
||||
retq
|
||||
|
||||
.size fn1,. - fn1
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.section .note.GNU-split-stack,"",@progbits
|
||||
.section .note.GNU-no-split-stack,"",@progbits
|
12
gold/testsuite/split_x86_64_n.s
Normal file
12
gold/testsuite/split_x86_64_n.s
Normal file
@ -0,0 +1,12 @@
|
||||
# split_x86_64_n.s: x86_64 specific, -fsplit-stack calling non-split
|
||||
|
||||
.text
|
||||
|
||||
.global fn3
|
||||
.type fn3,@function
|
||||
fn3:
|
||||
retq
|
||||
|
||||
.size fn3,. - fn3
|
||||
|
||||
.section .note.GNU-stack,"",@progbits
|
@ -61,7 +61,7 @@ class Target_test : public Sized_target<size, big_endian>
|
||||
relocate_section(const Relocate_info<size, big_endian>*, unsigned int,
|
||||
const unsigned char*, size_t, Output_section*, bool,
|
||||
unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
|
||||
section_size_type)
|
||||
section_size_type, const Reloc_symbol_changes*)
|
||||
{ ERROR("call to Target_test::relocate_section"); }
|
||||
|
||||
void
|
||||
|
@ -120,7 +120,8 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<64>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes*);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
@ -162,6 +163,13 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
||||
do_is_defined_by_abi(const Symbol* sym) const
|
||||
{ return strcmp(sym->name(), "__tls_get_addr") == 0; }
|
||||
|
||||
// Adjust -fstack-split code which calls non-stack-split code.
|
||||
void
|
||||
do_calls_non_split(Relobj* object, unsigned int shndx,
|
||||
section_offset_type fnoffset, section_size_type fnsize,
|
||||
unsigned char* view, section_size_type view_size,
|
||||
std::string* from, std::string* to) const;
|
||||
|
||||
// Return the size of the GOT section.
|
||||
section_size_type
|
||||
got_size()
|
||||
@ -2417,15 +2425,17 @@ Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
|
||||
// Relocate section data.
|
||||
|
||||
void
|
||||
Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<64>::Elf_Addr address,
|
||||
section_size_type view_size)
|
||||
Target_x86_64::relocate_section(
|
||||
const Relocate_info<64, false>* relinfo,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<64>::Elf_Addr address,
|
||||
section_size_type view_size,
|
||||
const Reloc_symbol_changes* reloc_symbol_changes)
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_RELA);
|
||||
|
||||
@ -2439,7 +2449,8 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
|
||||
needs_special_offset_handling,
|
||||
view,
|
||||
address,
|
||||
view_size);
|
||||
view_size,
|
||||
reloc_symbol_changes);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
@ -2657,6 +2668,63 @@ Target_x86_64::do_code_fill(section_size_type length) const
|
||||
return std::string(nops[length], length);
|
||||
}
|
||||
|
||||
// FNOFFSET in section SHNDX in OBJECT is the start of a function
|
||||
// compiled with -fstack-split. The function calls non-stack-split
|
||||
// code. We have to change the function so that it always ensures
|
||||
// that it has enough stack space to run some random function.
|
||||
|
||||
void
|
||||
Target_x86_64::do_calls_non_split(Relobj* object, unsigned int shndx,
|
||||
section_offset_type fnoffset,
|
||||
section_size_type fnsize,
|
||||
unsigned char* view,
|
||||
section_size_type view_size,
|
||||
std::string* from,
|
||||
std::string* to) const
|
||||
{
|
||||
// The function starts with a comparison of the stack pointer and a
|
||||
// field in the TCB. This is followed by a jump.
|
||||
|
||||
// cmp %fs:NN,%rsp
|
||||
if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
|
||||
&& fnsize > 9)
|
||||
{
|
||||
// We will call __morestack if the carry flag is set after this
|
||||
// comparison. We turn the comparison into an stc instruction
|
||||
// and some nops.
|
||||
view[fnoffset] = '\xf9';
|
||||
this->set_view_to_nop(view, view_size, fnoffset + 1, 8);
|
||||
}
|
||||
// lea NN(%rsp),%r10
|
||||
else if (this->match_view(view, view_size, fnoffset, "\x4c\x8d\x94\x24", 4)
|
||||
&& fnsize > 8)
|
||||
{
|
||||
// This is loading an offset from the stack pointer for a
|
||||
// comparison. The offset is negative, so we decrease the
|
||||
// offset by the amount of space we need for the stack. This
|
||||
// means we will avoid calling __morestack if there happens to
|
||||
// be plenty of space on the stack already.
|
||||
unsigned char* pval = view + fnoffset + 4;
|
||||
uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
|
||||
val -= parameters->options().split_stack_adjust_size();
|
||||
elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!object->has_no_split_stack())
|
||||
object->error(_("failed to match split-stack sequence at "
|
||||
"section %u offset %0zx"),
|
||||
shndx, fnoffset);
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to change the function so that it calls
|
||||
// __morestack_non_split instead of __morestack. The former will
|
||||
// allocate additional stack space.
|
||||
*from = "__morestack";
|
||||
*to = "__morestack_non_split";
|
||||
}
|
||||
|
||||
// The selector for x86_64 object files.
|
||||
|
||||
class Target_selector_x86_64 : public Target_selector_freebsd
|
||||
|
Loading…
Reference in New Issue
Block a user