aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/layout.cc64
-rw-r--r--gold/options.cc15
-rw-r--r--gold/options.h43
-rw-r--r--gold/output.h6
4 files changed, 103 insertions, 25 deletions
diff --git a/gold/layout.cc b/gold/layout.cc
index b28682e..265dfb2 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -621,11 +621,10 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
- // The only thing we really care about for PT_LOAD segments is
- // whether or not they are writable, so that is how we search
- // for them. People who need segments sorted on some other
- // basis will have to wait until we implement a mechanism for
- // them to describe the segments they want.
+ // In general the only thing we really care about for PT_LOAD
+ // segments is whether or not they are writable, so that is how
+ // we search for them. People who need segments sorted on some
+ // other basis will have to use a linker script.
Segment_list::const_iterator p;
for (p = this->segment_list_.begin();
@@ -635,6 +634,15 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
if ((*p)->type() == elfcpp::PT_LOAD
&& ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
{
+ // If -Tbss was specified, we need to separate the data
+ // and BSS segments.
+ if (this->options_.user_set_bss_segment_address())
+ {
+ if ((type == elfcpp::SHT_NOBITS)
+ == (*p)->has_any_data_sections())
+ continue;
+ }
+
(*p)->add_output_section(os, seg_flags);
break;
}
@@ -1264,14 +1272,18 @@ Layout::segment_precedes(const Output_segment* seg1,
return false;
// We sort PT_LOAD segments based on the flags. Readonly segments
- // come before writable segments. Then executable segments come
- // before non-executable segments. Then the unlikely case of a
- // non-readable segment comes before the normal case of a readable
- // segment. If there are multiple segments with the same type and
- // flags, we require that the address be set, and we sort by
- // virtual address and then physical address.
+ // come before writable segments. Then writable segments with data
+ // come before writable segments without data. Then executable
+ // segments come before non-executable segments. Then the unlikely
+ // case of a non-readable segment comes before the normal case of a
+ // readable segment. If there are multiple segments with the same
+ // type and flags, we require that the address be set, and we sort
+ // by virtual address and then physical address.
if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W))
return (flags1 & elfcpp::PF_W) == 0;
+ if ((flags1 & elfcpp::PF_W) != 0
+ && seg1->has_any_data_sections() != seg2->has_any_data_sections())
+ return seg1->has_any_data_sections();
if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X))
return (flags1 & elfcpp::PF_X) != 0;
if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
@@ -1298,7 +1310,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// and their section's addresses and offsets.
uint64_t addr;
if (this->options_.user_set_text_segment_address())
- addr = options_.text_segment_address();
+ addr = this->options_.text_segment_address();
else if (parameters->output_is_shared())
addr = 0;
else
@@ -1331,6 +1343,29 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
gold_unreachable();
load_seg = NULL;
+ bool are_addresses_set = (*p)->are_addresses_set();
+ if (are_addresses_set)
+ {
+ // When it comes to setting file offsets, we care about
+ // the physical address.
+ addr = (*p)->paddr();
+ }
+ else if (this->options_.user_set_data_segment_address()
+ && ((*p)->flags() & elfcpp::PF_W) != 0
+ && (!this->options_.user_set_bss_segment_address()
+ || (*p)->has_any_data_sections()))
+ {
+ addr = this->options_.data_segment_address();
+ are_addresses_set = true;
+ }
+ else if (this->options_.user_set_bss_segment_address()
+ && ((*p)->flags() & elfcpp::PF_W) != 0
+ && !(*p)->has_any_data_sections())
+ {
+ addr = this->options_.bss_segment_address();
+ are_addresses_set = true;
+ }
+
uint64_t orig_addr = addr;
uint64_t orig_off = off;
@@ -1340,13 +1375,8 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// FIXME: This should depend on the -n and -N options.
(*p)->set_minimum_p_align(target->common_pagesize());
- bool are_addresses_set = (*p)->are_addresses_set();
if (are_addresses_set)
{
- // When it comes to setting file offsets, we care about
- // the physical address.
- addr = (*p)->paddr();
-
// Adjust the file offset to the same address modulo the
// page size.
uint64_t unsigned_off = off;
diff --git a/gold/options.cc b/gold/options.cc
index db655a2..4d8f0b9 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -541,10 +541,17 @@ options::Command_line_options::options[] =
NULL, TWO_DASHES, &General_options::set_stats),
GENERAL_ARG('\0', "sysroot", N_("Set target system root directory"),
N_("--sysroot DIR"), TWO_DASHES, &General_options::set_sysroot),
- GENERAL_ARG('\0', "Ttext", N_("Set the address of the .text section"),
+ GENERAL_ARG('\0', "Tbss", N_("Set the address of the bss segment"),
+ N_("-Tbss ADDRESS"), ONE_DASH,
+ &General_options::set_bss_segment_address),
+ GENERAL_ARG('\0', "Tdata", N_("Set the address of the data segment"),
+ N_("-Tdata ADDRESS"), ONE_DASH,
+ &General_options::set_data_segment_address),
+ GENERAL_ARG('\0', "Ttext", N_("Set the address of the text segment"),
N_("-Ttext ADDRESS"), ONE_DASH,
&General_options::set_text_segment_address),
- // This must come after -Ttext since it's a prefix of it.
+ // This must come after -Ttext and friends since it's a prefix of
+ // them.
SPECIAL('T', "script", N_("Read linker script"),
N_("-T FILE, --script FILE"), TWO_DASHES,
&invoke_script),
@@ -651,7 +658,9 @@ General_options::General_options(Script_options* script_options)
is_static_(false),
print_stats_(false),
sysroot_(),
- text_segment_address_(-1U), // -1 indicates value not set by user
+ bss_segment_address_(-1U), // -1 indicates value not set by user
+ data_segment_address_(-1U),
+ text_segment_address_(-1U),
threads_(false),
thread_count_initial_(0),
thread_count_middle_(0),
diff --git a/gold/options.h b/gold/options.h
index c484b55..ef8e26f 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -260,6 +260,26 @@ class General_options
version_script() const
{ return *this->script_options_->version_script_info(); }
+ // -Tbss: The address of the BSS segment
+ uint64_t
+ bss_segment_address() const
+ { return this->bss_segment_address_; }
+
+ // Whether -Tbss was used.
+ bool
+ user_set_bss_segment_address() const
+ { return this->bss_segment_address_ != -1U; }
+
+ // -Tdata: The address of the data segment
+ uint64_t
+ data_segment_address() const
+ { return this->data_segment_address_; }
+
+ // Whether -Tdata was used.
+ bool
+ user_set_data_segment_address() const
+ { return this->data_segment_address_ != -1U; }
+
// -Ttext: The address of the .text section
uint64_t
text_segment_address() const
@@ -479,15 +499,26 @@ class General_options
{ this->sysroot_ = arg; }
void
- set_text_segment_address(const char* arg)
+ set_segment_address(const char* name, const char* arg, uint64_t* val)
{
char* endptr;
- this->text_segment_address_ = strtoull(arg, &endptr, 0);
- if (*endptr != '\0'
- || this->text_segment_address_ == -1U)
- gold_fatal(_("invalid argument to -Ttext: %s"), arg);
+ *val = strtoull(arg, &endptr, 0);
+ if (*endptr != '\0' || *val == -1U)
+ gold_fatal(_("invalid argument to %s: %s"), name, arg);
}
+ void
+ set_bss_segment_address(const char* arg)
+ { this->set_segment_address("-Tbss", arg, &this->bss_segment_address_); }
+
+ void
+ set_data_segment_address(const char* arg)
+ { this->set_segment_address("-Tdata", arg, &this->data_segment_address_); }
+
+ void
+ set_text_segment_address(const char* arg)
+ { this->set_segment_address("-Ttext", arg, &this->text_segment_address_); }
+
int
parse_thread_count(const char* arg)
{
@@ -582,6 +613,8 @@ class General_options
bool is_static_;
bool print_stats_;
std::string sysroot_;
+ uint64_t bss_segment_address_;
+ uint64_t data_segment_address_;
uint64_t text_segment_address_;
bool threads_;
int thread_count_initial_;
diff --git a/gold/output.h b/gold/output.h
index 8f7a564..8d0a853 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -2528,6 +2528,12 @@ class Output_segment
void
add_initial_output_data(Output_data*);
+ // Return true if this segment has any sections which hold actual
+ // data, rather than being a BSS section.
+ bool
+ has_any_data_sections() const
+ { return !this->output_data_.empty(); }
+
// Return the number of dynamic relocations applied to this segment.
unsigned int
dynamic_reloc_count() const;