[GOLD] Power10 stub selection
gold version of commit e10a07b32d
.
* options.h (DEFINE_enum): Add optional_arg__ param, adjust
all uses.
(General_options): Add --power10-stubs and --no-power10-stubs.
* options.cc (General_options::finalize): Handle --power10-stubs.
* powerpc.cc (set_power10_stubs): Don't set when --power10-stubs=no.
(power10_stubs_auto): New.
(struct Plt_stub_ent): Add toc_ and tocoff_. Don't use a bitfield
for indx_.
(struct Branch_stub_ent): Add toc_and tocoff_. Use bitfields for
iter_, notoc_ and save_res_.
(add_plt_call_entry): Set toc_. Adjust resizing conditions for
--power10-stubs=auto.
(add_long_branch_entry): Set toc_.
(add_eh_frame, define_stub_syms): No longer use const_iterators
for plt and long branch stub iteration.
(build_tls_opt_head, build_tls_opt_tail): Change parameters and
return value. Move tests for __tls_get_addr to callers.
(plt_call_size): Handle --power10-stubs=auto.
(branch_stub_size): Likewise.
(Stub_table::do_write): Likewise.
(relocate): Likewise.
This commit is contained in:
parent
608d61c202
commit
afd2ea2362
@ -1,3 +1,28 @@
|
|||||||
|
2020-07-27 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* options.h (DEFINE_enum): Add optional_arg__ param, adjust
|
||||||
|
all uses.
|
||||||
|
(General_options): Add --power10-stubs and --no-power10-stubs.
|
||||||
|
* options.cc (General_options::parse_no_power10_stubs): New.
|
||||||
|
(General_options::finalize): Handle --power10-stubs.
|
||||||
|
* powerpc.cc (set_power10_stubs): Don't set when --power10-stubs=no.
|
||||||
|
(power10_stubs_auto): New.
|
||||||
|
(struct Plt_stub_ent): Add toc_ and tocoff_. Don't use a bitfield
|
||||||
|
for indx_.
|
||||||
|
(struct Branch_stub_ent): Add toc_and tocoff_. Use bitfields for
|
||||||
|
iter_, notoc_ and save_res_.
|
||||||
|
(add_plt_call_entry): Set toc_. Adjust resizing conditions for
|
||||||
|
--power10-stubs=auto.
|
||||||
|
(add_long_branch_entry): Set toc_.
|
||||||
|
(add_eh_frame, define_stub_syms): No longer use const_iterators
|
||||||
|
for plt and long branch stub iteration.
|
||||||
|
(build_tls_opt_head, build_tls_opt_tail): Change parameters and
|
||||||
|
return value. Move tests for __tls_get_addr to callers.
|
||||||
|
(plt_call_size): Handle --power10-stubs=auto.
|
||||||
|
(branch_stub_size): Likewise.
|
||||||
|
(Stub_table::do_write): Likewise.
|
||||||
|
(relocate): Likewise.
|
||||||
|
|
||||||
2020-07-19 H.J. Lu <hongjiu.lu@intel.com>
|
2020-07-19 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* testsuite/bnd_ifunc_1.sh: Updated.
|
* testsuite/bnd_ifunc_1.sh: Updated.
|
||||||
|
@ -464,6 +464,14 @@ General_options::parse_plugin_opt(const char*, const char* arg,
|
|||||||
this->add_plugin_option(arg);
|
this->add_plugin_option(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
General_options::parse_no_power10_stubs(const char*, const char*,
|
||||||
|
Command_line*)
|
||||||
|
{
|
||||||
|
this->set_power10_stubs("no");
|
||||||
|
this->set_user_set_power10_stubs();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
General_options::parse_R(const char* option, const char* arg,
|
General_options::parse_R(const char* option, const char* arg,
|
||||||
Command_line* cmdline)
|
Command_line* cmdline)
|
||||||
@ -1183,6 +1191,27 @@ General_options::finalize()
|
|||||||
this->set_start_stop_visibility_enum(elfcpp::STV_PROTECTED);
|
this->set_start_stop_visibility_enum(elfcpp::STV_PROTECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the --power10-stubs argument.
|
||||||
|
if (!this->user_set_power10_stubs())
|
||||||
|
{
|
||||||
|
// --power10-stubs without an arg is equivalent to --power10-stubs=yes
|
||||||
|
// but not specifying --power10-stubs at all should be equivalent to
|
||||||
|
// --power10-stubs=auto. This doesn't fit into the notion of
|
||||||
|
// "default_value", used both as a static initializer and to provide
|
||||||
|
// a missing optional arg. Fix it here.
|
||||||
|
this->set_power10_stubs("auto");
|
||||||
|
this->set_power10_stubs_enum(POWER10_STUBS_AUTO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strcmp(this->power10_stubs(), "auto") == 0)
|
||||||
|
this->set_power10_stubs_enum(POWER10_STUBS_AUTO);
|
||||||
|
else if (strcmp(this->power10_stubs(), "no") == 0)
|
||||||
|
this->set_power10_stubs_enum(POWER10_STUBS_NO);
|
||||||
|
else if (strcmp(this->power10_stubs(), "yes") == 0)
|
||||||
|
this->set_power10_stubs_enum(POWER10_STUBS_YES);
|
||||||
|
}
|
||||||
|
|
||||||
// -M is equivalent to "-Map -".
|
// -M is equivalent to "-Map -".
|
||||||
if (this->print_map() && !this->user_set_Map())
|
if (this->print_map() && !this->user_set_Map())
|
||||||
{
|
{
|
||||||
|
@ -481,9 +481,9 @@ struct Struct_special : public Struct_var
|
|||||||
// After helparg__ should come an initializer list, like
|
// After helparg__ should come an initializer list, like
|
||||||
// {"foo", "bar", "baz"}
|
// {"foo", "bar", "baz"}
|
||||||
#define DEFINE_enum(varname__, dashes__, shortname__, default_value__, \
|
#define DEFINE_enum(varname__, dashes__, shortname__, default_value__, \
|
||||||
helpstring__, helparg__, ...) \
|
helpstring__, helparg__, optional_arg__, ...) \
|
||||||
DEFINE_var(varname__, dashes__, shortname__, default_value__, \
|
DEFINE_var(varname__, dashes__, shortname__, default_value__, \
|
||||||
default_value__, helpstring__, helparg__, false, \
|
default_value__, helpstring__, helparg__, optional_arg__, \
|
||||||
const char*, const char*, parse_choices_##varname__, false) \
|
const char*, const char*, parse_choices_##varname__, false) \
|
||||||
private: \
|
private: \
|
||||||
static void parse_choices_##varname__(const char* option_name, \
|
static void parse_choices_##varname__(const char* option_name, \
|
||||||
@ -703,7 +703,7 @@ class General_options
|
|||||||
N_("Use DT_NEEDED for all shared libraries"));
|
N_("Use DT_NEEDED for all shared libraries"));
|
||||||
|
|
||||||
DEFINE_enum(assert, options::ONE_DASH, '\0', NULL,
|
DEFINE_enum(assert, options::ONE_DASH, '\0', NULL,
|
||||||
N_("Ignored"), N_("[ignored]"),
|
N_("Ignored"), N_("[ignored]"), false,
|
||||||
{"definitions", "nodefinitions", "nosymbolic", "pure-text"});
|
{"definitions", "nodefinitions", "nosymbolic", "pure-text"});
|
||||||
|
|
||||||
// b
|
// b
|
||||||
@ -761,7 +761,7 @@ class General_options
|
|||||||
|
|
||||||
DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
|
DEFINE_enum(compress_debug_sections, options::TWO_DASHES, '\0', "none",
|
||||||
N_("Compress .debug_* sections in the output file"),
|
N_("Compress .debug_* sections in the output file"),
|
||||||
("[none,zlib,zlib-gnu,zlib-gabi]"),
|
("[none,zlib,zlib-gnu,zlib-gabi]"), false,
|
||||||
{"none", "zlib", "zlib-gnu", "zlib-gabi"});
|
{"none", "zlib", "zlib-gnu", "zlib-gabi"});
|
||||||
|
|
||||||
DEFINE_bool(copy_dt_needed_entries, options::TWO_DASHES, '\0', false,
|
DEFINE_bool(copy_dt_needed_entries, options::TWO_DASHES, '\0', false,
|
||||||
@ -934,7 +934,7 @@ class General_options
|
|||||||
N_("FRACTION"));
|
N_("FRACTION"));
|
||||||
|
|
||||||
DEFINE_enum(hash_style, options::TWO_DASHES, '\0', DEFAULT_HASH_STYLE,
|
DEFINE_enum(hash_style, options::TWO_DASHES, '\0', DEFAULT_HASH_STYLE,
|
||||||
N_("Dynamic hash style"), N_("[sysv,gnu,both]"),
|
N_("Dynamic hash style"), N_("[sysv,gnu,both]"), false,
|
||||||
{"sysv", "gnu", "both"});
|
{"sysv", "gnu", "both"});
|
||||||
|
|
||||||
// i
|
// i
|
||||||
@ -946,7 +946,7 @@ class General_options
|
|||||||
N_("Identical Code Folding. "
|
N_("Identical Code Folding. "
|
||||||
"\'--icf=safe\' Folds ctors, dtors and functions whose"
|
"\'--icf=safe\' Folds ctors, dtors and functions whose"
|
||||||
" pointers are definitely not taken"),
|
" pointers are definitely not taken"),
|
||||||
("[none,all,safe]"),
|
("[none,all,safe]"), false,
|
||||||
{"none", "all", "safe"});
|
{"none", "all", "safe"});
|
||||||
|
|
||||||
DEFINE_uint(icf_iterations, options::TWO_DASHES , '\0', 0,
|
DEFINE_uint(icf_iterations, options::TWO_DASHES , '\0', 0,
|
||||||
@ -1086,7 +1086,7 @@ class General_options
|
|||||||
|
|
||||||
DEFINE_enum(orphan_handling, options::TWO_DASHES, '\0', "place",
|
DEFINE_enum(orphan_handling, options::TWO_DASHES, '\0', "place",
|
||||||
N_("Orphan section handling"), N_("[place,discard,warn,error]"),
|
N_("Orphan section handling"), N_("[place,discard,warn,error]"),
|
||||||
{"place", "discard", "warn", "error"});
|
false, {"place", "discard", "warn", "error"});
|
||||||
|
|
||||||
// p
|
// p
|
||||||
|
|
||||||
@ -1141,6 +1141,12 @@ class General_options
|
|||||||
N_("Use posix_fallocate to reserve space in the output file"),
|
N_("Use posix_fallocate to reserve space in the output file"),
|
||||||
N_("Use fallocate or ftruncate to reserve space"));
|
N_("Use fallocate or ftruncate to reserve space"));
|
||||||
|
|
||||||
|
DEFINE_enum(power10_stubs, options::TWO_DASHES, '\0', "yes",
|
||||||
|
N_("(PowerPC64 only) stubs use power10 insns"),
|
||||||
|
N_("[=auto,no,yes]"), true, {"auto", "no", "yes"});
|
||||||
|
DEFINE_special(no_power10_stubs, options::TWO_DASHES, '\0',
|
||||||
|
N_("(PowerPC64 only) stubs do not use power10 insns"), NULL);
|
||||||
|
|
||||||
DEFINE_bool(preread_archive_symbols, options::TWO_DASHES, '\0', false,
|
DEFINE_bool(preread_archive_symbols, options::TWO_DASHES, '\0', false,
|
||||||
N_("Preread archive symbols when multi-threaded"), NULL);
|
N_("Preread archive symbols when multi-threaded"), NULL);
|
||||||
|
|
||||||
@ -1236,7 +1242,7 @@ class General_options
|
|||||||
DEFINE_enum(sort_section, options::TWO_DASHES, '\0', "none",
|
DEFINE_enum(sort_section, options::TWO_DASHES, '\0', "none",
|
||||||
N_("Sort sections by name. \'--no-text-reorder\'"
|
N_("Sort sections by name. \'--no-text-reorder\'"
|
||||||
" will override \'--sort-section=name\' for .text"),
|
" will override \'--sort-section=name\' for .text"),
|
||||||
N_("[none,name]"),
|
N_("[none,name]"), false,
|
||||||
{"none", "name"});
|
{"none", "name"});
|
||||||
|
|
||||||
DEFINE_uint(spare_dynamic_tags, options::TWO_DASHES, '\0', 5,
|
DEFINE_uint(spare_dynamic_tags, options::TWO_DASHES, '\0', 5,
|
||||||
@ -1287,7 +1293,7 @@ class General_options
|
|||||||
NULL);
|
NULL);
|
||||||
DEFINE_enum(target2, options::TWO_DASHES, '\0', NULL,
|
DEFINE_enum(target2, options::TWO_DASHES, '\0', NULL,
|
||||||
N_("(ARM only) Set R_ARM_TARGET2 relocation type"),
|
N_("(ARM only) Set R_ARM_TARGET2 relocation type"),
|
||||||
N_("[rel, abs, got-rel"),
|
N_("[rel, abs, got-rel"), false,
|
||||||
{"rel", "abs", "got-rel"});
|
{"rel", "abs", "got-rel"});
|
||||||
|
|
||||||
DEFINE_bool(text_reorder, options::TWO_DASHES, '\0', true,
|
DEFINE_bool(text_reorder, options::TWO_DASHES, '\0', true,
|
||||||
@ -1344,7 +1350,7 @@ class General_options
|
|||||||
DEFINE_enum(unresolved_symbols, options::TWO_DASHES, '\0', NULL,
|
DEFINE_enum(unresolved_symbols, options::TWO_DASHES, '\0', NULL,
|
||||||
N_("How to handle unresolved symbols"),
|
N_("How to handle unresolved symbols"),
|
||||||
("ignore-all,report-all,ignore-in-object-files,"
|
("ignore-all,report-all,ignore-in-object-files,"
|
||||||
"ignore-in-shared-libs"),
|
"ignore-in-shared-libs"), false,
|
||||||
{"ignore-all", "report-all", "ignore-in-object-files",
|
{"ignore-all", "report-all", "ignore-in-object-files",
|
||||||
"ignore-in-shared-libs"});
|
"ignore-in-shared-libs"});
|
||||||
|
|
||||||
@ -1507,7 +1513,7 @@ class General_options
|
|||||||
DEFINE_enum(start_stop_visibility, options::DASH_Z, '\0', "protected",
|
DEFINE_enum(start_stop_visibility, options::DASH_Z, '\0', "protected",
|
||||||
N_("ELF symbol visibility for synthesized "
|
N_("ELF symbol visibility for synthesized "
|
||||||
"__start_* and __stop_* symbols"),
|
"__start_* and __stop_* symbols"),
|
||||||
("[default,internal,hidden,protected]"),
|
("[default,internal,hidden,protected]"), false,
|
||||||
{"default", "internal", "hidden", "protected"});
|
{"default", "internal", "hidden", "protected"});
|
||||||
DEFINE_bool(text, options::DASH_Z, '\0', false,
|
DEFINE_bool(text, options::DASH_Z, '\0', false,
|
||||||
N_("Do not permit relocations in read-only segments"),
|
N_("Do not permit relocations in read-only segments"),
|
||||||
@ -1763,6 +1769,20 @@ class General_options
|
|||||||
start_stop_visibility_enum() const
|
start_stop_visibility_enum() const
|
||||||
{ return this->start_stop_visibility_enum_; }
|
{ return this->start_stop_visibility_enum_; }
|
||||||
|
|
||||||
|
enum Power10_stubs
|
||||||
|
{
|
||||||
|
// Use Power10 insns on @notoc calls/branches, non-Power10 elsewhere.
|
||||||
|
POWER10_STUBS_AUTO,
|
||||||
|
// Don't use Power10 insns
|
||||||
|
POWER10_STUBS_NO,
|
||||||
|
// Always use Power10 insns
|
||||||
|
POWER10_STUBS_YES
|
||||||
|
};
|
||||||
|
|
||||||
|
Power10_stubs
|
||||||
|
power10_stubs_enum() const
|
||||||
|
{ return this->power10_stubs_enum_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Don't copy this structure.
|
// Don't copy this structure.
|
||||||
General_options(const General_options&);
|
General_options(const General_options&);
|
||||||
@ -1826,6 +1846,10 @@ class General_options
|
|||||||
set_start_stop_visibility_enum(elfcpp::STV value)
|
set_start_stop_visibility_enum(elfcpp::STV value)
|
||||||
{ this->start_stop_visibility_enum_ = value; }
|
{ this->start_stop_visibility_enum_ = value; }
|
||||||
|
|
||||||
|
void
|
||||||
|
set_power10_stubs_enum(Power10_stubs value)
|
||||||
|
{ this->power10_stubs_enum_ = value; }
|
||||||
|
|
||||||
// These are called by finalize() to set up the search-path correctly.
|
// These are called by finalize() to set up the search-path correctly.
|
||||||
void
|
void
|
||||||
add_to_library_path_with_sysroot(const std::string& arg)
|
add_to_library_path_with_sysroot(const std::string& arg)
|
||||||
@ -1895,6 +1919,8 @@ class General_options
|
|||||||
Orphan_handling orphan_handling_enum_;
|
Orphan_handling orphan_handling_enum_;
|
||||||
// Symbol visibility for __start_* / __stop_* magic symbols.
|
// Symbol visibility for __start_* / __stop_* magic symbols.
|
||||||
elfcpp::STV start_stop_visibility_enum_;
|
elfcpp::STV start_stop_visibility_enum_;
|
||||||
|
// Power10 stubs option
|
||||||
|
Power10_stubs power10_stubs_enum_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The position-dependent options. We use this to store the state of
|
// The position-dependent options. We use this to store the state of
|
||||||
|
680
gold/powerpc.cc
680
gold/powerpc.cc
@ -1085,7 +1085,16 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
|||||||
void
|
void
|
||||||
set_power10_stubs()
|
set_power10_stubs()
|
||||||
{
|
{
|
||||||
this->power10_stubs_ = true;
|
if (parameters->options().power10_stubs_enum()
|
||||||
|
!= General_options::POWER10_STUBS_NO)
|
||||||
|
this->power10_stubs_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
power10_stubs_auto() const
|
||||||
|
{
|
||||||
|
return (parameters->options().power10_stubs_enum()
|
||||||
|
== General_options::POWER10_STUBS_AUTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -4621,26 +4630,32 @@ class Stub_table : public Output_relaxed_input_section
|
|||||||
struct Plt_stub_ent
|
struct Plt_stub_ent
|
||||||
{
|
{
|
||||||
Plt_stub_ent(unsigned int off, unsigned int indx)
|
Plt_stub_ent(unsigned int off, unsigned int indx)
|
||||||
: off_(off), indx_(indx), iter_(0), notoc_(0), r2save_(0), localentry0_(0)
|
: off_(off), indx_(indx), iter_(0), notoc_(0), toc_(0),
|
||||||
|
r2save_(0), localentry0_(0), tocoff_(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
unsigned int off_;
|
unsigned int off_;
|
||||||
unsigned int indx_ : 28;
|
unsigned int indx_;
|
||||||
unsigned int iter_ : 1;
|
unsigned int iter_ : 1;
|
||||||
unsigned int notoc_ : 1;
|
unsigned int notoc_ : 1;
|
||||||
|
unsigned int toc_ : 1;
|
||||||
unsigned int r2save_ : 1;
|
unsigned int r2save_ : 1;
|
||||||
unsigned int localentry0_ : 1;
|
unsigned int localentry0_ : 1;
|
||||||
|
unsigned int tocoff_ : 8;
|
||||||
};
|
};
|
||||||
struct Branch_stub_ent
|
struct Branch_stub_ent
|
||||||
{
|
{
|
||||||
Branch_stub_ent(unsigned int off, bool notoc, bool save_res)
|
Branch_stub_ent(unsigned int off, bool notoc, bool save_res)
|
||||||
: off_(off), iter_(false), notoc_(notoc), save_res_(save_res)
|
: off_(off), iter_(0), notoc_(notoc), toc_(0), save_res_(save_res),
|
||||||
|
tocoff_(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
unsigned int off_;
|
unsigned int off_;
|
||||||
bool iter_;
|
unsigned int iter_ : 1;
|
||||||
bool notoc_;
|
unsigned int notoc_ : 1;
|
||||||
bool save_res_;
|
unsigned int toc_ : 1;
|
||||||
|
unsigned int save_res_ : 1;
|
||||||
|
unsigned int tocoff_ : 8;
|
||||||
};
|
};
|
||||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
|
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
|
||||||
static const Address invalid_address = static_cast<Address>(0) - 1;
|
static const Address invalid_address = static_cast<Address>(0) - 1;
|
||||||
@ -4888,7 +4903,7 @@ class Stub_table : public Output_relaxed_input_section
|
|||||||
|
|
||||||
// Size of a given plt call stub.
|
// Size of a given plt call stub.
|
||||||
unsigned int
|
unsigned int
|
||||||
plt_call_size(typename Plt_stub_entries::const_iterator p) const;
|
plt_call_size(typename Plt_stub_entries::iterator p) const;
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
plt_call_align(unsigned int bytes) const
|
plt_call_align(unsigned int bytes) const
|
||||||
@ -4899,16 +4914,14 @@ class Stub_table : public Output_relaxed_input_section
|
|||||||
|
|
||||||
// Return long branch stub size.
|
// Return long branch stub size.
|
||||||
unsigned int
|
unsigned int
|
||||||
branch_stub_size(typename Branch_stub_entries::const_iterator p,
|
branch_stub_size(typename Branch_stub_entries::iterator p,
|
||||||
bool* need_lt);
|
bool* need_lt);
|
||||||
|
|
||||||
bool
|
void
|
||||||
build_tls_opt_head(unsigned char** pp,
|
build_tls_opt_head(unsigned char** pp, bool save_lr);
|
||||||
typename Plt_stub_entries::const_iterator cs);
|
|
||||||
|
|
||||||
bool
|
void
|
||||||
build_tls_opt_tail(unsigned char* p,
|
build_tls_opt_tail(unsigned char* p);
|
||||||
typename Plt_stub_entries::const_iterator cs);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
plt_error(const Plt_stub_key& p);
|
plt_error(const Plt_stub_key& p);
|
||||||
@ -5073,15 +5086,22 @@ Stub_table<size, big_endian>::add_plt_call_entry(
|
|||||||
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
|
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
|
||||||
{
|
{
|
||||||
if (!p.second && !p.first->second.notoc_
|
if (!p.second && !p.first->second.notoc_
|
||||||
&& !this->targ_->power10_stubs())
|
&& (!this->targ_->power10_stubs()
|
||||||
|
|| this->targ_->power10_stubs_auto()))
|
||||||
this->need_resize_ = true;
|
this->need_resize_ = true;
|
||||||
p.first->second.notoc_ = 1;
|
p.first->second.notoc_ = 1;
|
||||||
}
|
}
|
||||||
else if (!tocsave && !p.first->second.localentry0_)
|
else
|
||||||
{
|
{
|
||||||
if (!p.second && !p.first->second.r2save_)
|
if (!p.second && !p.first->second.toc_)
|
||||||
this->need_resize_ = true;
|
this->need_resize_ = true;
|
||||||
p.first->second.r2save_ = 1;
|
p.first->second.toc_ = 1;
|
||||||
|
if (!tocsave && !p.first->second.localentry0_)
|
||||||
|
{
|
||||||
|
if (!p.second && !p.first->second.r2save_)
|
||||||
|
this->need_resize_ = true;
|
||||||
|
p.first->second.r2save_ = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p.second || (this->resizing_ && !p.first->second.iter_))
|
if (p.second || (this->resizing_ && !p.first->second.iter_))
|
||||||
@ -5124,15 +5144,22 @@ Stub_table<size, big_endian>::add_plt_call_entry(
|
|||||||
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
|
if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
|
||||||
{
|
{
|
||||||
if (!p.second && !p.first->second.notoc_
|
if (!p.second && !p.first->second.notoc_
|
||||||
&& !this->targ_->power10_stubs())
|
&& (!this->targ_->power10_stubs()
|
||||||
|
|| this->targ_->power10_stubs_auto()))
|
||||||
this->need_resize_ = true;
|
this->need_resize_ = true;
|
||||||
p.first->second.notoc_ = 1;
|
p.first->second.notoc_ = 1;
|
||||||
}
|
}
|
||||||
else if (!tocsave && !p.first->second.localentry0_)
|
else
|
||||||
{
|
{
|
||||||
if (!p.second && !p.first->second.r2save_)
|
if (!p.second && !p.first->second.toc_)
|
||||||
this->need_resize_ = true;
|
this->need_resize_ = true;
|
||||||
p.first->second.r2save_ = 1;
|
p.first->second.toc_ = 1;
|
||||||
|
if (!tocsave && !p.first->second.localentry0_)
|
||||||
|
{
|
||||||
|
if (!p.second && !p.first->second.r2save_)
|
||||||
|
this->need_resize_ = true;
|
||||||
|
p.first->second.r2save_ = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p.second || (this->resizing_ && !p.first->second.iter_))
|
if (p.second || (this->resizing_ && !p.first->second.iter_))
|
||||||
@ -5221,11 +5248,18 @@ Stub_table<size, big_endian>::add_long_branch_entry(
|
|||||||
Branch_stub_ent ent(this->branch_size_, notoc, save_res);
|
Branch_stub_ent ent(this->branch_size_, notoc, save_res);
|
||||||
std::pair<typename Branch_stub_entries::iterator, bool> p
|
std::pair<typename Branch_stub_entries::iterator, bool> p
|
||||||
= this->long_branch_stubs_.insert(std::make_pair(key, ent));
|
= this->long_branch_stubs_.insert(std::make_pair(key, ent));
|
||||||
if (notoc && !p.first->second.notoc_)
|
if (notoc)
|
||||||
{
|
{
|
||||||
this->need_resize_ = true;
|
if (!p.second && !p.first->second.notoc_)
|
||||||
|
this->need_resize_ = true;
|
||||||
p.first->second.notoc_ = true;
|
p.first->second.notoc_ = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!p.second && !p.first->second.toc_)
|
||||||
|
this->need_resize_ = true;
|
||||||
|
p.first->second.toc_ = true;
|
||||||
|
}
|
||||||
gold_assert(save_res == p.first->second.save_res_);
|
gold_assert(save_res == p.first->second.save_res_);
|
||||||
if (p.second || (this->resizing_ && !p.first->second.iter_))
|
if (p.second || (this->resizing_ && !p.first->second.iter_))
|
||||||
{
|
{
|
||||||
@ -5320,7 +5354,7 @@ Stub_table<size, big_endian>::add_eh_frame(Layout* layout)
|
|||||||
if (!this->targ_->has_glink())
|
if (!this->targ_->has_glink())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
typedef typename Plt_stub_entries::const_iterator plt_iter;
|
typedef typename Plt_stub_entries::iterator plt_iter;
|
||||||
std::vector<plt_iter> calls;
|
std::vector<plt_iter> calls;
|
||||||
if (!this->plt_call_stubs_.empty())
|
if (!this->plt_call_stubs_.empty())
|
||||||
for (plt_iter cs = this->plt_call_stubs_.begin();
|
for (plt_iter cs = this->plt_call_stubs_.begin();
|
||||||
@ -5622,7 +5656,7 @@ Stub_table<size, big_endian>::define_stub_syms(Symbol_table* symtab)
|
|||||||
// output .symtab ordering depends on the order in which symbols
|
// output .symtab ordering depends on the order in which symbols
|
||||||
// are added to the linker symtab. We want reproducible output
|
// are added to the linker symtab. We want reproducible output
|
||||||
// so must sort the call stub symbols.
|
// so must sort the call stub symbols.
|
||||||
typedef typename Plt_stub_entries::const_iterator plt_iter;
|
typedef typename Plt_stub_entries::iterator plt_iter;
|
||||||
std::vector<plt_iter> sorted;
|
std::vector<plt_iter> sorted;
|
||||||
sorted.resize(this->plt_call_stubs_.size());
|
sorted.resize(this->plt_call_stubs_.size());
|
||||||
|
|
||||||
@ -5666,7 +5700,7 @@ Stub_table<size, big_endian>::define_stub_syms(Symbol_table* symtab)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef typename Branch_stub_entries::const_iterator branch_iter;
|
typedef typename Branch_stub_entries::iterator branch_iter;
|
||||||
for (branch_iter bs = this->long_branch_stubs_.begin();
|
for (branch_iter bs = this->long_branch_stubs_.begin();
|
||||||
bs != this->long_branch_stubs_.end();
|
bs != this->long_branch_stubs_.end();
|
||||||
++bs)
|
++bs)
|
||||||
@ -5688,88 +5722,72 @@ Stub_table<size, big_endian>::define_stub_syms(Symbol_table* symtab)
|
|||||||
// Emit the start of a __tls_get_addr_opt plt call stub.
|
// Emit the start of a __tls_get_addr_opt plt call stub.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
bool
|
void
|
||||||
Stub_table<size, big_endian>::build_tls_opt_head(
|
Stub_table<size, big_endian>::build_tls_opt_head(unsigned char** pp,
|
||||||
unsigned char** pp,
|
bool save_lr)
|
||||||
typename Plt_stub_entries::const_iterator cs)
|
|
||||||
{
|
{
|
||||||
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
unsigned char* p = *pp;
|
||||||
|
if (size == 64)
|
||||||
{
|
{
|
||||||
unsigned char* p = *pp;
|
write_insn<big_endian>(p, ld_11_3 + 0);
|
||||||
if (size == 64)
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, ld_12_3 + 8);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, mr_0_3);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, cmpdi_11_0);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, add_3_12_13);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, beqlr);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, mr_3_0);
|
||||||
|
p += 4;
|
||||||
|
if (save_lr)
|
||||||
{
|
{
|
||||||
write_insn<big_endian>(p, ld_11_3 + 0);
|
write_insn<big_endian>(p, mflr_11);
|
||||||
p += 4;
|
p += 4;
|
||||||
write_insn<big_endian>(p, ld_12_3 + 8);
|
write_insn<big_endian>(p, (std_11_1 + this->targ_->stk_linker()));
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, mr_0_3);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, cmpdi_11_0);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, add_3_12_13);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, beqlr);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, mr_3_0);
|
|
||||||
p += 4;
|
|
||||||
if (cs->second.r2save_ && !cs->second.localentry0_)
|
|
||||||
{
|
|
||||||
write_insn<big_endian>(p, mflr_11);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, (std_11_1 + this->targ_->stk_linker()));
|
|
||||||
p += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
write_insn<big_endian>(p, lwz_11_3 + 0);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, lwz_12_3 + 4);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, mr_0_3);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, cmpwi_11_0);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, add_3_12_2);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, beqlr);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, mr_3_0);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, nop);
|
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
*pp = p;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
else
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, lwz_11_3 + 0);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, lwz_12_3 + 4);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, mr_0_3);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, cmpwi_11_0);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, add_3_12_2);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, beqlr);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, mr_3_0);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, nop);
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
*pp = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the tail of a __tls_get_addr_opt plt call stub.
|
// Emit the tail of a __tls_get_addr_opt plt call stub.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
bool
|
void
|
||||||
Stub_table<size, big_endian>::build_tls_opt_tail(
|
Stub_table<size, big_endian>::build_tls_opt_tail(unsigned char* p)
|
||||||
unsigned char* p,
|
|
||||||
typename Plt_stub_entries::const_iterator cs)
|
|
||||||
{
|
{
|
||||||
if (size == 64
|
write_insn<big_endian>(p, bctrl);
|
||||||
&& cs->second.r2save_
|
p += 4;
|
||||||
&& !cs->second.localentry0_
|
write_insn<big_endian>(p, ld_2_1 + this->targ_->stk_toc());
|
||||||
&& this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
p += 4;
|
||||||
{
|
write_insn<big_endian>(p, ld_11_1 + this->targ_->stk_linker());
|
||||||
write_insn<big_endian>(p, bctrl);
|
p += 4;
|
||||||
p += 4;
|
write_insn<big_endian>(p, mtlr_11);
|
||||||
write_insn<big_endian>(p, ld_2_1 + this->targ_->stk_toc());
|
p += 4;
|
||||||
p += 4;
|
write_insn<big_endian>(p, blr);
|
||||||
write_insn<big_endian>(p, ld_11_1 + this->targ_->stk_linker());
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, mtlr_11);
|
|
||||||
p += 4;
|
|
||||||
write_insn<big_endian>(p, blr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit pc-relative plt call stub code.
|
// Emit pc-relative plt call stub code.
|
||||||
@ -5939,7 +5957,7 @@ build_notoc_offset(unsigned char* p, uint64_t off, bool load)
|
|||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
unsigned int
|
unsigned int
|
||||||
Stub_table<size, big_endian>::plt_call_size(
|
Stub_table<size, big_endian>::plt_call_size(
|
||||||
typename Plt_stub_entries::const_iterator p) const
|
typename Plt_stub_entries::iterator p) const
|
||||||
{
|
{
|
||||||
if (size == 32)
|
if (size == 32)
|
||||||
{
|
{
|
||||||
@ -5951,77 +5969,122 @@ Stub_table<size, big_endian>::plt_call_size(
|
|||||||
const Output_data_plt_powerpc<size, big_endian>* plt;
|
const Output_data_plt_powerpc<size, big_endian>* plt;
|
||||||
uint64_t plt_addr = this->plt_off(p, &plt);
|
uint64_t plt_addr = this->plt_off(p, &plt);
|
||||||
plt_addr += plt->address();
|
plt_addr += plt->address();
|
||||||
unsigned int bytes = 0;
|
if (this->targ_->power10_stubs()
|
||||||
const Symbol* gsym = p->first.sym_;
|
&& this->targ_->power10_stubs_auto())
|
||||||
if (this->targ_->is_tls_get_addr_opt(gsym))
|
|
||||||
{
|
{
|
||||||
if (p->second.r2save_ && !p->second.localentry0_)
|
unsigned int bytes = 0;
|
||||||
bytes = 13 * 4;
|
if (p->second.notoc_)
|
||||||
else
|
|
||||||
bytes = 7 * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->second.r2save_)
|
|
||||||
bytes += 4;
|
|
||||||
|
|
||||||
if (this->targ_->power10_stubs())
|
|
||||||
{
|
|
||||||
uint64_t from = this->stub_address() + p->second.off_ + bytes;
|
|
||||||
if (bytes > 8 * 4)
|
|
||||||
from -= 4 * 4;
|
|
||||||
uint64_t odd = from & 4;
|
|
||||||
uint64_t off = plt_addr - from;
|
|
||||||
if (off - odd + (1ULL << 33) < 1ULL << 34)
|
|
||||||
bytes += odd + 4 * 4;
|
|
||||||
else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
|
|
||||||
bytes += 7 * 4;
|
|
||||||
else
|
|
||||||
bytes += 8 * 4;
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->second.notoc_)
|
|
||||||
{
|
|
||||||
uint64_t from = this->stub_address() + p->second.off_ + bytes + 2 * 4;
|
|
||||||
if (bytes > 32)
|
|
||||||
from -= 4 * 4;
|
|
||||||
uint64_t off = plt_addr - from;
|
|
||||||
if (off + 0x8000 < 0x10000)
|
|
||||||
bytes += 7 * 4;
|
|
||||||
else if (off + 0x80008000ULL < 0x100000000ULL)
|
|
||||||
bytes += 8 * 4;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
bytes += 8 * 4;
|
if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
|
||||||
if (off + 0x800000000000ULL >= 0x1000000000000ULL
|
bytes = 7 * 4;
|
||||||
&& ((off >> 32) & 0xffff) != 0)
|
uint64_t from = this->stub_address() + p->second.off_ + bytes;
|
||||||
bytes += 4;
|
uint64_t odd = from & 4;
|
||||||
if (((off >> 32) & 0xffffffffULL) != 0)
|
uint64_t off = plt_addr - from;
|
||||||
bytes += 4;
|
if (off - odd + (1ULL << 33) < 1ULL << 34)
|
||||||
if (hi(off) != 0)
|
bytes += odd + 4 * 4;
|
||||||
bytes += 4;
|
else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
|
||||||
if (l(off) != 0)
|
bytes += 7 * 4;
|
||||||
bytes += 4;
|
else
|
||||||
|
bytes += 8 * 4;
|
||||||
|
bytes = this->plt_call_align(bytes);
|
||||||
}
|
}
|
||||||
return bytes;
|
unsigned int tail = 0;
|
||||||
|
if (p->second.toc_)
|
||||||
|
{
|
||||||
|
p->second.tocoff_ = bytes;
|
||||||
|
if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
|
||||||
|
{
|
||||||
|
bytes += 7 * 4;
|
||||||
|
if (p->second.r2save_ && !p->second.localentry0_)
|
||||||
|
{
|
||||||
|
bytes += 2 * 4;
|
||||||
|
tail = 4 * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p->second.r2save_)
|
||||||
|
bytes += 4;
|
||||||
|
uint64_t got_addr
|
||||||
|
= this->targ_->got_section()->output_section()->address();
|
||||||
|
const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
|
||||||
|
<const Powerpc_relobj<size, big_endian>*>(p->first.object_);
|
||||||
|
got_addr += ppcobj->toc_base_offset();
|
||||||
|
uint64_t off = plt_addr - got_addr;
|
||||||
|
bytes += 3 * 4 + 4 * (ha(off) != 0);
|
||||||
|
}
|
||||||
|
return bytes + tail;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
uint64_t got_addr = this->targ_->got_section()->output_section()->address();
|
|
||||||
const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
|
|
||||||
<const Powerpc_relobj<size, big_endian>*>(p->first.object_);
|
|
||||||
got_addr += ppcobj->toc_base_offset();
|
|
||||||
uint64_t off = plt_addr - got_addr;
|
|
||||||
bytes += 3 * 4 + 4 * (ha(off) != 0);
|
|
||||||
if (this->targ_->abiversion() < 2)
|
|
||||||
{
|
{
|
||||||
bool static_chain = parameters->options().plt_static_chain();
|
unsigned int bytes = 0;
|
||||||
bool thread_safe = this->targ_->plt_thread_safe();
|
unsigned int tail = 0;
|
||||||
bytes += (4
|
if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
|
||||||
+ 4 * static_chain
|
{
|
||||||
+ 8 * thread_safe
|
bytes = 7 * 4;
|
||||||
+ 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
|
if (p->second.r2save_ && !p->second.localentry0_)
|
||||||
|
{
|
||||||
|
bytes = 9 * 4;
|
||||||
|
tail = 4 * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->second.r2save_)
|
||||||
|
bytes += 4;
|
||||||
|
|
||||||
|
if (this->targ_->power10_stubs())
|
||||||
|
{
|
||||||
|
uint64_t from = this->stub_address() + p->second.off_ + bytes;
|
||||||
|
uint64_t odd = from & 4;
|
||||||
|
uint64_t off = plt_addr - from;
|
||||||
|
if (off - odd + (1ULL << 33) < 1ULL << 34)
|
||||||
|
bytes += odd + 4 * 4;
|
||||||
|
else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
|
||||||
|
bytes += 7 * 4;
|
||||||
|
else
|
||||||
|
bytes += 8 * 4;
|
||||||
|
return bytes + tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->second.notoc_)
|
||||||
|
{
|
||||||
|
uint64_t from = this->stub_address() + p->second.off_ + bytes + 2 * 4;
|
||||||
|
uint64_t off = plt_addr - from;
|
||||||
|
if (off + 0x8000 < 0x10000)
|
||||||
|
bytes += 7 * 4;
|
||||||
|
else if (off + 0x80008000ULL < 0x100000000ULL)
|
||||||
|
bytes += 8 * 4;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes += 8 * 4;
|
||||||
|
if (off + 0x800000000000ULL >= 0x1000000000000ULL
|
||||||
|
&& ((off >> 32) & 0xffff) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
if (((off >> 32) & 0xffffffffULL) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
if (hi(off) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
if (l(off) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
}
|
||||||
|
return bytes + tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t got_addr = this->targ_->got_section()->output_section()->address();
|
||||||
|
const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
|
||||||
|
<const Powerpc_relobj<size, big_endian>*>(p->first.object_);
|
||||||
|
got_addr += ppcobj->toc_base_offset();
|
||||||
|
uint64_t off = plt_addr - got_addr;
|
||||||
|
bytes += 3 * 4 + 4 * (ha(off) != 0);
|
||||||
|
if (this->targ_->abiversion() < 2)
|
||||||
|
{
|
||||||
|
bool static_chain = parameters->options().plt_static_chain();
|
||||||
|
bool thread_safe = this->targ_->plt_thread_safe();
|
||||||
|
bytes += (4
|
||||||
|
+ 4 * static_chain
|
||||||
|
+ 8 * thread_safe
|
||||||
|
+ 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
|
||||||
|
}
|
||||||
|
return bytes + tail;
|
||||||
}
|
}
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return long branch stub size.
|
// Return long branch stub size.
|
||||||
@ -6029,7 +6092,7 @@ Stub_table<size, big_endian>::plt_call_size(
|
|||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
unsigned int
|
unsigned int
|
||||||
Stub_table<size, big_endian>::branch_stub_size(
|
Stub_table<size, big_endian>::branch_stub_size(
|
||||||
typename Branch_stub_entries::const_iterator p,
|
typename Branch_stub_entries::iterator p,
|
||||||
bool* need_lt)
|
bool* need_lt)
|
||||||
{
|
{
|
||||||
Address loc = this->stub_address() + this->last_plt_size_ + p->second.off_;
|
Address loc = this->stub_address() + this->last_plt_size_ + p->second.off_;
|
||||||
@ -6043,46 +6106,56 @@ Stub_table<size, big_endian>::branch_stub_size(
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t off = p->first.dest_ - loc;
|
uint64_t off = p->first.dest_ - loc;
|
||||||
|
unsigned int bytes = 0;
|
||||||
if (p->second.notoc_)
|
if (p->second.notoc_)
|
||||||
{
|
{
|
||||||
if (this->targ_->power10_stubs())
|
if (this->targ_->power10_stubs())
|
||||||
{
|
{
|
||||||
Address odd = loc & 4;
|
Address odd = loc & 4;
|
||||||
if (off + (1 << 25) < 2 << 25)
|
if (off + (1 << 25) < 2 << 25)
|
||||||
return odd + 12;
|
bytes = odd + 12;
|
||||||
if (off - odd + (1ULL << 33) < 1ULL << 34)
|
else if (off - odd + (1ULL << 33) < 1ULL << 34)
|
||||||
return odd + 16;
|
bytes = odd + 16;
|
||||||
if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
|
else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
|
||||||
return 28;
|
bytes = 28;
|
||||||
return 32;
|
else
|
||||||
|
bytes = 32;
|
||||||
|
if (!(p->second.toc_ && this->targ_->power10_stubs_auto()))
|
||||||
|
return bytes;
|
||||||
|
p->second.tocoff_ = bytes;
|
||||||
}
|
}
|
||||||
off -= 8;
|
else
|
||||||
if (off + 0x8000 < 0x10000)
|
|
||||||
return 24;
|
|
||||||
if (off + 0x80008000ULL < 0x100000000ULL)
|
|
||||||
{
|
{
|
||||||
if (off + 24 + (1 << 25) < 2 << 25)
|
off -= 8;
|
||||||
return 28;
|
if (off + 0x8000 < 0x10000)
|
||||||
return 32;
|
return 24;
|
||||||
|
if (off + 0x80008000ULL < 0x100000000ULL)
|
||||||
|
{
|
||||||
|
if (off + 24 + (1 << 25) < 2 << 25)
|
||||||
|
return 28;
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 32;
|
||||||
|
if (off + 0x800000000000ULL >= 0x1000000000000ULL
|
||||||
|
&& ((off >> 32) & 0xffff) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
if (((off >> 32) & 0xffffffffULL) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
if (hi(off) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
if (l(off) != 0)
|
||||||
|
bytes += 4;
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
unsigned int bytes = 32;
|
|
||||||
if (off + 0x800000000000ULL >= 0x1000000000000ULL
|
|
||||||
&& ((off >> 32) & 0xffff) != 0)
|
|
||||||
bytes += 4;
|
|
||||||
if (((off >> 32) & 0xffffffffULL) != 0)
|
|
||||||
bytes += 4;
|
|
||||||
if (hi(off) != 0)
|
|
||||||
bytes += 4;
|
|
||||||
if (l(off) != 0)
|
|
||||||
bytes += 4;
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (off + (1 << 25) < 2 << 25)
|
if (off + (1 << 25) < 2 << 25)
|
||||||
return 4;
|
return bytes + 4;
|
||||||
if (!this->targ_->power10_stubs())
|
if (!this->targ_->power10_stubs()
|
||||||
|
|| (p->second.toc_ && this->targ_->power10_stubs_auto()))
|
||||||
*need_lt = true;
|
*need_lt = true;
|
||||||
return 16;
|
return bytes + 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
@ -6118,6 +6191,10 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
if (size == 64
|
if (size == 64
|
||||||
&& this->targ_->power10_stubs())
|
&& this->targ_->power10_stubs())
|
||||||
{
|
{
|
||||||
|
const Output_data_got_powerpc<size, big_endian>* got
|
||||||
|
= this->targ_->got_section();
|
||||||
|
Address got_os_addr = got->output_section()->address();
|
||||||
|
|
||||||
if (!this->plt_call_stubs_.empty())
|
if (!this->plt_call_stubs_.empty())
|
||||||
{
|
{
|
||||||
// Write out plt call stubs.
|
// Write out plt call stubs.
|
||||||
@ -6127,22 +6204,94 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
++cs)
|
++cs)
|
||||||
{
|
{
|
||||||
p = oview + cs->second.off_;
|
p = oview + cs->second.off_;
|
||||||
this->build_tls_opt_head(&p, cs);
|
|
||||||
if (cs->second.r2save_)
|
|
||||||
{
|
|
||||||
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
|
||||||
p += 4;
|
|
||||||
}
|
|
||||||
const Output_data_plt_powerpc<size, big_endian>* plt;
|
const Output_data_plt_powerpc<size, big_endian>* plt;
|
||||||
Address pltoff = this->plt_off(cs, &plt);
|
Address pltoff = this->plt_off(cs, &plt);
|
||||||
Address plt_addr = pltoff + plt->address();
|
Address plt_addr = pltoff + plt->address();
|
||||||
Address from = this->stub_address() + (p - oview);
|
if (this->targ_->power10_stubs_auto())
|
||||||
Address delta = plt_addr - from;
|
{
|
||||||
p = build_power10_offset<big_endian>(p, delta, from & 4, true);
|
if (cs->second.notoc_)
|
||||||
write_insn<big_endian>(p, mtctr_12);
|
{
|
||||||
p += 4;
|
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
if (!this->build_tls_opt_tail(p, cs))
|
this->build_tls_opt_head(&p, false);
|
||||||
write_insn<big_endian>(p, bctr);
|
Address from = this->stub_address() + (p - oview);
|
||||||
|
Address delta = plt_addr - from;
|
||||||
|
p = build_power10_offset<big_endian>(p, delta, from & 4,
|
||||||
|
true);
|
||||||
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, bctr);
|
||||||
|
p += 4;
|
||||||
|
p = oview + this->plt_call_align(p - oview);
|
||||||
|
}
|
||||||
|
if (cs->second.toc_)
|
||||||
|
{
|
||||||
|
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
{
|
||||||
|
bool save_lr
|
||||||
|
= cs->second.r2save_ && !cs->second.localentry0_;
|
||||||
|
this->build_tls_opt_head(&p, save_lr);
|
||||||
|
}
|
||||||
|
const Powerpc_relobj<size, big_endian>* ppcobj
|
||||||
|
= static_cast<const Powerpc_relobj<size, big_endian>*>(
|
||||||
|
cs->first.object_);
|
||||||
|
Address got_addr = got_os_addr + ppcobj->toc_base_offset();
|
||||||
|
Address off = plt_addr - got_addr;
|
||||||
|
|
||||||
|
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
|
||||||
|
this->plt_error(cs->first);
|
||||||
|
|
||||||
|
if (cs->second.r2save_)
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
if (ha(off) != 0)
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, addis_12_2 + ha(off));
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, ld_12_12 + l(off));
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, ld_12_2 + l(off));
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
|
p += 4;
|
||||||
|
if (cs->second.r2save_
|
||||||
|
&& !cs->second.localentry0_
|
||||||
|
&& this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
this->build_tls_opt_tail(p);
|
||||||
|
else
|
||||||
|
write_insn<big_endian>(p, bctr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
{
|
||||||
|
bool save_lr
|
||||||
|
= cs->second.r2save_ && !cs->second.localentry0_;
|
||||||
|
this->build_tls_opt_head(&p, save_lr);
|
||||||
|
}
|
||||||
|
if (cs->second.r2save_)
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
Address from = this->stub_address() + (p - oview);
|
||||||
|
Address delta = plt_addr - from;
|
||||||
|
p = build_power10_offset<big_endian>(p, delta, from & 4, true);
|
||||||
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
|
p += 4;
|
||||||
|
if (cs->second.r2save_
|
||||||
|
&& !cs->second.localentry0_
|
||||||
|
&& this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
this->build_tls_opt_tail(p);
|
||||||
|
else
|
||||||
|
write_insn<big_endian>(p, bctr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6158,19 +6307,76 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
p = oview + off;
|
p = oview + off;
|
||||||
Address loc = this->stub_address() + off;
|
Address loc = this->stub_address() + off;
|
||||||
Address delta = bs->first.dest_ - loc;
|
Address delta = bs->first.dest_ - loc;
|
||||||
if (bs->second.notoc_ || delta + (1 << 25) >= 2 << 25)
|
if (this->targ_->power10_stubs_auto())
|
||||||
{
|
{
|
||||||
unsigned char* startp = p;
|
if (bs->second.notoc_)
|
||||||
p = build_power10_offset<big_endian>(p, delta, loc & 4, false);
|
{
|
||||||
delta -= p - startp;
|
unsigned char* startp = p;
|
||||||
|
p = build_power10_offset<big_endian>(p, delta,
|
||||||
|
loc & 4, false);
|
||||||
|
delta -= p - startp;
|
||||||
|
startp = p;
|
||||||
|
if (delta + (1 << 25) < 2 << 25)
|
||||||
|
write_insn<big_endian>(p, b | (delta & 0x3fffffc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, bctr);
|
||||||
|
}
|
||||||
|
p += 4;
|
||||||
|
delta -= p - startp;
|
||||||
|
}
|
||||||
|
if (bs->second.toc_)
|
||||||
|
{
|
||||||
|
if (delta + (1 << 25) >= 2 << 25)
|
||||||
|
{
|
||||||
|
Address brlt_addr
|
||||||
|
= this->targ_->find_branch_lookup_table(bs->first.dest_);
|
||||||
|
gold_assert(brlt_addr != invalid_address);
|
||||||
|
brlt_addr += this->targ_->brlt_section()->address();
|
||||||
|
Address got_addr = got_os_addr + bs->first.toc_base_off_;
|
||||||
|
Address brltoff = brlt_addr - got_addr;
|
||||||
|
if (ha(brltoff) == 0)
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, ld_12_2 + l(brltoff));
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, addis_12_2 + ha(brltoff));
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, ld_12_12 + l(brltoff));
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta + (1 << 25) < 2 << 25)
|
||||||
|
write_insn<big_endian>(p, b | (delta & 0x3fffffc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, bctr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (delta + (1 << 25) < 2 << 25)
|
|
||||||
write_insn<big_endian>(p, b | (delta & 0x3fffffc));
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_insn<big_endian>(p, mtctr_12);
|
if (bs->second.notoc_ || delta + (1 << 25) >= 2 << 25)
|
||||||
p += 4;
|
{
|
||||||
write_insn<big_endian>(p, bctr);
|
unsigned char* startp = p;
|
||||||
|
p = build_power10_offset<big_endian>(p, delta,
|
||||||
|
loc & 4, false);
|
||||||
|
delta -= p - startp;
|
||||||
|
}
|
||||||
|
if (delta + (1 << 25) < 2 << 25)
|
||||||
|
write_insn<big_endian>(p, b | (delta & 0x3fffffc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
|
p += 4;
|
||||||
|
write_insn<big_endian>(p, bctr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6194,7 +6400,11 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
Address plt_addr = pltoff + plt->address();
|
Address plt_addr = pltoff + plt->address();
|
||||||
|
|
||||||
p = oview + cs->second.off_;
|
p = oview + cs->second.off_;
|
||||||
this->build_tls_opt_head(&p, cs);
|
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
{
|
||||||
|
bool save_lr = cs->second.r2save_ && !cs->second.localentry0_;
|
||||||
|
this->build_tls_opt_head(&p, save_lr);
|
||||||
|
}
|
||||||
if (cs->second.r2save_)
|
if (cs->second.r2save_)
|
||||||
{
|
{
|
||||||
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
||||||
@ -6231,7 +6441,11 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
}
|
}
|
||||||
write_insn<big_endian>(p, mtctr_12);
|
write_insn<big_endian>(p, mtctr_12);
|
||||||
p += 4;
|
p += 4;
|
||||||
if (!this->build_tls_opt_tail(p, cs))
|
if (cs->second.r2save_
|
||||||
|
&& !cs->second.localentry0_
|
||||||
|
&& this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
this->build_tls_opt_tail(p);
|
||||||
|
else
|
||||||
write_insn<big_endian>(p, bctr);
|
write_insn<big_endian>(p, bctr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6282,8 +6496,12 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
}
|
}
|
||||||
|
|
||||||
p = oview + cs->second.off_;
|
p = oview + cs->second.off_;
|
||||||
if (this->build_tls_opt_head(&p, cs))
|
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
use_fake_dep = thread_safe;
|
{
|
||||||
|
bool save_lr = cs->second.r2save_ && !cs->second.localentry0_;
|
||||||
|
this->build_tls_opt_head(&p, save_lr);
|
||||||
|
use_fake_dep = thread_safe;
|
||||||
|
}
|
||||||
if (cs->second.r2save_)
|
if (cs->second.r2save_)
|
||||||
{
|
{
|
||||||
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
|
||||||
@ -6345,8 +6563,10 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
write_insn<big_endian>(p, ld_2_2 + l(off + 8));
|
write_insn<big_endian>(p, ld_2_2 + l(off + 8));
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
if (this->build_tls_opt_tail(p, cs))
|
if (cs->second.r2save_
|
||||||
;
|
&& !cs->second.localentry0_
|
||||||
|
&& this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
this->build_tls_opt_tail(p);
|
||||||
else if (thread_safe && !use_fake_dep)
|
else if (thread_safe && !use_fake_dep)
|
||||||
{
|
{
|
||||||
write_insn<big_endian>(p, cmpldi_2_0);
|
write_insn<big_endian>(p, cmpldi_2_0);
|
||||||
@ -6427,7 +6647,8 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
|
|||||||
plt_addr += plt->address();
|
plt_addr += plt->address();
|
||||||
|
|
||||||
p = oview + cs->second.off_;
|
p = oview + cs->second.off_;
|
||||||
this->build_tls_opt_head(&p, cs);
|
if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
|
||||||
|
this->build_tls_opt_head(&p, false);
|
||||||
if (parameters->options().output_is_position_independent())
|
if (parameters->options().output_is_position_independent())
|
||||||
{
|
{
|
||||||
Address got_addr;
|
Address got_addr;
|
||||||
@ -10087,10 +10308,17 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
|
const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
|
||||||
elfcpp::Shdr<size, big_endian> shdr(relinfo->reloc_shdr);
|
elfcpp::Shdr<size, big_endian> shdr(relinfo->reloc_shdr);
|
||||||
size_t reloc_count = shdr.get_sh_size() / reloc_size;
|
size_t reloc_count = shdr.get_sh_size() / reloc_size;
|
||||||
|
if (size == 64
|
||||||
|
&& r_type != elfcpp::R_PPC64_REL24_NOTOC)
|
||||||
|
value += ent->tocoff_;
|
||||||
if (size == 64
|
if (size == 64
|
||||||
&& ent->r2save_
|
&& ent->r2save_
|
||||||
&& r_type == elfcpp::R_PPC64_REL24_NOTOC)
|
&& r_type == elfcpp::R_PPC64_REL24_NOTOC)
|
||||||
value += 4;
|
{
|
||||||
|
if (!(target->power10_stubs()
|
||||||
|
&& target->power10_stubs_auto()))
|
||||||
|
value += 4;
|
||||||
|
}
|
||||||
else if (size == 64
|
else if (size == 64
|
||||||
&& ent->r2save_
|
&& ent->r2save_
|
||||||
&& relnum < reloc_count - 1)
|
&& relnum < reloc_count - 1)
|
||||||
@ -10707,8 +10935,14 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||||||
value = (value - target->savres_section()->address()
|
value = (value - target->savres_section()->address()
|
||||||
+ stub_table->branch_size());
|
+ stub_table->branch_size());
|
||||||
else
|
else
|
||||||
value = (stub_table->stub_address() + stub_table->plt_size()
|
{
|
||||||
+ ent->off_);
|
value = (stub_table->stub_address()
|
||||||
|
+ stub_table->plt_size()
|
||||||
|
+ ent->off_);
|
||||||
|
if (size == 64
|
||||||
|
&& r_type != elfcpp::R_PPC64_REL24_NOTOC)
|
||||||
|
value += ent->tocoff_;
|
||||||
|
}
|
||||||
has_stub_value = true;
|
has_stub_value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user