* 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:
Ian Lance Taylor 2009-10-06 22:58:27 +00:00
parent 5aafa1cc49
commit 364c7fa5c9
32 changed files with 1321 additions and 63 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View 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

View 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

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

View 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

View 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

View 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

View 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

View 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

View File

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

View File

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