mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-09-10 01:42:21 +08:00
Implement PHDRS.
This commit is contained in:
@ -397,10 +397,13 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
|
||||
|
||||
hdr_os->set_after_input_sections();
|
||||
|
||||
Output_segment* hdr_oseg;
|
||||
hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
|
||||
elfcpp::PF_R);
|
||||
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
|
||||
if (!this->script_options_->saw_phdrs_clause())
|
||||
{
|
||||
Output_segment* hdr_oseg;
|
||||
hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
|
||||
elfcpp::PF_R);
|
||||
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
|
||||
}
|
||||
|
||||
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
|
||||
}
|
||||
@ -498,6 +501,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
||||
if (this->script_options_->saw_sections_clause())
|
||||
return os;
|
||||
|
||||
gold_assert(!this->script_options_->saw_phdrs_clause());
|
||||
|
||||
// This output section goes into a PT_LOAD segment.
|
||||
|
||||
elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
|
||||
@ -700,6 +705,8 @@ Layout::find_first_load_seg()
|
||||
return *p;
|
||||
}
|
||||
|
||||
gold_assert(!this->script_options_->saw_phdrs_clause());
|
||||
|
||||
Output_segment* load_seg = this->make_output_segment(elfcpp::PT_LOAD,
|
||||
elfcpp::PF_R);
|
||||
return load_seg;
|
||||
@ -758,7 +765,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
||||
|
||||
// Create the PT_PHDR segment which will hold the program
|
||||
// headers.
|
||||
phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
|
||||
if (!this->script_options_->saw_phdrs_clause())
|
||||
phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
|
||||
|
||||
// Create the dynamic symbol table, including the hash table.
|
||||
Output_section* dynstr;
|
||||
@ -816,6 +824,14 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
||||
this->special_output_list_.push_back(file_header);
|
||||
this->special_output_list_.push_back(segment_headers);
|
||||
|
||||
if (this->script_options_->saw_phdrs_clause())
|
||||
{
|
||||
// Support use of FILEHDRS and PHDRS attachments in a PHDRS
|
||||
// clause in a linker script.
|
||||
Script_sections* ss = this->script_options_->script_sections();
|
||||
ss->put_headers_in_phdrs(file_header, segment_headers);
|
||||
}
|
||||
|
||||
// We set the output section indexes in set_segment_offsets and
|
||||
// set_section_indexes.
|
||||
unsigned int shndx = 1;
|
||||
@ -997,6 +1013,8 @@ Layout::create_executable_stack_info(const Target* target)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->script_options_->saw_phdrs_clause())
|
||||
return;
|
||||
int flags = elfcpp::PF_R | elfcpp::PF_W;
|
||||
if (is_stack_executable)
|
||||
flags |= elfcpp::PF_X;
|
||||
@ -1861,9 +1879,12 @@ Layout::create_interp(const Target* target)
|
||||
false);
|
||||
osec->add_output_section_data(odata);
|
||||
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
|
||||
elfcpp::PF_R);
|
||||
oseg->add_initial_output_section(osec, elfcpp::PF_R);
|
||||
if (!this->script_options_->saw_phdrs_clause())
|
||||
{
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
|
||||
elfcpp::PF_R);
|
||||
oseg->add_initial_output_section(osec, elfcpp::PF_R);
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the .dynamic section and PT_DYNAMIC segment.
|
||||
@ -1872,11 +1893,14 @@ void
|
||||
Layout::finish_dynamic_section(const Input_objects* input_objects,
|
||||
const Symbol_table* symtab)
|
||||
{
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
|
||||
(elfcpp::PF_R
|
||||
| elfcpp::PF_W));
|
||||
oseg->add_initial_output_section(this->dynamic_section_,
|
||||
elfcpp::PF_R | elfcpp::PF_W);
|
||||
if (!this->script_options_->saw_phdrs_clause())
|
||||
{
|
||||
Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
|
||||
(elfcpp::PF_R
|
||||
| elfcpp::PF_W));
|
||||
oseg->add_initial_output_section(this->dynamic_section_,
|
||||
elfcpp::PF_R | elfcpp::PF_W);
|
||||
}
|
||||
|
||||
Output_data_dynamic* const odyn = this->dynamic_data_;
|
||||
|
||||
|
@ -2480,6 +2480,55 @@ Output_segment::output_section_count_list(const Output_data_list* pdl) const
|
||||
return count;
|
||||
}
|
||||
|
||||
// Return the section attached to the list segment with the lowest
|
||||
// load address. This is used when handling a PHDRS clause in a
|
||||
// linker script.
|
||||
|
||||
Output_section*
|
||||
Output_segment::section_with_lowest_load_address() const
|
||||
{
|
||||
Output_section* found = NULL;
|
||||
uint64_t found_lma = 0;
|
||||
this->lowest_load_address_in_list(&this->output_data_, &found, &found_lma);
|
||||
|
||||
Output_section* found_data = found;
|
||||
this->lowest_load_address_in_list(&this->output_bss_, &found, &found_lma);
|
||||
if (found != found_data && found_data != NULL)
|
||||
{
|
||||
gold_error(_("nobits section %s may not precede progbits section %s "
|
||||
"in same segment"),
|
||||
found->name(), found_data->name());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Look through a list for a section with a lower load address.
|
||||
|
||||
void
|
||||
Output_segment::lowest_load_address_in_list(const Output_data_list* pdl,
|
||||
Output_section** found,
|
||||
uint64_t* found_lma) const
|
||||
{
|
||||
for (Output_data_list::const_iterator p = pdl->begin();
|
||||
p != pdl->end();
|
||||
++p)
|
||||
{
|
||||
if (!(*p)->is_section())
|
||||
continue;
|
||||
Output_section* os = static_cast<Output_section*>(*p);
|
||||
uint64_t lma = (os->has_load_address()
|
||||
? os->load_address()
|
||||
: os->address());
|
||||
if (*found == NULL || lma < *found_lma)
|
||||
{
|
||||
*found = os;
|
||||
*found_lma = lma;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the segment data into *OPHDR.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
@ -2342,6 +2342,12 @@ class Output_segment
|
||||
this->are_addresses_set_ = true;
|
||||
}
|
||||
|
||||
// Set the segment flags. This is only used if we have a PHDRS
|
||||
// clause which explicitly specifies the flags.
|
||||
void
|
||||
set_flags(elfcpp::Elf_Word flags)
|
||||
{ this->flags_ = flags; }
|
||||
|
||||
// Set the address of the segment to ADDR and the offset to *POFF
|
||||
// and set the addresses and offsets of all contained output
|
||||
// sections accordingly. Set the section indexes of all contained
|
||||
@ -2372,6 +2378,12 @@ class Output_segment
|
||||
unsigned int
|
||||
output_section_count() const;
|
||||
|
||||
// Return the section attached to the list segment with the lowest
|
||||
// load address. This is used when handling a PHDRS clause in a
|
||||
// linker script.
|
||||
Output_section*
|
||||
section_with_lowest_load_address() const;
|
||||
|
||||
// Write the segment header into *OPHDR.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
@ -2411,6 +2423,13 @@ class Output_segment
|
||||
unsigned int
|
||||
dynamic_reloc_count_list(const Output_data_list*) const;
|
||||
|
||||
// Find the section with the lowest load address in an
|
||||
// Output_data_list.
|
||||
void
|
||||
lowest_load_address_in_list(const Output_data_list* pdl,
|
||||
Output_section** found,
|
||||
uint64_t* found_lma) const;
|
||||
|
||||
// Write the section headers in the list into V.
|
||||
template<int size, bool big_endian>
|
||||
unsigned char*
|
||||
|
@ -94,15 +94,6 @@ struct Parser_output_section_header
|
||||
enum Section_constraint constraint;
|
||||
};
|
||||
|
||||
/* The information we store for an output section trailer in the bison
|
||||
parser. */
|
||||
|
||||
struct Parser_output_section_trailer
|
||||
{
|
||||
/* The fill value. This may be NULL. */
|
||||
Expression_ptr fill;
|
||||
};
|
||||
|
||||
/* We keep vectors of strings. In order to manage this in both C and
|
||||
C++, we use a pointer to a vector. This assumes that all pointers
|
||||
look the same. */
|
||||
@ -114,6 +105,18 @@ typedef String_list* String_list_ptr;
|
||||
typedef void* String_list_ptr;
|
||||
#endif
|
||||
|
||||
/* The information we store for an output section trailer in the bison
|
||||
parser. */
|
||||
|
||||
struct Parser_output_section_trailer
|
||||
{
|
||||
/* The fill value. This may be NULL. */
|
||||
Expression_ptr fill;
|
||||
/* The program segments this section should go into. This may be
|
||||
NULL. */
|
||||
String_list_ptr phdrs;
|
||||
};
|
||||
|
||||
/* The different sorts we can find in a linker script. */
|
||||
|
||||
enum Sort_wildcard
|
||||
@ -165,6 +168,22 @@ struct Input_section_spec
|
||||
struct Wildcard_sections input_sections;
|
||||
};
|
||||
|
||||
/* Information for a program header. */
|
||||
|
||||
struct Phdr_info
|
||||
{
|
||||
/* A boolean value: whether to include the file header. */
|
||||
int includes_filehdr;
|
||||
/* A boolean value: whether to include the program headers. */
|
||||
int includes_phdrs;
|
||||
/* A boolean value: whether the flags field is valid. */
|
||||
int is_flags_valid;
|
||||
/* The value to use for the flags. */
|
||||
unsigned int flags;
|
||||
/* The load address. */
|
||||
Expression_ptr load_address;
|
||||
};
|
||||
|
||||
struct Version_dependency_list;
|
||||
struct Version_expression_list;
|
||||
struct Version_tree;
|
||||
@ -329,6 +348,17 @@ script_string_list_push_back(String_list_ptr, const char*, size_t);
|
||||
extern String_list_ptr
|
||||
script_string_list_append(String_list_ptr, String_list_ptr);
|
||||
|
||||
/* Define a new program header. */
|
||||
|
||||
extern void
|
||||
script_add_phdr(void* closure, const char* name, size_t namelen,
|
||||
unsigned int type, const struct Phdr_info*);
|
||||
|
||||
/* Convert a program header string to a type. */
|
||||
|
||||
extern unsigned int
|
||||
script_phdr_string_to_type(void* closure, const char*, size_t);
|
||||
|
||||
/* Called by the bison parser for expressions. */
|
||||
|
||||
extern Expression_ptr
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fnmatch.h>
|
||||
@ -96,6 +97,15 @@ class Sections_element
|
||||
alternate_constraint(Output_section_definition*, Section_constraint)
|
||||
{ return false; }
|
||||
|
||||
// Get the list of segments to use for an allocated section when
|
||||
// using a PHDRS clause. If this is an allocated section, return
|
||||
// the Output_section, and set *PHDRS_LIST to the list of PHDRS to
|
||||
// which it should be attached. If the PHDRS were not specified,
|
||||
// don't change *PHDRS_LIST.
|
||||
virtual Output_section*
|
||||
allocate_to_segment(String_list**)
|
||||
{ return NULL; }
|
||||
|
||||
// Print the element for debugging purposes.
|
||||
virtual void
|
||||
print(FILE* f) const = 0;
|
||||
@ -1172,6 +1182,14 @@ class Output_section_definition : public Sections_element
|
||||
bool
|
||||
alternate_constraint(Output_section_definition*, Section_constraint);
|
||||
|
||||
// Get the list of segments to use for an allocated section when
|
||||
// using a PHDRS clause. If this is an allocated section, return
|
||||
// the Output_section, and set *PHDRS_LIST to the list of PHDRS to
|
||||
// which it should be attached. If the PHDRS were not specified,
|
||||
// don't change *PHDRS_LIST.
|
||||
Output_section*
|
||||
allocate_to_segment(String_list** phdrs_list);
|
||||
|
||||
// Print the contents to the FILE. This is for debugging.
|
||||
void
|
||||
print(FILE*) const;
|
||||
@ -1193,6 +1211,9 @@ class Output_section_definition : public Sections_element
|
||||
Section_constraint constraint_;
|
||||
// The fill value. This may be NULL.
|
||||
Expression* fill_;
|
||||
// The list of segments this section should go into. This may be
|
||||
// NULL.
|
||||
String_list* phdrs_;
|
||||
// The list of elements defining the section.
|
||||
Output_section_elements elements_;
|
||||
// The Output_section created for this definition. This will be
|
||||
@ -1213,6 +1234,7 @@ Output_section_definition::Output_section_definition(
|
||||
subalign_(header->subalign),
|
||||
constraint_(header->constraint),
|
||||
fill_(NULL),
|
||||
phdrs_(NULL),
|
||||
elements_(),
|
||||
output_section_(NULL)
|
||||
{
|
||||
@ -1224,6 +1246,7 @@ void
|
||||
Output_section_definition::finish(const Parser_output_section_trailer* trailer)
|
||||
{
|
||||
this->fill_ = trailer->fill;
|
||||
this->phdrs_ = trailer->phdrs;
|
||||
}
|
||||
|
||||
// Add a symbol to be defined.
|
||||
@ -1392,58 +1415,92 @@ Output_section_definition::place_orphan_here(const Output_section *os,
|
||||
|
||||
if (os->type() == elfcpp::SHT_NOBITS)
|
||||
{
|
||||
if (this->name_ == ".bss")
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_NOBITS)
|
||||
return true;
|
||||
if (this->name_ == ".bss")
|
||||
return true;
|
||||
}
|
||||
else if (os->type() == elfcpp::SHT_NOTE)
|
||||
{
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_NOTE)
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->name_.compare(0, 5, ".note") == 0)
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->name_ == ".interp")
|
||||
return true;
|
||||
if (this->name_ == ".interp"
|
||||
|| this->name_.compare(0, 5, ".note") == 0)
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_PROGBITS
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
|
||||
return true;
|
||||
}
|
||||
else if (os->type() == elfcpp::SHT_REL || os->type() == elfcpp::SHT_RELA)
|
||||
{
|
||||
if (this->name_.compare(0, 4, ".rel") == 0)
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->output_section_ != NULL
|
||||
&& (this->output_section_->type() == elfcpp::SHT_REL
|
||||
|| this->output_section_->type() == elfcpp::SHT_RELA))
|
||||
return true;
|
||||
if (this->name_.compare(0, 4, ".rel") == 0)
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_PROGBITS
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
|
||||
return true;
|
||||
}
|
||||
else if (os->type() == elfcpp::SHT_PROGBITS
|
||||
&& (os->flags() & elfcpp::SHF_WRITE) != 0)
|
||||
{
|
||||
if (this->name_ == ".data")
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_PROGBITS
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
|
||||
return true;
|
||||
if (this->name_ == ".data")
|
||||
return true;
|
||||
}
|
||||
else if (os->type() == elfcpp::SHT_PROGBITS
|
||||
&& (os->flags() & elfcpp::SHF_EXECINSTR) != 0)
|
||||
{
|
||||
if (this->name_ == ".text")
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_PROGBITS
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) != 0)
|
||||
return true;
|
||||
if (this->name_ == ".text")
|
||||
return true;
|
||||
}
|
||||
else if (os->type() == elfcpp::SHT_PROGBITS)
|
||||
else if (os->type() == elfcpp::SHT_PROGBITS
|
||||
|| (os->type() != elfcpp::SHT_PROGBITS
|
||||
&& (os->flags() & elfcpp::SHF_WRITE) == 0))
|
||||
{
|
||||
if (this->name_ == ".rodata")
|
||||
{
|
||||
*exact = true;
|
||||
return true;
|
||||
}
|
||||
if (this->output_section_ != NULL
|
||||
&& this->output_section_->type() == elfcpp::SHT_PROGBITS
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) == 0)
|
||||
return true;
|
||||
if (this->name_ == ".rodata")
|
||||
&& (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1651,6 +1708,24 @@ Output_section_definition::alternate_constraint(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the list of segments to use for an allocated section when using
|
||||
// a PHDRS clause. If this is an allocated section, return the
|
||||
// Output_section, and set *PHDRS_LIST to the list of PHDRS to which
|
||||
// it should be attached. If the PHDRS were not specified, don't
|
||||
// change *PHDRS_LIST.
|
||||
|
||||
Output_section*
|
||||
Output_section_definition::allocate_to_segment(String_list** phdrs_list)
|
||||
{
|
||||
if (this->output_section_ == NULL)
|
||||
return NULL;
|
||||
if ((this->output_section_->flags() & elfcpp::SHF_ALLOC) == 0)
|
||||
return NULL;
|
||||
if (this->phdrs_ != NULL)
|
||||
*phdrs_list = this->phdrs_;
|
||||
return this->output_section_;
|
||||
}
|
||||
|
||||
// Print for debugging.
|
||||
|
||||
void
|
||||
@ -1725,6 +1800,12 @@ class Orphan_output_section : public Sections_element
|
||||
void
|
||||
set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*);
|
||||
|
||||
// Get the list of segments to use for an allocated section when
|
||||
// using a PHDRS clause. If this is an allocated section, return
|
||||
// the Output_section.
|
||||
Output_section*
|
||||
allocate_to_segment(String_list**);
|
||||
|
||||
// Print for debugging.
|
||||
void
|
||||
print(FILE* f) const
|
||||
@ -1797,13 +1878,125 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
|
||||
*dot_value = address;
|
||||
}
|
||||
|
||||
// Get the list of segments to use for an allocated section when using
|
||||
// a PHDRS clause. If this is an allocated section, return the
|
||||
// Output_section. We don't change the list of segments.
|
||||
|
||||
Output_section*
|
||||
Orphan_output_section::allocate_to_segment(String_list**)
|
||||
{
|
||||
if ((this->os_->flags() & elfcpp::SHF_ALLOC) == 0)
|
||||
return NULL;
|
||||
return this->os_;
|
||||
}
|
||||
|
||||
// Class Phdrs_element. A program header from a PHDRS clause.
|
||||
|
||||
class Phdrs_element
|
||||
{
|
||||
public:
|
||||
Phdrs_element(const char* name, size_t namelen, unsigned int type,
|
||||
bool includes_filehdr, bool includes_phdrs,
|
||||
bool is_flags_valid, unsigned int flags,
|
||||
Expression* load_address)
|
||||
: name_(name, namelen), type_(type), includes_filehdr_(includes_filehdr),
|
||||
includes_phdrs_(includes_phdrs), is_flags_valid_(is_flags_valid),
|
||||
flags_(flags), load_address_(load_address), load_address_value_(0),
|
||||
segment_(NULL)
|
||||
{ }
|
||||
|
||||
// Return the name of this segment.
|
||||
const std::string&
|
||||
name() const
|
||||
{ return this->name_; }
|
||||
|
||||
// Return the type of the segment.
|
||||
unsigned int
|
||||
type() const
|
||||
{ return this->type_; }
|
||||
|
||||
// Whether to include the file header.
|
||||
bool
|
||||
includes_filehdr() const
|
||||
{ return this->includes_filehdr_; }
|
||||
|
||||
// Whether to include the program headers.
|
||||
bool
|
||||
includes_phdrs() const
|
||||
{ return this->includes_phdrs_; }
|
||||
|
||||
// Return whether there is a load address.
|
||||
bool
|
||||
has_load_address() const
|
||||
{ return this->load_address_ != NULL; }
|
||||
|
||||
// Evaluate the load address expression if there is one.
|
||||
void
|
||||
eval_load_address(Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
if (this->load_address_ != NULL)
|
||||
this->load_address_value_ = this->load_address_->eval(symtab, layout);
|
||||
}
|
||||
|
||||
// Return the load address.
|
||||
uint64_t
|
||||
load_address() const
|
||||
{
|
||||
gold_assert(this->load_address_ != NULL);
|
||||
return this->load_address_value_;
|
||||
}
|
||||
|
||||
// Create the segment.
|
||||
Output_segment*
|
||||
create_segment(Layout* layout)
|
||||
{
|
||||
this->segment_ = layout->make_output_segment(this->type_, this->flags_);
|
||||
return this->segment_;
|
||||
}
|
||||
|
||||
// Return the segment.
|
||||
Output_segment*
|
||||
segment()
|
||||
{ return this->segment_; }
|
||||
|
||||
// Set the segment flags if appropriate.
|
||||
void
|
||||
set_flags_if_valid()
|
||||
{
|
||||
if (this->is_flags_valid_)
|
||||
this->segment_->set_flags(this->flags_);
|
||||
}
|
||||
|
||||
private:
|
||||
// The name used in the script.
|
||||
std::string name_;
|
||||
// The type of the segment (PT_LOAD, etc.).
|
||||
unsigned int type_;
|
||||
// Whether this segment includes the file header.
|
||||
bool includes_filehdr_;
|
||||
// Whether this segment includes the section headers.
|
||||
bool includes_phdrs_;
|
||||
// Whether the flags were explicitly specified.
|
||||
bool is_flags_valid_;
|
||||
// The flags for this segment (PF_R, etc.) if specified.
|
||||
unsigned int flags_;
|
||||
// The expression for the load address for this segment. This may
|
||||
// be NULL.
|
||||
Expression* load_address_;
|
||||
// The actual load address from evaluating the expression.
|
||||
uint64_t load_address_value_;
|
||||
// The segment itself.
|
||||
Output_segment* segment_;
|
||||
};
|
||||
|
||||
// Class Script_sections.
|
||||
|
||||
Script_sections::Script_sections()
|
||||
: saw_sections_clause_(false),
|
||||
in_sections_clause_(false),
|
||||
sections_elements_(NULL),
|
||||
output_section_(NULL)
|
||||
output_section_(NULL),
|
||||
phdrs_elements_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -2071,6 +2264,14 @@ Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
|
||||
++p)
|
||||
(*p)->set_section_addresses(symtab, layout, &dot_has_value, &dot_value);
|
||||
|
||||
if (this->phdrs_elements_ != NULL)
|
||||
{
|
||||
for (Phdrs_elements::iterator p = this->phdrs_elements_->begin();
|
||||
p != this->phdrs_elements_->end();
|
||||
++p)
|
||||
(*p)->eval_load_address(symtab, layout);
|
||||
}
|
||||
|
||||
return this->create_segments(layout);
|
||||
}
|
||||
|
||||
@ -2129,6 +2330,45 @@ Script_sections::is_bss_section(const Output_section* os)
|
||||
&& (os->flags() & elfcpp::SHF_TLS) == 0);
|
||||
}
|
||||
|
||||
// Return the size taken by the file header and the program headers.
|
||||
|
||||
size_t
|
||||
Script_sections::total_header_size(Layout* layout) const
|
||||
{
|
||||
size_t segment_count = layout->segment_count();
|
||||
size_t file_header_size;
|
||||
size_t segment_headers_size;
|
||||
if (parameters->get_size() == 32)
|
||||
{
|
||||
file_header_size = elfcpp::Elf_sizes<32>::ehdr_size;
|
||||
segment_headers_size = segment_count * elfcpp::Elf_sizes<32>::phdr_size;
|
||||
}
|
||||
else if (parameters->get_size() == 64)
|
||||
{
|
||||
file_header_size = elfcpp::Elf_sizes<64>::ehdr_size;
|
||||
segment_headers_size = segment_count * elfcpp::Elf_sizes<64>::phdr_size;
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
return file_header_size + segment_headers_size;
|
||||
}
|
||||
|
||||
// Return the amount we have to subtract from the LMA to accomodate
|
||||
// headers of the given size. The complication is that the file
|
||||
// header have to be at the start of a page, as otherwise it will not
|
||||
// be at the start of the file.
|
||||
|
||||
uint64_t
|
||||
Script_sections::header_size_adjustment(uint64_t lma,
|
||||
size_t sizeof_headers) const
|
||||
{
|
||||
const uint64_t abi_pagesize = parameters->target()->abi_pagesize();
|
||||
uint64_t hdr_lma = lma - sizeof_headers;
|
||||
hdr_lma &= ~(abi_pagesize - 1);
|
||||
return lma - hdr_lma;
|
||||
}
|
||||
|
||||
// Create the PT_LOAD segments when using a SECTIONS clause. Returns
|
||||
// the segment which should hold the file header and segment headers,
|
||||
// if any.
|
||||
@ -2141,6 +2381,9 @@ Script_sections::create_segments(Layout* layout)
|
||||
if (parameters->output_is_object())
|
||||
return NULL;
|
||||
|
||||
if (this->saw_phdrs_clause())
|
||||
return create_segments_from_phdrs_clause(layout);
|
||||
|
||||
Layout::Section_list sections;
|
||||
layout->get_allocated_sections(§ions);
|
||||
|
||||
@ -2240,23 +2483,7 @@ Script_sections::create_segments(Layout* layout)
|
||||
// efficient in any case. We try to use the first PT_LOAD segment
|
||||
// if we can, otherwise we make a new one.
|
||||
|
||||
size_t segment_count = layout->segment_count();
|
||||
size_t file_header_size;
|
||||
size_t segment_headers_size;
|
||||
if (parameters->get_size() == 32)
|
||||
{
|
||||
file_header_size = elfcpp::Elf_sizes<32>::ehdr_size;
|
||||
segment_headers_size = segment_count * elfcpp::Elf_sizes<32>::phdr_size;
|
||||
}
|
||||
else if (parameters->get_size() == 64)
|
||||
{
|
||||
file_header_size = elfcpp::Elf_sizes<64>::ehdr_size;
|
||||
segment_headers_size = segment_count * elfcpp::Elf_sizes<64>::phdr_size;
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
size_t sizeof_headers = file_header_size + segment_headers_size;
|
||||
size_t sizeof_headers = this->total_header_size(layout);
|
||||
|
||||
if (first_seg != NULL
|
||||
&& (first_seg->paddr() & (abi_pagesize - 1)) >= sizeof_headers)
|
||||
@ -2275,13 +2502,9 @@ Script_sections::create_segments(Layout* layout)
|
||||
uint64_t vma = first_seg->vaddr();
|
||||
uint64_t lma = first_seg->paddr();
|
||||
|
||||
// We want a segment with the same relationship between VMA and
|
||||
// LMA, but with enough room for the headers, and aligned to
|
||||
// load at the start of a page.
|
||||
uint64_t hdr_lma = lma - sizeof_headers;
|
||||
hdr_lma &= ~(abi_pagesize - 1);
|
||||
if (lma >= hdr_lma && vma >= (lma - hdr_lma))
|
||||
load_seg->set_addresses(vma - (lma - hdr_lma), hdr_lma);
|
||||
uint64_t subtract = this->header_size_adjustment(lma, sizeof_headers);
|
||||
if (lma >= subtract && vma >= subtract)
|
||||
load_seg->set_addresses(vma - subtract, lma - subtract);
|
||||
else
|
||||
{
|
||||
// We could handle this case by create the file header
|
||||
@ -2304,6 +2527,8 @@ Script_sections::create_note_and_tls_segments(
|
||||
Layout* layout,
|
||||
const Layout::Section_list* sections)
|
||||
{
|
||||
gold_assert(!this->saw_phdrs_clause());
|
||||
|
||||
bool saw_tls = false;
|
||||
for (Layout::Section_list::const_iterator p = sections->begin();
|
||||
p != sections->end();
|
||||
@ -2356,12 +2581,34 @@ Script_sections::create_note_and_tls_segments(
|
||||
}
|
||||
}
|
||||
|
||||
// Add a program header. The PHDRS clause is syntactically distinct
|
||||
// from the SECTIONS clause, but we implement it with the SECTIONS
|
||||
// support becauase PHDRS is useless if there is no SECTIONS clause.
|
||||
|
||||
void
|
||||
Script_sections::add_phdr(const char* name, size_t namelen, unsigned int type,
|
||||
bool includes_filehdr, bool includes_phdrs,
|
||||
bool is_flags_valid, unsigned int flags,
|
||||
Expression* load_address)
|
||||
{
|
||||
if (this->phdrs_elements_ == NULL)
|
||||
this->phdrs_elements_ = new Phdrs_elements();
|
||||
this->phdrs_elements_->push_back(new Phdrs_element(name, namelen, type,
|
||||
includes_filehdr,
|
||||
includes_phdrs,
|
||||
is_flags_valid, flags,
|
||||
load_address));
|
||||
}
|
||||
|
||||
// Return the number of segments we expect to create based on the
|
||||
// SECTIONS clause. This is used to implement SIZEOF_HEADERS.
|
||||
|
||||
size_t
|
||||
Script_sections::expected_segment_count(const Layout* layout) const
|
||||
{
|
||||
if (this->saw_phdrs_clause())
|
||||
return this->phdrs_elements_->size();
|
||||
|
||||
Layout::Section_list sections;
|
||||
layout->get_allocated_sections(§ions);
|
||||
|
||||
@ -2398,6 +2645,189 @@ Script_sections::expected_segment_count(const Layout* layout) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Create the segments from a PHDRS clause. Return the segment which
|
||||
// should hold the file header and program headers, if any.
|
||||
|
||||
Output_segment*
|
||||
Script_sections::create_segments_from_phdrs_clause(Layout* layout)
|
||||
{
|
||||
this->attach_sections_using_phdrs_clause(layout);
|
||||
return this->set_phdrs_clause_addresses(layout);
|
||||
}
|
||||
|
||||
// Create the segments from the PHDRS clause, and put the output
|
||||
// sections in them.
|
||||
|
||||
void
|
||||
Script_sections::attach_sections_using_phdrs_clause(Layout* layout)
|
||||
{
|
||||
typedef std::map<std::string, Output_segment*> Name_to_segment;
|
||||
Name_to_segment name_to_segment;
|
||||
for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
|
||||
p != this->phdrs_elements_->end();
|
||||
++p)
|
||||
name_to_segment[(*p)->name()] = (*p)->create_segment(layout);
|
||||
|
||||
// Walk through the output sections and attach them to segments.
|
||||
// Output sections in the script which do not list segments are
|
||||
// attached to the same set of segments as the immediately preceding
|
||||
// output section.
|
||||
String_list* phdr_names = NULL;
|
||||
for (Sections_elements::const_iterator p = this->sections_elements_->begin();
|
||||
p != this->sections_elements_->end();
|
||||
++p)
|
||||
{
|
||||
Output_section* os = (*p)->allocate_to_segment(&phdr_names);
|
||||
if (os == NULL)
|
||||
continue;
|
||||
|
||||
if (phdr_names == NULL)
|
||||
{
|
||||
gold_error(_("allocated section not in any segment"));
|
||||
continue;
|
||||
}
|
||||
|
||||
bool in_load_segment = false;
|
||||
for (String_list::const_iterator q = phdr_names->begin();
|
||||
q != phdr_names->end();
|
||||
++q)
|
||||
{
|
||||
Name_to_segment::const_iterator r = name_to_segment.find(*q);
|
||||
if (r == name_to_segment.end())
|
||||
gold_error(_("no segment %s"), q->c_str());
|
||||
else
|
||||
{
|
||||
elfcpp::Elf_Word seg_flags =
|
||||
Layout::section_flags_to_segment(os->flags());
|
||||
r->second->add_output_section(os, seg_flags);
|
||||
|
||||
if (r->second->type() == elfcpp::PT_LOAD)
|
||||
{
|
||||
if (in_load_segment)
|
||||
gold_error(_("section in two PT_LOAD segments"));
|
||||
in_load_segment = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_load_segment)
|
||||
gold_error(_("allocated section not in any PT_LOAD segment"));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the addresses for segments created from a PHDRS clause. Return
|
||||
// the segment which should hold the file header and program headers,
|
||||
// if any.
|
||||
|
||||
Output_segment*
|
||||
Script_sections::set_phdrs_clause_addresses(Layout* layout)
|
||||
{
|
||||
Output_segment* load_seg = NULL;
|
||||
for (Phdrs_elements::const_iterator p = this->phdrs_elements_->begin();
|
||||
p != this->phdrs_elements_->end();
|
||||
++p)
|
||||
{
|
||||
// Note that we have to set the flags after adding the output
|
||||
// sections to the segment, as adding an output segment can
|
||||
// change the flags.
|
||||
(*p)->set_flags_if_valid();
|
||||
|
||||
Output_segment* oseg = (*p)->segment();
|
||||
|
||||
if (oseg->type() != elfcpp::PT_LOAD)
|
||||
{
|
||||
// The addresses of non-PT_LOAD segments are set from the
|
||||
// PT_LOAD segments.
|
||||
if ((*p)->has_load_address())
|
||||
gold_error(_("may only specify load address for PT_LOAD segment"));
|
||||
continue;
|
||||
}
|
||||
|
||||
// The output sections should have addresses from the SECTIONS
|
||||
// clause. The addresses don't have to be in order, so find the
|
||||
// one with the lowest load address. Use that to set the
|
||||
// address of the segment.
|
||||
|
||||
Output_section* osec = oseg->section_with_lowest_load_address();
|
||||
if (osec == NULL)
|
||||
{
|
||||
oseg->set_addresses(0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t vma = osec->address();
|
||||
uint64_t lma = osec->has_load_address() ? osec->load_address() : vma;
|
||||
|
||||
// Override the load address of the section with the load
|
||||
// address specified for the segment.
|
||||
if ((*p)->has_load_address())
|
||||
{
|
||||
if (osec->has_load_address())
|
||||
gold_warning(_("PHDRS load address overrides "
|
||||
"section %s load address"),
|
||||
osec->name());
|
||||
|
||||
lma = (*p)->load_address();
|
||||
}
|
||||
|
||||
bool headers = (*p)->includes_filehdr() && (*p)->includes_phdrs();
|
||||
if (!headers && ((*p)->includes_filehdr() || (*p)->includes_phdrs()))
|
||||
{
|
||||
// We could support this if we wanted to.
|
||||
gold_error(_("using only one of FILEHDR and PHDRS is "
|
||||
"not currently supported"));
|
||||
}
|
||||
if (headers)
|
||||
{
|
||||
size_t sizeof_headers = this->total_header_size(layout);
|
||||
uint64_t subtract = this->header_size_adjustment(lma,
|
||||
sizeof_headers);
|
||||
if (lma >= subtract && vma >= subtract)
|
||||
{
|
||||
lma -= subtract;
|
||||
vma -= subtract;
|
||||
}
|
||||
else
|
||||
{
|
||||
gold_error(_("sections loaded on first page without room "
|
||||
"for file and program headers "
|
||||
"are not supported"));
|
||||
}
|
||||
|
||||
if (load_seg != NULL)
|
||||
gold_error(_("using FILEHDR and PHDRS on more than one "
|
||||
"PT_LOAD segment is not currently supported"));
|
||||
load_seg = oseg;
|
||||
}
|
||||
|
||||
oseg->set_addresses(vma, lma);
|
||||
}
|
||||
|
||||
return load_seg;
|
||||
}
|
||||
|
||||
// Add the file header and segment headers to non-load segments
|
||||
// specified in the PHDRS clause.
|
||||
|
||||
void
|
||||
Script_sections::put_headers_in_phdrs(Output_data* file_header,
|
||||
Output_data* segment_headers)
|
||||
{
|
||||
gold_assert(this->saw_phdrs_clause());
|
||||
for (Phdrs_elements::iterator p = this->phdrs_elements_->begin();
|
||||
p != this->phdrs_elements_->end();
|
||||
++p)
|
||||
{
|
||||
if ((*p)->type() != elfcpp::PT_LOAD)
|
||||
{
|
||||
if ((*p)->includes_phdrs())
|
||||
(*p)->segment()->add_initial_output_data(segment_headers);
|
||||
if ((*p)->includes_filehdr())
|
||||
(*p)->segment()->add_initial_output_data(file_header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print the SECTIONS clause to F for debugging.
|
||||
|
||||
void
|
||||
|
@ -36,6 +36,8 @@ struct Parser_output_section_trailer;
|
||||
struct Input_section_spec;
|
||||
class Expression;
|
||||
class Sections_element;
|
||||
class Phdrs_element;
|
||||
class Output_data;
|
||||
class Output_section_definition;
|
||||
class Output_section;
|
||||
class Output_segment;
|
||||
@ -64,6 +66,12 @@ class Script_sections
|
||||
in_sections_clause() const
|
||||
{ return this->in_sections_clause_; }
|
||||
|
||||
// Return whether we ever saw a PHDRS clause. We ignore the PHDRS
|
||||
// clause unless we also saw a SECTIONS clause.
|
||||
bool
|
||||
saw_phdrs_clause() const
|
||||
{ return this->saw_sections_clause_ && this->phdrs_elements_ != NULL; }
|
||||
|
||||
// Start processing entries for an output section.
|
||||
void
|
||||
start_output_section(const char* name, size_t namelen,
|
||||
@ -134,11 +142,22 @@ class Script_sections
|
||||
Output_segment*
|
||||
set_section_addresses(Symbol_table*, Layout*);
|
||||
|
||||
// Add a program header definition.
|
||||
void
|
||||
add_phdr(const char* name, size_t namelen, unsigned int type,
|
||||
bool filehdr, bool phdrs, bool is_flags_valid, unsigned int flags,
|
||||
Expression* load_address);
|
||||
|
||||
// Return the number of segments we expect to create based on the
|
||||
// SECTIONS clause.
|
||||
size_t
|
||||
expected_segment_count(const Layout*) const;
|
||||
|
||||
// Add the file header and segment header to non-load segments as
|
||||
// specified by the PHDRS clause.
|
||||
void
|
||||
put_headers_in_phdrs(Output_data* file_header, Output_data* segment_headers);
|
||||
|
||||
// Print the contents to the FILE. This is for debugging.
|
||||
void
|
||||
print(FILE*) const;
|
||||
@ -146,6 +165,8 @@ class Script_sections
|
||||
private:
|
||||
typedef std::vector<Sections_element*> Sections_elements;
|
||||
|
||||
typedef std::vector<Phdrs_element*> Phdrs_elements;
|
||||
|
||||
// Create segments.
|
||||
Output_segment*
|
||||
create_segments(Layout*);
|
||||
@ -158,6 +179,27 @@ class Script_sections
|
||||
static bool
|
||||
is_bss_section(const Output_section*);
|
||||
|
||||
// Return the total size of the headers.
|
||||
size_t
|
||||
total_header_size(Layout* layout) const;
|
||||
|
||||
// Return the amount we have to subtract from the LMA to accomodate
|
||||
// headers of the given size.
|
||||
uint64_t
|
||||
header_size_adjustment(uint64_t lma, size_t sizeof_headers) const;
|
||||
|
||||
// Create the segments from a PHDRS clause.
|
||||
Output_segment*
|
||||
create_segments_from_phdrs_clause(Layout* layout);
|
||||
|
||||
// Attach sections to segments from a PHDRS clause.
|
||||
void
|
||||
attach_sections_using_phdrs_clause(Layout*);
|
||||
|
||||
// Set addresses of segments from a PHDRS clause.
|
||||
Output_segment*
|
||||
set_phdrs_clause_addresses(Layout*);
|
||||
|
||||
// True if we ever saw a SECTIONS clause.
|
||||
bool saw_sections_clause_;
|
||||
// True if we are currently processing a SECTIONS clause.
|
||||
@ -166,6 +208,8 @@ class Script_sections
|
||||
Sections_elements* sections_elements_;
|
||||
// The current output section, if there is one.
|
||||
Output_section_definition* output_section_;
|
||||
// The list of program headers in the PHDRS clause.
|
||||
Phdrs_elements* phdrs_elements_;
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
@ -2431,8 +2431,13 @@ script_new_string_list(const char* str, size_t len)
|
||||
extern "C" String_list_ptr
|
||||
script_string_list_push_back(String_list_ptr pv, const char* str, size_t len)
|
||||
{
|
||||
pv->push_back(std::string(str, len));
|
||||
return pv;
|
||||
if (pv == NULL)
|
||||
return script_new_string_list(str, len);
|
||||
else
|
||||
{
|
||||
pv->push_back(std::string(str, len));
|
||||
return pv;
|
||||
}
|
||||
}
|
||||
|
||||
// Concatenate two string lists. Either or both may be NULL. The way
|
||||
@ -2449,3 +2454,55 @@ script_string_list_append(String_list_ptr pv1, String_list_ptr pv2)
|
||||
pv1->insert(pv1->end(), pv2->begin(), pv2->end());
|
||||
return pv1;
|
||||
}
|
||||
|
||||
// Add a new program header.
|
||||
|
||||
extern "C" void
|
||||
script_add_phdr(void* closurev, const char* name, size_t namelen,
|
||||
unsigned int type, const Phdr_info* info)
|
||||
{
|
||||
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
|
||||
bool includes_filehdr = info->includes_filehdr != 0;
|
||||
bool includes_phdrs = info->includes_phdrs != 0;
|
||||
bool is_flags_valid = info->is_flags_valid != 0;
|
||||
Script_sections* ss = closure->script_options()->script_sections();
|
||||
ss->add_phdr(name, namelen, type, includes_filehdr, includes_phdrs,
|
||||
is_flags_valid, info->flags, info->load_address);
|
||||
}
|
||||
|
||||
// Convert a program header string to a type.
|
||||
|
||||
#define PHDR_TYPE(NAME) { #NAME, sizeof(#NAME) - 1, elfcpp::NAME }
|
||||
|
||||
static struct
|
||||
{
|
||||
const char* name;
|
||||
size_t namelen;
|
||||
unsigned int val;
|
||||
} phdr_type_names[] =
|
||||
{
|
||||
PHDR_TYPE(PT_NULL),
|
||||
PHDR_TYPE(PT_LOAD),
|
||||
PHDR_TYPE(PT_DYNAMIC),
|
||||
PHDR_TYPE(PT_INTERP),
|
||||
PHDR_TYPE(PT_NOTE),
|
||||
PHDR_TYPE(PT_SHLIB),
|
||||
PHDR_TYPE(PT_PHDR),
|
||||
PHDR_TYPE(PT_TLS),
|
||||
PHDR_TYPE(PT_GNU_EH_FRAME),
|
||||
PHDR_TYPE(PT_GNU_STACK),
|
||||
PHDR_TYPE(PT_GNU_RELRO)
|
||||
};
|
||||
|
||||
extern "C" unsigned int
|
||||
script_phdr_string_to_type(void* closurev, const char* name, size_t namelen)
|
||||
{
|
||||
for (unsigned int i = 0;
|
||||
i < sizeof(phdr_type_names) / sizeof(phdr_type_names[0]);
|
||||
++i)
|
||||
if (namelen == phdr_type_names[i].namelen
|
||||
&& strncmp(name, phdr_type_names[i].name, namelen) == 0)
|
||||
return phdr_type_names[i].val;
|
||||
yyerror(closurev, _("unknown PHDR type (try integer)"));
|
||||
return elfcpp::PT_NULL;
|
||||
}
|
||||
|
@ -331,6 +331,11 @@ class Script_options
|
||||
saw_sections_clause() const
|
||||
{ return this->script_sections_.saw_sections_clause(); }
|
||||
|
||||
// Whether we saw a PHDRS clause.
|
||||
bool
|
||||
saw_phdrs_clause() const
|
||||
{ return this->script_sections_.saw_phdrs_clause(); }
|
||||
|
||||
// Set section addresses using a SECTIONS clause. Return the
|
||||
// segment which should hold the file header and segment headers;
|
||||
// this may return NULL, in which case the headers are not in a
|
||||
|
@ -540,6 +540,15 @@ ver_matching_def.so: ver_matching_def.cc gcctestdir/ld
|
||||
$(CXXLINK) -O0 -Bgcctestdir/ -shared $(srcdir)/ver_matching_def.cc -Wl,--version-script=$(srcdir)/version_script.map
|
||||
ver_matching_test.stdout: ver_matching_def.so
|
||||
objdump -T ver_matching_def.so | c++filt > ver_matching_test.stdout
|
||||
|
||||
check_PROGRAMS += script_test_3
|
||||
check_SCRIPTS += script_test_3.sh
|
||||
check_DATA += script_test_3.stdout
|
||||
MOSTLYCLEANFILES += script_test_3.stdout
|
||||
script_test_3: basic_test.o gcctestdir/ld script_test_3.t
|
||||
$(CXXLINK) -Bgcctestdir/ basic_test.o -T $(srcdir)/script_test_3.t
|
||||
script_test_3.stdout: script_test_3
|
||||
objdump -p script_test_3 > script_test_3.stdout
|
||||
endif OBJDUMP_AND_CPPFILT
|
||||
|
||||
endif GCC
|
||||
|
@ -44,7 +44,8 @@ host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \
|
||||
$(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \
|
||||
$(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7)
|
||||
$(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \
|
||||
$(am__EXEEXT_8)
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = basic_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \
|
||||
@ -189,9 +190,13 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \
|
||||
@NATIVE_LINKER_FALSE@ ../libgold.a ../../libiberty/libiberty.a \
|
||||
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1) \
|
||||
@NATIVE_LINKER_FALSE@ $(am__DEPENDENCIES_1)
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_11 = ver_matching_test.sh
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_12 = ver_matching_test.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_13 = ver_matching_test.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_11 = ver_matching_test.sh \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ script_test_3.sh
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_12 = ver_matching_test.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ script_test_3.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_13 = ver_matching_test.stdout \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ script_test_3.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__append_14 = script_test_3
|
||||
subdir = testsuite
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
@ -258,6 +263,7 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test$(EXEEXT) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2$(EXEEXT)
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@am__EXEEXT_8 = script_test_3$(EXEEXT)
|
||||
basic_pic_test_SOURCES = basic_pic_test.c
|
||||
basic_pic_test_OBJECTS = basic_pic_test.$(OBJEXT)
|
||||
basic_pic_test_LDADD = $(LDADD)
|
||||
@ -386,6 +392,12 @@ am__script_test_2_SOURCES_DIST = script_test_2.cc script_test_2a.cc \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2b.$(OBJEXT)
|
||||
script_test_2_OBJECTS = $(am_script_test_2_OBJECTS)
|
||||
script_test_2_LDADD = $(LDADD)
|
||||
script_test_3_SOURCES = script_test_3.c
|
||||
script_test_3_OBJECTS = script_test_3.$(OBJEXT)
|
||||
script_test_3_LDADD = $(LDADD)
|
||||
script_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
|
||||
../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1)
|
||||
am__tls_pic_test_SOURCES_DIST = tls_test_main.cc
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
|
||||
tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
|
||||
@ -555,8 +567,8 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
|
||||
flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
|
||||
flagstest_o_specialfile_and_compress_debug_sections.c \
|
||||
$(object_unittest_SOURCES) $(script_test_1_SOURCES) \
|
||||
$(script_test_2_SOURCES) $(tls_pic_test_SOURCES) \
|
||||
$(tls_shared_ie_test_SOURCES) \
|
||||
$(script_test_2_SOURCES) script_test_3.c \
|
||||
$(tls_pic_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
|
||||
$(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
|
||||
$(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
|
||||
$(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
|
||||
@ -590,7 +602,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
|
||||
flagstest_compress_debug_sections.c flagstest_o_specialfile.c \
|
||||
flagstest_o_specialfile_and_compress_debug_sections.c \
|
||||
$(object_unittest_SOURCES) $(am__script_test_1_SOURCES_DIST) \
|
||||
$(am__script_test_2_SOURCES_DIST) \
|
||||
$(am__script_test_2_SOURCES_DIST) script_test_3.c \
|
||||
$(am__tls_pic_test_SOURCES_DIST) \
|
||||
$(am__tls_shared_ie_test_SOURCES_DIST) \
|
||||
$(am__tls_shared_nonpic_test_SOURCES_DIST) \
|
||||
@ -1101,6 +1113,15 @@ script_test_1$(EXEEXT): $(script_test_1_OBJECTS) $(script_test_1_DEPENDENCIES)
|
||||
script_test_2$(EXEEXT): $(script_test_2_OBJECTS) $(script_test_2_DEPENDENCIES)
|
||||
@rm -f script_test_2$(EXEEXT)
|
||||
$(CXXLINK) $(script_test_2_LDFLAGS) $(script_test_2_OBJECTS) $(script_test_2_LDADD) $(LIBS)
|
||||
@GCC_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES)
|
||||
@GCC_FALSE@ @rm -f script_test_3$(EXEEXT)
|
||||
@GCC_FALSE@ $(LINK) $(script_test_3_LDFLAGS) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
|
||||
@NATIVE_LINKER_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES)
|
||||
@NATIVE_LINKER_FALSE@ @rm -f script_test_3$(EXEEXT)
|
||||
@NATIVE_LINKER_FALSE@ $(LINK) $(script_test_3_LDFLAGS) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
|
||||
@OBJDUMP_AND_CPPFILT_FALSE@script_test_3$(EXEEXT): $(script_test_3_OBJECTS) $(script_test_3_DEPENDENCIES)
|
||||
@OBJDUMP_AND_CPPFILT_FALSE@ @rm -f script_test_3$(EXEEXT)
|
||||
@OBJDUMP_AND_CPPFILT_FALSE@ $(LINK) $(script_test_3_LDFLAGS) $(script_test_3_OBJECTS) $(script_test_3_LDADD) $(LIBS)
|
||||
tls_pic_test$(EXEEXT): $(tls_pic_test_OBJECTS) $(tls_pic_test_DEPENDENCIES)
|
||||
@rm -f tls_pic_test$(EXEEXT)
|
||||
$(CXXLINK) $(tls_pic_test_LDFLAGS) $(tls_pic_test_OBJECTS) $(tls_pic_test_LDADD) $(LIBS)
|
||||
@ -1202,6 +1223,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2a.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_2b.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script_test_3.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testfile.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmain.Po@am__quote@
|
||||
@ -1654,6 +1676,10 @@ uninstall-am: uninstall-info-am
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ $(CXXLINK) -O0 -Bgcctestdir/ -shared $(srcdir)/ver_matching_def.cc -Wl,--version-script=$(srcdir)/version_script.map
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ver_matching_test.stdout: ver_matching_def.so
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ objdump -T ver_matching_def.so | c++filt > ver_matching_test.stdout
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@script_test_3: basic_test.o gcctestdir/ld script_test_3.t
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o -T $(srcdir)/script_test_3.t
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@script_test_3.stdout: script_test_3
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@@OBJDUMP_AND_CPPFILT_TRUE@ objdump -p script_test_3 > script_test_3.stdout
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
|
59
gold/testsuite/script_test_3.sh
Executable file
59
gold/testsuite/script_test_3.sh
Executable file
@ -0,0 +1,59 @@
|
||||
#!/bin/sh
|
||||
|
||||
# script_test_3.sh -- test PHDRS
|
||||
|
||||
# Copyright 2008 Free Software Foundation, Inc.
|
||||
# Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
# This file is part of gold.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
|
||||
# This file goes with script_test_3.t, which is a linker script which
|
||||
# uses a PHDRS clause. We run objdump -p on a program linked with
|
||||
# that linker script.
|
||||
|
||||
check()
|
||||
{
|
||||
if ! grep -q "$2" "$1"
|
||||
then
|
||||
echo "Did not find expected segment in $1:"
|
||||
echo " $2"
|
||||
echo ""
|
||||
echo "Actual output below:"
|
||||
cat "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_count()
|
||||
{
|
||||
if test "`grep -c "$2" "$1"`" != "$3"
|
||||
then
|
||||
echo "Did not find expected segment in $1:"
|
||||
echo " $2"
|
||||
echo ""
|
||||
echo "Actual output below:"
|
||||
cat "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_count script_test_3.stdout "INTERP off" 1
|
||||
check_count script_test_3.stdout "LOAD off" 3
|
||||
check_count script_test_3.stdout "DYNAMIC off" 1
|
||||
|
||||
exit 0
|
43
gold/testsuite/script_test_3.t
Normal file
43
gold/testsuite/script_test_3.t
Normal file
@ -0,0 +1,43 @@
|
||||
/* script_test_3.t -- linker script test 3 for gold
|
||||
|
||||
Copyright 2008 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
This file is part of gold.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* With luck this will work everywhere. */
|
||||
. = 0x10000000;
|
||||
|
||||
/* With luck this will be enough to get the program working. */
|
||||
.interp : { *(.interp) } :text :interp
|
||||
.text : { *(.text) } :text
|
||||
.dynamic : { *(.dynamic) } :text :dynamic
|
||||
.data : { *(.data) } :data
|
||||
.bss : { *(.bss) } :bss
|
||||
}
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FILEHDR PHDRS FLAGS(5);
|
||||
interp PT_INTERP;
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
data PT_LOAD;
|
||||
bss PT_LOAD;
|
||||
}
|
@ -30,6 +30,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "script-c.h"
|
||||
|
||||
@ -70,6 +71,8 @@
|
||||
struct Wildcard_section wildcard_section;
|
||||
/* A list of strings. */
|
||||
String_list_ptr string_list;
|
||||
/* Information for a program header. */
|
||||
struct Phdr_info phdr_info;
|
||||
/* Used for version scripts and within VERSION {}. */
|
||||
struct Version_dependency_list* deplist;
|
||||
struct Version_expression_list* versyms;
|
||||
@ -198,12 +201,15 @@
|
||||
%type <output_section_header> section_header
|
||||
%type <output_section_trailer> section_trailer
|
||||
%type <constraint> opt_constraint
|
||||
%type <string_list> opt_phdr
|
||||
%type <integer> data_length
|
||||
%type <input_section_spec> input_section_no_keep
|
||||
%type <wildcard_sections> wildcard_sections
|
||||
%type <wildcard_section> wildcard_file wildcard_section
|
||||
%type <string_list> exclude_names
|
||||
%type <string> wildcard_name
|
||||
%type <integer> phdr_type
|
||||
%type <phdr_info> phdr_info
|
||||
%type <versyms> vers_defns
|
||||
%type <versnode> vers_tag
|
||||
%type <deplist> verdep
|
||||
@ -232,6 +238,7 @@ file_cmd:
|
||||
{ script_end_group(closure); }
|
||||
| OPTION '(' string ')'
|
||||
{ script_parse_option(closure, $3.value, $3.length); }
|
||||
| PHDRS '{' phdrs_defs '}'
|
||||
| SEARCH_DIR '(' string ')'
|
||||
{ script_add_search_dir(closure, $3.value, $3.length); }
|
||||
| SECTIONS '{'
|
||||
@ -365,6 +372,7 @@ section_trailer:
|
||||
opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
|
||||
{
|
||||
$$.fill = $4;
|
||||
$$.phdrs = $3;
|
||||
}
|
||||
;
|
||||
|
||||
@ -385,8 +393,9 @@ opt_at_memspec:
|
||||
/* The program segment an output section should go into. */
|
||||
opt_phdr:
|
||||
opt_phdr ':' string
|
||||
{ yyerror(closure, "program headers are not supported"); }
|
||||
{ $$ = script_string_list_push_back($1, $3.value, $3.length); }
|
||||
| /* empty */
|
||||
{ $$ = NULL; }
|
||||
;
|
||||
|
||||
/* The value to use to fill an output section. FIXME: This does not
|
||||
@ -587,6 +596,64 @@ file_or_sections_cmd:
|
||||
{ script_add_assertion(closure, $3, $5.value, $5.length); }
|
||||
;
|
||||
|
||||
/* A list of program header definitions. */
|
||||
phdrs_defs:
|
||||
phdrs_defs phdr_def
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
/* A program header definition. */
|
||||
phdr_def:
|
||||
string phdr_type phdr_info ';'
|
||||
{ script_add_phdr(closure, $1.value, $1.length, $2, &$3); }
|
||||
;
|
||||
|
||||
/* A program header type. The GNU linker accepts a general expression
|
||||
here, but that would be a pain because we would have to dig into
|
||||
the expression structure. It's unlikely that anybody uses anything
|
||||
other than a string or a number here, so that is all we expect. */
|
||||
phdr_type:
|
||||
string
|
||||
{ $$ = script_phdr_string_to_type(closure, $1.value, $1.length); }
|
||||
| INTEGER
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
/* Additional information for a program header. */
|
||||
phdr_info:
|
||||
/* empty */
|
||||
{ memset(&$$, 0, sizeof(struct Phdr_info)); }
|
||||
| string phdr_info
|
||||
{
|
||||
$$ = $2;
|
||||
if ($1.length == 7 && strncmp($1.value, "FILEHDR", 7) == 0)
|
||||
$$.includes_filehdr = 1;
|
||||
else
|
||||
yyerror(closure, "PHDRS syntax error");
|
||||
}
|
||||
| PHDRS phdr_info
|
||||
{
|
||||
$$ = $2;
|
||||
$$.includes_phdrs = 1;
|
||||
}
|
||||
| string '(' INTEGER ')' phdr_info
|
||||
{
|
||||
$$ = $5;
|
||||
if ($1.length == 5 && strncmp($1.value, "FLAGS", 5) == 0)
|
||||
{
|
||||
$$.is_flags_valid = 1;
|
||||
$$.flags = $3;
|
||||
}
|
||||
else
|
||||
yyerror(closure, "PHDRS syntax error");
|
||||
}
|
||||
| AT '(' parse_exp ')' phdr_info
|
||||
{
|
||||
$$ = $5;
|
||||
$$.load_address = $3;
|
||||
}
|
||||
;
|
||||
|
||||
/* Set a symbol to a value. */
|
||||
assignment:
|
||||
string '=' parse_exp
|
||||
|
Reference in New Issue
Block a user