summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2012-12-08 09:07:30 +1100
committerChris Johns <chrisj@rtems.org>2012-12-08 09:07:30 +1100
commit4c10232ae7298504c124c33a8c0dc27c86dad5b5 (patch)
treef2745cad4ebf5cb07111191fe6f0cd8b7dd22cd5
parentc6add3b2f603f4cf9be8bfe4bb4c27ccf9c086fa (diff)
Add support to demand load relocation records.
Support has been added to load relocation record on demand. The relocation records are not read when the object file is first opened and read. They are read only when being written to the output file. This save loading lots of records into memory from libraries to be thrown away. The RAP format now supports writing out relocation records.
-rw-r--r--rld-elf-types.h31
-rw-r--r--rld-elf.cpp231
-rw-r--r--rld-elf.h114
-rw-r--r--rld-files.cpp53
-rw-r--r--rld-files.h47
-rw-r--r--rld-rap.cpp416
-rw-r--r--rld-symbols.cpp37
-rw-r--r--rld-symbols.h17
8 files changed, 786 insertions, 160 deletions
diff --git a/rld-elf-types.h b/rld-elf-types.h
index a272587..c305976 100644
--- a/rld-elf-types.h
+++ b/rld-elf-types.h
@@ -36,20 +36,23 @@ namespace rld
/**
* Hide the types from libelf we use.
*/
- typedef ::GElf_Half elf_half;
- typedef ::GElf_Word elf_word;
- typedef ::GElf_Xword elf_xword;
- typedef ::Elf_Type elf_type;
- typedef ::GElf_Addr elf_addr;
- typedef ::GElf_Off elf_off;
- typedef ::GElf_Sym elf_sym;
- typedef ::Elf_Kind elf_kind;
- typedef ::Elf_Scn elf_scn;
- typedef ::GElf_Ehdr elf_ehdr;
- typedef ::GElf_Shdr elf_shdr;
- typedef ::GElf_Phdr elf_phdr;
- typedef ::Elf_Data elf_data;
- typedef ::Elf elf;
+ typedef ::GElf_Half elf_half;
+ typedef ::GElf_Word elf_word;
+ typedef ::GElf_Xword elf_xword;
+ typedef ::GElf_Sxword elf_sxword;
+ typedef ::Elf_Type elf_type;
+ typedef ::GElf_Addr elf_addr;
+ typedef ::GElf_Off elf_off;
+ typedef ::GElf_Sym elf_sym;
+ typedef ::Elf_Kind elf_kind;
+ typedef ::Elf_Scn elf_scn;
+ typedef ::GElf_Ehdr elf_ehdr;
+ typedef ::GElf_Shdr elf_shdr;
+ typedef ::GElf_Phdr elf_phdr;
+ typedef ::Elf_Data elf_data;
+ typedef ::GElf_Rel elf_rel;
+ typedef ::GElf_Rela elf_rela;
+ typedef ::Elf elf;
}
}
diff --git a/rld-elf.cpp b/rld-elf.cpp
index 13ed1ab..2e1f10e 100644
--- a/rld-elf.cpp
+++ b/rld-elf.cpp
@@ -64,6 +64,57 @@ namespace rld
}
}
+ relocation::relocation (const symbols::symbol& sym,
+ elf_addr offset,
+ elf_xword info,
+ elf_sxword addend)
+ : sym (&sym),
+ offset_ (offset),
+ info_ (info),
+ addend_ (addend)
+ {
+ }
+
+ relocation::relocation ()
+ : sym (0),
+ offset_ (0),
+ info_ (0),
+ addend_ (0)
+ {
+ }
+
+ std::string
+ relocation::name () const
+ {
+ if (sym)
+ return sym->name ();
+ return "";
+ }
+
+ elf_addr
+ relocation::offset () const
+ {
+ return offset_;
+ }
+
+ uint32_t
+ relocation::type () const
+ {
+ return GELF_R_TYPE (info_);
+ }
+
+ elf_xword
+ relocation::info () const
+ {
+ return info_;
+ }
+
+ elf_sxword
+ relocation::addend () const
+ {
+ return addend_;
+ }
+
section::section (file& file_,
int index_,
const std::string& name_,
@@ -80,7 +131,8 @@ namespace rld
index_ (index_),
name_ (name_),
scn (0),
- data_ (0)
+ data_ (0),
+ rela (false)
{
if (!file_.is_writable ())
throw rld::error ("not writable",
@@ -115,7 +167,8 @@ namespace rld
: file_ (&file_),
index_ (index_),
scn (0),
- data_ (0)
+ data_ (0),
+ rela (false)
{
memset (&shdr, 0, sizeof (shdr));
@@ -141,7 +194,9 @@ namespace rld
name_ (orig.name_),
scn (orig.scn),
shdr (orig.shdr),
- data_ (orig.data_)
+ data_ (orig.data_),
+ rela (orig.rela),
+ relocs (orig.relocs)
{
}
@@ -149,7 +204,8 @@ namespace rld
: file_ (0),
index_ (-1),
scn (0),
- data_ (0)
+ data_ (0),
+ rela (false)
{
memset (&shdr, 0, sizeof (shdr));
}
@@ -268,6 +324,12 @@ namespace rld
return size () / entry_size ();
}
+ bool
+ section::get_reloc_type () const
+ {
+ return rela;
+ }
+
void
section::set_name (unsigned int index)
{
@@ -278,6 +340,24 @@ namespace rld
}
void
+ section::set_reloc_type (bool rela_)
+ {
+ rela = rela_;
+ }
+
+ void
+ section::add (const relocation& reloc)
+ {
+ relocs.push_back (reloc);
+ }
+
+ const relocations&
+ section::get_relocations () const
+ {
+ return relocs;
+ }
+
+ void
section::check (const char* where) const
{
if (!file_ || (index_ < 0) || !scn)
@@ -660,11 +740,38 @@ namespace rld
}
}
+ section&
+ file::get_section (int index)
+ {
+ load_sections ();
+ for (section_table::iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ section& sec = (*si).second;
+ if (index == sec.index ())
+ return sec;
+ }
+
+ throw rld::error ("section index '" + rld::to_string (index) + "'not found",
+ "elf:file:get_section: " + name_);
+ }
+
+ int
+ file::strings_section () const
+ {
+ check_ehdr ("strings_sections");
+ return ehdr->e_shstrndx;
+ }
+
void
file::load_symbols ()
{
if (symbols.empty ())
{
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:symbol: " << name () << std::endl;
+
sections symbol_secs;
get_sections (symbol_secs, SHT_SYMTAB);
@@ -683,21 +790,17 @@ namespace rld
if (!::gelf_getsym (sec.data (), s, &esym))
error ("gelf_getsym");
- std::string name = get_string (sec.link (), esym.st_name);
+ std::string name = get_string (sec.link (), esym.st_name);
+ symbols::symbol sym (s, name, esym);
- if (!name.empty ())
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
{
- symbols::symbol sym (name, esym);
-
- if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
- {
- std::cout << "elf:symbol: ";
- sym.output (std::cout);
- std::cout << std::endl;
- }
-
- symbols.push_back (sym);
+ std::cout << "elf:symbol: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
}
+
+ symbols.push_back (sym);
}
}
}
@@ -740,7 +843,9 @@ namespace rld
*/
bool add = false;
- if ((stype == STT_NOTYPE) && (sym.index () == SHN_UNDEF))
+ if ((stype == STT_NOTYPE) &&
+ (sbind == STB_GLOBAL) &&
+ (sym.section_index () == SHN_UNDEF))
{
if (unresolved)
add = true;
@@ -761,11 +866,95 @@ namespace rld
}
}
- int
- file::strings_section () const
+ const symbols::symbol&
+ file::get_symbol (const int index) const
{
- check_ehdr ("strings_sections");
- return ehdr->e_shstrndx;
+ for (symbols::bucket::const_iterator si = symbols.begin ();
+ si != symbols.end ();
+ ++si)
+ {
+ const symbols::symbol& sym = *si;
+ if (index == sym.index ())
+ return sym;
+ }
+
+ throw rld::error ("symbol index '" + rld::to_string (index) + "' not found",
+ "elf:file:get_symbol: " + name_);
+ }
+
+ void
+ file::load_relocations ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: " << name () << std::endl;
+
+ sections rel_secs;
+
+ get_sections (rel_secs, SHT_REL);
+ get_sections (rel_secs, SHT_RELA);
+
+ for (sections::iterator si = rel_secs.begin ();
+ si != rel_secs.end ();
+ ++si)
+ {
+ section& sec = *(*si);
+ section& targetsec = get_section (sec.info ());
+ int rels = sec.entries ();
+ bool rela = sec.type () == SHT_RELA;
+
+ targetsec.set_reloc_type (rela);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: " << sec.name ()
+ << " -> " << targetsec.name ()
+ << std::endl;
+
+ for (int r = 0; r < rels; ++r)
+ {
+ if (rela)
+ {
+ elf_rela erela;
+
+ if (!::gelf_getrela (sec.data (), r, &erela))
+ error ("gelf_getrela");
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: rela: offset: " << erela.r_offset
+ << " sym:" << GELF_R_SYM (erela.r_info)
+ << " type:" << GELF_R_TYPE (erela.r_info)
+ << " addend:" << erela.r_addend
+ << std::endl;
+
+ const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info));
+
+ relocation reloc (sym,
+ erela.r_offset,
+ erela.r_info,
+ erela.r_addend);
+
+ targetsec.add (reloc);
+ }
+ else
+ {
+ elf_rel erel;
+
+ if (!::gelf_getrel (sec.data (), r, &erel))
+ error ("gelf_getrel");
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "elf:reloc: rel: offset: " << erel.r_offset
+ << " sym:" << GELF_R_SYM (erel.r_info)
+ << " type:" << GELF_R_TYPE (erel.r_info)
+ << std::endl;
+
+ const symbols::symbol& sym = get_symbol (erel.r_info);
+
+ relocation reloc (sym, erel.r_offset, erel.r_info);
+
+ targetsec.add (reloc);
+ }
+ }
+ }
}
std::string
diff --git a/rld-elf.h b/rld-elf.h
index a856892..780b486 100644
--- a/rld-elf.h
+++ b/rld-elf.h
@@ -27,6 +27,7 @@
#include <list>
#include <map>
+#include <vector>
#include <rld.h>
@@ -40,6 +41,66 @@ namespace rld
class file;
/**
+ * A relocation record.
+ */
+ class relocation
+ {
+ public:
+ /**
+ * Construct a relocation record.
+ *
+ * @param offset The offset in the section the relocation applies to.
+ * @param info The relocation info.
+ * @param addend The constant addend value.
+ */
+ relocation (const symbols::symbol& sym,
+ elf_addr offset,
+ elf_xword info,
+ elf_sxword addend = 0);
+
+ /**
+ * Default constructor.
+ */
+ relocation ();
+
+ /**
+ * The name of the symbol.
+ */
+ std::string name () const;
+
+ /**
+ * The offset.
+ */
+ elf_addr offset () const;
+
+ /**
+ * The type of the relocation record.
+ */
+ uint32_t type () const;
+
+ /**
+ * The info.
+ */
+ elf_xword info () const;
+
+ /**
+ * The constant addend.
+ */
+ elf_sxword addend () const;
+
+ private:
+ const symbols::symbol* sym; //< The symbol reference.
+ elf_addr offset_; //< The offset in the section.
+ elf_xword info_; //< The record's information.
+ elf_sxword addend_; //< The constant addend value.
+ };
+
+ /**
+ * A container of relocation records.
+ */
+ typedef std::vector < relocation > relocations;
+
+ /**
* An ELF Section. The current implementation only supports a single data
* descriptor with a section.
*/
@@ -233,11 +294,37 @@ namespace rld
int entries () const;
/**
+ * Return true if the relocation record have an addend field.
+ *
+ * @retval true The relocation record have the addend field.
+ */
+ bool get_reloc_type () const;
+
+ /**
* Set the name index if writable. This is normally done
* automatically when adding the section to the file.
*/
void set_name (unsigned int index);
+ /**
+ * Set the type of relocation records.
+ *
+ * @param rela If true the records are rela type.
+ */
+ void set_reloc_type (bool rela);
+
+ /**
+ * Add a relocation.
+ *
+ * @param reloc The relocation record to add.
+ */
+ void add (const relocation& reloc);
+
+ /**
+ * Get the relocations.
+ */
+ const relocations& get_relocations () const;
+
private:
/**
@@ -260,6 +347,8 @@ namespace rld
elf_scn* scn; //< ELF private section data.
elf_shdr shdr; //< The section header.
elf_data* data_; //< The section's data.
+ bool rela; //< The type of relocation records.
+ relocations relocs; //< The relocation records.
};
/**
@@ -318,7 +407,7 @@ namespace rld
*/
typedef std::list < program_header > program_headers;
- /**
+ /**
* An ELF file.
*/
class file
@@ -427,6 +516,14 @@ namespace rld
void get_sections (sections& filtered_secs, unsigned int type);
/**
+ * Return the section with given index.
+ *
+ * @param index The section's index to look for.
+ * @retval section The section matching the index.
+ */
+ section& get_section (int index);
+
+ /**
* Return the index of the string section.
*/
int strings_section () const;
@@ -472,6 +569,21 @@ namespace rld
bool global = true);
/**
+ * Get the symbol by index in the symtabl section.
+ */
+ const symbols::symbol& get_symbol (const int index) const;
+
+ /**
+ * Load the relocation records.
+ */
+ void load_relocations ();
+
+ /**
+ * Clear the relocation records.
+ */
+ void clear_relocations ();
+
+ /**
* Set the ELF header. Must be writable.
*
* The classes are:
diff --git a/rld-files.cpp b/rld-files.cpp
index 94508a1..c296ab1 100644
--- a/rld-files.cpp
+++ b/rld-files.cpp
@@ -18,6 +18,8 @@
#include "config.h"
#endif
+#include <algorithm>
+
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -413,7 +415,7 @@ namespace rld
size_t to_read = size;
while (have_read < size)
{
- ssize_t rsize = ::read (fd (), buffer, to_read);
+ const ssize_t rsize = ::read (fd (), buffer, to_read);
if (rsize < 0)
throw rld::error (strerror (errno), "read:" + name ().path ());
if (rsize == 0)
@@ -428,12 +430,12 @@ namespace rld
ssize_t
image::write (const void* buffer_, size_t size)
{
- const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
+ const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
size_t have_written = 0;
size_t to_write = size;
while (have_written < size)
{
- ssize_t wsize = ::write (fd (), buffer, to_write);
+ const ssize_t wsize = ::write (fd (), buffer, to_write);
if (wsize < 0)
throw rld::error (strerror (errno), "write:" + name ().path ());
have_written += wsize;
@@ -900,6 +902,15 @@ namespace rld
close ();
}
+ relocation::relocation (const elf::relocation& er)
+ : name (er.name ()),
+ offset (er.offset ()),
+ type (er.type ()),
+ info (er.info ()),
+ addend (er.addend ())
+ {
+ }
+
section::section (const elf::section& es)
: name (es.name ()),
index (es.index ()),
@@ -909,7 +920,23 @@ namespace rld
link (es.link ()),
info (es.info ()),
flags (es.flags ()),
- offset (es.offset ()){
+ offset (es.offset ()),
+ rela (es.get_reloc_type ())
+ {
+ load_relocations (es);
+ }
+
+ void
+ section::load_relocations (const elf::section& es)
+ {
+ rela = es.get_reloc_type ();
+ const elf::relocations& es_relocs = es.get_relocations ();
+ for (elf::relocations::const_iterator ri = es_relocs.begin ();
+ ri != es_relocs.end ();
+ ++ri)
+ {
+ relocs.push_back (relocation (*ri));
+ }
}
size_t
@@ -1134,6 +1161,24 @@ namespace rld
}
}
+ void
+ object::load_relocations ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "object:load-relocs: " << name ().full () << std::endl;
+
+ elf ().load_relocations ();
+
+ for (sections::iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ section& sec = *si;
+ const elf::section& elf_sec = elf ().get_section (sec.index);
+ sec.load_relocations (elf_sec);
+ }
+ }
+
int
object::references () const
{
diff --git a/rld-files.h b/rld-files.h
index de49b4c..65934e9 100644
--- a/rld-files.h
+++ b/rld-files.h
@@ -511,6 +511,37 @@ namespace rld
};
/**
+ * A relocation record. We extract what we want because the elf::section
+ * class requires the image be left open as references are alive. We
+ * extract and keep the data we need to create the image.
+ */
+ struct relocation
+ {
+ const std::string name; //< The name of the symbol.
+ const uint32_t offset; //< The section offset.
+ const uint32_t type; //< The type of relocation record.
+ const uint32_t info; //< The ELF info field.
+ const int32_t addend; //< The constant addend.
+
+ /**
+ * Construct from an ELF relocation record.
+ */
+ relocation (const elf::relocation& er);
+
+ private:
+ /**
+ * The default constructor is not allowed due to all elements being
+ * const.
+ */
+ relocation ();
+ };
+
+ /**
+ * A container of relocations.
+ */
+ typedef std::list < relocation > relocations;
+
+ /**
* The sections attributes. We extract what we want because the
* elf::section class requires the image be left open as references are
* alive. We extract and keep the data we need to create the image.
@@ -526,12 +557,23 @@ namespace rld
const uint32_t info; //< The ELF info field.
const uint32_t flags; //< The ELF flags.
const off_t offset; //< The ELF file offset.
+ bool rela; //< Relocation records have the addend field.
+ relocations relocs; //< The sections relocations.
/**
* Construct from an ELF section.
+ *
+ * @param es The ELF section to load the object file section from.
*/
section (const elf::section& es);
+ /**
+ * Load the ELF relocations.
+ *
+ * @param es The ELF section to load the relocations from.
+ */
+ void load_relocations (const elf::section& es);
+
private:
/**
* The default constructor is not allowed due to all elements being
@@ -622,6 +664,11 @@ namespace rld
void load_symbols (symbols::table& symbols, bool local = false);
/**
+ * Load the relocations.
+ */
+ void load_relocations ();
+
+ /**
* References to the image.
*/
virtual int references () const;
diff --git a/rld-rap.cpp b/rld-rap.cpp
index c6f8c47..53e5172 100644
--- a/rld-rap.cpp
+++ b/rld-rap.cpp
@@ -66,6 +66,27 @@ namespace rld
};
/**
+ * RAP relocation record.
+ */
+ struct relocation
+ {
+ std::string name; //< The symbol name if there is one.
+ uint32_t offset; //< The offset in the section to apply the fixup.
+ uint32_t info; //< The ELF info record.
+ uint32_t addend; //< The ELF constant addend.
+
+ /**
+ * Construct the relocation.
+ */
+ relocation (const files::relocation& reloc, uint32_t offset = 0);
+ };
+
+ /**
+ * Relocation records.
+ */
+ typedef std::list < relocation > relocations;
+
+ /**
* The RAP section data.
*/
struct section
@@ -74,6 +95,8 @@ namespace rld
uint32_t size; //< The size of the section.
uint32_t offset; //< The offset of the section.
uint32_t align; //< The alignment of the section.
+ bool rela; //< The relocation record has an addend field.
+ relocations relocs; //< The relocations for this section.
/**
* Operator to add up section data.
@@ -84,6 +107,26 @@ namespace rld
* Default constructor.
*/
section ();
+
+ /**
+ * Clear the section.
+ */
+ void clear ();
+
+ /**
+ * Update based on the section in the object file.
+ */
+ void update (const files::sections& secs);
+
+ /**
+ * Set the offset of this section based on the previous section.
+ */
+ void set_offset (const section& sec);
+
+ /**
+ * Set the alignment.
+ */
+ void set_alignment (const section& sec);
};
/**
@@ -103,7 +146,7 @@ namespace rld
const uint32_t data; //< The ELF st.info field.
/**
- * The default constructor.
+ * The constructor.
*/
external (const uint32_t name,
const sections sec,
@@ -136,7 +179,6 @@ namespace rld
files::sections dtor; //< The static destructor table.
files::sections data; //< All initialised read/write data.
files::sections bss; //< All uninitialised read/write data
- files::sections relocs; //< All relocation records.
files::sections symtab; //< All exported symbols.
files::sections strtab; //< All exported strings.
section secs[rap_secs]; //< The sections of interest.
@@ -187,10 +229,19 @@ namespace rld
/**
* Load the layout data from the object files.
+ *
+ * @param app_objects The object files in the application.
*/
void layout (const files::object_list& app_objects);
/**
+ * Collection the symbols from the object file.
+ *
+ * @param obj The object file to collection the symbol from.
+ */
+ void collect_symbols (const object& obj);
+
+ /**
* Write the compressed output file.
*/
void write (compress::compressor& comp,
@@ -204,6 +255,16 @@ namespace rld
files::object& obj,
const files::sections& secs);
+ /**
+ * Write the external symbols.
+ */
+ void write_externals (compress::compressor& comp);
+
+ /**
+ * Write the relocation records for all the object files.
+ */
+ void write_relocations (compress::compressor& comp);
+
private:
objects objs; //< The RAP objects
@@ -260,13 +321,22 @@ namespace rld
<< std::setw (15) << sec.name
<< " " << flags
<< " size: " << std::setw (5) << sec.size
- << " align: " << sec.alignment
+ << " align: " << std::setw (3) << sec.alignment
+ << " relocs: " << sec.relocs.size ()
<< std::right << std::endl;
}
}
}
}
+ relocation::relocation (const files::relocation& reloc, uint32_t offset)
+ : name (reloc.name),
+ offset (offset + reloc.offset),
+ info (reloc.info),
+ addend (reloc.info)
+ {
+ }
+
section::section ()
: size (0),
offset (0),
@@ -274,6 +344,14 @@ namespace rld
{
}
+ void
+ section::clear ()
+ {
+ size = 0;
+ offset = 0;
+ align = 0;
+ }
+
section&
section::operator += (const section& sec)
{
@@ -290,18 +368,86 @@ namespace rld
"rap::section");
size += sec.size;
- offset = sec.offset + sec.size;
+ }
+
+ return *this;
+ }
+
+ void
+ section::set_alignment (const section& sec)
+ {
+ if (align == 0)
+ align = sec.align;
+ else if (align != sec.align)
+ throw rld::error ("Alignments do not match for section '" + name + "'",
+ "rap::section");
+ }
- uint32_t mask = (1 << (align - 1)) - 1;
+ void
+ section::set_offset (const section& sec)
+ {
+ offset = sec.offset + sec.size;
+ if (align > 1)
+ {
+ uint32_t mask = align - 1;
if (offset & mask)
{
offset &= ~mask;
- offset += (1 << align);
+ offset += align;
}
}
- return *this;
+ for (relocations::iterator ri = relocs.begin ();
+ ri != relocs.end ();
+ ++ri)
+ {
+ relocation& reloc = *ri;
+ reloc.offset += offset;
+ }
+ }
+
+ void
+ section::update (const files::sections& secs)
+ {
+ if (!secs.empty ())
+ {
+ align = (*(secs.begin ())).alignment;
+ size = files::sum_sizes (secs);
+ }
+ }
+
+ /**
+ * Helper for for_each to get the relocations.
+ */
+ class section_relocs:
+ public std::unary_function < const files::section, void >
+ {
+ public:
+
+ section_relocs (section& sec);
+
+ void operator () (const files::section& fsec);
+
+ private:
+
+ section& sec;
+ };
+
+ section_relocs::section_relocs (section& sec)
+ : sec (sec)
+ {
+ }
+
+ void
+ section_relocs::operator () (const files::section& fsec)
+ {
+ for (files::relocations::const_iterator ri = fsec.relocs.begin ();
+ ri != fsec.relocs.end ();
+ ++ri)
+ {
+ sec.relocs.push_back (relocation (*ri, sec.offset));
+ }
}
external::external (const uint32_t name,
@@ -339,10 +485,28 @@ namespace rld
secs[s].name = section_names[s];
/*
+ * Get the relocation records. Setting the offset will update them.
+ * section.
+ */
+
+ obj.open ();
+ try
+ {
+ obj.begin ();
+ obj.load_relocations ();
+ obj.end ();
+ obj.close ();
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+
+ /*
* Get from the object file the various sections we need to format a
* memory layout.
*/
-
obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, SHF_WRITE | SHF_EXECINSTR);
obj.get_sections (ctor, ".ctors");
@@ -352,45 +516,31 @@ namespace rld
obj.get_sections (symtab, SHT_SYMTAB);
obj.get_sections (strtab, ".strtab");
- /*
- * Only interested in the relocation records for the text sections.
- */
- for (files::sections::const_iterator ti = text.begin ();
- ti != text.end ();
- ++ti)
- {
- files::section sec = *ti;
- obj.get_sections (relocs, ".rel" + sec.name);
- obj.get_sections (relocs, ".rela" + sec.name);
- }
-
- secs[rap_text].size = files::sum_sizes (text);
- if (!text.empty ())
- secs[rap_text].align = (*text.begin ()).alignment;
-
- secs[rap_const].size = files::sum_sizes (const_);
- if (!const_.empty ())
- secs[rap_const].align = (*const_.begin ()).alignment;
-
- secs[rap_ctor].size = files::sum_sizes (ctor);
- if (!ctor.empty ())
- secs[rap_ctor].align = (*ctor.begin ()).alignment;
-
- secs[rap_dtor].size = files::sum_sizes (dtor);
- if (!dtor.empty ())
- secs[rap_dtor].align = (*dtor.begin ()).alignment;
-
- secs[rap_data].size = files::sum_sizes (data);
- if (!data.empty ())
- secs[rap_data].align = (*data.begin ()).alignment;
-
- secs[rap_bss].size = files::sum_sizes (bss);
- if (!bss.empty ())
- secs[rap_bss].align = (*bss.begin ()).alignment;
+ secs[rap_text].update (text);
+ secs[rap_const].update (const_);
+ secs[rap_ctor].update (ctor);
+ secs[rap_dtor].update (dtor);
+ secs[rap_data].update (data);
+ secs[rap_bss].update (bss);
+
+ std::for_each (text.begin (), text.end (),
+ section_relocs (secs[rap_text]));
+ std::for_each (const_.begin (), const_.end (),
+ section_relocs (secs[rap_const]));
+ std::for_each (ctor.begin (), ctor.end (),
+ section_relocs (secs[rap_ctor]));
+ std::for_each (dtor.begin (), dtor.end (),
+ section_relocs (secs[rap_dtor]));
+ std::for_each (data.begin (), data.end (),
+ section_relocs (secs[rap_data]));
+ std::for_each (bss.begin (), bss.end (),
+ section_relocs (secs[rap_bss]));
symtab_size = files::sum_sizes (symtab);
strtab_size = files::sum_sizes (strtab);
- relocs_size = files::sum_sizes (relocs);
+ relocs_size = 0;
+ for (int s = 0; s < rap_secs; ++s)
+ relocs_size += secs[s].relocs.size ();
if (rld::verbose () >= RLD_VERBOSE_TRACE)
{
@@ -402,9 +552,10 @@ namespace rld
output ("data", secs[rap_data].size, data);
if (secs[rap_bss].size)
std::cout << " bss: size: " << secs[rap_bss].size << std::endl;
- output ("relocs", relocs_size, relocs);
output ("symtab", symtab_size, symtab);
output ("strtab", strtab_size, strtab);
+ if (relocs_size)
+ std::cout << " relocs: size: " << relocs_size << std::endl;
}
}
@@ -416,7 +567,6 @@ namespace rld
dtor (orig.dtor),
data (orig.data),
bss (orig.bss),
- relocs (orig.relocs),
symtab (orig.symtab),
strtab (orig.strtab),
symtab_off (orig.symtab_off),
@@ -459,8 +609,8 @@ namespace rld
if (sec)
return rap_bss;
- throw rld::error ("Section index not found: " + obj.name ().full (),
- "rap::object");
+ throw rld::error ("Section index '" + rld::to_string (index) +
+ "' not found: " + obj.name ().full (), "rap::object");
}
image::image ()
@@ -494,74 +644,86 @@ namespace rld
}
for (int s = 0; s < rap_secs; ++s)
- {
- secs[s].size = 0;
- secs[s].offset = 0;
- secs[s].align = 0;
- }
+ secs[s].clear ();
- for (objects::iterator oi = objs.begin ();
+ symtab_size = 0;
+ strtab.clear ();
+
+ for (objects::iterator oi = objs.begin (), poi = objs.begin ();
oi != objs.end ();
++oi)
{
object& obj = *oi;
- secs[rap_text] += obj.secs[rap_text];
- secs[rap_const] += obj.secs[rap_const];
- secs[rap_ctor] += obj.secs[rap_ctor];
- secs[rap_dtor] += obj.secs[rap_dtor];
- secs[rap_data] += obj.secs[rap_data];
- secs[rap_bss] += obj.secs[rap_bss];
-
- symtab_size = 0;
- strtab.clear ();
-
- uint32_t sym_count = 0;
-
- symbols::pointers& esyms = obj.obj.external_symbols ();
- for (symbols::pointers::const_iterator ei = esyms.begin ();
- ei != esyms.end ();
- ++ei, ++sym_count)
+ /*
+ * Update the offsets in the object file. We need the object's offset
+ * to set the relocation offset's correctly as they are relative to the
+ * object file.
+ */
+ if (oi != objs.begin ())
{
- const symbols::symbol& sym = *(*ei);
-
- if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC))
- {
- if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK))
- {
- externs.push_back (external (strtab.size () + 2,
- obj.find (sym.index ()),
- sym.value (),
- sym.info ()));
- symtab_size += external::rap_size;
- strtab += sym.name ();
- strtab += '\0';
- }
- }
+ object& pobj = *poi;
+ for (int s = 1; s < rap_secs; ++s)
+ obj.secs[s].set_offset (pobj.secs[s]);
+ ++poi;
}
+ for (int s = 0; s < rap_secs; ++s)
+ secs[s] += obj.secs[s];
+
+ collect_symbols (obj);
+
relocs_size += obj.relocs_size;
}
- if (rld::verbose () >= RLD_VERBOSE_INFO)
+ for (int s = 1; s < rap_secs; ++s)
+ secs[s].set_offset (secs[s - 1]);
+
+ if (1 || rld::verbose () >= RLD_VERBOSE_INFO)
{
uint32_t total = (secs[rap_text].size + secs[rap_data].size +
secs[rap_data].size + secs[rap_bss].size +
symtab_size + strtab.size() + relocs_size);
std::cout << "rap::layout: total:" << total
- << " text:" << secs[rap_text].size
- << " const:" << secs[rap_const].size
- << " ctor:" << secs[rap_ctor].size
- << " dtor:" << secs[rap_dtor].size
- << " data:" << secs[rap_data].size
- << " bss:" << secs[rap_bss].size
- << " symbols:" << symtab_size << " (" << externs.size () << ')'
+ << " text:" << secs[rap_text].size << " (" << secs[rap_text].offset
+ << ") const:" << secs[rap_const].size << " (" << secs[rap_const].offset
+ << ") ctor:" << secs[rap_ctor].size << " (" << secs[rap_ctor].offset
+ << ") dtor:" << secs[rap_dtor].size << " (" << secs[rap_dtor].offset
+ << ") data:" << secs[rap_data].size << " (" << secs[rap_data].offset
+ << ") bss:" << secs[rap_bss].size << " (" << secs[rap_bss].offset
+ << ") symbols:" << symtab_size << " (" << externs.size () << ')'
<< " strings:" << strtab.size ()
<< " relocs:" << relocs_size
<< std::endl;
}
}
+ void
+ image::collect_symbols (const object& obj)
+ {
+ symbols::pointers& esyms = obj.obj.external_symbols ();
+ for (symbols::pointers::const_iterator ei = esyms.begin ();
+ ei != esyms.end ();
+ ++ei)
+ {
+ const symbols::symbol& sym = *(*ei);
+
+ if ((sym.type () == STT_OBJECT) || (sym.type () == STT_FUNC))
+ {
+ if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK))
+ {
+ externs.push_back (external (strtab.size () + 2,
+ obj.find (sym.section_index ()),
+ sym.value (),
+ sym.info ()));
+ symtab_size += external::rap_size;
+ strtab += sym.name ();
+ strtab += '\0';
+ }
+ }
+ }
+ }
+
/**
* Helper for for_each to write out the various sections.
*/
@@ -668,15 +830,8 @@ namespace rld
comp << strtab;
- for (externals::const_iterator ei = externs.begin ();
- ei != externs.end ();
- ++ei)
- {
- const external& ext = *ei;
- comp << (uint32_t) ((ext.sec << 16) | ext.data)
- << ext.name
- << ext.value;
- }
+ write_externals (comp);
+ write_relocations (comp);
}
void
@@ -709,6 +864,63 @@ namespace rld
}
void
+ image::write_externals (compress::compressor& comp)
+ {
+ for (externals::const_iterator ei = externs.begin ();
+ ei != externs.end ();
+ ++ei)
+ {
+ const external& ext = *ei;
+ comp << (uint32_t) ((ext.sec << 16) | ext.data)
+ << ext.name
+ << ext.value;
+ }
+ }
+
+ void
+ image::write_relocations (compress::compressor& comp)
+ {
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ section& sec = obj.secs[s];
+ relocations& relocs = sec.relocs;
+ uint32_t header = relocs.size ();
+
+ header |= sec.rela ? (1 << 31) : 0;
+
+ comp << header;
+
+ for (relocations::const_iterator ri = relocs.begin ();
+ ri != relocs.end ();
+ ++ri)
+ {
+ const relocation& reloc = *ri;
+ std::size_t size = strtab.find (reloc.name);
+ uint32_t info = GELF_R_TYPE (reloc.info);
+
+ if (size)
+ info |= size << 8;
+ else
+ info |= (1 << 31) | (reloc.name.size () << 8);
+
+ comp << info << reloc.offset;
+
+ if (sec.rela)
+ comp << reloc.addend;
+
+ if (!size)
+ comp << reloc.name;
+ }
+ }
+ }
+ }
+
+ void
write (files::image& app,
const std::string& init,
const std::string& fini,
diff --git a/rld-symbols.cpp b/rld-symbols.cpp
index 3174ce4..982ef4d 100644
--- a/rld-symbols.cpp
+++ b/rld-symbols.cpp
@@ -50,43 +50,46 @@ namespace rld
}
symbol::symbol ()
- : object_ (0),
+ : index_ (-1),
+ object_ (0),
references_ (0)
{
memset (&esym_, 0, sizeof (esym_));
}
- symbol::symbol (const std::string& name,
+ symbol::symbol (int index,
+ const std::string& name,
files::object& object,
const elf::elf_sym& esym)
- : name_ (name),
+ : index_ (index),
+ name_ (name),
object_ (&object),
esym_ (esym),
references_ (0)
{
if (!object_)
throw rld_error_at ("object pointer is 0");
- if (name_.empty ())
- throw rld_error_at ("name is empty in " + object.name ().full ());
if (is_cplusplus ())
denamgle_name (name_, demangled_);
}
- symbol::symbol (const std::string& name, const elf::elf_sym& esym)
- : name_ (name),
+ symbol::symbol (int index,
+ const std::string& name,
+ const elf::elf_sym& esym)
+ : index_ (index),
+ name_ (name),
object_ (0),
esym_ (esym),
references_ (0)
{
- if (name_.empty ())
- throw rld_error_at ("name is empty");
if (is_cplusplus ())
denamgle_name (name_, demangled_);
}
symbol::symbol (const std::string& name,
const elf::elf_addr value)
- : name_ (name),
+ : index_ (-1),
+ name_ (name),
object_ (0),
references_ (0)
{
@@ -96,7 +99,8 @@ namespace rld
symbol::symbol (const char* name,
const elf::elf_addr value)
- : name_ (name),
+ : index_ (-1),
+ name_ (name),
object_ (0),
references_ (0)
{
@@ -104,6 +108,12 @@ namespace rld
esym_.st_value = value;
}
+ int
+ symbol::index () const
+ {
+ return index_;
+ }
+
const std::string&
symbol::name () const
{
@@ -135,7 +145,7 @@ namespace rld
}
int
- symbol::index () const
+ symbol::section_index () const
{
return esym_.st_shndx;
}
@@ -237,7 +247,8 @@ namespace rld
break;
}
- out << binding
+ out << std::setw (4) << index_
+ << ' ' << binding
<< ' ' << type
<< " 0x" << std::setw (8) << std::setfill ('0') << std::hex
<< es.st_value
diff --git a/rld-symbols.h b/rld-symbols.h
index dcb0d3e..e602e36 100644
--- a/rld-symbols.h
+++ b/rld-symbols.h
@@ -58,14 +58,15 @@ namespace rld
/**
* Construct an exported symbol with a object file.
*/
- symbol (const std::string& name,
+ symbol (int index,
+ const std::string& name,
files::object& object,
const elf::elf_sym& esym);
/**
- * Construct an unresolved symbol with no object file.
+ * Construct a symbol with no object file and an ELF index.
*/
- symbol (const std::string& name, const elf::elf_sym& esym);
+ symbol (int index, const std::string& name, const elf::elf_sym& esym);
/**
* Construct a linker symbol that is internally created.
@@ -80,6 +81,11 @@ namespace rld
elf::elf_addr value = 0);
/**
+ * The symbol's index in the symtab section of the ELF file.
+ */
+ int index () const;
+
+ /**
* The symbol's name.
*/
const std::string& name () const;
@@ -105,9 +111,9 @@ namespace rld
int binding () const;
/**
- * The synbol's section index.
+ * The symbol's section index.
*/
- int index () const;
+ int section_index () const;
/**
* The value of the symbol.
@@ -159,6 +165,7 @@ namespace rld
private:
+ int index_; //< The symbol's index in the ELF file.
std::string name_; //< The name of the symbol.
std::string demangled_; //< If a C++ symbol the demangled name.
files::object* object_; //< The object file containing the symbol.