Implement -Tdata and -Tbss.

This commit is contained in:
Ian Lance Taylor 2008-02-13 22:47:28 +00:00
parent 3edc73f245
commit 756ac4a80d
4 changed files with 103 additions and 25 deletions

View file

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

View file

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

View file

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

View file

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