Fully implement the SECTIONS clause.
This commit is contained in:
parent
d16c732117
commit
a445fddf82
24 changed files with 3087 additions and 441 deletions
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
356
gold/layout.cc
356
gold/layout.cc
|
@ -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,
|
||||
Output_section* os = this->choose_output_section(object,
|
||||
name,
|
||||
shdr.get_sh_type(),
|
||||
shdr.get_sh_flags());
|
||||
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,
|
||||
const char* const name = ".eh_frame";
|
||||
Output_section* os = this->choose_output_section(object,
|
||||
name,
|
||||
elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC);
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
if (os == NULL)
|
||||
return NULL;
|
||||
|
||||
if (this->eh_frame_section_ == NULL)
|
||||
{
|
||||
|
@ -319,16 +382,17 @@ 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,
|
||||
this->choose_output_section(NULL,
|
||||
".eh_frame_hdr",
|
||||
elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC);
|
||||
elfcpp::SHF_ALLOC,
|
||||
false);
|
||||
|
||||
Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, this->eh_frame_data_);
|
||||
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();
|
||||
|
@ -341,6 +405,7 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
|
|||
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gold_assert(this->eh_frame_section_ == os);
|
||||
|
||||
|
@ -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,11 +437,9 @@ 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);
|
||||
Output_section* os = this->choose_output_section(NULL, name, type, flags,
|
||||
false);
|
||||
if (os != NULL)
|
||||
os->add_output_section_data(posd);
|
||||
}
|
||||
|
||||
|
@ -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_);
|
||||
if (load_seg != NULL)
|
||||
load_seg->add_initial_output_data(segment_headers);
|
||||
this->special_output_list_.push_back(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());
|
||||
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());
|
||||
(*p)->set_minimum_p_align(target->common_pagesize());
|
||||
|
||||
bool are_addresses_set = (*p)->are_addresses_set();
|
||||
if (are_addresses_set)
|
||||
{
|
||||
// When it comes to setting file offsets, we care about
|
||||
// the physical address.
|
||||
addr = (*p)->paddr();
|
||||
|
||||
// Adjust the file offset to the same address modulo the
|
||||
// page size.
|
||||
uint64_t unsigned_off = off;
|
||||
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 (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
|
||||
{
|
||||
uint64_t align = (*p)->addralign();
|
||||
|
||||
addr = align_address(addr, align);
|
||||
aligned_addr = addr;
|
||||
if ((addr & (abi_pagesize - 1)) != 0)
|
||||
addr = addr + abi_pagesize;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned int shndx_hold = *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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
261
gold/output.cc
261
gold/output.cc
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
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());
|
||||
|
||||
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
|
||||
|
|
245
gold/output.h
245
gold/output.h
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
398
gold/po/gold.pot
398
gold/po/gold.pot
|
@ -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
|
@ -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.
|
||||
|
|
122
gold/script.cc
122
gold/script.cc
|
@ -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,6 +1077,8 @@ Script_options::add_symbol_assignment(const char* name, size_t length,
|
|||
Expression* value, bool provide,
|
||||
bool hidden)
|
||||
{
|
||||
if (length != 1 || name[0] != '.')
|
||||
{
|
||||
if (this->script_sections_.in_sections_clause())
|
||||
this->script_sections_.add_symbol_assignment(name, length, value,
|
||||
provide, hidden);
|
||||
|
@ -1015,6 +1088,16 @@ Script_options::add_symbol_assignment(const char* name, size_t length,
|
|||
provide, hidden);
|
||||
this->symbol_assignments_.push_back(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an assertion.
|
||||
|
@ -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)
|
||||
{
|
||||
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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
69
gold/testsuite/script_test_2.cc
Normal file
69
gold/testsuite/script_test_2.cc
Normal 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);
|
||||
}
|
63
gold/testsuite/script_test_2.t
Normal file
63
gold/testsuite/script_test_2.t
Normal 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 = .;
|
||||
}
|
24
gold/testsuite/script_test_2a.cc
Normal file
24
gold/testsuite/script_test_2a.cc
Normal 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";
|
24
gold/testsuite/script_test_2b.cc
Normal file
24
gold/testsuite/script_test_2b.cc
Normal 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";
|
|
@ -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; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue