summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2016-12-07 14:15:59 +1030
committerAlan Modra <amodra@gmail.com>2017-02-22 09:40:21 +1030
commit386391cf13601ddab6746e3cf3d2326542e93cdb (patch)
treed7161f14f9ddf566368e8c03d61e39512a178dc1
parent983d1db4d7b5644b8c16a64bb6cb7267f602ebef (diff)
downloadbinutils-gdb-386391cf13601ddab6746e3cf3d2326542e93cdb.tar.gz
[GOLD] PowerPC --stub-group-multi
Adds a new option, defaulting to off, that allows a group of stubs to serve multiple output sections. Prior to this patch powerpc gold allowed this unconditionally, which is a little unsafe with clever code that discards/reuses sections at runtime. * options.h (--stub-group-multi): New PowerPC option. * powerpc.cc (Stub_control): Add multi_os_ var and param to constructor. Sort start_ var later. Comment State. (Stub_control::can_add_to_stub_group): Heed multi_os_. (Target_powerpc::group_sections): Update.
-rw-r--r--gold/ChangeLog7
-rw-r--r--gold/options.h4
-rw-r--r--gold/powerpc.cc49
3 files changed, 41 insertions, 19 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index d45bb48b71c..0839ddb7011 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -2,6 +2,13 @@
Apply from master
2016-12-07 Alan Modra <amodra@gmail.com>
+ * options.h (--stub-group-multi): New PowerPC option.
+ * powerpc.cc (Stub_control): Add multi_os_ var and param
+ to constructor. Sort start_ var later. Comment State.
+ (Stub_control::can_add_to_stub_group): Heed multi_os_.
+ (Target_powerpc::group_sections): Update.
+
+ 2016-12-07 Alan Modra <amodra@gmail.com>
PR gold/20878
* powerpc.cc (Stub_control): Replace stubs_always_before_branch_
with stubs_always_after_branch_, group_end_addr_ with
diff --git a/gold/options.h b/gold/options.h
index f63758ba976..f990153f17d 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -1101,6 +1101,10 @@ class General_options
"stubs are always after the group. 1 means use default size"),
N_("SIZE"));
+ DEFINE_bool(stub_group_multi, options::TWO_DASHES, '\0', false,
+ N_("(PowerpC only) Allow a group of stubs to serve multiple "
+ "output sections"), NULL);
+
DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
N_("Use less memory and more disk I/O "
"(included only for compatibility with GNU ld)"), NULL);
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 931f177901c..7d4a384ad8b 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -2441,11 +2441,11 @@ class Stub_control
// value of the parameter --stub-group-size. If --stub-group-size
// is passed a negative value, we restrict stubs to be always after
// the stubbed branches.
- Stub_control(int32_t size, bool no_size_errors)
- : state_(NO_GROUP), stub_group_size_(abs(size)),
- stubs_always_after_branch_(size < 0),
- suppress_size_errors_(no_size_errors), group_size_(0),
- group_start_addr_(0), owner_(NULL), output_section_(NULL)
+ Stub_control(int32_t size, bool no_size_errors, bool multi_os)
+ : stub_group_size_(abs(size)), stubs_always_after_branch_(size < 0),
+ suppress_size_errors_(no_size_errors), multi_os_(multi_os),
+ state_(NO_GROUP), group_size_(0), group_start_addr_(0),
+ owner_(NULL), output_section_(NULL)
{
}
@@ -2475,15 +2475,20 @@ class Stub_control
private:
typedef enum
{
+ // Initial state.
NO_GROUP,
+ // Adding group sections before the stubs.
FINDING_STUB_SECTION,
+ // Adding group sections after the stubs.
HAS_STUB_SECTION
} State;
- State state_;
uint32_t stub_group_size_;
bool stubs_always_after_branch_;
bool suppress_size_errors_;
+ // True if a stub group can serve multiple output sections.
+ bool multi_os_;
+ State state_;
// Current max size of group. Starts at stub_group_size_ but is
// reduced to stub_group_size_/1024 on seeing a section with
// external conditional branches.
@@ -2537,7 +2542,19 @@ Stub_control::can_add_to_stub_group(Output_section* o,
? this_size
: (long long) end_addr - this->group_start_addr_));
- if (this->state_ == HAS_STUB_SECTION)
+ if (this->state_ == NO_GROUP)
+ {
+ // Only here on very first use of Stub_control
+ this->owner_ = i;
+ this->output_section_ = o;
+ this->state_ = FINDING_STUB_SECTION;
+ this->group_size_ = group_size;
+ this->group_start_addr_ = start_addr;
+ return true;
+ }
+ else if (!this->multi_os_ && this->output_section_ != o)
+ ;
+ else if (this->state_ == HAS_STUB_SECTION)
{
// Can we add this section, which is after the stubs, to the
// group?
@@ -2571,20 +2588,13 @@ Stub_control::can_add_to_stub_group(Output_section* o,
return true;
}
}
- else if (this->state_ == NO_GROUP)
- {
- // Only here on very first use of Stub_control
- this->owner_ = i;
- this->output_section_ = o;
- this->state_ = FINDING_STUB_SECTION;
- this->group_size_ = group_size;
- this->group_start_addr_ = start_addr;
- return true;
- }
else
gold_unreachable();
- gold_debug(DEBUG_TARGET, "nope, didn't fit\n");
+ gold_debug(DEBUG_TARGET,
+ !this->multi_os_ && this->output_section_ != o
+ ? "nope, new output section\n"
+ : "nope, didn't fit\n");
// The section fails to fit in the current group. Set up a few
// things for the next group. owner_ and output_section_ will be
@@ -2604,7 +2614,8 @@ Target_powerpc<size, big_endian>::group_sections(Layout* layout,
const Task*,
bool no_size_errors)
{
- Stub_control stub_control(this->stub_group_size_, no_size_errors);
+ Stub_control stub_control(this->stub_group_size_, no_size_errors,
+ parameters->options().stub_group_multi());
// Group input sections and insert stub table
Stub_table_owner* table_owner = NULL;