2010-11-08 Doug Kwan <dougkwan@google.com>
Cary Coutant <ccoutant@google.com> * arm.cc (Arm_exidx_merge_section::build_contents): New method. (Arm_exidx_merge_section::section_contents_): New data member. (Arm_input_section::Arm_input_section): Initialize original_contents_. (Arm_input_section::~Arm_input_section): De-allocate memory. (Arm_input_section::original_contents_): New data member. (Arm_exidx_fixup::process_exidx_section): Pass EXIDX section contents in parameters instead of calling Object::section_contents without locking. (Arm_output_section::group_section): New parameter TASK. Pass it to callees that need locking objects. (Arm_output_section::fix_exidx_coverage): New parameter TASK. Use it to lock EXIDX input sections. Fix a formatting issue. Call Arm_exidx_merged_section::build_contents to create merged section contents. (Arm_output_section::create_stub_group): New parameter TASK. Use it to lock object of stub table owner. (Arm_exidx_input_section::Arm_exidx_input_section): Add new parameter TEXT_SIZE to initialize data member TEXT_SIZE_. (Arm_exidx_input_section::addralign): Fix typo in comment. (Arm_exidx_input_section::text_size): New method. (Target_arm::do_relax): New parameter TASK. Pass it to callees that require locking objects. Lock objects before scanning for stubs and updating local symbols. (Arm_input_section<big_endian>::init): Copy contents of original input section. (Arm_input_section<big_endian>::do_write): Use saved contents of original input section instead of calling Object::section_contents without locking. (Arm_exidx_cantunwind::do_fixed_endian_write): Find out text section size without calling Object::section_size(). (Arm_exidx_merged_section::Arm_exidx_merged_section): Add sanity check for size. Allocate a buffer for merged EXIDX entries. (Arm_exidx_merged_section::build_contents): New method. (Arm_exidx_merged_section::do_write): Move merge section contents building code to Arm_exidx_merged_section::build_contetns. Write out contetns in buffer instead of building it on the fly. (Arm_relobj::make_exidx_input_section): Also pass text section size to Arm_exidx_input_section constructor. (Arm_relobj::do_read_symbols): Fix memory leak. Fix a formatting issue. (Arm_dynobj::do_read_symbols): Fix memory leak. * layout.cc (Layout::finalize): Pass TASK to Target::relax(). * target.h: (class Task): Add forward declaration. (Target::relax): Add new parameter TASK and pass it to Target::do_relax(). (Target::do_relax):: New parameter TASK. Fix a formatting issue.
This commit is contained in:
parent
efd11a33a1
commit
f625ae503e
4 changed files with 241 additions and 100 deletions
|
@ -1,3 +1,52 @@
|
|||
2010-11-08 Doug Kwan <dougkwan@google.com>
|
||||
Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* arm.cc (Arm_exidx_merge_section::build_contents): New method.
|
||||
(Arm_exidx_merge_section::section_contents_): New data member.
|
||||
(Arm_input_section::Arm_input_section): Initialize original_contents_.
|
||||
(Arm_input_section::~Arm_input_section): De-allocate memory.
|
||||
(Arm_input_section::original_contents_): New data member.
|
||||
(Arm_exidx_fixup::process_exidx_section): Pass EXIDX section contents
|
||||
in parameters instead of calling Object::section_contents without
|
||||
locking.
|
||||
(Arm_output_section::group_section): New parameter TASK. Pass it
|
||||
to callees that need locking objects.
|
||||
(Arm_output_section::fix_exidx_coverage): New parameter TASK. Use it
|
||||
to lock EXIDX input sections. Fix a formatting issue. Call
|
||||
Arm_exidx_merged_section::build_contents to create merged section
|
||||
contents.
|
||||
(Arm_output_section::create_stub_group): New parameter TASK. Use it
|
||||
to lock object of stub table owner.
|
||||
(Arm_exidx_input_section::Arm_exidx_input_section): Add new parameter
|
||||
TEXT_SIZE to initialize data member TEXT_SIZE_.
|
||||
(Arm_exidx_input_section::addralign): Fix typo in comment.
|
||||
(Arm_exidx_input_section::text_size): New method.
|
||||
(Target_arm::do_relax): New parameter TASK. Pass it to callees
|
||||
that require locking objects. Lock objects before scanning for stubs
|
||||
and updating local symbols.
|
||||
(Arm_input_section<big_endian>::init): Copy contents of original
|
||||
input section.
|
||||
(Arm_input_section<big_endian>::do_write): Use saved contents of
|
||||
original input section instead of calling Object::section_contents
|
||||
without locking.
|
||||
(Arm_exidx_cantunwind::do_fixed_endian_write): Find out text section
|
||||
size without calling Object::section_size().
|
||||
(Arm_exidx_merged_section::Arm_exidx_merged_section): Add sanity check
|
||||
for size. Allocate a buffer for merged EXIDX entries.
|
||||
(Arm_exidx_merged_section::build_contents): New method.
|
||||
(Arm_exidx_merged_section::do_write): Move merge section contents
|
||||
building code to Arm_exidx_merged_section::build_contetns. Write
|
||||
out contetns in buffer instead of building it on the fly.
|
||||
(Arm_relobj::make_exidx_input_section): Also pass text section size
|
||||
to Arm_exidx_input_section constructor.
|
||||
(Arm_relobj::do_read_symbols): Fix memory leak. Fix a formatting issue.
|
||||
(Arm_dynobj::do_read_symbols): Fix memory leak.
|
||||
* layout.cc (Layout::finalize): Pass TASK to Target::relax().
|
||||
* target.h: (class Task): Add forward declaration.
|
||||
(Target::relax): Add new parameter TASK and pass it to
|
||||
Target::do_relax().
|
||||
(Target::do_relax):: New parameter TASK. Fix a formatting issue.
|
||||
|
||||
2010-11-05 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
PR gold/10708
|
||||
|
|
283
gold/arm.cc
283
gold/arm.cc
|
@ -1104,6 +1104,10 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section
|
|||
const Arm_exidx_section_offset_map& section_offset_map,
|
||||
uint32_t deleted_bytes);
|
||||
|
||||
// Build output contents.
|
||||
void
|
||||
build_contents(const unsigned char*, section_size_type);
|
||||
|
||||
// Return the original EXIDX input section.
|
||||
const Arm_exidx_input_section&
|
||||
exidx_input_section() const
|
||||
|
@ -1128,6 +1132,10 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section
|
|||
const Arm_exidx_input_section& exidx_input_section_;
|
||||
// Section offset map.
|
||||
const Arm_exidx_section_offset_map& section_offset_map_;
|
||||
// Merged section contents. We need to keep build the merged section
|
||||
// and save it here to avoid accessing the original EXIDX section when
|
||||
// we cannot lock the sections' object.
|
||||
unsigned char* section_contents_;
|
||||
};
|
||||
|
||||
// A class to wrap an ordinary input section containing executable code.
|
||||
|
@ -1138,11 +1146,12 @@ class Arm_input_section : public Output_relaxed_input_section
|
|||
public:
|
||||
Arm_input_section(Relobj* relobj, unsigned int shndx)
|
||||
: Output_relaxed_input_section(relobj, shndx, 1),
|
||||
original_addralign_(1), original_size_(0), stub_table_(NULL)
|
||||
original_addralign_(1), original_size_(0), stub_table_(NULL),
|
||||
original_contents_(NULL)
|
||||
{ }
|
||||
|
||||
~Arm_input_section()
|
||||
{ }
|
||||
{ delete[] this->original_contents_; }
|
||||
|
||||
// Initialize.
|
||||
void
|
||||
|
@ -1228,6 +1237,10 @@ class Arm_input_section : public Output_relaxed_input_section
|
|||
uint32_t original_size_;
|
||||
// Stub table.
|
||||
Stub_table<big_endian>* stub_table_;
|
||||
// Original section contents. We have to make a copy here since the file
|
||||
// containing the original section may not be locked when we need to access
|
||||
// the contents.
|
||||
unsigned char* original_contents_;
|
||||
};
|
||||
|
||||
// Arm_exidx_fixup class. This is used to define a number of methods
|
||||
|
@ -1247,14 +1260,17 @@ class Arm_exidx_fixup
|
|||
~Arm_exidx_fixup()
|
||||
{ delete this->section_offset_map_; }
|
||||
|
||||
// Process an EXIDX section for entry merging. Return number of bytes to
|
||||
// be deleted in output. If parts of the input EXIDX section are merged
|
||||
// a heap allocated Arm_exidx_section_offset_map is store in the located
|
||||
// PSECTION_OFFSET_MAP. The caller owns the map and is reponsible for
|
||||
// releasing it.
|
||||
// Process an EXIDX section for entry merging. SECTION_CONTENTS points
|
||||
// to the EXIDX contents and SECTION_SIZE is the size of the contents. Return
|
||||
// number of bytes to be deleted in output. If parts of the input EXIDX
|
||||
// section are merged a heap allocated Arm_exidx_section_offset_map is store
|
||||
// in the located PSECTION_OFFSET_MAP. The caller owns the map and is
|
||||
// reponsible for releasing it.
|
||||
template<bool big_endian>
|
||||
uint32_t
|
||||
process_exidx_section(const Arm_exidx_input_section* exidx_input_section,
|
||||
const unsigned char* section_contents,
|
||||
section_size_type section_size,
|
||||
Arm_exidx_section_offset_map** psection_offset_map);
|
||||
|
||||
// Append an EXIDX_CANTUNWIND entry pointing at the end of the last
|
||||
|
@ -1339,7 +1355,7 @@ class Arm_output_section : public Output_section
|
|||
|
||||
// Group input sections for stub generation.
|
||||
void
|
||||
group_sections(section_size_type, bool, Target_arm<big_endian>*);
|
||||
group_sections(section_size_type, bool, Target_arm<big_endian>*, const Task*);
|
||||
|
||||
// Downcast a base pointer to an Arm_output_section pointer. This is
|
||||
// not type-safe but we only use Arm_output_section not the base class.
|
||||
|
@ -1358,7 +1374,8 @@ class Arm_output_section : public Output_section
|
|||
fix_exidx_coverage(Layout* layout,
|
||||
const Text_section_list& sorted_text_section,
|
||||
Symbol_table* symtab,
|
||||
bool merge_exidx_entries);
|
||||
bool merge_exidx_entries,
|
||||
const Task* task);
|
||||
|
||||
// Link an EXIDX section into its corresponding text section.
|
||||
void
|
||||
|
@ -1374,7 +1391,8 @@ class Arm_output_section : public Output_section
|
|||
Input_section_list::const_iterator,
|
||||
Input_section_list::const_iterator,
|
||||
Target_arm<big_endian>*,
|
||||
std::vector<Output_relaxed_input_section*>*);
|
||||
std::vector<Output_relaxed_input_section*>*,
|
||||
const Task* task);
|
||||
};
|
||||
|
||||
// Arm_exidx_input_section class. This represents an EXIDX input section.
|
||||
|
@ -1386,9 +1404,10 @@ class Arm_exidx_input_section
|
|||
static_cast<section_offset_type>(-1);
|
||||
|
||||
Arm_exidx_input_section(Relobj* relobj, unsigned int shndx,
|
||||
unsigned int link, uint32_t size, uint32_t addralign)
|
||||
unsigned int link, uint32_t size,
|
||||
uint32_t addralign, uint32_t text_size)
|
||||
: relobj_(relobj), shndx_(shndx), link_(link), size_(size),
|
||||
addralign_(addralign), has_errors_(false)
|
||||
addralign_(addralign), text_size_(text_size), has_errors_(false)
|
||||
{ }
|
||||
|
||||
~Arm_exidx_input_section()
|
||||
|
@ -1416,11 +1435,16 @@ class Arm_exidx_input_section
|
|||
size() const
|
||||
{ return this->size_; }
|
||||
|
||||
// Reutnr address alignment of EXIDX input section.
|
||||
// Return address alignment of EXIDX input section.
|
||||
uint32_t
|
||||
addralign() const
|
||||
{ return this->addralign_; }
|
||||
|
||||
// Return size of the associated text input section.
|
||||
uint32_t
|
||||
text_size() const
|
||||
{ return this->text_size_; }
|
||||
|
||||
// Whether there are any errors in the EXIDX input section.
|
||||
bool
|
||||
has_errors() const
|
||||
|
@ -1442,6 +1466,8 @@ class Arm_exidx_input_section
|
|||
uint32_t size_;
|
||||
// Address alignment of this. For ARM 32-bit is sufficient.
|
||||
uint32_t addralign_;
|
||||
// Size of associated text section.
|
||||
uint32_t text_size_;
|
||||
// Whether this has any errors.
|
||||
bool has_errors_;
|
||||
};
|
||||
|
@ -2499,7 +2525,7 @@ class Target_arm : public Sized_target<32, big_endian>
|
|||
{ return !parameters->options().relocatable(); }
|
||||
|
||||
bool
|
||||
do_relax(int, const Input_objects*, Symbol_table*, Layout*);
|
||||
do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*);
|
||||
|
||||
// Determine whether an object attribute tag takes an integer, a
|
||||
// string or both.
|
||||
|
@ -2802,7 +2828,7 @@ class Target_arm : public Sized_target<32, big_endian>
|
|||
|
||||
// Group input sections for stub generation.
|
||||
void
|
||||
group_sections(Layout*, section_size_type, bool);
|
||||
group_sections(Layout*, section_size_type, bool, const Task*);
|
||||
|
||||
// Scan a relocation for stub generation.
|
||||
void
|
||||
|
@ -2827,7 +2853,8 @@ class Target_arm : public Sized_target<32, big_endian>
|
|||
// Fix .ARM.exidx section coverage.
|
||||
void
|
||||
fix_exidx_coverage(Layout*, const Input_objects*,
|
||||
Arm_output_section<big_endian>*, Symbol_table*);
|
||||
Arm_output_section<big_endian>*, Symbol_table*,
|
||||
const Task*);
|
||||
|
||||
// Functors for STL set.
|
||||
struct output_section_address_less_than
|
||||
|
@ -5086,13 +5113,23 @@ Arm_input_section<big_endian>::init()
|
|||
Relobj* relobj = this->relobj();
|
||||
unsigned int shndx = this->shndx();
|
||||
|
||||
// Cache these to speed up size and alignment queries. It is too slow
|
||||
// to call section_addraglin and section_size every time.
|
||||
// We have to cache original size, alignment and contents to avoid locking
|
||||
// the original file.
|
||||
this->original_addralign_ =
|
||||
convert_types<uint32_t, uint64_t>(relobj->section_addralign(shndx));
|
||||
|
||||
// This is not efficient but we expect only a small number of relaxed
|
||||
// input sections for stubs.
|
||||
section_size_type section_size;
|
||||
const unsigned char* section_contents =
|
||||
relobj->section_contents(shndx, §ion_size, false);
|
||||
this->original_size_ =
|
||||
convert_types<uint32_t, uint64_t>(relobj->section_size(shndx));
|
||||
|
||||
gold_assert(this->original_contents_ == NULL);
|
||||
this->original_contents_ = new unsigned char[section_size];
|
||||
memcpy(this->original_contents_, section_contents, section_size);
|
||||
|
||||
// We want to make this look like the original input section after
|
||||
// output sections are finalized.
|
||||
Output_section* os = relobj->output_section(shndx);
|
||||
|
@ -5110,10 +5147,9 @@ void
|
|||
Arm_input_section<big_endian>::do_write(Output_file* of)
|
||||
{
|
||||
// We have to write out the original section content.
|
||||
section_size_type section_size;
|
||||
const unsigned char* section_contents =
|
||||
this->relobj()->section_contents(this->shndx(), §ion_size, false);
|
||||
of->write(this->offset(), section_contents, section_size);
|
||||
gold_assert(this->original_contents_ != NULL);
|
||||
of->write(this->offset(), this->original_contents_,
|
||||
this->original_size_);
|
||||
|
||||
// If this owns a stub table and it is not empty, write it.
|
||||
if (this->is_stub_table_owner() && !this->stub_table_->empty())
|
||||
|
@ -5184,8 +5220,18 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of)
|
|||
Arm_address output_offset =
|
||||
arm_relobj->get_output_section_offset(this->shndx_);
|
||||
Arm_address section_start;
|
||||
section_size_type section_size;
|
||||
|
||||
// Find out the end of the text section referred by this.
|
||||
if (output_offset != Arm_relobj<big_endian>::invalid_address)
|
||||
section_start = os->address() + output_offset;
|
||||
{
|
||||
section_start = os->address() + output_offset;
|
||||
const Arm_exidx_input_section* exidx_input_section =
|
||||
arm_relobj->exidx_input_section_by_link(this->shndx_);
|
||||
gold_assert(exidx_input_section != NULL);
|
||||
section_size =
|
||||
convert_to_section_size_type(exidx_input_section->text_size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Currently this only happens for a relaxed section.
|
||||
|
@ -5193,11 +5239,11 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of)
|
|||
os->find_relaxed_input_section(this->relobj_, this->shndx_);
|
||||
gold_assert(poris != NULL);
|
||||
section_start = poris->address();
|
||||
section_size = convert_to_section_size_type(poris->data_size());
|
||||
}
|
||||
|
||||
// We always append this to the end of an EXIDX section.
|
||||
Arm_address output_address =
|
||||
section_start + this->relobj_->section_size(this->shndx_);
|
||||
Arm_address output_address = section_start + section_size;
|
||||
|
||||
// Write out the entry. The first word either points to the beginning
|
||||
// or after the end of a text section. The second word is the special
|
||||
|
@ -5229,9 +5275,59 @@ Arm_exidx_merged_section::Arm_exidx_merged_section(
|
|||
exidx_input_section_(exidx_input_section),
|
||||
section_offset_map_(section_offset_map)
|
||||
{
|
||||
// If we retain or discard the whole EXIDX input section, we would
|
||||
// not be here.
|
||||
gold_assert(deleted_bytes != 0
|
||||
&& deleted_bytes != this->exidx_input_section_.size());
|
||||
|
||||
// Fix size here so that we do not need to implement set_final_data_size.
|
||||
this->set_data_size(exidx_input_section.size() - deleted_bytes);
|
||||
uint32_t size = exidx_input_section.size() - deleted_bytes;
|
||||
this->set_data_size(size);
|
||||
this->fix_data_size();
|
||||
|
||||
// Allocate buffer for section contents and build contents.
|
||||
this->section_contents_ = new unsigned char[size];
|
||||
}
|
||||
|
||||
// Build the contents of a merged EXIDX output section.
|
||||
|
||||
void
|
||||
Arm_exidx_merged_section::build_contents(
|
||||
const unsigned char* original_contents,
|
||||
section_size_type original_size)
|
||||
{
|
||||
// Go over spans of input offsets and write only those that are not
|
||||
// discarded.
|
||||
section_offset_type in_start = 0;
|
||||
section_offset_type out_start = 0;
|
||||
section_offset_type in_max =
|
||||
convert_types<section_offset_type>(original_size);
|
||||
section_offset_type out_max =
|
||||
convert_types<section_offset_type>(this->data_size());
|
||||
for (Arm_exidx_section_offset_map::const_iterator p =
|
||||
this->section_offset_map_.begin();
|
||||
p != this->section_offset_map_.end();
|
||||
++p)
|
||||
{
|
||||
section_offset_type in_end = p->first;
|
||||
gold_assert(in_end >= in_start);
|
||||
section_offset_type out_end = p->second;
|
||||
size_t in_chunk_size = convert_types<size_t>(in_end - in_start + 1);
|
||||
if (out_end != -1)
|
||||
{
|
||||
size_t out_chunk_size =
|
||||
convert_types<size_t>(out_end - out_start + 1);
|
||||
|
||||
gold_assert(out_chunk_size == in_chunk_size
|
||||
&& in_end < in_max && out_end < out_max);
|
||||
|
||||
memcpy(this->section_contents_ + out_start,
|
||||
original_contents + in_start,
|
||||
out_chunk_size);
|
||||
out_start += out_chunk_size;
|
||||
}
|
||||
in_start += in_chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
// Given an input OBJECT, an input section index SHNDX within that
|
||||
|
@ -5290,11 +5386,6 @@ Arm_exidx_merged_section::do_output_offset(
|
|||
void
|
||||
Arm_exidx_merged_section::do_write(Output_file* of)
|
||||
{
|
||||
// If we retain or discard the whole EXIDX input section, we would
|
||||
// not be here.
|
||||
gold_assert(this->data_size() != this->exidx_input_section_.size()
|
||||
&& this->data_size() != 0);
|
||||
|
||||
off_t offset = this->offset();
|
||||
const section_size_type oview_size = this->data_size();
|
||||
unsigned char* const oview = of->get_output_view(offset, oview_size);
|
||||
|
@ -5302,38 +5393,7 @@ Arm_exidx_merged_section::do_write(Output_file* of)
|
|||
Output_section* os = this->relobj()->output_section(this->shndx());
|
||||
gold_assert(os != NULL);
|
||||
|
||||
// Get contents of EXIDX input section.
|
||||
section_size_type section_size;
|
||||
const unsigned char* section_contents =
|
||||
this->relobj()->section_contents(this->shndx(), §ion_size, false);
|
||||
gold_assert(section_size == this->exidx_input_section_.size());
|
||||
|
||||
// Go over spans of input offsets and write only those that are not
|
||||
// discarded.
|
||||
section_offset_type in_start = 0;
|
||||
section_offset_type out_start = 0;
|
||||
for(Arm_exidx_section_offset_map::const_iterator p =
|
||||
this->section_offset_map_.begin();
|
||||
p != this->section_offset_map_.end();
|
||||
++p)
|
||||
{
|
||||
section_offset_type in_end = p->first;
|
||||
gold_assert(in_end >= in_start);
|
||||
section_offset_type out_end = p->second;
|
||||
size_t in_chunk_size = convert_types<size_t>(in_end - in_start + 1);
|
||||
if (out_end != -1)
|
||||
{
|
||||
size_t out_chunk_size =
|
||||
convert_types<size_t>(out_end - out_start + 1);
|
||||
gold_assert(out_chunk_size == in_chunk_size);
|
||||
memcpy(oview + out_start, section_contents + in_start,
|
||||
out_chunk_size);
|
||||
out_start += out_chunk_size;
|
||||
}
|
||||
in_start += in_chunk_size;
|
||||
}
|
||||
|
||||
gold_assert(convert_to_section_size_type(out_start) == oview_size);
|
||||
memcpy(oview, this->section_contents_, oview_size);
|
||||
of->write_output_view(this->offset(), oview_size, oview);
|
||||
}
|
||||
|
||||
|
@ -5414,21 +5474,22 @@ Arm_exidx_fixup::update_offset_map(
|
|||
}
|
||||
|
||||
// Process EXIDX_INPUT_SECTION for EXIDX entry merging. Return the number of
|
||||
// bytes deleted. If some entries are merged, also store a pointer to a newly
|
||||
// created Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The
|
||||
// caller owns the map and is responsible for releasing it after use.
|
||||
// bytes deleted. SECTION_CONTENTS points to the contents of the EXIDX
|
||||
// section and SECTION_SIZE is the number of bytes pointed by SECTION_CONTENTS.
|
||||
// If some entries are merged, also store a pointer to a newly created
|
||||
// Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The caller
|
||||
// owns the map and is responsible for releasing it after use.
|
||||
|
||||
template<bool big_endian>
|
||||
uint32_t
|
||||
Arm_exidx_fixup::process_exidx_section(
|
||||
const Arm_exidx_input_section* exidx_input_section,
|
||||
const unsigned char* section_contents,
|
||||
section_size_type section_size,
|
||||
Arm_exidx_section_offset_map** psection_offset_map)
|
||||
{
|
||||
Relobj* relobj = exidx_input_section->relobj();
|
||||
unsigned shndx = exidx_input_section->shndx();
|
||||
section_size_type section_size;
|
||||
const unsigned char* section_contents =
|
||||
relobj->section_contents(shndx, §ion_size, false);
|
||||
|
||||
if ((section_size % 8) != 0)
|
||||
{
|
||||
|
@ -5508,7 +5569,8 @@ Arm_output_section<big_endian>::create_stub_group(
|
|||
Input_section_list::const_iterator end,
|
||||
Input_section_list::const_iterator owner,
|
||||
Target_arm<big_endian>* target,
|
||||
std::vector<Output_relaxed_input_section*>* new_relaxed_sections)
|
||||
std::vector<Output_relaxed_input_section*>* new_relaxed_sections,
|
||||
const Task* task)
|
||||
{
|
||||
// We use a different kind of relaxed section in an EXIDX section.
|
||||
// The static casting from Output_relaxed_input_section to
|
||||
|
@ -5531,7 +5593,9 @@ Arm_output_section<big_endian>::create_stub_group(
|
|||
else
|
||||
{
|
||||
gold_assert(owner->is_input_section());
|
||||
// Create a new relaxed input section.
|
||||
// Create a new relaxed input section. We need to lock the original
|
||||
// file.
|
||||
Task_lock_obj<Object> tl(task, owner->relobj());
|
||||
arm_input_section =
|
||||
target->new_arm_input_section(owner->relobj(), owner->shndx());
|
||||
new_relaxed_sections->push_back(arm_input_section);
|
||||
|
@ -5576,7 +5640,8 @@ void
|
|||
Arm_output_section<big_endian>::group_sections(
|
||||
section_size_type group_size,
|
||||
bool stubs_always_after_branch,
|
||||
Target_arm<big_endian>* target)
|
||||
Target_arm<big_endian>* target,
|
||||
const Task* task)
|
||||
{
|
||||
// We only care about sections containing code.
|
||||
if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0)
|
||||
|
@ -5633,7 +5698,8 @@ Arm_output_section<big_endian>::group_sections(
|
|||
{
|
||||
gold_assert(group_end != this->input_sections().end());
|
||||
this->create_stub_group(group_begin, group_end, group_end,
|
||||
target, &new_relaxed_sections);
|
||||
target, &new_relaxed_sections,
|
||||
task);
|
||||
state = NO_GROUP;
|
||||
}
|
||||
else
|
||||
|
@ -5655,7 +5721,7 @@ Arm_output_section<big_endian>::group_sections(
|
|||
{
|
||||
gold_assert(group_end != this->input_sections().end());
|
||||
this->create_stub_group(group_begin, group_end, stub_table,
|
||||
target, &new_relaxed_sections);
|
||||
target, &new_relaxed_sections, task);
|
||||
state = NO_GROUP;
|
||||
}
|
||||
break;
|
||||
|
@ -5665,9 +5731,10 @@ Arm_output_section<big_endian>::group_sections(
|
|||
}
|
||||
|
||||
// If we see an input section and currently there is no group, start
|
||||
// a new one. Skip any empty sections.
|
||||
// a new one. Skip any empty sections. We look at the data size
|
||||
// instead of calling p->relobj()->section_size() to avoid locking.
|
||||
if ((p->is_input_section() || p->is_relaxed_input_section())
|
||||
&& (p->relobj()->section_size(p->shndx()) != 0))
|
||||
&& (p->data_size() != 0))
|
||||
{
|
||||
if (state == NO_GROUP)
|
||||
{
|
||||
|
@ -5692,7 +5759,7 @@ Arm_output_section<big_endian>::group_sections(
|
|||
(state == FINDING_STUB_SECTION
|
||||
? group_end
|
||||
: stub_table),
|
||||
target, &new_relaxed_sections);
|
||||
target, &new_relaxed_sections, task);
|
||||
}
|
||||
|
||||
// Convert input section into relaxed input section in a batch.
|
||||
|
@ -5740,7 +5807,8 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
|
|||
Layout* layout,
|
||||
const Text_section_list& sorted_text_sections,
|
||||
Symbol_table* symtab,
|
||||
bool merge_exidx_entries)
|
||||
bool merge_exidx_entries,
|
||||
const Task* task)
|
||||
{
|
||||
// We should only do this for the EXIDX output section.
|
||||
gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX);
|
||||
|
@ -5823,10 +5891,19 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
|
|||
continue;
|
||||
}
|
||||
|
||||
// We need to access the contents of the EXIDX section, lock the
|
||||
// object here.
|
||||
Task_lock_obj<Object> tl(task, exidx_relobj);
|
||||
section_size_type exidx_size;
|
||||
const unsigned char* exidx_contents =
|
||||
exidx_relobj->section_contents(exidx_shndx, &exidx_size, false);
|
||||
|
||||
// Fix up coverage and append input section to output data list.
|
||||
Arm_exidx_section_offset_map* section_offset_map = NULL;
|
||||
uint32_t deleted_bytes =
|
||||
exidx_fixup.process_exidx_section<big_endian>(exidx_input_section,
|
||||
exidx_contents,
|
||||
exidx_size,
|
||||
§ion_offset_map);
|
||||
|
||||
if (deleted_bytes == exidx_input_section->size())
|
||||
|
@ -5844,9 +5921,12 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
|
|||
// Some entries are merged. We need to convert this EXIDX input
|
||||
// section into a relaxed section.
|
||||
gold_assert(section_offset_map != NULL);
|
||||
|
||||
Arm_exidx_merged_section* merged_section =
|
||||
new Arm_exidx_merged_section(*exidx_input_section,
|
||||
*section_offset_map, deleted_bytes);
|
||||
merged_section->build_contents(exidx_contents, exidx_size);
|
||||
|
||||
const std::string secname = exidx_relobj->section_name(exidx_shndx);
|
||||
this->add_relaxed_input_section(layout, merged_section, secname);
|
||||
arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx);
|
||||
|
@ -6541,7 +6621,8 @@ Arm_relobj<big_endian>::make_exidx_input_section(
|
|||
// Create an Arm_exidx_input_section object for this EXIDX section.
|
||||
Arm_exidx_input_section* exidx_input_section =
|
||||
new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(),
|
||||
shdr.get_sh_addralign());
|
||||
shdr.get_sh_addralign(),
|
||||
text_shdr.get_sh_size());
|
||||
|
||||
gold_assert(this->exidx_section_map_[shndx] == NULL);
|
||||
this->exidx_section_map_[shndx] = exidx_input_section;
|
||||
|
@ -6647,10 +6728,10 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
|
|||
section_offset_type section_offset = shdr.get_sh_offset();
|
||||
section_size_type section_size =
|
||||
convert_to_section_size_type(shdr.get_sh_size());
|
||||
File_view* view = this->get_lasting_view(section_offset,
|
||||
section_size, true, false);
|
||||
const unsigned char* view =
|
||||
this->get_view(section_offset, section_size, true, false);
|
||||
this->attributes_section_data_ =
|
||||
new Attributes_section_data(view->data(), section_size);
|
||||
new Attributes_section_data(view, section_size);
|
||||
}
|
||||
else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX)
|
||||
{
|
||||
|
@ -6725,7 +6806,7 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
|
|||
locsize, true, true);
|
||||
|
||||
// Process the deferred EXIDX sections.
|
||||
for(unsigned int i = 0; i < deferred_exidx_sections.size(); ++i)
|
||||
for (unsigned int i = 0; i < deferred_exidx_sections.size(); ++i)
|
||||
{
|
||||
unsigned int shndx = deferred_exidx_sections[i];
|
||||
elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size);
|
||||
|
@ -6909,10 +6990,10 @@ Arm_dynobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
|
|||
section_offset_type section_offset = shdr.get_sh_offset();
|
||||
section_size_type section_size =
|
||||
convert_to_section_size_type(shdr.get_sh_size());
|
||||
File_view* view = this->get_lasting_view(section_offset,
|
||||
section_size, true, false);
|
||||
const unsigned char* view =
|
||||
this->get_view(section_offset, section_size, true, false);
|
||||
this->attributes_section_data_ =
|
||||
new Attributes_section_data(view->data(), section_size);
|
||||
new Attributes_section_data(view, section_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -11160,7 +11241,8 @@ void
|
|||
Target_arm<big_endian>::group_sections(
|
||||
Layout* layout,
|
||||
section_size_type group_size,
|
||||
bool stubs_always_after_branch)
|
||||
bool stubs_always_after_branch,
|
||||
const Task* task)
|
||||
{
|
||||
// Group input sections and insert stub table
|
||||
Layout::Section_list section_list;
|
||||
|
@ -11172,7 +11254,7 @@ Target_arm<big_endian>::group_sections(
|
|||
Arm_output_section<big_endian>* output_section =
|
||||
Arm_output_section<big_endian>::as_arm_output_section(*p);
|
||||
output_section->group_sections(group_size, stubs_always_after_branch,
|
||||
this);
|
||||
this, task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11184,7 +11266,8 @@ Target_arm<big_endian>::do_relax(
|
|||
int pass,
|
||||
const Input_objects* input_objects,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout)
|
||||
Layout* layout,
|
||||
const Task* task)
|
||||
{
|
||||
// No need to generate stubs if this is a relocatable link.
|
||||
gold_assert(!parameters->options().relocatable());
|
||||
|
@ -11233,7 +11316,7 @@ Target_arm<big_endian>::do_relax(
|
|||
stub_group_size = std::max(stub_group_size, cortex_a8_group_size);
|
||||
}
|
||||
|
||||
group_sections(layout, stub_group_size, stubs_always_after_branch);
|
||||
group_sections(layout, stub_group_size, stubs_always_after_branch, task);
|
||||
|
||||
// Also fix .ARM.exidx section coverage.
|
||||
Arm_output_section<big_endian>* exidx_output_section = NULL;
|
||||
|
@ -11257,7 +11340,7 @@ Target_arm<big_endian>::do_relax(
|
|||
if (exidx_output_section != NULL)
|
||||
{
|
||||
this->fix_exidx_coverage(layout, input_objects, exidx_output_section,
|
||||
symtab);
|
||||
symtab, task);
|
||||
done_exidx_fixup = true;
|
||||
}
|
||||
}
|
||||
|
@ -11306,6 +11389,9 @@ Target_arm<big_endian>::do_relax(
|
|||
{
|
||||
Arm_relobj<big_endian>* arm_relobj =
|
||||
Arm_relobj<big_endian>::as_arm_relobj(*op);
|
||||
// Lock the object so we can read from it. This is only called
|
||||
// single-threaded from Layout::finalize, so it is OK to lock.
|
||||
Task_lock_obj<Object> tl(task, arm_relobj);
|
||||
arm_relobj->scan_sections_for_stubs(this, symtab, layout);
|
||||
}
|
||||
|
||||
|
@ -11336,7 +11422,7 @@ Target_arm<big_endian>::do_relax(
|
|||
// need to update output sections, so we record all output sections needing
|
||||
// update above and scan the sections here to find out what sections need
|
||||
// to be updated.
|
||||
for(Layout::Section_list::const_iterator p = layout->section_list().begin();
|
||||
for (Layout::Section_list::const_iterator p = layout->section_list().begin();
|
||||
p != layout->section_list().end();
|
||||
++p)
|
||||
{
|
||||
|
@ -11368,7 +11454,11 @@ Target_arm<big_endian>::do_relax(
|
|||
// symbols defined in parts of input sections that are discarded by
|
||||
// relaxation.
|
||||
if (arm_relobj->output_local_symbol_count_needs_update())
|
||||
arm_relobj->update_output_local_symbol_count();
|
||||
{
|
||||
// We need to lock the object's file to update it.
|
||||
Task_lock_obj<Object> tl(task, arm_relobj);
|
||||
arm_relobj->update_output_local_symbol_count();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11710,7 +11800,8 @@ Target_arm<big_endian>::fix_exidx_coverage(
|
|||
Layout* layout,
|
||||
const Input_objects* input_objects,
|
||||
Arm_output_section<big_endian>* exidx_section,
|
||||
Symbol_table* symtab)
|
||||
Symbol_table* symtab,
|
||||
const Task* task)
|
||||
{
|
||||
// We need to look at all the input sections in output in ascending
|
||||
// order of of output address. We do that by building a sorted list
|
||||
|
@ -11751,7 +11842,7 @@ Target_arm<big_endian>::fix_exidx_coverage(
|
|||
typedef typename Arm_output_section<big_endian>::Text_section_list
|
||||
Text_section_list;
|
||||
Text_section_list sorted_text_sections;
|
||||
for(typename Sorted_output_section_list::iterator p =
|
||||
for (typename Sorted_output_section_list::iterator p =
|
||||
sorted_output_sections.begin();
|
||||
p != sorted_output_sections.end();
|
||||
++p)
|
||||
|
@ -11762,7 +11853,7 @@ Target_arm<big_endian>::fix_exidx_coverage(
|
|||
}
|
||||
|
||||
exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab,
|
||||
merge_exidx_entries());
|
||||
merge_exidx_entries(), task);
|
||||
}
|
||||
|
||||
Target_selector_arm<false> target_selector_arm;
|
||||
|
|
|
@ -1943,7 +1943,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
pass++;
|
||||
}
|
||||
while (target->may_relax()
|
||||
&& target->relax(pass, input_objects, symtab, this));
|
||||
&& target->relax(pass, input_objects, symtab, this, task));
|
||||
|
||||
// Set the file offsets of all the non-data sections we've seen so
|
||||
// far which don't have to wait for the input sections. We need
|
||||
|
|
|
@ -56,6 +56,7 @@ class Symbol_table;
|
|||
class Output_data;
|
||||
class Output_section;
|
||||
class Input_objects;
|
||||
class Task;
|
||||
|
||||
// The abstract class for target specific handling.
|
||||
|
||||
|
@ -332,13 +333,13 @@ class Target
|
|||
// Perform a relaxation pass. Return true if layout may be changed.
|
||||
bool
|
||||
relax(int pass, const Input_objects* input_objects, Symbol_table* symtab,
|
||||
Layout* layout)
|
||||
Layout* layout, const Task* task)
|
||||
{
|
||||
// Run the dummy relaxation pass twice if relaxation debugging is enabled.
|
||||
if (is_debugging_enabled(DEBUG_RELAXATION))
|
||||
return pass < 2;
|
||||
|
||||
return this->do_relax(pass, input_objects, symtab, layout);
|
||||
return this->do_relax(pass, input_objects, symtab, layout, task);
|
||||
}
|
||||
|
||||
// Return the target-specific name of attributes section. This is
|
||||
|
@ -555,7 +556,7 @@ class Target
|
|||
|
||||
// Virtual function which may be overriden by the child class.
|
||||
virtual bool
|
||||
do_relax(int, const Input_objects*, Symbol_table*, Layout*)
|
||||
do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*)
|
||||
{ return false; }
|
||||
|
||||
// A function for targets to call. Return whether BYTES/LEN matches
|
||||
|
|
Loading…
Add table
Reference in a new issue