Compress all debug sections.

This commit is contained in:
Ian Lance Taylor 2007-12-01 06:34:12 +00:00
parent f80c84b330
commit 96803768f1
15 changed files with 386 additions and 417 deletions

View File

@ -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)
Output_compressed_section::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()
{
// 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.

View File

@ -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_;
};

View File

@ -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)
@ -1069,6 +1093,10 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
if (*p == this->symtab_section_)
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;
@ -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);

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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&);