Fully implement the SECTIONS clause.

This commit is contained in:
Ian Lance Taylor 2008-02-04 05:43:05 +00:00
parent d16c732117
commit a445fddf82
24 changed files with 3087 additions and 441 deletions

View File

@ -131,6 +131,10 @@ class Elf_file
typename File::Location
section_contents(unsigned int shndx);
// Return the size of section SHNDX.
typename Elf_types<size>::Elf_WXword
section_size(unsigned int shndx);
// Return the flags of section SHNDX.
typename Elf_types<size>::Elf_WXword
section_flags(unsigned int shndx);
@ -147,6 +151,9 @@ class Elf_file
Elf_Word
section_info(unsigned int shndx);
// Return the addralign field of section SHNDX.
typename Elf_types<size>::Elf_WXword
section_addralign(unsigned int shndx);
private:
// Shared constructor code.
@ -296,6 +303,25 @@ Elf_file<size, big_endian, File>::section_contents(unsigned int shndx)
return typename File::Location(shdr.get_sh_offset(), shdr.get_sh_size());
}
// Get the size of section SHNDX.
template<int size, bool big_endian, typename File>
typename Elf_types<size>::Elf_WXword
Elf_file<size, big_endian, File>::section_size(unsigned int shndx)
{
File* const file = this->file_;
if (shndx >= this->shnum())
file->error(_("section_size: bad shndx %u >= %u"),
shndx, this->shnum());
typename File::View v(file->view(this->section_header_offset(shndx),
This::shdr_size));
Ef_shdr shdr(v.data());
return shdr.get_sh_size();
}
// Return the section flags of section SHNDX.
template<int size, bool big_endian, typename File>
@ -372,6 +398,25 @@ Elf_file<size, big_endian, File>::section_info(unsigned int shndx)
return shdr.get_sh_info();
}
// Return the sh_addralign field of section SHNDX.
template<int size, bool big_endian, typename File>
typename Elf_types<size>::Elf_WXword
Elf_file<size, big_endian, File>::section_addralign(unsigned int shndx)
{
File* const file = this->file_;
if (shndx >= this->shnum())
file->error(_("section_addralign: bad shndx %u >= %u"),
shndx, this->shnum());
typename File::View v(file->view(this->section_header_offset(shndx),
This::shdr_size));
Ef_shdr shdr(v.data());
return shdr.get_sh_addralign();
}
} // End namespace elfcpp.
#endif // !defined(ELFCPP_FILE_H)

View File

@ -23,6 +23,7 @@
#include "gold.h"
#include "symtab.h"
#include "layout.h"
#include "defstd.h"
// This is a simple file which defines the standard symbols like
@ -251,8 +252,11 @@ namespace gold
void
define_standard_symbols(Symbol_table* symtab, const Layout* layout)
{
symtab->define_symbols(layout, in_section_count, in_section);
symtab->define_symbols(layout, in_segment_count, in_segment);
bool saw_sections_clause = layout->script_options()->saw_sections_clause();
symtab->define_symbols(layout, in_section_count, in_section,
saw_sections_clause);
symtab->define_symbols(layout, in_segment_count, in_segment,
saw_sections_clause);
}
} // End namespace gold.

View File

@ -176,6 +176,11 @@ class Sized_dynobj : public Dynobj
void
do_add_symbols(Symbol_table*, Read_symbols_data*);
// Get the size of a section.
uint64_t
do_section_size(unsigned int shndx)
{ return this->elf_file_.section_size(shndx); }
// Get the name of a section.
std::string
do_section_name(unsigned int shndx)
@ -207,6 +212,11 @@ class Sized_dynobj : public Dynobj
do_section_info(unsigned int shndx)
{ return this->elf_file_.section_info(shndx); }
// Return the section alignment.
uint64_t
do_section_addralign(unsigned int shndx)
{ return this->elf_file_.section_addralign(shndx); }
private:
// For convenience.
typedef Sized_dynobj<size, big_endian> This;

View File

@ -36,24 +36,75 @@ namespace gold
// This file holds the code which handles linker expressions.
// The dot symbol, which linker scripts refer to simply as ".",
// requires special treatment. The dot symbol is set several times,
// section addresses will refer to it, output sections will change it,
// and it can be set based on the value of other symbols. We simplify
// the handling by prohibiting setting the dot symbol to the value of
// a non-absolute symbol.
// When evaluating the value of an expression, we pass in a pointer to
// this struct, so that the expression evaluation can find the
// information it needs.
struct Expression::Expression_eval_info
{
// The symbol table.
const Symbol_table* symtab;
// The layout--we use this to get section information.
const Layout* layout;
// Whether expressions can refer to the dot symbol. The dot symbol
// is only available within a SECTIONS clause.
bool is_dot_available;
// Whether the dot symbol currently has a value.
bool dot_has_value;
// The current value of the dot symbol.
uint64_t dot_value;
// Points to the IS_ABSOLUTE variable, which is set to false if the
// expression uses a value which is not absolute.
bool* is_absolute;
};
// Evaluate an expression.
uint64_t
Expression::eval(const Symbol_table* symtab, const Layout* layout)
{
bool dummy;
return this->eval_maybe_dot(symtab, layout, false, false, 0, &dummy);
}
// Evaluate an expression which may refer to the dot symbol.
uint64_t
Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
bool dot_has_value, uint64_t dot_value,
bool* is_absolute)
{
return this->eval_maybe_dot(symtab, layout, true, dot_has_value, dot_value,
is_absolute);
}
// Evaluate an expression which may or may not refer to the dot
// symbol.
uint64_t
Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
bool is_dot_available, bool dot_has_value,
uint64_t dot_value, bool* is_absolute)
{
Expression_eval_info eei;
eei.symtab = symtab;
eei.layout = layout;
eei.is_dot_available = is_dot_available;
eei.dot_has_value = dot_has_value;
eei.dot_value = dot_value;
// We assume the value is absolute, and only set this to false if we
// find a section relative reference.
*is_absolute = true;
eei.is_absolute = is_absolute;
return this->value(&eei);
}
@ -115,6 +166,14 @@ Symbol_expression::value(const Expression_eval_info* eei)
return 0;
}
// If this symbol does not have an absolute value, then the whole
// expression does not have an absolute value. This is not strictly
// accurate: the subtraction of two symbols in the same section is
// absolute. This is unlikely to matter in practice, as this value
// is only used for error checking.
if (!sym->value_is_absolute())
*eei->is_absolute = false;
if (parameters->get_size() == 32)
return eei->symtab->get_sized_symbol<32>(sym)->value();
else if (parameters->get_size() == 64)
@ -141,10 +200,21 @@ class Dot_expression : public Expression
};
uint64_t
Dot_expression::value(const Expression_eval_info*)
Dot_expression::value(const Expression_eval_info* eei)
{
gold_error("dot symbol unimplemented");
return 0;
if (!eei->is_dot_available)
{
gold_error(_("invalid reference to dot symbol outside of "
"SECTIONS clause"));
return 0;
}
else if (!eei->dot_has_value)
{
gold_error(_("invalid reference to dot symbol before "
"it has been given a value"));
return 0;
}
return eei->dot_value;
}
// A string. This is either the name of a symbol, or ".".
@ -549,6 +619,10 @@ Addr_expression::value(const Expression_eval_info* eei)
section_name);
return 0;
}
// Note that the address of a section is an absolute address, and we
// should not clear *EEI->IS_ABSOLUTE here.
return os->address();
}

View File

@ -198,17 +198,16 @@ queue_middle_tasks(const General_options& options,
// handles some cases we want to see before we read the relocs.
layout->create_initial_dynamic_sections(symtab);
// Predefine standard symbols. This should be fast, so we don't
// bother to create a task for it.
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab);
// Predefine standard symbols.
define_standard_symbols(symtab, layout);
// Define __start and __stop symbols for output sections where
// appropriate.
layout->define_section_symbols(symtab);
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab);
// Read the relocations of the input files. We do this to find
// which symbols are used by relocations which require a GOT and/or
// a PLT entry, or a COPY reloc. When we implement garbage

View File

@ -29,6 +29,8 @@
#include "parameters.h"
#include "options.h"
#include "script.h"
#include "script-sections.h"
#include "output.h"
#include "symtab.h"
#include "dynobj.h"
@ -185,11 +187,11 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
Output_section*
Layout::find_output_section(const char* name) const
{
for (Section_name_map::const_iterator p = this->section_name_map_.begin();
p != this->section_name_map_.end();
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
if (strcmp(p->second->name(), name) == 0)
return p->second;
if (strcmp((*p)->name(), name) == 0)
return *p;
return NULL;
}
@ -211,19 +213,13 @@ Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
}
// Return the output section to use for section NAME with type TYPE
// and section flags FLAGS.
// and section flags FLAGS. NAME must be canonicalized in the string
// pool, and NAME_KEY is the key.
Output_section*
Layout::get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags)
{
// We should ignore some flags.
flags &= ~ (elfcpp::SHF_INFO_LINK
| elfcpp::SHF_LINK_ORDER
| elfcpp::SHF_GROUP
| elfcpp::SHF_MERGE
| elfcpp::SHF_STRINGS);
const Key key(name_key, std::make_pair(type, flags));
const std::pair<Key, Output_section*> v(key, NULL);
std::pair<Section_name_map::iterator, bool> ins(
@ -241,6 +237,80 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key,
}
}
// Pick the output section to use for section NAME, in input file
// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a
// linker created section. ADJUST_NAME is true if we should apply the
// standard name mappings in Layout::output_section_name. This will
// return NULL if the input section should be discarded.
Output_section*
Layout::choose_output_section(const Relobj* relobj, const char* name,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
bool adjust_name)
{
// We should ignore some flags. FIXME: This will need some
// adjustment for ld -r.
flags &= ~ (elfcpp::SHF_INFO_LINK
| elfcpp::SHF_LINK_ORDER
| elfcpp::SHF_GROUP
| elfcpp::SHF_MERGE
| elfcpp::SHF_STRINGS);
if (this->script_options_->saw_sections_clause())
{
// We are using a SECTIONS clause, so the output section is
// chosen based only on the name.
Script_sections* ss = this->script_options_->script_sections();
const char* file_name = relobj == NULL ? NULL : relobj->name().c_str();
Output_section** output_section_slot;
name = ss->output_section_name(file_name, name, &output_section_slot);
if (name == NULL)
{
// The SECTIONS clause says to discard this input section.
return NULL;
}
// If this is an orphan section--one not mentioned in the linker
// script--then OUTPUT_SECTION_SLOT will be NULL, and we do the
// default processing below.
if (output_section_slot != NULL)
{
if (*output_section_slot != NULL)
return *output_section_slot;
// We don't put sections found in the linker script into
// SECTION_NAME_MAP_. That keeps us from getting confused
// if an orphan section is mapped to a section with the same
// name as one in the linker script.
name = this->namepool_.add(name, false, NULL);
Output_section* os = this->make_output_section(name, type, flags);
os->set_found_in_sections_clause();
*output_section_slot = os;
return os;
}
}
// FIXME: Handle SHF_OS_NONCONFORMING somewhere.
// Turn NAME from the name of the input section into the name of the
// output section.
size_t len = strlen(name);
if (adjust_name && !parameters->output_is_object())
name = Layout::output_section_name(name, &len);
Stringpool::Key name_key;
name = this->namepool_.add_with_length(name, len, true, &name_key);
// Find or make the output section. The output section is selected
// based on the section name, type, and flags.
return this->get_output_section(name, name_key, type, flags);
}
// Return the output section to use for input section SHNDX, with name
// NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the
// index of a relocation section which applies to this section, or 0
@ -260,27 +330,18 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
if (!this->include_section(object, name, shdr))
return NULL;
// If we are not doing a relocateable link, choose the name to use
// for the output section.
size_t len = strlen(name);
if (!parameters->output_is_object())
name = Layout::output_section_name(name, &len);
// FIXME: Handle SHF_OS_NONCONFORMING here.
// Canonicalize the section name.
Stringpool::Key name_key;
name = this->namepool_.add_with_length(name, len, true, &name_key);
// Find the output section. The output section is selected based on
// the section name, type, and flags.
Output_section* os = this->get_output_section(name, name_key,
shdr.get_sh_type(),
shdr.get_sh_flags());
Output_section* os = this->choose_output_section(object,
name,
shdr.get_sh_type(),
shdr.get_sh_flags(),
true);
if (os == NULL)
return NULL;
// FIXME: Handle SHF_LINK_ORDER somewhere.
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx);
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx,
this->script_options_->saw_sections_clause());
return os;
}
@ -304,12 +365,14 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS);
gold_assert(shdr.get_sh_flags() == elfcpp::SHF_ALLOC);
Stringpool::Key name_key;
const char* name = this->namepool_.add(".eh_frame", false, &name_key);
Output_section* os = this->get_output_section(name, name_key,
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC);
const char* const name = ".eh_frame";
Output_section* os = this->choose_output_section(object,
name,
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC,
false);
if (os == NULL)
return NULL;
if (this->eh_frame_section_ == NULL)
{
@ -319,26 +382,28 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
if (this->options_.create_eh_frame_hdr())
{
Stringpool::Key hdr_name_key;
const char* hdr_name = this->namepool_.add(".eh_frame_hdr",
false,
&hdr_name_key);
Output_section* hdr_os =
this->get_output_section(hdr_name, hdr_name_key,
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC);
this->choose_output_section(NULL,
".eh_frame_hdr",
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC,
false);
Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, this->eh_frame_data_);
hdr_os->add_output_section_data(hdr_posd);
if (hdr_os != NULL)
{
Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os,
this->eh_frame_data_);
hdr_os->add_output_section_data(hdr_posd);
hdr_os->set_after_input_sections();
hdr_os->set_after_input_sections();
Output_segment* hdr_oseg =
new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
this->segment_list_.push_back(hdr_oseg);
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
Output_segment* hdr_oseg =
new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
this->segment_list_.push_back(hdr_oseg);
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
}
}
}
@ -357,7 +422,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
{
// We couldn't handle this .eh_frame section for some reason.
// Add it as a normal section.
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx);
bool saw_sections_clause = this->script_options_->saw_sections_clause();
*off = os->add_input_section(object, shndx, name, shdr, reloc_shndx,
saw_sections_clause);
}
return os;
@ -370,12 +437,10 @@ Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags,
Output_section_data* posd)
{
// Canonicalize the name.
Stringpool::Key name_key;
name = this->namepool_.add(name, true, &name_key);
Output_section* os = this->get_output_section(name, name_key, type, flags);
os->add_output_section_data(posd);
Output_section* os = this->choose_output_section(NULL, name, type, flags,
false);
if (os != NULL)
os->add_output_section_data(posd);
}
// Map section flags to segment flags.
@ -428,6 +493,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
this->unattached_section_list_.push_back(os);
else
{
// If we have a SECTIONS clause, we can't handle the attachment
// to segments until after we've seen all the sections.
if (this->script_options_->saw_sections_clause())
return os;
// This output section goes into a PT_LOAD segment.
elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
@ -581,7 +651,7 @@ Layout::define_section_symbols(Symbol_table* symtab)
elfcpp::STV_DEFAULT,
0, // nonvis
false, // offset_is_from_end
false); // only_if_ref
true); // only_if_ref
symtab->define_in_output_data(stop_name.c_str(),
NULL, // version
@ -593,7 +663,7 @@ Layout::define_section_symbols(Symbol_table* symtab)
elfcpp::STV_DEFAULT,
0, // nonvis
true, // offset_is_from_end
false); // only_if_ref
true); // only_if_ref
}
}
}
@ -664,17 +734,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
this->create_gold_note();
this->create_executable_stack_info(target);
Output_segment* phdr_seg = NULL;
if (!parameters->doing_static_link())
if (!parameters->output_is_object() && !parameters->doing_static_link())
{
// There was a dynamic object in the link. We need to create
// some information for the dynamic linker.
// Create the PT_PHDR segment which will hold the program
// headers.
phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
this->segment_list_.push_back(phdr_seg);
// Create the dynamic symbol table, including the hash table.
Output_section* dynstr;
std::vector<Symbol*> dynamic_symbols;
@ -703,15 +767,30 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
dynamic_symbols, dynstr);
}
// FIXME: Handle PT_GNU_STACK.
// If there is a SECTIONS clause, put all the input sections into
// the required order.
Output_segment* load_seg;
if (this->script_options_->saw_sections_clause())
load_seg = this->set_section_addresses_from_script(symtab);
else
load_seg = this->find_first_load_seg();
Output_segment* load_seg = this->find_first_load_seg();
Output_segment* phdr_seg = NULL;
if (load_seg != NULL
&& !parameters->output_is_object()
&& !parameters->doing_static_link())
{
// Create the PT_PHDR segment which will hold the program
// headers.
phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
this->segment_list_.push_back(phdr_seg);
}
// Lay out the segment headers.
Output_segment_headers* segment_headers;
segment_headers = new Output_segment_headers(this->segment_list_);
load_seg->add_initial_output_data(segment_headers);
this->special_output_list_.push_back(segment_headers);
if (load_seg != NULL)
load_seg->add_initial_output_data(segment_headers);
if (phdr_seg != NULL)
phdr_seg->add_initial_output_data(segment_headers);
@ -719,8 +798,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
Output_file_header* file_header;
file_header = new Output_file_header(target, symtab, segment_headers,
this->script_options_->entry());
load_seg->add_initial_output_data(file_header);
if (load_seg != NULL)
load_seg->add_initial_output_data(file_header);
this->special_output_list_.push_back(file_header);
this->special_output_list_.push_back(segment_headers);
// We set the output section indexes in set_segment_offsets and
// set_section_indexes.
@ -970,6 +1052,27 @@ Layout::segment_precedes(const Output_segment* seg1,
return flags1 < flags2;
}
// If the addresses are set already, sort by load address.
if (seg1->are_addresses_set())
{
if (!seg2->are_addresses_set())
return true;
unsigned int section_count1 = seg1->output_section_count();
unsigned int section_count2 = seg2->output_section_count();
if (section_count1 == 0 && section_count2 > 0)
return true;
if (section_count1 > 0 && section_count2 == 0)
return false;
uint64_t paddr1 = seg1->first_section_load_address();
uint64_t paddr2 = seg2->first_section_load_address();
if (paddr1 != paddr2)
return paddr1 < paddr2;
}
else if (seg2->are_addresses_set())
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
@ -984,15 +1087,9 @@ Layout::segment_precedes(const Output_segment* seg1,
if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
return (flags1 & elfcpp::PF_R) == 0;
uint64_t vaddr1 = seg1->vaddr();
uint64_t vaddr2 = seg2->vaddr();
if (vaddr1 != vaddr2)
return vaddr1 < vaddr2;
uint64_t paddr1 = seg1->paddr();
uint64_t paddr2 = seg2->paddr();
gold_assert(paddr1 != paddr2);
return paddr1 < paddr2;
// We shouldn't get here--we shouldn't create segments which we
// can't distinguish.
gold_unreachable();
}
// Set the file offsets of all the segments, and all the sections they
@ -1010,13 +1107,29 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
uint64_t addr;
if (parameters->output_is_shared())
addr = 0;
else if (options_.user_set_text_segment_address())
if (this->options_.user_set_text_segment_address())
addr = options_.text_segment_address();
else if (parameters->output_is_shared())
addr = 0;
else
addr = target->default_text_segment_address();
off_t off = 0;
// If LOAD_SEG is NULL, then the file header and segment headers
// will not be loadable. But they still need to be at offset 0 in
// the file. Set their offsets now.
if (load_seg == NULL)
{
for (Data_list::iterator p = this->special_output_list_.begin();
p != this->special_output_list_.end();
++p)
{
off = align_address(off, (*p)->addralign());
(*p)->set_address_and_file_offset(0, off);
off += (*p)->data_size();
}
}
bool was_readonly = false;
for (Segment_list::iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
@ -1028,34 +1141,55 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
gold_unreachable();
load_seg = NULL;
// If the last segment was readonly, and this one is not,
// then skip the address forward one page, maintaining the
// same position within the page. This lets us store both
// segments overlapping on a single page in the file, but
// the loader will put them on different pages in memory.
uint64_t orig_addr = addr;
uint64_t orig_off = off;
uint64_t aligned_addr = addr;
uint64_t aligned_addr = 0;
uint64_t abi_pagesize = target->abi_pagesize();
// FIXME: This should depend on the -n and -N options.
(*p)->set_minimum_addralign(target->common_pagesize());
// FIXME: This should depend on the -n and -N options.
(*p)->set_minimum_p_align(target->common_pagesize());
if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
bool are_addresses_set = (*p)->are_addresses_set();
if (are_addresses_set)
{
uint64_t align = (*p)->addralign();
// When it comes to setting file offsets, we care about
// the physical address.
addr = (*p)->paddr();
addr = align_address(addr, align);
// Adjust the file offset to the same address modulo the
// page size.
uint64_t unsigned_off = off;
uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1))
| (addr & (abi_pagesize - 1)));
if (aligned_off < unsigned_off)
aligned_off += abi_pagesize;
off = aligned_off;
}
else
{
// If the last segment was readonly, and this one is
// not, then skip the address forward one page,
// maintaining the same position within the page. This
// lets us store both segments overlapping on a single
// page in the file, but the loader will put them on
// different pages in memory.
addr = align_address(addr, (*p)->maximum_alignment());
aligned_addr = addr;
if ((addr & (abi_pagesize - 1)) != 0)
addr = addr + abi_pagesize;
if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
{
if ((addr & (abi_pagesize - 1)) != 0)
addr = addr + abi_pagesize;
}
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
}
unsigned int shndx_hold = *pshndx;
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
uint64_t new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
uint64_t new_addr = (*p)->set_section_addresses(false, addr, &off,
pshndx);
// Now that we know the size of this segment, we may be able
// to save a page in memory, at the cost of wasting some
@ -1063,7 +1197,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// page. Here we use the real machine page size rather than
// the ABI mandated page size.
if (aligned_addr != addr)
if (!are_addresses_set && aligned_addr != addr)
{
uint64_t common_pagesize = target->common_pagesize();
uint64_t first_off = (common_pagesize
@ -1078,8 +1212,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
{
*pshndx = shndx_hold;
addr = align_address(aligned_addr, common_pagesize);
addr = align_address(addr, (*p)->maximum_alignment());
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
new_addr = (*p)->set_section_addresses(true, addr, &off,
pshndx);
}
}
@ -1172,6 +1308,30 @@ Layout::set_section_indexes(unsigned int shndx)
return shndx;
}
// Set the section addresses according to the linker script. This is
// only called when we see a SECTIONS clause. This returns the
// program segment which should hold the file header and segment
// headers, if any. It will return NULL if they should not be in a
// segment.
Output_segment*
Layout::set_section_addresses_from_script(Symbol_table* symtab)
{
Script_sections* ss = this->script_options_->script_sections();
gold_assert(ss->saw_sections_clause());
// Place each orphaned output section in the script.
for (Section_list::iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if (!(*p)->found_in_sections_clause())
ss->place_orphan(*p);
}
return this->script_options_->set_section_addresses(symtab, this);
}
// Count the local symbols in the regular symbol table and the dynamic
// symbol table, and build the respective string pools.
@ -1963,6 +2123,28 @@ Layout::add_comdat(const char* signature, bool group)
}
}
// Store the allocated sections into the section list.
void
Layout::get_allocated_sections(Section_list* section_list) const
{
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
section_list->push_back(*p);
}
// Create an output segment.
Output_segment*
Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
{
Output_segment* oseg = new Output_segment(type, flags);
this->segment_list_.push_back(oseg);
return oseg;
}
// Write out the Output_sections. Most won't have anything to write,
// since most of the data will come from input sections which are
// handled elsewhere. But some Output_sections do have Output_data.

View File

@ -260,11 +260,11 @@ class Layout
void
print_stats() const;
// The list of segments.
// A list of segments.
typedef std::vector<Output_segment*> Segment_list;
// The list of sections not attached to a segment.
// A list of sections.
typedef std::vector<Output_section*> Section_list;
@ -272,6 +272,24 @@ class Layout
// either a section or a segment.
typedef std::vector<Output_data*> Data_list;
// Store the allocated sections into the section list. This is used
// by the linker script code.
void
get_allocated_sections(Section_list*) const;
// Make a segment. This is used by the linker script code.
Output_segment*
make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags);
// Return the number of segments.
size_t
segment_count() const
{ return this->segment_list_.size(); }
// Map from section flags to segment flags.
static elfcpp::Elf_Word
section_flags_to_segment(elfcpp::Elf_Xword flags);
private:
Layout(const Layout&);
Layout& operator=(const Layout&);
@ -376,6 +394,12 @@ class Layout
get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags);
// Choose the output section for NAME in RELOBJ.
Output_section*
choose_output_section(const Relobj* relobj, const char* name,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
bool adjust_name);
// Create a new Output_section.
Output_section*
make_output_section(const char* name, elfcpp::Elf_Word type,
@ -405,14 +429,14 @@ class Layout
unsigned int
set_section_indexes(unsigned int pshndx);
// Set the section addresses when using a script.
Output_segment*
set_section_addresses_from_script(Symbol_table*);
// Return whether SEG1 comes before SEG2 in the output file.
static bool
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
// Map from section flags to segment flags.
static elfcpp::Elf_Word
section_flags_to_segment(elfcpp::Elf_Xword flags);
// A mapping used for group signatures.
typedef Unordered_map<std::string, bool> Signatures;

View File

@ -206,8 +206,12 @@ class Object
const unsigned char*
section_contents(unsigned int shndx, section_size_type* plen, bool cache);
// Return the name of a section given a section index. This is only
// used for error messages.
// Return the size of a section given a section index.
uint64_t
section_size(unsigned int shndx)
{ return this->do_section_size(shndx); }
// Return the name of a section given a section index.
std::string
section_name(unsigned int shndx)
{ return this->do_section_name(shndx); }
@ -232,6 +236,11 @@ class Object
section_info(unsigned int shndx)
{ return this->do_section_info(shndx); }
// Return the required section alignment given a section index.
uint64_t
section_addralign(unsigned int shndx)
{ return this->do_section_addralign(shndx); }
// Read the symbol information.
void
read_symbols(Read_symbols_data* sd)
@ -344,6 +353,10 @@ class Object
virtual Location
do_section_contents(unsigned int shndx) = 0;
// Get the size of a section--implemented by child class.
virtual uint64_t
do_section_size(unsigned int shndx) = 0;
// Get the name of a section--implemented by child class.
virtual std::string
do_section_name(unsigned int shndx) = 0;
@ -364,6 +377,10 @@ class Object
virtual unsigned int
do_section_info(unsigned int shndx) = 0;
// Get section alignment--implemented by child class.
virtual uint64_t
do_section_addralign(unsigned int shndx) = 0;
// Get the file. We pass on const-ness.
Input_file*
input_file()
@ -1136,6 +1153,11 @@ class Sized_relobj : public Relobj
do_relocate(const General_options& options, const Symbol_table* symtab,
const Layout*, Output_file* of);
// Get the size of a section.
uint64_t
do_section_size(unsigned int shndx)
{ return this->elf_file_.section_size(shndx); }
// Get the name of a section.
std::string
do_section_name(unsigned int shndx)
@ -1166,6 +1188,11 @@ class Sized_relobj : public Relobj
do_section_info(unsigned int shndx)
{ return this->elf_file_.section_info(shndx); }
// Return the section alignment.
uint64_t
do_section_addralign(unsigned int shndx)
{ return this->elf_file_.section_addralign(shndx); }
private:
// For convenience.
typedef Sized_relobj<size, big_endian> This;

View File

@ -275,6 +275,7 @@ Output_segment_headers::do_sized_write(Output_file* of)
{
const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size;
off_t all_phdrs_size = this->segment_list_.size() * phdr_size;
gold_assert(all_phdrs_size == this->data_size());
unsigned char* view = of->get_output_view(this->offset(),
all_phdrs_size);
unsigned char* v = view;
@ -287,6 +288,8 @@ Output_segment_headers::do_sized_write(Output_file* of)
v += phdr_size;
}
gold_assert(v - view == all_phdrs_size);
of->write_output_view(this->offset(), all_phdrs_size, view);
}
@ -1371,6 +1374,15 @@ Output_section::Input_section::set_address_and_file_offset(
this->u2_.posd->set_address_and_file_offset(address, file_offset);
}
// Reset the address and file offset.
void
Output_section::Input_section::reset_address_and_file_offset()
{
if (!this->is_input_section())
this->u2_.posd->reset_address_and_file_offset();
}
// Finalize the data size.
void
@ -1444,6 +1456,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
: name_(name),
addralign_(0),
entsize_(0),
load_address_(0),
link_section_(NULL),
link_(0),
info_section_(NULL),
@ -1463,6 +1476,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
should_link_to_dynsym_(false),
after_input_sections_(false),
requires_postprocessing_(false),
found_in_sections_clause_(false),
has_load_address_(false),
tls_offset_(0)
{
// An unallocated section has no address. Forcing this means that
@ -1495,7 +1510,9 @@ Output_section::set_entsize(uint64_t v)
// receive special handling. In the normal case we don't always keep
// track of input sections for an Output_section. Instead, each
// Object keeps track of the Output_section for each of its input
// sections.
// sections. However, if HAVE_SECTIONS_SCRIPT is true, we do keep
// track of input sections here; this is used when SECTIONS appears in
// a linker script.
template<int size, bool big_endian>
off_t
@ -1503,7 +1520,8 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx)
unsigned int reloc_shndx,
bool have_sections_script)
{
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
if ((addralign & (addralign - 1)) != 0)
@ -1517,6 +1535,11 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
this->addralign_ = addralign;
typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
this->flags_ |= (sh_flags
& (elfcpp::SHF_WRITE
| elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR));
uint64_t entsize = shdr.get_sh_entsize();
// .debug_str is a mergeable string section, but is not always so
@ -1547,6 +1570,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
addralign);
if (aligned_offset_in_section > offset_in_section
&& !have_sections_script
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
&& object->target()->has_code_fill())
{
@ -1572,7 +1596,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
// We need to keep track of this section if we are already keeping
// track of sections, or if we are relaxing. FIXME: Add test for
// relaxing.
if (!this->input_sections_.empty())
if (have_sections_script || !this->input_sections_.empty())
this->input_sections_.push_back(Input_section(object, shndx,
shdr.get_sh_size(),
addralign));
@ -1587,6 +1611,15 @@ Output_section::add_output_section_data(Output_section_data* posd)
{
Input_section inp(posd);
this->add_output_section_data(&inp);
if (posd->is_data_size_valid())
{
off_t offset_in_section = this->current_data_size_for_child();
off_t aligned_offset_in_section = align_address(offset_in_section,
posd->addralign());
this->set_current_data_size_for_child(aligned_offset_in_section
+ posd->data_size());
}
}
// Add arbitrary data to an output section by Input_section.
@ -1809,6 +1842,17 @@ Output_section::set_final_data_size()
this->set_data_size(off - startoff);
}
// Reset the address and file offset.
void
Output_section::do_reset_address_and_file_offset()
{
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
p->reset_address_and_file_offset();
}
// Set the TLS offset. Called only for SHT_TLS sections.
void
@ -1863,7 +1907,7 @@ Output_section::do_write(Output_file* of)
{
std::string fill_data(parameters->target()->code_fill(p->length()));
of->write(output_section_file_offset + p->section_offset(),
fill_data.data(), fill_data.size());
fill_data.data(), fill_data.size());
}
for (Input_section_list::iterator p = this->input_sections_.begin();
@ -1917,7 +1961,8 @@ Output_section::write_to_postprocessing_buffer()
++p)
{
std::string fill_data(target->code_fill(p->length()));
memcpy(buffer + p->section_offset(), fill_data.data(), fill_data.size());
memcpy(buffer + p->section_offset(), fill_data.data(),
fill_data.size());
}
off_t off = this->first_input_offset_;
@ -1931,6 +1976,89 @@ Output_section::write_to_postprocessing_buffer()
}
}
// Get the input sections for linker script processing. We leave
// behind the Output_section_data entries. Note that this may be
// slightly incorrect for merge sections. We will leave them behind,
// but it is possible that the script says that they should follow
// some other input sections, as in:
// .rodata { *(.rodata) *(.rodata.cst*) }
// For that matter, we don't handle this correctly:
// .rodata { foo.o(.rodata.cst*) *(.rodata.cst*) }
// With luck this will never matter.
uint64_t
Output_section::get_input_sections(
uint64_t address,
const std::string& fill,
std::list<std::pair<Relobj*, unsigned int> >* input_sections)
{
uint64_t orig_address = address;
address = align_address(address, this->addralign());
Input_section_list remaining;
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
{
if (p->is_input_section())
input_sections->push_back(std::make_pair(p->relobj(), p->shndx()));
else
{
uint64_t aligned_address = align_address(address, p->addralign());
if (aligned_address != address && !fill.empty())
{
section_size_type length =
convert_to_section_size_type(aligned_address - address);
std::string this_fill;
this_fill.reserve(length);
while (this_fill.length() + fill.length() <= length)
this_fill += fill;
if (this_fill.length() < length)
this_fill.append(fill, 0, length - this_fill.length());
Output_section_data* posd = new Output_data_const(this_fill, 0);
remaining.push_back(Input_section(posd));
}
address = aligned_address;
remaining.push_back(*p);
p->finalize_data_size();
address += p->data_size();
}
}
this->input_sections_.swap(remaining);
this->first_input_offset_ = 0;
uint64_t data_size = address - orig_address;
this->set_current_data_size_for_child(data_size);
return data_size;
}
// Add an input section from a script.
void
Output_section::add_input_section_for_script(Relobj* object,
unsigned int shndx,
off_t data_size,
uint64_t addralign)
{
if (addralign > this->addralign_)
this->addralign_ = addralign;
off_t offset_in_section = this->current_data_size_for_child();
off_t aligned_offset_in_section = align_address(offset_in_section,
addralign);
this->set_current_data_size_for_child(aligned_offset_in_section
+ data_size);
this->input_sections_.push_back(Input_section(object, shndx,
data_size, addralign));
}
// Print stats for merge sections to stderr.
void
@ -1951,12 +2079,14 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
vaddr_(0),
paddr_(0),
memsz_(0),
align_(0),
max_align_(0),
min_p_align_(0),
offset_(0),
filesz_(0),
type_(type),
flags_(flags),
is_align_known_(false)
is_max_align_known_(false),
are_addresses_set_(false)
{
}
@ -1968,7 +2098,7 @@ Output_segment::add_output_section(Output_section* os,
bool front)
{
gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
gold_assert(!this->is_align_known_);
gold_assert(!this->is_max_align_known_);
// Update the segment flags.
this->flags_ |= seg_flags;
@ -2069,38 +2199,37 @@ Output_segment::add_output_section(Output_section* os,
void
Output_segment::add_initial_output_data(Output_data* od)
{
gold_assert(!this->is_align_known_);
gold_assert(!this->is_max_align_known_);
this->output_data_.push_front(od);
}
// Return the maximum alignment of the Output_data in Output_segment.
// Once we compute this, we prohibit new sections from being added.
uint64_t
Output_segment::addralign()
Output_segment::maximum_alignment()
{
if (!this->is_align_known_)
if (!this->is_max_align_known_)
{
uint64_t addralign;
addralign = Output_segment::maximum_alignment(&this->output_data_);
if (addralign > this->align_)
this->align_ = addralign;
addralign = Output_segment::maximum_alignment_list(&this->output_data_);
if (addralign > this->max_align_)
this->max_align_ = addralign;
addralign = Output_segment::maximum_alignment(&this->output_bss_);
if (addralign > this->align_)
this->align_ = addralign;
addralign = Output_segment::maximum_alignment_list(&this->output_bss_);
if (addralign > this->max_align_)
this->max_align_ = addralign;
this->is_align_known_ = true;
this->is_max_align_known_ = true;
}
return this->align_;
return this->max_align_;
}
// Return the maximum alignment of a list of Output_data.
uint64_t
Output_segment::maximum_alignment(const Output_data_list* pdl)
Output_segment::maximum_alignment_list(const Output_data_list* pdl)
{
uint64_t ret = 0;
for (Output_data_list::const_iterator p = pdl->begin();
@ -2136,33 +2265,41 @@ Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const
return count;
}
// Set the section addresses for an Output_segment. ADDR is the
// address and *POFF is the file offset. Set the section indexes
// starting with *PSHNDX. Return the address of the immediately
// following segment. Update *POFF and *PSHNDX.
// Set the section addresses for an Output_segment. If RESET is true,
// reset the addresses first. ADDR is the address and *POFF is the
// file offset. Set the section indexes starting with *PSHNDX.
// Return the address of the immediately following segment. Update
// *POFF and *PSHNDX.
uint64_t
Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff,
unsigned int* pshndx)
{
gold_assert(this->type_ == elfcpp::PT_LOAD);
this->vaddr_ = addr;
this->paddr_ = addr;
if (!reset && this->are_addresses_set_)
{
gold_assert(this->paddr_ == addr);
addr = this->vaddr_;
}
else
{
this->vaddr_ = addr;
this->paddr_ = addr;
this->are_addresses_set_ = true;
}
off_t orig_off = *poff;
this->offset_ = orig_off;
*poff = align_address(*poff, this->addralign());
addr = this->set_section_list_addresses(&this->output_data_, addr, poff,
pshndx);
addr = this->set_section_list_addresses(reset, &this->output_data_,
addr, poff, pshndx);
this->filesz_ = *poff - orig_off;
off_t off = *poff;
uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
poff, pshndx);
uint64_t ret = this->set_section_list_addresses(reset, &this->output_bss_,
addr, poff, pshndx);
this->memsz_ = *poff - orig_off;
// Ignore the file offset adjustments made by the BSS Output_data
@ -2176,7 +2313,7 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
// structures.
uint64_t
Output_segment::set_section_list_addresses(Output_data_list* pdl,
Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
uint64_t addr, off_t* poff,
unsigned int* pshndx)
{
@ -2188,7 +2325,23 @@ Output_segment::set_section_list_addresses(Output_data_list* pdl,
++p)
{
off = align_address(off, (*p)->addralign());
(*p)->set_address_and_file_offset(addr + (off - startoff), off);
if (reset)
(*p)->reset_address_and_file_offset();
// When using a linker script the section will most likely
// already have an address.
if (!(*p)->is_address_valid())
(*p)->set_address_and_file_offset(addr + (off - startoff), off);
else
{
// The script may have inserted a skip forward, but it
// better not have moved backward.
gold_assert((*p)->address() >= addr);
off = startoff + ((*p)->address() - addr);
(*p)->set_file_offset(off);
(*p)->finalize_data_size();
}
// Unless this is a PT_TLS segment, we want to ignore the size
// of a SHF_TLS/SHT_NOBITS section. Such a section does not
@ -2217,12 +2370,15 @@ Output_segment::set_offset()
{
gold_assert(this->type_ != elfcpp::PT_LOAD);
gold_assert(!this->are_addresses_set_);
if (this->output_data_.empty() && this->output_bss_.empty())
{
this->vaddr_ = 0;
this->paddr_ = 0;
this->are_addresses_set_ = true;
this->memsz_ = 0;
this->align_ = 0;
this->min_p_align_ = 0;
this->offset_ = 0;
this->filesz_ = 0;
return;
@ -2234,7 +2390,10 @@ Output_segment::set_offset()
else
first = this->output_data_.front();
this->vaddr_ = first->address();
this->paddr_ = this->vaddr_;
this->paddr_ = (first->has_load_address()
? first->load_address()
: this->vaddr_);
this->are_addresses_set_ = true;
this->offset_ = first->offset();
if (this->output_data_.empty())
@ -2275,6 +2434,26 @@ Output_segment::set_tls_offsets()
(*p)->set_tls_offset(this->vaddr_);
}
// Return the address of the first section.
uint64_t
Output_segment::first_section_load_address() const
{
for (Output_data_list::const_iterator p = this->output_data_.begin();
p != this->output_data_.end();
++p)
if ((*p)->is_section())
return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address();
for (Output_data_list::const_iterator p = this->output_bss_.begin();
p != this->output_bss_.end();
++p)
if ((*p)->is_section())
return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address();
gold_unreachable();
}
// Return the number of Output_sections in an Output_segment.
unsigned int
@ -2313,7 +2492,7 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr)
ophdr->put_p_filesz(this->filesz_);
ophdr->put_p_memsz(this->memsz_);
ophdr->put_p_flags(this->flags_);
ophdr->put_p_align(this->addralign());
ophdr->put_p_align(std::max(this->min_p_align_, this->maximum_alignment()));
}
// Write the section headers into V.
@ -2534,7 +2713,8 @@ Output_section::add_input_section<32, false>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<32, false>& shdr,
unsigned int reloc_shndx);
unsigned int reloc_shndx,
bool have_sections_script);
#endif
#ifdef HAVE_TARGET_32_BIG
@ -2545,7 +2725,8 @@ Output_section::add_input_section<32, true>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<32, true>& shdr,
unsigned int reloc_shndx);
unsigned int reloc_shndx,
bool have_sections_script);
#endif
#ifdef HAVE_TARGET_64_LITTLE
@ -2556,7 +2737,8 @@ Output_section::add_input_section<64, false>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<64, false>& shdr,
unsigned int reloc_shndx);
unsigned int reloc_shndx,
bool have_sections_script);
#endif
#ifdef HAVE_TARGET_64_BIG
@ -2567,7 +2749,8 @@ Output_section::add_input_section<64, true>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<64, true>& shdr,
unsigned int reloc_shndx);
unsigned int reloc_shndx,
bool have_sections_script);
#endif
#ifdef HAVE_TARGET_32_LITTLE

View File

@ -88,11 +88,32 @@ class Output_data
return this->offset_;
}
// Reset the address and file offset. This essentially disables the
// sanity testing about duplicate and unknown settings.
void
reset_address_and_file_offset()
{
this->is_address_valid_ = false;
this->is_offset_valid_ = false;
this->is_data_size_valid_ = false;
this->do_reset_address_and_file_offset();
}
// Return the required alignment.
uint64_t
addralign() const
{ return this->do_addralign(); }
// Return whether this has a load address.
bool
has_load_address() const
{ return this->do_has_load_address(); }
// Return the load address.
uint64_t
load_address() const
{ return this->do_load_address(); }
// Return whether this is an Output_section.
bool
is_section() const
@ -224,6 +245,16 @@ class Output_data
virtual uint64_t
do_addralign() const = 0;
// Return whether this has a load address.
virtual bool
do_has_load_address() const
{ return false; }
// Return the load address.
virtual uint64_t
do_load_address() const
{ gold_unreachable(); }
// Return whether this is an Output_section.
virtual bool
do_is_section() const
@ -258,6 +289,11 @@ class Output_data
set_final_data_size()
{ gold_unreachable(); }
// A hook for resetting the address and file offset.
virtual void
do_reset_address_and_file_offset()
{ }
// Set the TLS offset. Called only for SHT_TLS sections.
virtual void
do_set_tls_offset(uint64_t)
@ -1491,13 +1527,16 @@ class Output_section : public Output_data
// Add a new input section SHNDX, named NAME, with header SHDR, from
// object OBJECT. RELOC_SHNDX is the index of a relocation section
// which applies to this section, or 0 if none, or -1U if more than
// one. Return the offset within the output section.
// one. HAVE_SECTIONS_SCRIPT is true if we have a SECTIONS clause
// in a linker script; in that case we need to keep track of input
// sections associated with an output section. Return the offset
// within the output section.
template<int size, bool big_endian>
off_t
add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx,
const char *name,
const elfcpp::Shdr<size, big_endian>& shdr,
unsigned int reloc_shndx);
unsigned int reloc_shndx, bool have_sections_script);
// Add generated data POSD to this output section.
void
@ -1527,6 +1566,14 @@ class Output_section : public Output_data
void
set_entsize(uint64_t v);
// Set the load address.
void
set_load_address(uint64_t load_address)
{
this->load_address_ = load_address;
this->has_load_address_ = true;
}
// Set the link field to the output section index of a section.
void
set_link_section(const Output_data* od)
@ -1709,12 +1756,53 @@ class Output_section : public Output_data
uint64_t
starting_output_address(const Relobj* object, unsigned int shndx) const;
// Record that this output section was found in the SECTIONS clause
// of a linker script.
void
set_found_in_sections_clause()
{ this->found_in_sections_clause_ = true; }
// Return whether this output section was found in the SECTIONS
// clause of a linker script.
bool
found_in_sections_clause() const
{ return this->found_in_sections_clause_; }
// Write the section header into *OPHDR.
template<int size, bool big_endian>
void
write_header(const Layout*, const Stringpool*,
elfcpp::Shdr_write<size, big_endian>*) const;
// The next few calls are for linker script support.
// Store the list of input sections for this Output_section into the
// list passed in. This removes the input sections, leaving only
// any Output_section_data elements. This returns the size of those
// Output_section_data elements. ADDRESS is the address of this
// output section. FILL is the fill value to use, in case there are
// any spaces between the remaining Output_section_data elements.
uint64_t
get_input_sections(uint64_t address, const std::string& fill,
std::list<std::pair<Relobj*, unsigned int > >*);
// Add an input section from a script.
void
add_input_section_for_script(Relobj* object, unsigned int shndx,
off_t data_size, uint64_t addralign);
// Set the current size of the output section.
void
set_current_data_size(off_t size)
{ this->set_current_data_size_for_child(size); }
// Get the current size of the output section.
off_t
current_data_size() const
{ return this->current_data_size_for_child(); }
// End of linker script support.
// Print merge statistics to stderr.
void
print_merge_stats();
@ -1732,7 +1820,7 @@ class Output_section : public Output_data
void
do_set_out_shndx(unsigned int shndx)
{
gold_assert(this->out_shndx_ == -1U);
gold_assert(this->out_shndx_ == -1U || this->out_shndx_ == shndx);
this->out_shndx_ = shndx;
}
@ -1743,6 +1831,10 @@ class Output_section : public Output_data
virtual void
set_final_data_size();
// Reset the address and file offset.
void
do_reset_address_and_file_offset();
// Write the data to the file. For a typical Output_section, this
// does nothing: the data is written out by calling Object::Relocate
// on each input object. But if there are any Output_section_data
@ -1755,6 +1847,19 @@ class Output_section : public Output_data
do_addralign() const
{ return this->addralign_; }
// Return whether there is a load address.
bool
do_has_load_address() const
{ return this->has_load_address_; }
// Return the load address.
uint64_t
do_load_address() const
{
gold_assert(this->has_load_address_);
return this->load_address_;
}
// Return whether this is an Output_section.
bool
do_is_section() const
@ -1877,6 +1982,15 @@ class Output_section : public Output_data
off_t
data_size() const;
// Whether this is an input section.
bool
is_input_section() const
{
return (this->shndx_ != OUTPUT_SECTION_CODE
&& this->shndx_ != MERGE_DATA_SECTION_CODE
&& this->shndx_ != MERGE_STRING_SECTION_CODE);
}
// Return whether this is a merge section which matches the
// parameters.
bool
@ -1890,6 +2004,22 @@ class Output_section : public Output_data
&& this->addralign() == addralign);
}
// Return the object for an input section.
Relobj*
relobj() const
{
gold_assert(this->is_input_section());
return this->u2_.object;
}
// Return the input section index for an input section.
unsigned int
shndx() const
{
gold_assert(this->is_input_section());
return this->shndx_;
}
// Set the output section.
void
set_output_section(Output_section* os)
@ -1905,6 +2035,10 @@ class Output_section : public Output_data
set_address_and_file_offset(uint64_t address, off_t file_offset,
off_t section_file_offset);
// Reset the address and file offset.
void
reset_address_and_file_offset();
// Finalize the data size.
void
finalize_data_size();
@ -1968,15 +2102,6 @@ class Output_section : public Output_data
MERGE_STRING_SECTION_CODE = -3U
};
// Whether this is an input section.
bool
is_input_section() const
{
return (this->shndx_ != OUTPUT_SECTION_CODE
&& this->shndx_ != MERGE_DATA_SECTION_CODE
&& this->shndx_ != MERGE_STRING_SECTION_CODE);
}
// For an ordinary input section, this is the section index in the
// input file. For an Output_section_data, this is
// OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
@ -2007,15 +2132,16 @@ class Output_section : public Output_data
typedef std::vector<Input_section> Input_section_list;
// Fill data. This is used to fill in data between input sections.
// When we have to keep track of the input sections, we can use an
// Output_data_const, but we don't want to have to keep track of
// input sections just to implement fills. For a fill we record the
// offset, and the actual data to be written out.
// It is also used for data statements (BYTE, WORD, etc.) in linker
// scripts. When we have to keep track of the input sections, we
// can use an Output_data_const, but we don't want to have to keep
// track of input sections just to implement fills.
class Fill
{
public:
Fill(off_t section_offset, off_t length)
: section_offset_(section_offset), length_(length)
: section_offset_(section_offset),
length_(convert_to_section_size_type(length))
{ }
// Return section offset.
@ -2024,7 +2150,7 @@ class Output_section : public Output_data
{ return this->section_offset_; }
// Return fill length.
off_t
section_size_type
length() const
{ return this->length_; }
@ -2032,7 +2158,7 @@ class Output_section : public Output_data
// The offset within the output section.
off_t section_offset_;
// The length of the space to fill.
off_t length_;
section_size_type length_;
};
typedef std::vector<Fill> Fill_list;
@ -2064,6 +2190,10 @@ class Output_section : public Output_data
uint64_t addralign_;
// The section entry size.
uint64_t entsize_;
// The load address. This is only used when using a linker script
// with a SECTIONS clause. The has_load_address_ field indicates
// whether this field is valid.
uint64_t load_address_;
// The file offset is in the parent class.
// Set the section link field to the index of this section.
const Output_data* link_section_;
@ -2076,7 +2206,7 @@ class Output_section : public Output_data
// The section type.
const elfcpp::Elf_Word type_;
// The section flags.
const elfcpp::Elf_Xword flags_;
elfcpp::Elf_Xword flags_;
// The section index.
unsigned int out_shndx_;
// If there is a STT_SECTION for this output section in the normal
@ -2121,6 +2251,11 @@ class Output_section : public Output_data
// Whether this section requires post processing after all
// relocations have been applied.
bool requires_postprocessing_ : 1;
// Whether an input section was mapped to this output section
// because of a SECTIONS clause in a linker script.
bool found_in_sections_clause_ : 1;
// Whether this section has an explicitly specified load address.
bool has_load_address_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
@ -2168,7 +2303,7 @@ class Output_segment
// Return the maximum alignment of the Output_data.
uint64_t
addralign();
maximum_alignment();
// Add an Output_section to this segment.
void
@ -2189,23 +2324,40 @@ class Output_segment
unsigned int
dynamic_reloc_count() const;
// Set the address of the segment to ADDR and the offset to *POFF
// (aligned if necessary), and set the addresses and offsets of all
// contained output sections accordingly. Set the section indexes
// of all contained output sections starting with *PSHNDX. Return
// the address of the immediately following segment. Update *POFF
// and *PSHNDX. This should only be called for a PT_LOAD segment.
// Return the address of the first section.
uint64_t
set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx);
first_section_load_address() const;
// Return whether the addresses have been set already.
bool
are_addresses_set() const
{ return this->are_addresses_set_; }
// Set the addresses.
void
set_addresses(uint64_t vaddr, uint64_t paddr)
{
this->vaddr_ = vaddr;
this->paddr_ = paddr;
this->are_addresses_set_ = true;
}
// 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
// output sections starting with *PSHNDX. If RESET is true, first
// reset the addresses of the contained sections. Return the
// address of the immediately following segment. Update *POFF and
// *PSHNDX. This should only be called for a PT_LOAD segment.
uint64_t
set_section_addresses(bool reset, uint64_t addr, off_t* poff,
unsigned int* pshndx);
// Set the minimum alignment of this segment. This may be adjusted
// upward based on the section alignments.
void
set_minimum_addralign(uint64_t align)
{
gold_assert(!this->is_align_known_);
this->align_ = align;
}
set_minimum_p_align(uint64_t align)
{ this->min_p_align_ = align; }
// Set the offset of this segment based on the section. This should
// only be called for a non-PT_LOAD segment.
@ -2244,12 +2396,12 @@ class Output_segment
// Find the maximum alignment in an Output_data_list.
static uint64_t
maximum_alignment(const Output_data_list*);
maximum_alignment_list(const Output_data_list*);
// Set the section addresses in an Output_data_list.
uint64_t
set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff,
unsigned int* pshndx);
set_section_list_addresses(bool reset, Output_data_list*, uint64_t addr,
off_t* poff, unsigned int* pshndx);
// Return the number of Output_sections in an Output_data_list.
unsigned int
@ -2276,10 +2428,17 @@ class Output_segment
uint64_t paddr_;
// The size of the segment in memory.
uint64_t memsz_;
// The segment alignment. The is_align_known_ field indicates
// whether this has been finalized. It can be set to a minimum
// value before it is finalized.
uint64_t align_;
// The maximum section alignment. The is_max_align_known_ field
// indicates whether this has been finalized.
uint64_t max_align_;
// The required minimum value for the p_align field. This is used
// for PT_LOAD segments. Note that this does not mean that
// addresses should be aligned to this value; it means the p_paddr
// and p_vaddr fields must be congruent modulo this value. For
// non-PT_LOAD segments, the dynamic linker works more efficiently
// if the p_align field has the more conventional value, although it
// can align as needed.
uint64_t min_p_align_;
// The offset of the segment data within the file.
off_t offset_;
// The size of the segment data in the file.
@ -2288,8 +2447,10 @@ class Output_segment
elfcpp::Elf_Word type_;
// The segment flags.
elfcpp::Elf_Word flags_;
// Whether we have finalized align_.
bool is_align_known_;
// Whether we have finalized max_align_.
bool is_max_align_known_ : 1;
// Whether vaddr and paddr were set by a linker script.
bool are_addresses_set_ : 1;
};
// This class represents the output file.

View File

@ -45,6 +45,8 @@ resolve.cc
script.cc
script-c.h
script.h
script-sections.cc
script-sections.h
stringpool.cc
stringpool.h
symtab.cc

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-01-09 11:37-0800\n"
"POT-Creation-Date: 2008-02-01 22:48-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -61,7 +61,7 @@ msgstr ""
msgid "%s: member at %zu is not an ELF object"
msgstr ""
#: compressed_output.cc:126
#: compressed_output.cc:127
msgid "not compressing section data: zlib error"
msgstr ""
@ -70,115 +70,115 @@ msgstr ""
msgid "%s: can not read directory: %s"
msgstr ""
#: dynobj.cc:145
#: dynobj.cc:147
#, c-format
msgid "unexpected duplicate type %u section: %u, %u"
msgstr ""
#: dynobj.cc:181
#: dynobj.cc:183
#, c-format
msgid "unexpected link in section %u header: %u != %u"
msgstr ""
#: dynobj.cc:217
#: dynobj.cc:219
#, c-format
msgid "DYNAMIC section %u link out of range: %u"
msgstr ""
#: dynobj.cc:225
#: dynobj.cc:227
#, c-format
msgid "DYNAMIC section %u link %u is not a strtab"
msgstr ""
#: dynobj.cc:253
#: dynobj.cc:255
#, c-format
msgid "DT_SONAME value out of range: %lld >= %lld"
msgstr ""
#: dynobj.cc:265
#: dynobj.cc:267
#, c-format
msgid "DT_NEEDED value out of range: %lld >= %lld"
msgstr ""
#: dynobj.cc:278
#: dynobj.cc:280
msgid "missing DT_NULL in dynamic segment"
msgstr ""
#: dynobj.cc:323
#: dynobj.cc:325
#, c-format
msgid "invalid dynamic symbol table name index: %u"
msgstr ""
#: dynobj.cc:330
#: dynobj.cc:332
#, c-format
msgid "dynamic symbol table name section has wrong type: %u"
msgstr ""
#: dynobj.cc:404 object.cc:251 object.cc:589
#: dynobj.cc:406 object.cc:251 object.cc:589
#, c-format
msgid "bad section name offset for section %u: %lu"
msgstr ""
#: dynobj.cc:433
#: dynobj.cc:435
#, c-format
msgid "duplicate definition for version %u"
msgstr ""
#: dynobj.cc:462
#: dynobj.cc:464
#, c-format
msgid "unexpected verdef version %u"
msgstr ""
#: dynobj.cc:478
#: dynobj.cc:480
#, c-format
msgid "verdef vd_cnt field too small: %u"
msgstr ""
#: dynobj.cc:486
#: dynobj.cc:488
#, c-format
msgid "verdef vd_aux field out of range: %u"
msgstr ""
#: dynobj.cc:497
#: dynobj.cc:499
#, c-format
msgid "verdaux vda_name field out of range: %u"
msgstr ""
#: dynobj.cc:507
#: dynobj.cc:509
#, c-format
msgid "verdef vd_next field out of range: %u"
msgstr ""
#: dynobj.cc:541
#: dynobj.cc:543
#, c-format
msgid "unexpected verneed version %u"
msgstr ""
#: dynobj.cc:550
#: dynobj.cc:552
#, c-format
msgid "verneed vn_aux field out of range: %u"
msgstr ""
#: dynobj.cc:564
#: dynobj.cc:566
#, c-format
msgid "vernaux vna_name field out of range: %u"
msgstr ""
#: dynobj.cc:575
#: dynobj.cc:577
#, c-format
msgid "verneed vna_next field out of range: %u"
msgstr ""
#: dynobj.cc:586
#: dynobj.cc:588
#, c-format
msgid "verneed vn_next field out of range: %u"
msgstr ""
#: dynobj.cc:634
#: dynobj.cc:636
msgid "size of dynamic symbols is not multiple of symbol size"
msgstr ""
#: dynobj.cc:1316
#: dynobj.cc:1355
#, c-format
msgid "symbol %s has undefined version %s"
msgstr ""
@ -203,64 +203,60 @@ msgstr ""
msgid "%s: "
msgstr ""
#: expression.cc:104
#: expression.cc:113
#, c-format
msgid "undefined symbol '%s' referenced in expression"
msgstr ""
#: expression.cc:427
#: expression.cc:566
msgid "DEFINED not implemented"
msgstr ""
#: expression.cc:433
#: expression.cc:572
msgid "SIZEOF_HEADERS not implemented"
msgstr ""
#: expression.cc:439
#: expression.cc:578
msgid "ALIGNOF not implemented"
msgstr ""
#: expression.cc:445
#: expression.cc:584
msgid "SIZEOF not implemented"
msgstr ""
#: expression.cc:451
msgid "ADDR not implemented"
msgstr ""
#: expression.cc:457
#: expression.cc:590
msgid "LOADADDR not implemented"
msgstr ""
#: expression.cc:463
#: expression.cc:596
msgid "ORIGIN not implemented"
msgstr ""
#: expression.cc:469
#: expression.cc:602
msgid "LENGTH not implemented"
msgstr ""
#: expression.cc:475
#: expression.cc:608
msgid "CONSTANT not implemented"
msgstr ""
#: expression.cc:481
#: expression.cc:614
msgid "ABSOLUTE not implemented"
msgstr ""
#: expression.cc:487
#: expression.cc:620
msgid "DATA_SEGMENT_ALIGN not implemented"
msgstr ""
#: expression.cc:493
#: expression.cc:626
msgid "DATA_SEGMENT_RELRO_END not implemented"
msgstr ""
#: expression.cc:499
#: expression.cc:632
msgid "DATA_SEGMENT_END not implemented"
msgstr ""
#: expression.cc:505
#: expression.cc:638
msgid "SEGMENT_START not implemented"
msgstr ""
@ -319,34 +315,34 @@ msgstr ""
msgid "%s: maximum bytes mapped for read at one time: %llu\n"
msgstr ""
#: fileread.cc:628
#: fileread.cc:642
#, c-format
msgid "cannot find -l%s"
msgstr ""
#: fileread.cc:655
#: fileread.cc:669
#, c-format
msgid "cannot find %s"
msgstr ""
#: fileread.cc:666
#: fileread.cc:680
#, c-format
msgid "cannot open %s: %s"
msgstr ""
#: gold.cc:72
#: gold.cc:73
#, c-format
msgid "%s: internal error in %s, at %s:%d\n"
msgstr ""
#. We had some input files, but we weren't able to open any of
#. them.
#: gold.cc:118 gold.cc:166
#: gold.cc:119 gold.cc:167
msgid "no input files"
msgstr ""
#. We print out just the first .so we see; there may be others.
#: gold.cc:181
#: gold.cc:182
#, c-format
msgid "cannot mix -static with dynamic object %s"
msgstr ""
@ -412,42 +408,42 @@ msgid "pthread_cond_broadcast failed: %s"
msgstr ""
#. FIXME: This needs to specify the location somehow.
#: i386.cc:160 i386.cc:1484 x86_64.cc:172 x86_64.cc:1373
#: i386.cc:160 i386.cc:1490 x86_64.cc:172 x86_64.cc:1375
msgid "missing expected TLS relocation"
msgstr ""
#: i386.cc:810 x86_64.cc:764 x86_64.cc:978
#: i386.cc:809 x86_64.cc:764 x86_64.cc:978
#, c-format
msgid "%s: unsupported reloc %u against local symbol"
msgstr ""
#: i386.cc:917 i386.cc:1213 x86_64.cc:889 x86_64.cc:1160
#: i386.cc:916 i386.cc:1214 x86_64.cc:889 x86_64.cc:1162
#, c-format
msgid "%s: unexpected reloc %u in object file"
msgstr ""
#: i386.cc:1056 x86_64.cc:992 x86_64.cc:1256
#: i386.cc:1055 x86_64.cc:992 x86_64.cc:1258
#, c-format
msgid "%s: unsupported reloc %u against global symbol %s"
msgstr ""
#: i386.cc:1367
#: i386.cc:1368
#, c-format
msgid "%s: unsupported RELA reloc section"
msgstr ""
#: i386.cc:1627 x86_64.cc:1575
#: i386.cc:1640 x86_64.cc:1577
#, c-format
msgid "unexpected reloc %u in object file"
msgstr ""
#: i386.cc:1659 i386.cc:1734 i386.cc:1741 i386.cc:1772 i386.cc:1825
#: x86_64.cc:1596 x86_64.cc:1676 x86_64.cc:1700
#: i386.cc:1672 i386.cc:1747 i386.cc:1754 i386.cc:1785 i386.cc:1838
#: x86_64.cc:1598 x86_64.cc:1678 x86_64.cc:1702
#, c-format
msgid "unsupported reloc %u"
msgstr ""
#: i386.cc:1749
#: i386.cc:1762
msgid "both SUN and GNU model TLS relocations"
msgstr ""
@ -604,365 +600,378 @@ msgstr ""
msgid "unable to parse script file %s"
msgstr ""
#: options.cc:185
#: options.cc:174
#, c-format
msgid "unable to parse version script file %s"
msgstr ""
#: options.cc:201
#, c-format
msgid ""
"Usage: %s [options] file...\n"
"Options:\n"
msgstr ""
#: options.cc:356
#: options.cc:372
msgid "Allow unresolved references in shared libraries"
msgstr ""
#: options.cc:360
#: options.cc:376
msgid "Do not allow unresolved references in shared libraries"
msgstr ""
#: options.cc:364
#: options.cc:380
msgid "Only set DT_NEEDED for dynamic libs if used"
msgstr ""
#: options.cc:367
#: options.cc:383
msgid "Always DT_NEEDED for dynamic libs (default)"
msgstr ""
#: options.cc:370
#: options.cc:386
msgid "-l searches for shared libraries"
msgstr ""
#: options.cc:374
#: options.cc:390
msgid "-l does not search for shared libraries"
msgstr ""
#: options.cc:377
#: options.cc:393
msgid "Bind defined symbols locally"
msgstr ""
#: options.cc:385
#: options.cc:401
msgid "Compress .debug_* sections in the output file (default is none)"
msgstr ""
#: options.cc:387
#: options.cc:403
msgid "--compress-debug-sections=[none"
msgstr ""
#: options.cc:387
#: options.cc:403
msgid "]"
msgstr ""
#: options.cc:390
#: options.cc:406
msgid "Define a symbol"
msgstr ""
#: options.cc:391
#: options.cc:407
msgid "--defsym SYMBOL=EXPRESSION"
msgstr ""
#: options.cc:393
#: options.cc:409
msgid "Demangle C++ symbols in log messages"
msgstr ""
#: options.cc:396
#: options.cc:412
msgid "Do not demangle C++ symbols in log messages"
msgstr ""
#: options.cc:399
#: options.cc:415
msgid "Try to detect violations of the One Definition Rule"
msgstr ""
#: options.cc:401
#: options.cc:417
msgid "Set program start address"
msgstr ""
#: options.cc:402
#: options.cc:418
msgid "-e ADDRESS, --entry ADDRESS"
msgstr ""
#: options.cc:404
#: options.cc:420
msgid "Export all dynamic symbols"
msgstr ""
#: options.cc:406
#: options.cc:422
msgid "Create exception frame header"
msgstr ""
#: options.cc:408
#: options.cc:424
msgid "Set shared library name"
msgstr ""
#: options.cc:409
#: options.cc:425
msgid "-h FILENAME, -soname FILENAME"
msgstr ""
#: options.cc:411
#: options.cc:427
msgid "Set dynamic linker path"
msgstr ""
#: options.cc:412
#: options.cc:428
msgid "-I PROGRAM, --dynamic-linker PROGRAM"
msgstr ""
#: options.cc:414
#: options.cc:430
msgid "Search for library LIBNAME"
msgstr ""
#: options.cc:415
#: options.cc:431
msgid "-lLIBNAME, --library LIBNAME"
msgstr ""
#: options.cc:417
#: options.cc:433
msgid "Add directory to search path"
msgstr ""
#: options.cc:418
#: options.cc:434
msgid "-L DIR, --library-path DIR"
msgstr ""
#: options.cc:420
#: options.cc:436
msgid "Ignored for compatibility"
msgstr ""
#: options.cc:422
#: options.cc:438
msgid "Set output file name"
msgstr ""
#: options.cc:423
#: options.cc:439
msgid "-o FILE, --output FILE"
msgstr ""
#: options.cc:425
#: options.cc:441
msgid "Optimize output file size"
msgstr ""
#: options.cc:426
#: options.cc:442
msgid "-O level"
msgstr ""
#: options.cc:428
#: options.cc:444
msgid "Generate relocatable output"
msgstr ""
#: options.cc:430
#: options.cc:446
msgid "Add DIR to runtime search path"
msgstr ""
#: options.cc:431
#: options.cc:447
msgid "-R DIR, -rpath DIR"
msgstr ""
#: options.cc:434
#: options.cc:450
msgid "Add DIR to link time shared library search path"
msgstr ""
#: options.cc:435
#: options.cc:451
msgid "--rpath-link DIR"
msgstr ""
#: options.cc:437
#: options.cc:453
msgid "Strip all symbols"
msgstr ""
#: options.cc:440
#: options.cc:456
msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
msgstr ""
#. This must come after -Sdebug since it's a prefix of it.
#: options.cc:444
#: options.cc:460
msgid "Strip debugging information"
msgstr ""
#: options.cc:446
#: options.cc:462
msgid "Generate shared library"
msgstr ""
#: options.cc:448
#: options.cc:464
msgid "Do not link against shared libraries"
msgstr ""
#: options.cc:450
#: options.cc:466
msgid "Print resource usage statistics"
msgstr ""
#: options.cc:452
#: options.cc:468
msgid "Set target system root directory"
msgstr ""
#: options.cc:453
#: options.cc:469
msgid "--sysroot DIR"
msgstr ""
#: options.cc:454
#: options.cc:470
msgid "Set the address of the .text section"
msgstr ""
#: options.cc:455
#: options.cc:471
msgid "-Ttext ADDRESS"
msgstr ""
#. This must come after -Ttext since it's a prefix of it.
#: options.cc:458
#: options.cc:474
msgid "Read linker script"
msgstr ""
#: options.cc:459
#: options.cc:475
msgid "-T FILE, --script FILE"
msgstr ""
#: options.cc:461
msgid "Run the linker multi-threaded"
msgstr ""
#: options.cc:463
msgid "Do not run the linker multi-threaded"
msgstr ""
#: options.cc:465
msgid "Number of threads to use"
msgstr ""
#: options.cc:466
msgid "--thread-count COUNT"
msgstr ""
#: options.cc:469
msgid "Number of threads to use in initial pass"
msgstr ""
#: options.cc:470
msgid "--thread-count-initial COUNT"
msgstr ""
#: options.cc:473
msgid "Number of threads to use in middle pass"
msgstr ""
#: options.cc:474
msgid "--thread-count-middle COUNT"
msgstr ""
#: options.cc:477
msgid "Number of threads to use in final pass"
msgid "Read version script"
msgstr ""
#: options.cc:478
msgid "--thread-count-final COUNT"
msgid "--version-script FILE"
msgstr ""
#: options.cc:481
msgid "Include all archive contents"
#: options.cc:480
msgid "Run the linker multi-threaded"
msgstr ""
#: options.cc:482
msgid "Do not run the linker multi-threaded"
msgstr ""
#: options.cc:484
msgid "Number of threads to use"
msgstr ""
#: options.cc:485
msgid "--thread-count COUNT"
msgstr ""
#: options.cc:488
msgid "Number of threads to use in initial pass"
msgstr ""
#: options.cc:489
msgid "--thread-count-initial COUNT"
msgstr ""
#: options.cc:492
msgid "Number of threads to use in middle pass"
msgstr ""
#: options.cc:493
msgid "--thread-count-middle COUNT"
msgstr ""
#: options.cc:496
msgid "Number of threads to use in final pass"
msgstr ""
#: options.cc:497
msgid "--thread-count-final COUNT"
msgstr ""
#: options.cc:500
msgid "Include all archive contents"
msgstr ""
#: options.cc:504
msgid "Include only needed archive contents"
msgstr ""
#: options.cc:490
#: options.cc:509
msgid ""
"Subcommands as follows:\n"
" -z execstack Mark output as requiring executable stack\n"
" -z noexecstack Mark output as not requiring executable stack"
msgstr ""
#: options.cc:493
#: options.cc:512
msgid "-z SUBCOMMAND"
msgstr ""
#: options.cc:496
#: options.cc:515
msgid "Start a library search group"
msgstr ""
#: options.cc:498
#: options.cc:517
msgid "End a library search group"
msgstr ""
#: options.cc:500
#: options.cc:519
msgid "Report usage information"
msgstr ""
#: options.cc:502
#: options.cc:521
msgid "Report version information"
msgstr ""
#: options.cc:504
msgid "Turn on debugging (all,task)"
#: options.cc:523
msgid "Turn on debugging (all,task,script)"
msgstr ""
#: options.cc:505
#: options.cc:524
msgid "--debug=TYPE"
msgstr ""
#: options.cc:600
#: options.cc:620
#, c-format
msgid "%s: unrecognized -z subcommand: %s\n"
msgstr ""
#: options.cc:623
#: options.cc:643
#, c-format
msgid "%s: unrecognized --debug subcommand: %s\n"
msgstr ""
#: options.cc:812
#: options.cc:832
msgid "unexpected argument"
msgstr ""
#: options.cc:819 options.cc:871 options.cc:952
#: options.cc:839 options.cc:891 options.cc:972
msgid "missing argument"
msgstr ""
#: options.cc:832 options.cc:880
#: options.cc:852 options.cc:900
msgid "unknown option"
msgstr ""
#: options.cc:898
#: options.cc:918
#, c-format
msgid "%s: missing group end\n"
msgstr ""
#: options.cc:1026
#: options.cc:1046
msgid "may not nest groups"
msgstr ""
#: options.cc:1036
#: options.cc:1056
msgid "group end without group start"
msgstr ""
#: options.cc:1046
#: options.cc:1066
#, c-format
msgid "%s: use the --help option for usage information\n"
msgstr ""
#: options.cc:1055
#: options.cc:1075
#, c-format
msgid "%s: %s: %s\n"
msgstr ""
#: options.cc:1064
#: options.cc:1084
#, c-format
msgid "%s: -%c: %s\n"
msgstr ""
#: options.h:358
#: options.h:363
#, c-format
msgid "invalid optimization level: %s"
msgstr ""
#: options.h:404
#: options.h:409
#, c-format
msgid "unsupported argument to --compress-debug-sections: %s"
msgstr ""
#: options.h:458
#: options.h:463
#, c-format
msgid "invalid argument to -Ttext: %s"
msgstr ""
#: options.h:467
#: options.h:472
#, c-format
msgid "invalid thread count: %s"
msgstr ""
#: options.h:475
#: options.h:480
msgid "--threads not supported"
msgstr ""
@ -971,42 +980,42 @@ msgstr ""
msgid "invalid alignment %lu for section \"%s\""
msgstr ""
#: output.cc:2418
#: output.cc:2416
#, c-format
msgid "%s: open: %s"
msgstr ""
#: output.cc:2438
#: output.cc:2436
#, c-format
msgid "%s: mremap: %s"
msgstr ""
#: output.cc:2474
#: output.cc:2472
#, c-format
msgid "%s: lseek: %s"
msgstr ""
#: output.cc:2477 output.cc:2514
#: output.cc:2475 output.cc:2512
#, c-format
msgid "%s: write: %s"
msgstr ""
#: output.cc:2485
#: output.cc:2483
#, c-format
msgid "%s: mmap: %s"
msgstr ""
#: output.cc:2495
#: output.cc:2493
#, c-format
msgid "%s: munmap: %s"
msgstr ""
#: output.cc:2512
#: output.cc:2510
#, c-format
msgid "%s: write: unexpected 0 return-value"
msgstr ""
#: output.cc:2524
#: output.cc:2522
#, c-format
msgid "%s: close: %s"
msgstr ""
@ -1016,13 +1025,8 @@ msgstr ""
msgid "%s: file is empty"
msgstr ""
#: readsyms.cc:185
#, c-format
msgid "%s: ordinary object found in input group"
msgstr ""
#. Here we have to handle any other input file types we need.
#: readsyms.cc:242
#: readsyms.cc:231
#, c-format
msgid "%s: not an object or archive"
msgstr ""
@ -1075,14 +1079,14 @@ msgstr ""
msgid "%s: previous definition here"
msgstr ""
#: script.cc:1413
#: script.cc:1890
#, c-format
msgid "%s:%d:%d: %s"
msgstr ""
#. There are some options that we could handle here--e.g.,
#. -lLIBRARY. Should we bother?
#: script.cc:1539
#: script.cc:2026
#, c-format
msgid ""
"%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts "
@ -1104,51 +1108,51 @@ msgstr ""
msgid "%s: %s Stringdata structures: %zu\n"
msgstr ""
#: symtab.cc:603
#: symtab.cc:627
#, c-format
msgid "bad global symbol name offset %u at %zu"
msgstr ""
#: symtab.cc:682
#: symtab.cc:730
msgid "too few symbol versions"
msgstr ""
#: symtab.cc:711
#: symtab.cc:762
#, c-format
msgid "bad symbol name offset %u at %zu"
msgstr ""
#: symtab.cc:765
#: symtab.cc:816
#, c-format
msgid "versym for symbol %zu out of range: %u"
msgstr ""
#: symtab.cc:773
#: symtab.cc:824
#, c-format
msgid "versym for symbol %zu has no name: %u"
msgstr ""
#: symtab.cc:1499 symtab.cc:1715
#: symtab.cc:1625 symtab.cc:1824
#, c-format
msgid "%s: unsupported symbol section 0x%x"
msgstr ""
#: symtab.cc:1839
#: symtab.cc:1952
#, c-format
msgid "%s: undefined reference to '%s'"
msgstr ""
#: symtab.cc:1924
#: symtab.cc:2037
#, c-format
msgid "%s: symbol table entries: %zu; buckets: %zu\n"
msgstr ""
#: symtab.cc:1927
#: symtab.cc:2040
#, c-format
msgid "%s: symbol table entries: %zu\n"
msgstr ""
#: symtab.cc:1996
#: symtab.cc:2109
#, c-format
msgid ""
"while linking %s: symbol '%s' defined in multiple places (possible ODR "
@ -1188,12 +1192,12 @@ msgstr ""
msgid "%s failed: %s"
msgstr ""
#: x86_64.cc:1281
#: x86_64.cc:1283
#, c-format
msgid "%s: unsupported REL reloc section"
msgstr ""
#: x86_64.cc:1748
#: x86_64.cc:1750
#, c-format
msgid "unsupported reloc type %u"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,8 @@ struct Input_section_spec;
class Expression;
class Sections_element;
class Output_section_definition;
class Output_section;
class Output_segment;
class Script_sections
{
@ -79,6 +81,11 @@ class Script_sections
void
add_symbol_assignment(const char* name, size_t length, Expression* value,
bool provide, bool hidden);
// Add an assignment to the special dot symbol.
void
add_dot_assignment(Expression* value);
// Add an assertion.
void
add_assertion(Expression* check, const char* message, size_t messagelen);
@ -91,6 +98,42 @@ class Script_sections
void
add_input_section(const Input_section_spec* spec, bool keep);
// Add any symbols we are defining to the symbol table.
void
add_symbols_to_table(Symbol_table*);
// Finalize symbol values and check assertions.
void
finalize_symbols(Symbol_table* symtab, const Layout* layout);
// Find the name of the output section to use for an input file name
// and section name. This returns a name, and sets
// *OUTPUT_SECTION_SLOT to point to the address where the actual
// output section may be stored.
// 1) If the input section should be discarded, this returns NULL
// and sets *OUTPUT_SECTION_SLOT to NULL.
// 2) If the input section is mapped by the SECTIONS clause, this
// returns the name to use for the output section (in permanent
// storage), and sets *OUTPUT_SECTION_SLOT to point to where the
// output section should be stored. **OUTPUT_SECTION_SLOT will be
// non-NULL if we have seen this output section already.
// 3) If the input section is not mapped by the SECTIONS clause,
// this returns SECTION_NAME, and sets *OUTPUT_SECTION_SLOT to
// NULL.
const char*
output_section_name(const char* file_name, const char* section_name,
Output_section*** output_section_slot);
// Place a marker for an orphan output section into the SECTIONS
// clause.
void
place_orphan(Output_section* os);
// Set the addresses of all the output sections. Return the segment
// which holds the file header and segment headers, if any.
Output_segment*
set_section_addresses(Symbol_table*, Layout*);
// Print the contents to the FILE. This is for debugging.
void
print(FILE*) const;
@ -98,6 +141,18 @@ class Script_sections
private:
typedef std::vector<Sections_element*> Sections_elements;
// Create segments.
Output_segment*
create_segments(Layout*);
// Create PT_NOTE and PT_TLS segments.
void
create_note_and_tls_segments(Layout*, const std::vector<Output_section*>*);
// Return whether the section is a BSS section.
static bool
is_bss_section(const Output_section*);
// True if we ever saw a SECTIONS clause.
bool saw_sections_clause_;
// True if we are currently processing a SECTIONS clause.

View File

@ -912,6 +912,29 @@ Symbol_assignment::add_to_table(Symbol_table* symtab)
void
Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
{
this->finalize_maybe_dot(symtab, layout, false, false, 0);
}
// Finalize a symbol value which can refer to the dot symbol.
void
Symbol_assignment::finalize_with_dot(Symbol_table* symtab,
const Layout* layout,
bool dot_has_value,
uint64_t dot_value)
{
this->finalize_maybe_dot(symtab, layout, true, dot_has_value, dot_value);
}
// Finalize a symbol value, internal version.
void
Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab,
const Layout* layout,
bool is_dot_available,
bool dot_has_value,
uint64_t dot_value)
{
// If we were only supposed to provide this symbol, the sym_ field
// will be NULL if the symbol was not referenced.
@ -924,7 +947,8 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
this->sized_finalize<32>(symtab, layout);
this->sized_finalize<32>(symtab, layout, is_dot_available, dot_has_value,
dot_value);
#else
gold_unreachable();
#endif
@ -932,7 +956,8 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
this->sized_finalize<64>(symtab, layout);
this->sized_finalize<64>(symtab, layout, is_dot_available, dot_has_value,
dot_value);
#else
gold_unreachable();
#endif
@ -943,10 +968,56 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
template<int size>
void
Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout)
Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
bool is_dot_available, bool dot_has_value,
uint64_t dot_value)
{
bool dummy;
uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout,
is_dot_available,
dot_has_value, dot_value,
&dummy);
Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
ssym->set_value(this->val_->eval(symtab, layout));
ssym->set_value(final_val);
}
// Set the symbol value if the expression yields an absolute value.
void
Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
bool is_dot_available, bool dot_has_value,
uint64_t dot_value)
{
if (this->sym_ == NULL)
return;
bool is_absolute;
uint64_t val = this->val_->eval_maybe_dot(symtab, layout, is_dot_available,
dot_has_value, dot_value,
&is_absolute);
if (!is_absolute)
return;
if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(this->sym_);
ssym->set_value(val);
#else
gold_unreachable();
#endif
}
else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
Sized_symbol<64>* ssym = symtab->get_sized_symbol<64>(this->sym_);
ssym->set_value(val);
#else
gold_unreachable();
#endif
}
else
gold_unreachable();
}
// Print for debugging.
@ -1006,14 +1077,26 @@ Script_options::add_symbol_assignment(const char* name, size_t length,
Expression* value, bool provide,
bool hidden)
{
if (this->script_sections_.in_sections_clause())
this->script_sections_.add_symbol_assignment(name, length, value,
provide, hidden);
if (length != 1 || name[0] != '.')
{
if (this->script_sections_.in_sections_clause())
this->script_sections_.add_symbol_assignment(name, length, value,
provide, hidden);
else
{
Symbol_assignment* p = new Symbol_assignment(name, length, value,
provide, hidden);
this->symbol_assignments_.push_back(p);
}
}
else
{
Symbol_assignment* p = new Symbol_assignment(name, length, value,
provide, hidden);
this->symbol_assignments_.push_back(p);
if (provide || hidden)
gold_error(_("invalid use of PROVIDE for dot symbol"));
if (!this->script_sections_.in_sections_clause())
gold_error(_("invalid assignment to dot outside of SECTIONS"));
else
this->script_sections_.add_dot_assignment(value);
}
}
@ -1041,9 +1124,10 @@ Script_options::add_symbols_to_table(Symbol_table* symtab)
p != this->symbol_assignments_.end();
++p)
(*p)->add_to_table(symtab);
this->script_sections_.add_symbols_to_table(symtab);
}
// Finalize symbol values.
// Finalize symbol values. Also check assertions.
void
Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
@ -1052,6 +1136,29 @@ Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
p != this->symbol_assignments_.end();
++p)
(*p)->finalize(symtab, layout);
for (Assertions::iterator p = this->assertions_.begin();
p != this->assertions_.end();
++p)
(*p)->check(symtab, layout);
this->script_sections_.finalize_symbols(symtab, layout);
}
// Set section addresses. We set all the symbols which have absolute
// values. Then we let the SECTIONS clause do its thing. This
// returns the segment which holds the file header and segment
// headers, if any.
Output_segment*
Script_options::set_section_addresses(Symbol_table* symtab, Layout* layout)
{
for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
p != this->symbol_assignments_.end();
++p)
(*p)->set_if_absolute(symtab, layout, false, false, 0);
return this->script_sections_.set_section_addresses(symtab, layout);
}
// This class holds data passed through the parser to the lexer and to
@ -2279,8 +2386,13 @@ extern "C" String_sort_list_ptr
script_string_sort_list_add(String_sort_list_ptr pv,
const struct Wildcard_section* string_sort)
{
pv->push_back(*string_sort);
return pv;
if (pv == NULL)
return script_new_string_sort_list(string_sort);
else
{
pv->push_back(*string_sort);
return pv;
}
}
// Create a new list of strings.

View File

@ -46,6 +46,7 @@ class Input_argument;
class Input_objects;
class Input_group;
class Input_file;
class Output_segment;
class Task_token;
class Workqueue;
struct Version_dependency_list;
@ -65,10 +66,27 @@ class Expression
virtual ~Expression()
{ }
// Return the value of the expression.
// Return the value of the expression which is not permitted to
// refer to the dot symbol.
uint64_t
eval(const Symbol_table*, const Layout*);
// Return the value of an expression which is permitted to refer to
// the dot symbol. This sets *IS_ABSOLUTE to indicate whether this
// is an absolute value; it will be false if a non-absolute symbol
// was referenced in the expression; this is used to detect invalid
// uses when setting a section address.
uint64_t
eval_with_dot(const Symbol_table*, const Layout*, bool dot_has_value,
uint64_t dot_value, bool* is_absolute);
// Return the value of an expression which may or may not be
// permitted to refer to the dot symbol, depending on
// is_dot_available.
uint64_t
eval_maybe_dot(const Symbol_table*, const Layout*, bool is_dot_available,
bool dot_has_value, uint64_t dot_value, bool* is_absolute);
// Print the expression to the FILE. This is for debugging.
virtual void
print(FILE*) const = 0;
@ -181,17 +199,35 @@ class Symbol_assignment
add_to_table(Symbol_table*);
// Finalize the symbol value.
void finalize(Symbol_table*, const Layout*);
void
finalize(Symbol_table*, const Layout*);
// Finalize the symbol value when it can refer to the dot symbol.
void
finalize_with_dot(Symbol_table*, const Layout*, bool dot_has_value,
uint64_t dot_value);
// Set the symbol value, but only if the value is absolute. This is
// used while processing a SECTIONS clause.
void
set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available,
bool dot_has_value, uint64_t dot_value);
// Print the assignment to the FILE. This is for debugging.
void
print(FILE*) const;
private:
// Shared by finalize and finalize_with_dot.
void
finalize_maybe_dot(Symbol_table*, const Layout*, bool is_dot_available,
bool dot_has_value, uint64_t dot_value);
// Sized version of finalize.
template<int size>
void
sized_finalize(Symbol_table*, const Layout*);
sized_finalize(Symbol_table*, const Layout*, bool is_dot_available,
bool dot_has_value, uint64_t dot_value);
// Symbol name.
std::string name_;
@ -274,7 +310,7 @@ class Script_options
void
add_symbols_to_table(Symbol_table*);
// Finalize the symbol values.
// Finalize the symbol values. Also check assertions.
void
finalize_symbols(Symbol_table*, const Layout*);
@ -290,6 +326,18 @@ class Script_options
script_sections()
{ return &this->script_sections_; }
// Whether we saw a SECTIONS clause.
bool
saw_sections_clause() const
{ return this->script_sections_.saw_sections_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
// loadable segment.
Output_segment*
set_section_addresses(Symbol_table*, Layout*);
// Print the script to the FILE. This is for debugging.
void
print(FILE*) const;

View File

@ -298,6 +298,25 @@ Symbol::final_value_is_known() const
return parameters->doing_static_link();
}
// Return whether the symbol has an absolute value.
bool
Symbol::value_is_absolute() const
{
switch (this->source_)
{
case FROM_OBJECT:
return this->u_.from_object.shndx == elfcpp::SHN_ABS;
case IN_OUTPUT_DATA:
case IN_OUTPUT_SEGMENT:
return false;
case CONSTANT:
return true;
default:
gold_unreachable();
}
}
// Class Symbol_table.
Symbol_table::Symbol_table(unsigned int count,
@ -1336,7 +1355,8 @@ Symbol_table::do_define_as_constant(
void
Symbol_table::define_symbols(const Layout* layout, int count,
const Define_symbol_in_section* p)
const Define_symbol_in_section* p,
bool only_if_ref)
{
for (int i = 0; i < count; ++i, ++p)
{
@ -1345,11 +1365,12 @@ Symbol_table::define_symbols(const Layout* layout, int count,
this->define_in_output_data(p->name, NULL, os, p->value,
p->size, p->type, p->binding,
p->visibility, p->nonvis,
p->offset_is_from_end, p->only_if_ref);
p->offset_is_from_end,
only_if_ref || p->only_if_ref);
else
this->define_as_constant(p->name, NULL, 0, p->size, p->type,
p->binding, p->visibility, p->nonvis,
p->only_if_ref);
only_if_ref || p->only_if_ref);
}
}
@ -1357,7 +1378,8 @@ Symbol_table::define_symbols(const Layout* layout, int count,
void
Symbol_table::define_symbols(const Layout* layout, int count,
const Define_symbol_in_segment* p)
const Define_symbol_in_segment* p,
bool only_if_ref)
{
for (int i = 0; i < count; ++i, ++p)
{
@ -1368,11 +1390,12 @@ Symbol_table::define_symbols(const Layout* layout, int count,
this->define_in_output_segment(p->name, NULL, os, p->value,
p->size, p->type, p->binding,
p->visibility, p->nonvis,
p->offset_base, p->only_if_ref);
p->offset_base,
only_if_ref || p->only_if_ref);
else
this->define_as_constant(p->name, NULL, 0, p->size, p->type,
p->binding, p->visibility, p->nonvis,
p->only_if_ref);
only_if_ref || p->only_if_ref);
}
}

View File

@ -552,6 +552,10 @@ class Symbol
return true;
}
// Return whether this symbol currently has an absolute value.
bool
value_is_absolute() const;
// Return whether there should be a warning for references to this
// symbol.
bool
@ -1053,13 +1057,17 @@ class Symbol_table
elfcpp::STB binding, elfcpp::STV visibility,
unsigned char nonvis, bool only_if_ref);
// Define a set of symbols in output sections.
// Define a set of symbols in output sections. If ONLY_IF_REF is
// true, only define them if they are referenced.
void
define_symbols(const Layout*, int count, const Define_symbol_in_section*);
define_symbols(const Layout*, int count, const Define_symbol_in_section*,
bool only_if_ref);
// Define a set of symbols in output segments.
// Define a set of symbols in output segments. If ONLY_IF_REF is
// true, only defined them if they are referenced.
void
define_symbols(const Layout*, int count, const Define_symbol_in_segment*);
define_symbols(const Layout*, int count, const Define_symbol_in_segment*,
bool only_if_ref);
// Define SYM using a COPY reloc. POSD is the Output_data where the
// symbol should be defined--typically a .dyn.bss section. VALUE is

View File

@ -527,6 +527,11 @@ script_test_1_SOURCES = script_test_1.cc
script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
check_PROGRAMS += script_test_2
script_test_2_SOURCES = script_test_2.cc script_test_2a.cc script_test_2b.cc
script_test_2_DEPENDENCIES = gcctestdir/ld script_test_2.t
script_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_2.t
if OBJDUMP_AND_CPPFILT
check_SCRIPTS += ver_matching_test.sh
check_DATA += ver_matching_test.stdout

View File

@ -0,0 +1,69 @@
// script_test_2.cc -- linker script test 2 for gold -*- C++ -*-
// 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.
// A test of some uses of the SECTIONS clause. Look at
// script_test_2.t to make sense of this test.
#include <cassert>
#include <cstddef>
#include <cstring>
#include <stdint.h>
extern char start_test_area[];
extern char start_test_area_1[];
extern char start_data[];
extern char end_data[];
extern char start_fill[];
extern char end_fill[];
extern char end_test_area[];
int
main(int, char**)
{
assert(reinterpret_cast<uintptr_t>(start_test_area) == 0x20000001);
assert(reinterpret_cast<uintptr_t>(start_test_area_1) == 0x20000010);
// We should see the string from script_test_2b.o next. The
// subalign should move it up to 0x20000020.
for (int i = 0; i < 16; ++i)
assert(start_test_area_1[i] == 0);
assert(strcmp(start_test_area_1 + 16, "test b") == 0);
// Next the string from script_test_2a.o, after the subalign.
for (int i = 16 + 7; i < 48; ++i)
assert(start_test_area_1[i] == 0);
assert(strcmp(start_test_area_1 + 48, "test a") == 0);
// Move four bytes forward to start_data.
assert(reinterpret_cast<uintptr_t>(start_test_area_1 + 48 + 7 + 4)
== reinterpret_cast<uintptr_t>(start_data));
assert(memcmp(start_data, "\1\2\0\4\0\0\0\010\0\0\0\0\0\0\0", 15) == 0
|| memcmp(start_data, "\1\0\2\0\0\0\4\0\0\0\0\0\0\0\010", 15) == 0);
assert(end_data == start_data + 15);
// Check that FILL works as expected.
assert(start_fill == end_data);
assert(memcmp(start_fill, "\x12\x34\x56\x78\x12\x34\x56\0", 8) == 0);
assert(end_fill == start_fill + 8);
assert(end_test_area == end_fill);
}

View File

@ -0,0 +1,63 @@
/* script_test_2.t -- linker script test 2 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. */
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
/* Now the real test. */
. = 0x20000001;
start_test_area = .;
.gold_test ALIGN(16) : SUBALIGN(32) {
start_test_area_1 = .;
/* No sections should wind up here, because of the EXCLUDE_FILE. */
*( EXCLUDE_FILE(script_test*) .gold_test)
/* This should match only script_test_2b.o. */
script_test_2b.o(.gold_test)
/* This should match the remaining sections. */
*(.gold_test)
. = . + 4;
start_data = .;
BYTE(1)
SHORT(2)
LONG(4)
QUAD(8)
end_data = .;
start_fill = .;
FILL(0x12345678);
. = . + 7;
BYTE(0)
end_fill = .;
}
end_test_area = .;
}

View File

@ -0,0 +1,24 @@
// script_test_2a.cc -- linker script test 2, file 1 -*- C++ -*-
// 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.
char script_test_string_a[] __attribute__ ((section(".gold_test"))) =
"test a";

View File

@ -0,0 +1,24 @@
// script_test_2a.cc -- linker script test 2, file 2 -*- C++ -*-
// 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.
char script_test_string_b[] __attribute__ ((section(".gold_test"))) =
"test b";

View File

@ -371,7 +371,8 @@ opt_phdr:
| /* empty */
;
/* The value to use to fill an output section. */
/* The value to use to fill an output section. FIXME: This does not
handle a string of arbitrary length. */
opt_fill:
'=' exp
{ $$ = $2; }