From 756ac4a80d33f8c434c41fdd6b7f58fef8d1e1ba Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 13 Feb 2008 22:47:28 +0000 Subject: [PATCH] Implement -Tdata and -Tbss. --- gold/layout.cc | 64 ++++++++++++++++++++++++++++++++++++------------- gold/options.cc | 15 +++++++++--- gold/options.h | 43 +++++++++++++++++++++++++++++---- gold/output.h | 6 +++++ 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/gold/layout.cc b/gold/layout.cc index b28682e6a21..265dfb26d31 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 db655a2e4c6..4d8f0b9f68f 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 c484b55e5e4..ef8e26fa6ad 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 8f7a5644759..8d0a853b3f0 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; -- 2.30.2