Implement -Tdata and -Tbss.
This commit is contained in:
parent
3edc73f245
commit
756ac4a80d
4 changed files with 103 additions and 25 deletions
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue