summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/compressed_output.cc177
-rw-r--r--gold/compressed_output.h93
-rw-r--r--gold/layout.cc51
-rw-r--r--gold/layout.h6
-rw-r--r--gold/merge.cc17
-rw-r--r--gold/merge.h10
-rw-r--r--gold/object.cc3
-rw-r--r--gold/object.h1
-rw-r--r--gold/output.cc164
-rw-r--r--gold/output.h142
-rw-r--r--gold/parameters.cc27
-rw-r--r--gold/parameters.h27
-rw-r--r--gold/reloc.cc79
-rw-r--r--gold/stringpool.cc4
-rw-r--r--gold/stringpool.h2
15 files changed, 386 insertions, 417 deletions
diff --git a/gold/compressed_output.cc b/gold/compressed_output.cc
index bf5f6407d3b..d12bfda03c2 100644
--- a/gold/compressed_output.cc
+++ b/gold/compressed_output.cc
@@ -26,8 +26,8 @@
#include <zlib.h>
#endif
-#include "compressed_output.h"
#include "parameters.h"
+#include "compressed_output.h"
namespace gold
{
@@ -89,187 +89,60 @@ zlib_compressed_suffix(unsigned long uncompressed_size)
return std::string(".zlib.") + size_string;
}
-// Class Output_compressed_section_data.
-
-// Add an input section. In this case, we just keep track of the sections.
-
-bool
-Output_compressed_section_data::do_add_input_section(Relobj* obj,
- unsigned int shndx)
-{
- this->objects_.push_back(Object_entry(obj, shndx));
- return true;
-}
+// Class Output_compressed_section.
// Set the final data size of a compressed section. This is where
// we actually compress the section data.
void
-Output_compressed_section_data::set_final_data_size()
+Output_compressed_section::set_final_data_size()
{
- // FIXME: assert that relocations have already been applied.
-
- off_t uncompressed_size = 0;
- for (std::vector<Object_entry>::iterator it = this->objects_.begin();
- it != this->objects_.end();
- ++it)
- {
- it->contents
- = it->object->section_contents(it->shndx, &it->length, false);
- uncompressed_size += it->length;
- }
+ off_t uncompressed_size = this->postprocessing_buffer_size();
// (Try to) compress the data.
unsigned long compressed_size;
- char* uncompressed_data = new char[uncompressed_size];
- off_t pos = 0;
- for (std::vector<Object_entry>::const_iterator it = this->objects_.begin();
- it != this->objects_.end();
- ++it)
- {
- memcpy(uncompressed_data + pos,
- reinterpret_cast<const char*>(it->contents),
- it->length);
- pos += it->length;
- }
+ unsigned char* u_uncompressed_data = this->postprocessing_buffer();
+ char* uncompressed_data = reinterpret_cast<char*>(u_uncompressed_data);
+
+ // At this point the contents of all regular input sections will
+ // have been copied into the postprocessing buffer, and relocations
+ // will have been applied. Now we need to copy in the contents of
+ // anything other than a regular input section.
+ this->write_to_postprocessing_buffer();
bool success = false;
- if (options_.zlib_compress_debug_sections())
+ if (this->options_->zlib_compress_debug_sections())
success = zlib_compress(uncompressed_data, uncompressed_size,
&this->data_, &compressed_size);
if (success)
{
- delete[] uncompressed_data;
+ std::string suffix(zlib_compressed_suffix(uncompressed_size));
+ this->new_section_name_ = std::string(this->name()) + suffix;
+ this->set_name(this->new_section_name_.c_str());
this->set_data_size(compressed_size);
- this->new_section_name_ = zlib_compressed_suffix(uncompressed_size);
}
else
{
- gold_warning(_("Not compressing section data: zlib error"));
+ gold_warning(_("not compressing section data: zlib error"));
gold_assert(this->data_ == NULL);
- this->data_ = uncompressed_data;
this->set_data_size(uncompressed_size);
}
}
-// Change the name of the output section to reflect it's compressed.
-// The layout routines call into this right before finalizing the
-// shstrtab.
-
-const char*
-Output_compressed_section_data::do_modified_output_section_name(
- const char* name)
-{
- // This mean we never compressed the data.
- if (this->new_section_name_.empty())
- return NULL;
- this->new_section_name_ = std::string(name) + this->new_section_name_;
- return this->new_section_name_.c_str();
-}
-
// Write out a compressed section. If we couldn't compress, we just
// write it out as normal, uncompressed data.
void
-Output_compressed_section_data::do_write(Output_file* of)
-{
- unsigned char* uview = of->get_output_view(this->offset(),
- this->data_size());
- char* view = reinterpret_cast<char*>(uview);
- memcpy(view, this->data_, this->data_size());
- of->write_output_view(this->offset(), this->data_size(), uview);
-}
-
-// Class Output_compressed_string.
-
-// Add an input section. We don't do anything special here.
-
-template<typename Char_type>
-bool
-Output_compressed_string<Char_type>::do_add_input_section(Relobj* object,
- unsigned int shndx)
-{
- return Output_merge_string<Char_type>::do_add_input_section(object, shndx);
-}
-
-// Set the final data size of a compressed section. This is where
-// we actually compress the section data.
-
-template<typename Char_type>
-void
-Output_compressed_string<Char_type>::set_final_data_size()
+Output_compressed_section::do_write(Output_file* of)
{
- // First let the superclass finalize all its data, then write it to
- // a buffer.
- unsigned long uncompressed_size = this->finalize_merged_data();
- char* uncompressed_data = new char[uncompressed_size];
- this->stringpool_to_buffer(uncompressed_data, uncompressed_size);
-
- // (Try to) compress the data.
- unsigned long compressed_size;
- if (options_.zlib_compress_debug_sections()
- && zlib_compress(uncompressed_data, uncompressed_size,
- &this->compressed_data_, &compressed_size))
- {
- this->set_data_size(compressed_size);
- // Save some memory.
- this->clear_stringpool();
- // We will be renaming the section to name.zlib.uncompressed_size.
- this->new_section_name_ = zlib_compressed_suffix(uncompressed_size);
- }
+ off_t offset = this->offset();
+ off_t data_size = this->data_size();
+ unsigned char* view = of->get_output_view(offset, data_size);
+ if (this->data_ == NULL)
+ memcpy(view, this->postprocessing_buffer(), data_size);
else
- {
- this->compressed_data_ = NULL;
- this->set_data_size(uncompressed_size);
- }
-
- delete[] uncompressed_data;
+ memcpy(view, this->data_, data_size);
+ of->write_output_view(offset, data_size, view);
}
-// Change the name of the output section to reflect it's compressed.
-// The layout routines call into this right before finalizing the
-// shstrtab.
-
-template<typename Char_type>
-const char*
-Output_compressed_string<Char_type>::do_modified_output_section_name(
- const char* name)
-{
- // This mean we never compressed the data
- if (this->new_section_name_.empty())
- return NULL;
- this->new_section_name_ = std::string(name) + this->new_section_name_;
- return this->new_section_name_.c_str();
-}
-
-// Write out a compressed string section. If we couldn't compress,
-// we just write out the normal string section.
-
-template<typename Char_type>
-void
-Output_compressed_string<Char_type>::do_write(Output_file* of)
-{
- if (this->compressed_data_ == NULL)
- Output_merge_string<Char_type>::do_write(of);
- else
- {
- unsigned char* uview = of->get_output_view(this->offset(),
- this->data_size());
- char* view = reinterpret_cast<char*>(uview);
- memcpy(view, this->compressed_data_, this->data_size());
- of->write_output_view(this->offset(), this->data_size(), uview);
- }
-}
-
-// Instantiate the templates we need.
-
-template
-class Output_compressed_string<char>;
-
-template
-class Output_compressed_string<uint16_t>;
-
-template
-class Output_compressed_string<uint32_t>;
-
} // End namespace gold.
diff --git a/gold/compressed_output.h b/gold/compressed_output.h
index 589dacc372d..d9bb0c4c460 100644
--- a/gold/compressed_output.h
+++ b/gold/compressed_output.h
@@ -29,106 +29,43 @@
#define GOLD_COMPRESSED_OUTPUT_H
#include <string>
-#include <vector>
#include "output.h"
-#include "merge.h"
namespace gold
{
class General_options;
-// This is used for compressing a section before emitting it in the
-// output file. This only works for unloaded sections, since it
-// assumes the final section contents are available at
-// set_final_data_size() time. For loaded sections (those that end up
-// in segments), this is not true; relocations are applied after
-// set_final_data_size() is called. However, for unloaded sections,
-// we can -- and do -- postpone calling finalize_data_size() until
-// after relocations are applies.
+// This is used for a section whose data should be compressed. It is
+// a regular Output_section which computes its contents into a buffer
+// and then postprocesses it.
-class Output_compressed_section_data : public Output_section_data
+class Output_compressed_section : public Output_section
{
public:
- Output_compressed_section_data(uint64_t addralign,
- const General_options& options)
- : Output_section_data(addralign), options_(options), data_(NULL)
- { }
+ Output_compressed_section(const General_options* options,
+ const char* name, elfcpp::Elf_Word flags,
+ elfcpp::Elf_Xword type)
+ : Output_section(name, flags, type),
+ options_(options)
+ { this->set_requires_postprocessing(); }
protected:
- // Add an input section.
- bool
- do_add_input_section(Relobj* object, unsigned int shndx);
-
// Set the final data size.
void
set_final_data_size();
- // Change the name of the output section to reflect it's compressed.
- const char*
- do_modified_output_section_name(const char* name);
-
- // Write the data to the file.
+ // Write out the compressed contents.
void
do_write(Output_file*);
private:
- struct Object_entry
- {
- Relobj* object;
- unsigned int shndx;
- const unsigned char* contents;
- off_t length;
-
- Object_entry(Relobj* o, unsigned int s)
- : object(o), shndx(s), contents(NULL), length(0)
- { }
- };
-
- const General_options& options_;
- std::vector<Object_entry> objects_;
+ // The options--this includes the compression type.
+ const General_options* options_;
+ // The compressed data.
char* data_;
- std::string new_section_name_;
-};
-
-// This is a special case for when the output section is a string
-// section and does not have any relocations to apply to it.
-
-template<typename Char_type>
-class Output_compressed_string : public Output_merge_string<Char_type>
-{
- public:
- Output_compressed_string(uint64_t addralign,
- const General_options& options)
- : Output_merge_string<Char_type>(addralign),
- options_(options), compressed_data_(NULL)
- { }
-
- ~Output_compressed_string()
- { delete[] compressed_data_; }
-
- protected:
- // Add an input section.
- bool
- do_add_input_section(Relobj* object, unsigned int shndx);
-
- // Set the final data size. Also compresses the buffer.
- void
- set_final_data_size();
-
- // Change the name of the output section to reflect it's compressed.
- const char*
- do_modified_output_section_name(const char* name);
-
- // Write the data to the file.
- void
- do_write(Output_file*);
-
- private:
- const General_options& options_;
- char* compressed_data_;
- // This is just a buffer to store the section name in "permanent" storage.
+ // The new section name if we do compress.
std::string new_section_name_;
};
diff --git a/gold/layout.cc b/gold/layout.cc
index f7c1e40be39..39008cd46fe 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -32,6 +32,7 @@
#include "symtab.h"
#include "dynobj.h"
#include "ehframe.h"
+#include "compressed_output.h"
#include "layout.h"
namespace gold
@@ -386,6 +387,22 @@ Layout::section_flags_to_segment(elfcpp::Elf_Xword flags)
return ret;
}
+// Sometimes we compress sections. This is typically done for
+// sections that are not part of normal program execution (such as
+// .debug_* sections), and where the readers of these sections know
+// how to deal with compressed sections. (To make it easier for them,
+// we will rename the ouput section in such cases from .foo to
+// .foo.zlib.nnnn, where nnnn is the uncompressed size.) This routine
+// doesn't say for certain whether we'll compress -- it depends on
+// commandline options as well -- just whether this section is a
+// candidate for compression.
+
+static bool
+is_compressible_debug_section(const char* secname)
+{
+ return (strncmp(secname, ".debug", sizeof(".debug") - 1) == 0);
+}
+
// Make a new Output_section, and attach it to segments as
// appropriate.
@@ -393,7 +410,14 @@ Output_section*
Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{
- Output_section* os = new Output_section(this->options_, name, type, flags);
+ Output_section* os;
+ if ((flags & elfcpp::SHF_ALLOC) == 0
+ && this->options_.compress_debug_sections()
+ && is_compressible_debug_section(name))
+ os = new Output_compressed_section(&this->options_, name, type, flags);
+ else
+ os = new Output_section(name, type, flags);
+
this->section_list_.push_back(os);
if ((flags & elfcpp::SHF_ALLOC) == 0)
@@ -1070,6 +1094,10 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
continue;
if (pass == BEFORE_INPUT_SECTIONS_PASS
+ && (*p)->requires_postprocessing())
+ (*p)->create_postprocessing_buffer();
+
+ if (pass == BEFORE_INPUT_SECTIONS_PASS
&& (*p)->after_input_sections())
continue;
else if (pass == AFTER_INPUT_SECTIONS_PASS
@@ -1085,23 +1113,14 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
(*p)->set_file_offset(off);
(*p)->finalize_data_size();
off += (*p)->data_size();
+
+ // At this point the name must be set.
+ if (pass != STRTAB_AFTER_INPUT_SECTIONS_PASS)
+ this->namepool_.add((*p)->name(), false, NULL);
}
return off;
}
-// Allow any section not associated with a segment to change its
-// output section name at the last minute.
-
-void
-Layout::modify_section_names()
-{
- for (Section_list::iterator p = this->unattached_section_list_.begin();
- p != this->unattached_section_list_.end();
- ++p)
- if ((*p)->maybe_modify_output_section_name())
- this->namepool_.add((*p)->name(), true, NULL);
-}
-
// Set the section indexes of all the sections not associated with a
// segment.
@@ -1911,10 +1930,6 @@ Layout::write_sections_after_input_sections(Output_file* of)
off_t off = this->output_file_size_;
off = this->set_section_offsets(off, AFTER_INPUT_SECTIONS_PASS);
- // Determine the final section names as well (at least, for sections
- // that we haven't written yet).
- this->modify_section_names();
-
// Now that we've finalized the names, we can finalize the shstrab.
off = this->set_section_offsets(off, STRTAB_AFTER_INPUT_SECTIONS_PASS);
diff --git a/gold/layout.h b/gold/layout.h
index cff29ed22a5..d909acec94b 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -356,12 +356,6 @@ class Layout
off_t
set_section_offsets(off_t, Section_offset_pass pass);
- // We also allow any section not associated with a segment to change
- // its output section name at the last minute. Compressed sections
- // use this to embed compression info in their name.
- void
- modify_section_names();
-
// Set the final section indexes of all the sections not associated
// with a segment. Returns the next unused index.
unsigned int
diff --git a/gold/merge.cc b/gold/merge.cc
index 215bc341c03..98ea89e1340 100644
--- a/gold/merge.cc
+++ b/gold/merge.cc
@@ -445,6 +445,14 @@ Output_merge_data::do_write(Output_file* of)
of->write(this->offset(), this->p_, this->len_);
}
+// Write the data to a buffer.
+
+void
+Output_merge_data::do_write_to_buffer(unsigned char* buffer)
+{
+ memcpy(buffer, this->p_, this->len_);
+}
+
// Class Output_merge_string.
// Add an input section to a merged string section.
@@ -535,6 +543,15 @@ Output_merge_string<Char_type>::do_write(Output_file* of)
this->stringpool_.write(of, this->offset());
}
+// Write a merged string section to a buffer.
+
+template<typename Char_type>
+void
+Output_merge_string<Char_type>::do_write_to_buffer(unsigned char* buffer)
+{
+ this->stringpool_.write_to_buffer(buffer, this->data_size());
+}
+
// Instantiate the templates we need.
template
diff --git a/gold/merge.h b/gold/merge.h
index a28ff425cf9..adafb0bc389 100644
--- a/gold/merge.h
+++ b/gold/merge.h
@@ -120,6 +120,10 @@ class Output_merge_data : public Output_merge_base
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char*);
+
private:
// We build a hash table of the fixed-size constants. Each constant
// is stored as a pointer into the section data we are accumulating.
@@ -227,9 +231,13 @@ class Output_merge_string : public Output_merge_base
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char*);
+
// Writes the stringpool to a buffer.
void
- stringpool_to_buffer(char* buffer, size_t buffer_size)
+ stringpool_to_buffer(unsigned char* buffer, size_t buffer_size)
{ this->stringpool_.write_to_buffer(buffer, buffer_size); }
// Clears all the data in the stringpool, to save on memory.
diff --git a/gold/object.cc b/gold/object.cc
index ecefa8bf393..fee249fbc55 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -1103,8 +1103,7 @@ Input_objects::add_object(Object* obj)
}
}
- set_parameters_size_and_endianness(target->get_size(),
- target->is_big_endian());
+ set_parameters_target(target);
return true;
}
diff --git a/gold/object.h b/gold/object.h
index 6991d264700..40839bc7f41 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -960,6 +960,7 @@ class Sized_relobj : public Relobj
off_t offset;
off_t view_size;
bool is_input_output_view;
+ bool is_postprocessing_view;
};
typedef std::vector<View_size> Views;
diff --git a/gold/output.cc b/gold/output.cc
index 351c21dee3f..59658c79942 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -32,7 +32,6 @@
#include "libiberty.h" // for unlink_if_ordinary()
#include "parameters.h"
-#include "compressed_output.h"
#include "object.h"
#include "symtab.h"
#include "reloc.h"
@@ -987,13 +986,25 @@ Output_section::Input_section::data_size() const
// Set the address and file offset.
void
-Output_section::Input_section::set_address(uint64_t addr, off_t off,
- off_t secoff)
+Output_section::Input_section::set_address_and_file_offset(
+ uint64_t address,
+ off_t file_offset,
+ off_t section_file_offset)
{
if (this->is_input_section())
- this->u2_.object->set_section_offset(this->shndx_, off - secoff);
+ this->u2_.object->set_section_offset(this->shndx_,
+ file_offset - section_file_offset);
else
- this->u2_.posd->set_address_and_file_offset(addr, off);
+ this->u2_.posd->set_address_and_file_offset(address, file_offset);
+}
+
+// Finalize the data size.
+
+void
+Output_section::Input_section::finalize_data_size()
+{
+ if (!this->is_input_section())
+ this->u2_.posd->finalize_data_size();
}
// Try to turn an input offset into an output offset.
@@ -1030,15 +1041,23 @@ Output_section::Input_section::write(Output_file* of)
this->u2_.posd->write(of);
}
+// Write the data to a buffer. As for write(), we don't have to do
+// anything for an input section.
+
+void
+Output_section::Input_section::write_to_buffer(unsigned char* buffer)
+{
+ if (!this->is_input_section())
+ this->u2_.posd->write_to_buffer(buffer);
+}
+
// Output_section methods.
// Construct an Output_section. NAME will point into a Stringpool.
-Output_section::Output_section(const General_options& options,
- const char* name, elfcpp::Elf_Word type,
+Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
- : options_(options),
- name_(name),
+ : name_(name),
addralign_(0),
entsize_(0),
link_section_(NULL),
@@ -1053,6 +1072,7 @@ Output_section::Output_section(const General_options& options,
input_sections_(),
first_input_offset_(0),
fills_(),
+ postprocessing_buffer_(NULL),
needs_symtab_index_(false),
needs_dynsym_index_(false),
should_link_to_symtab_(false),
@@ -1082,22 +1102,6 @@ Output_section::set_entsize(uint64_t v)
gold_assert(this->entsize_ == v);
}
-// Sometimes we compress sections. This is typically done for
-// sections that are not part of normal program execution (such as
-// .debug_* sections), and where the readers of these sections know
-// how to deal with compressed sections. (To make it easier for them,
-// we will rename the ouput section in such cases from .foo to
-// .foo.zlib.nnnn, where nnnn is the uncompressed size.) This routine
-// doesn't say for certain whether we'll compress -- it depends on
-// commandline options as well -- just whether this section is a
-// candidate for compression.
-
-static bool
-is_compressible_section(const char* secname)
-{
- return (strncmp(secname, ".debug", sizeof(".debug") - 1) == 0);
-}
-
// Add the input section SHNDX, with header SHDR, named SECNAME, in
// OBJECT, to the Output_section. RELOC_SHNDX is the index of a
// relocation section which applies to this section, or 0 if none, or
@@ -1145,8 +1149,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
&& reloc_shndx == 0)
{
if (this->add_merge_input_section(object, shndx, sh_flags,
- entsize, addralign,
- is_compressible_section(secname)))
+ entsize, addralign))
{
// Tell the relocation routines that they need to call the
// output_offset method to determine the final address.
@@ -1233,8 +1236,7 @@ Output_section::add_output_merge_section(Output_section_data* posd,
bool
Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
uint64_t flags, uint64_t entsize,
- uint64_t addralign,
- bool is_compressible_section)
+ uint64_t addralign)
{
bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
@@ -1258,25 +1260,6 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
Output_section_data* posd;
if (!is_string)
posd = new Output_merge_data(entsize, addralign);
- else if (is_compressible_section && options_.compress_debug_sections())
- {
- switch (entsize)
- {
- case 1:
- posd = new Output_compressed_string<char>(addralign, this->options_);
- break;
- case 2:
- posd = new Output_compressed_string<uint16_t>(addralign,
- this->options_);
- break;
- case 4:
- posd = new Output_compressed_string<uint32_t>(addralign,
- this->options_);
- break;
- default:
- return false;
- }
- }
else
{
switch (entsize)
@@ -1407,36 +1390,14 @@ Output_section::set_final_data_size()
++p)
{
off = align_address(off, p->addralign());
- p->set_address(address + (off - startoff), off, startoff);
+ p->set_address_and_file_offset(address + (off - startoff), off,
+ startoff);
off += p->data_size();
}
this->set_data_size(off - startoff);
}
-// Ask each output_section_data member if it wants to change the name
-// of the output section. If any of them says yes, use this to set
-// the new name. This should be called after all processing of this
-// output section is done, but before the name is finally committed to
-// the output-section's header.
-
-bool
-Output_section::maybe_modify_output_section_name()
-{
- for (Input_section_list::const_iterator it = input_sections_.begin();
- it != input_sections_.end();
- ++it)
- {
- const char* newname = it->modified_output_section_name(this->name());
- if (newname != NULL)
- {
- this->set_name(newname);
- return true;
- }
- }
- return false;
-}
-
// Write the section header to *OSHDR.
template<int size, bool big_endian>
@@ -1474,6 +1435,8 @@ Output_section::write_header(const Layout* layout,
void
Output_section::do_write(Output_file* of)
{
+ gold_assert(!this->requires_postprocessing());
+
off_t output_section_file_offset = this->offset();
for (Fill_list::iterator p = this->fills_.begin();
p != this->fills_.end();
@@ -1490,6 +1453,63 @@ Output_section::do_write(Output_file* of)
p->write(of);
}
+// If a section requires postprocessing, create the buffer to use.
+
+void
+Output_section::create_postprocessing_buffer()
+{
+ gold_assert(this->requires_postprocessing());
+ gold_assert(this->postprocessing_buffer_ == NULL);
+
+ if (!this->input_sections_.empty())
+ {
+ off_t off = this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ p->finalize_data_size();
+ off += p->data_size();
+ }
+ this->set_current_data_size_for_child(off);
+ }
+
+ off_t buffer_size = this->current_data_size_for_child();
+ this->postprocessing_buffer_ = new unsigned char[buffer_size];
+}
+
+// Write all the data of an Output_section into the postprocessing
+// buffer. This is used for sections which require postprocessing,
+// such as compression. Input sections are handled by
+// Object::Relocate.
+
+void
+Output_section::write_to_postprocessing_buffer()
+{
+ gold_assert(this->requires_postprocessing());
+
+ Target* target = parameters->target();
+ unsigned char* buffer = this->postprocessing_buffer();
+ for (Fill_list::iterator p = this->fills_.begin();
+ p != this->fills_.end();
+ ++p)
+ {
+ std::string fill_data(target->code_fill(p->length()));
+ memcpy(buffer + p->section_offset(), fill_data.data(), fill_data.size());
+ }
+
+ off_t off = this->first_input_offset_;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ off = align_address(off, p->addralign());
+ p->write_to_buffer(buffer + off);
+ off += p->data_size();
+ }
+}
+
// Output segment methods.
Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
diff --git a/gold/output.h b/gold/output.h
index 95d95f65582..fafd62b1faa 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -432,15 +432,6 @@ class Output_section_data : public Output_data
add_input_section(Relobj* object, unsigned int shndx)
{ return this->do_add_input_section(object, shndx); }
- // This class may change the output section name. This is called
- // right before shstrtab is written, so after all input-section
- // layout processing is done. The input is the old name, and the
- // output should be a new name (which will be copied into permanent
- // storage) to change the name, or NULL to keep the name as-is.
- virtual const char*
- do_modified_output_section_name(const char*)
- { return NULL; }
-
// Given an input OBJECT, an input section index SHNDX within that
// object, and an OFFSET relative to the start of that input
// section, return whether or not the corresponding offset within
@@ -452,6 +443,12 @@ class Output_section_data : public Output_data
off_t *poutput) const
{ return this->do_output_offset(object, shndx, offset, poutput); }
+ // Write the contents to a buffer. This is used for sections which
+ // require postprocessing, such as compression.
+ void
+ write_to_buffer(unsigned char* buffer)
+ { this->do_write_to_buffer(buffer); }
+
protected:
// The child class must implement do_write.
@@ -472,6 +469,13 @@ class Output_section_data : public Output_data
do_output_offset(const Relobj*, unsigned int, off_t, off_t*) const
{ return false; }
+ // The child class may implement write_to_buffer. Most child
+ // classes can not appear in a compressed section, and they do not
+ // implement this.
+ virtual void
+ do_write_to_buffer(unsigned char*)
+ { gold_unreachable(); }
+
// Return the required alignment.
uint64_t
do_addralign() const
@@ -545,6 +549,11 @@ class Output_data_const : public Output_section_data
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { memcpy(buffer, this->data_.data(), this->data_.size()); }
+
private:
std::string data_;
};
@@ -565,6 +574,11 @@ class Output_data_const_buffer : public Output_section_data
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { memcpy(buffer, this->p_, this->data_size()); }
+
private:
const unsigned char* p_;
};
@@ -629,6 +643,11 @@ class Output_data_strtab : public Output_section_data
void
do_write(Output_file*);
+ // Write the data to a buffer.
+ void
+ do_write_to_buffer(unsigned char* buffer)
+ { this->strtab_->write_to_buffer(buffer, this->data_size()); }
+
private:
Stringpool* strtab_;
};
@@ -1317,8 +1336,7 @@ class Output_section : public Output_data
{
public:
// Create an output section, giving the name, type, and flags.
- Output_section(const General_options& options,
- const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
+ Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
virtual ~Output_section();
// Add a new input section SHNDX, named NAME, with header SHDR, from
@@ -1341,13 +1359,6 @@ class Output_section : public Output_data
name() const
{ return this->name_; }
- // Modify the section name. This should be called only after this
- // section is done being constructed. The input should be a pointer
- // into layout's namepool_.
- void
- set_name(const char* newname)
- { this->name_ = newname; }
-
// Return the section type.
elfcpp::Elf_Word
type() const
@@ -1506,11 +1517,23 @@ class Output_section : public Output_data
requires_postprocessing() const
{ return this->requires_postprocessing_; }
- // Record that this section requires postprocessing after all
- // relocations have been applied.
+ // If a section requires postprocessing, return the buffer to use.
+ unsigned char*
+ postprocessing_buffer() const
+ {
+ gold_assert(this->postprocessing_buffer_ != NULL);
+ return this->postprocessing_buffer_;
+ }
+
+ // If a section requires postprocessing, create the buffer to use.
void
- set_requires_postprocessing()
- { this->requires_postprocessing_ = true; }
+ create_postprocessing_buffer();
+
+ // If a section requires postprocessing, this is the size of the
+ // buffer to which relocations should be applied.
+ off_t
+ postprocessing_buffer_size() const
+ { return this->current_data_size_for_child(); }
// Return whether the offset OFFSET in the input section SHNDX in
// object OBJECT is being included in the link.
@@ -1535,16 +1558,6 @@ class Output_section : public Output_data
write_header(const Layout*, const Stringpool*,
elfcpp::Shdr_write<size, big_endian>*) const;
- // This class may change the output section name. This is called
- // right before shstrtab is written, so after all input-section
- // layout processing is done. This calls
- // do_modified_output_section_name() on all its output_section_data
- // members, and changes the name if any member so suggests. If
- // several members would suggest, this takes the first, arbitrarily.
- // Return true if the name was modified, false else.
- bool
- maybe_modify_output_section_name();
-
protected:
// Return the section index in the output file.
unsigned int
@@ -1566,14 +1579,14 @@ class Output_section : public Output_data
// Output_section, there is nothing to do, but if there are any
// Output_section_data objects we need to set their final addresses
// here.
- void
+ virtual void
set_final_data_size();
// 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
// objects we do need to write them out here.
- void
+ virtual void
do_write(Output_file*);
// Return the address alignment--function required by parent class.
@@ -1596,6 +1609,36 @@ class Output_section : public Output_data
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
{ return (this->flags_ & flag) != 0; }
+ // Modify the section name. This is only permitted for an
+ // unallocated section, and only before the size has been finalized.
+ // Otherwise the name will not get into Layout::namepool_.
+ void
+ set_name(const char* newname)
+ {
+ gold_assert((this->flags_ & elfcpp::SHF_ALLOC) == 0);
+ gold_assert(!this->is_data_size_valid());
+ this->name_ = newname;
+ }
+
+ // This may be implemented by a child class.
+ virtual void
+ do_finalize_name(Layout*)
+ { }
+
+ // Record that this section requires postprocessing after all
+ // relocations have been applied. This is called by a child class.
+ void
+ set_requires_postprocessing()
+ {
+ this->requires_postprocessing_ = true;
+ this->after_input_sections_ = true;
+ }
+
+ // Write all the data of an Output_section into the postprocessing
+ // buffer.
+ void
+ write_to_postprocessing_buffer();
+
private:
// In some cases we need to keep a list of the input sections
// associated with this output section. We only need the list if we
@@ -1685,19 +1728,15 @@ class Output_section : public Output_data
}
// Set the address and file offset. This is called during
- // Layout::finalize. SECOFF is the file offset of the enclosing
- // section.
+ // Layout::finalize. SECTION_FILE_OFFSET is the file offset of
+ // the enclosing section.
void
- set_address(uint64_t addr, off_t off, off_t secoff);
+ set_address_and_file_offset(uint64_t address, off_t file_offset,
+ off_t section_file_offset);
- // Call modified_output_section_name on the output-section-data object.
- const char*
- modified_output_section_name(const char* name) const
- {
- if (this->is_input_section())
- return NULL;
- return this->u2_.posd->do_modified_output_section_name(name);
- }
+ // Finalize the data size.
+ void
+ finalize_data_size();
// Add an input section, for SHF_MERGE sections.
bool
@@ -1721,6 +1760,11 @@ class Output_section : public Output_data
void
write(Output_file*);
+ // Write the data to a buffer. This does nothing for an input
+ // section.
+ void
+ write_to_buffer(unsigned char*);
+
private:
// Code values which appear in shndx_. If the value is not one of
// these codes, it is the input section index in the object file.
@@ -1813,8 +1857,7 @@ class Output_section : public Output_data
// handled.
bool
add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
- uint64_t entsize, uint64_t addralign,
- bool can_compress_section);
+ uint64_t entsize, uint64_t addralign);
// Add an output SHF_MERGE section POSD to this output section.
// IS_STRING indicates whether it is a SHF_STRINGS section, and
@@ -1826,8 +1869,6 @@ class Output_section : public Output_data
// Most of these fields are only valid after layout.
- // General options.
- const General_options& options_;
// The name of the section. This will point into a Stringpool.
const char* name_;
// The section address is in the parent class.
@@ -1869,6 +1910,9 @@ class Output_section : public Output_data
// often will need fill sections without needing to keep track of
// input sections.
Fill_list fills_;
+ // If the section requires postprocessing, this buffer holds the
+ // section contents during relocation.
+ unsigned char* postprocessing_buffer_;
// Whether this output section needs a STT_SECTION symbol in the
// normal symbol table. This will be true if there is a relocation
// which needs it.
diff --git a/gold/parameters.cc b/gold/parameters.cc
index cd05ffee8dd..e6b96825353 100644
--- a/gold/parameters.cc
+++ b/gold/parameters.cc
@@ -23,6 +23,7 @@
#include "gold.h"
#include "options.h"
+#include "target.h"
#include "parameters.h"
namespace gold
@@ -37,7 +38,7 @@ Parameters::Parameters(Errors* errors)
symbolic_(false), demangle_(false), detect_odr_violations_(false),
optimization_level_(0), export_dynamic_(false), debug_(0),
is_doing_static_link_valid_(false), doing_static_link_(false),
- is_size_and_endian_valid_(false), size_(0), is_big_endian_(false)
+ is_target_valid_(false), target_(NULL)
{
}
@@ -85,22 +86,20 @@ Parameters::set_doing_static_link(bool doing_static_link)
this->is_doing_static_link_valid_ = true;
}
-// Set the size and endianness.
+// Set the target.
void
-Parameters::set_size_and_endianness(int size, bool is_big_endian)
+Parameters::set_target(Target* target)
{
- if (!this->is_size_and_endian_valid_)
+ if (!this->is_target_valid_)
{
- this->size_ = size;
- this->is_big_endian_ = is_big_endian;
- this->is_size_and_endian_valid_ = true;
+ this->target_ = target;
+ this->size_ = target->get_size();
+ this->is_big_endian_ = target->is_big_endian();
+ this->is_target_valid_ = true;
}
else
- {
- gold_assert(size == this->size_);
- gold_assert(is_big_endian == this->is_big_endian_);
- }
+ gold_assert(target == this->target_);
}
// Our local version of the variable, which is not const.
@@ -135,12 +134,12 @@ set_parameters_doing_static_link(bool doing_static_link)
static_parameters->set_doing_static_link(doing_static_link);
}
-// Set the size and endianness.
+// Set the target.
void
-set_parameters_size_and_endianness(int size, bool is_big_endian)
+set_parameters_target(Target* target)
{
- static_parameters->set_size_and_endianness(size, is_big_endian);
+ static_parameters->set_target(target);
}
} // End namespace gold.
diff --git a/gold/parameters.h b/gold/parameters.h
index 4b764e32149..2467295c857 100644
--- a/gold/parameters.h
+++ b/gold/parameters.h
@@ -28,6 +28,7 @@ namespace gold
class General_options;
class Errors;
+class Target;
// Here we define the Parameters class which simply holds simple
// general parameters which apply to the entire link. We use a global
@@ -199,12 +200,20 @@ class Parameters
return this->doing_static_link_;
}
+ // The target of the output file we are generating.
+ Target*
+ target() const
+ {
+ gold_assert(this->is_target_valid_);
+ return this->target_;
+ }
+
// The size of the output file we are generating. This should
// return 32 or 64.
int
get_size() const
{
- gold_assert(this->is_size_and_endian_valid_);
+ gold_assert(this->is_target_valid_);
return this->size_;
}
@@ -212,7 +221,7 @@ class Parameters
bool
is_big_endian() const
{
- gold_assert(this->is_size_and_endian_valid_);
+ gold_assert(this->is_target_valid_);
return this->is_big_endian_;
}
@@ -224,9 +233,9 @@ class Parameters
void
set_doing_static_link(bool doing_static_link);
- // Set the size and endianness.
+ // Set the target.
void
- set_size_and_endianness(int size, bool is_big_endian);
+ set_target(Target* target);
private:
// The types of output files.
@@ -291,8 +300,10 @@ class Parameters
bool is_doing_static_link_valid_;
// Whether we are doing a static link.
bool doing_static_link_;
- // Whether the size_ and is_big_endian_ fields are valid.
- bool is_size_and_endian_valid_;
+ // Whether the target_ field is valid.
+ bool is_target_valid_;
+ // The target.
+ Target* target_;
// The size of the output file--32 or 64.
int size_;
// Whether the output file is big endian.
@@ -308,8 +319,8 @@ extern void initialize_parameters(Errors*);
// Set the options.
extern void set_parameters_from_options(const General_options*);
-// Set the size and endianness of the global parameters variable.
-extern void set_parameters_size_and_endianness(int size, bool is_big_endian);
+// Set the target recorded in the global parameters variable.
+extern void set_parameters_target(Target* target);
// Set whether we are doing a static link.
extern void set_parameters_doing_static_link(bool doing_static_link);
diff --git a/gold/reloc.cc b/gold/reloc.cc
index d50674f6d77..2763be5ba4b 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -376,12 +376,16 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
{
if (views[i].view != NULL)
{
- if (views[i].is_input_output_view)
- of->write_input_output_view(views[i].offset, views[i].view_size,
- views[i].view);
- else
- of->write_output_view(views[i].offset, views[i].view_size,
- views[i].view);
+ if (!views[i].is_postprocessing_view)
+ {
+ if (views[i].is_input_output_view)
+ of->write_input_output_view(views[i].offset,
+ views[i].view_size,
+ views[i].view);
+ else
+ of->write_output_view(views[i].offset, views[i].view_size,
+ views[i].view);
+ }
}
}
@@ -419,17 +423,50 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
continue;
+ // In the normal case, this input section is simply mapped to
+ // the output section at offset OUTPUT_OFFSET.
+
+ // However, if OUTPUT_OFFSET == -1, then input data is handled
+ // specially--e.g., a .eh_frame section. The relocation
+ // routines need to check for each reloc where it should be
+ // applied. For this case, we need an input/output view for the
+ // entire contents of the section in the output file. We don't
+ // want to copy the contents of the input section to the output
+ // section; the output section contents were already written,
+ // and we waited for them in Relocate_task::is_runnable because
+ // relocs_must_follow_section_writes is set for the object.
+
+ // Regardless of which of the above cases is true, we have to
+ // check requires_postprocessing of the output section. If that
+ // is false, then we work with views of the output file
+ // directly. If it is true, then we work with a separate
+ // buffer, and the output section is responsible for writing the
+ // final data to the output file.
+
+ off_t output_section_offset;
+ off_t output_section_size;
+ if (!os->requires_postprocessing())
+ {
+ output_section_offset = os->offset();
+ output_section_size = os->data_size();
+ }
+ else
+ {
+ output_section_offset = 0;
+ output_section_size = os->postprocessing_buffer_size();
+ }
+
off_t view_start;
off_t view_size;
if (output_offset != -1)
{
- view_start = os->offset() + output_offset;
+ view_start = output_section_offset + output_offset;
view_size = shdr.get_sh_size();
}
else
{
- view_start = os->offset();
- view_size = os->data_size();
+ view_start = output_section_offset;
+ view_size = output_section_size;
}
if (view_size == 0)
@@ -437,15 +474,25 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
gold_assert(output_offset == -1
|| (output_offset >= 0
- && output_offset + view_size <= os->data_size()));
+ && output_offset + view_size <= output_section_size));
unsigned char* view;
- if (output_offset == -1)
- view = of->get_input_output_view(view_start, view_size);
+ if (os->requires_postprocessing())
+ {
+ unsigned char* buffer = os->postprocessing_buffer();
+ view = buffer + view_start;
+ if (output_offset != -1)
+ this->read(shdr.get_sh_offset(), view_size, view);
+ }
else
{
- view = of->get_output_view(view_start, view_size);
- this->read(shdr.get_sh_offset(), view_size, view);
+ if (output_offset == -1)
+ view = of->get_input_output_view(view_start, view_size);
+ else
+ {
+ view = of->get_output_view(view_start, view_size);
+ this->read(shdr.get_sh_offset(), view_size, view);
+ }
}
pvs->view = view;
@@ -455,6 +502,7 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
pvs->offset = view_start;
pvs->view_size = view_size;
pvs->is_input_output_view = output_offset == -1;
+ pvs->is_postprocessing_view = os->requires_postprocessing();
}
}
@@ -543,6 +591,9 @@ Sized_relobj<size, big_endian>::relocate_sections(
continue;
}
+ gold_assert(output_offset != -1
+ || this->relocs_must_follow_section_writes());
+
relinfo.reloc_shndx = i;
relinfo.data_shndx = index;
target->relocate_section(&relinfo,
diff --git a/gold/stringpool.cc b/gold/stringpool.cc
index 42a2fdabfdb..6d3ecfa0e17 100644
--- a/gold/stringpool.cc
+++ b/gold/stringpool.cc
@@ -426,7 +426,7 @@ Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s)
template<typename Stringpool_char>
void
-Stringpool_template<Stringpool_char>::write_to_buffer(char* buffer,
+Stringpool_template<Stringpool_char>::write_to_buffer(unsigned char* buffer,
size_t bufsize)
{
gold_assert(this->strtab_size_ != 0);
@@ -452,7 +452,7 @@ Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset)
{
gold_assert(this->strtab_size_ != 0);
unsigned char* view = of->get_output_view(offset, this->strtab_size_);
- this->write_to_buffer(reinterpret_cast<char*>(view), this->strtab_size_);
+ this->write_to_buffer(view, this->strtab_size_);
of->write_output_view(offset, this->strtab_size_, view);
}
diff --git a/gold/stringpool.h b/gold/stringpool.h
index 57725a5c599..e902b8e4aae 100644
--- a/gold/stringpool.h
+++ b/gold/stringpool.h
@@ -147,7 +147,7 @@ class Stringpool_template
// specified size. buffer_size should be at least
// get_strtab_size().
void
- write_to_buffer(char* buffer, size_t buffer_size);
+ write_to_buffer(unsigned char* buffer, size_t buffer_size);
private:
Stringpool_template(const Stringpool_template&);