summaryrefslogtreecommitdiff
path: root/linkers/rld-rap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linkers/rld-rap.cpp')
-rw-r--r--linkers/rld-rap.cpp1668
1 files changed, 1668 insertions, 0 deletions
diff --git a/linkers/rld-rap.cpp b/linkers/rld-rap.cpp
new file mode 100644
index 0000000..9b87279
--- /dev/null
+++ b/linkers/rld-rap.cpp
@@ -0,0 +1,1668 @@
+/*
+ * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_ld
+ *
+ * @brief RTEMS Linker.
+ *
+ * @todo Set the RAP alignment as the max of all alignments.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <algorithm>
+#include <list>
+#include <iomanip>
+
+#include <rld.h>
+#include <rld-compression.h>
+#include <rld-rap.h>
+
+namespace rld
+{
+ namespace rap
+ {
+
+ /**
+ * Output details or not.
+ */
+ bool add_obj_details = true;
+
+ /**
+ * Store the path of object files.
+ */
+ std::string rpath;
+
+ /**
+ * The names of the RAP sections.
+ */
+ static const char* section_names[rap_secs] =
+ {
+ ".text",
+ ".const",
+ ".ctor",
+ ".dtor",
+ ".data",
+ ".bss"
+ };
+
+ /**
+ * RAP relocation record. This one does not have const fields.
+ */
+ struct relocation
+ {
+ 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.
+ std::string symname; //< The symbol name if there is one.
+ uint32_t symtype; //< The type of symbol.
+ int symsect; //< The symbol's RAP section.
+ uint32_t symvalue; //< The symbol's default value.
+ uint32_t symbinding;//< The symbol's binding.
+
+ /**
+ * Construct the relocation using the file relocation, the offset of the
+ * section in the target RAP section and the RAP section of the symbol.
+ */
+ relocation (const files::relocation& reloc, const uint32_t offset);
+ };
+
+ /**
+ * Relocation records.
+ */
+ typedef std::vector < relocation > relocations;
+
+ /**
+ * Relocation symname sorter for the relocations container.
+ */
+ class reloc_symname_compare
+ {
+ public:
+ bool operator () (const relocation& lhs,
+ const relocation& rhs) const {
+ return lhs.symname < rhs.symname;
+ }
+ };
+
+ /**
+ * Relocation offset sorter for the relocations container.
+ */
+ class reloc_offset_compare
+ {
+ public:
+ bool operator () (const relocation& lhs,
+ const relocation& rhs) const {
+ if (lhs.symname == rhs.symname)
+ return lhs.offset < rhs.offset;
+ else return false;
+ }
+ };
+
+ /**
+ * An object section's offset, size and alignment.
+ */
+ struct osection
+ {
+ std::string name; //< The name of the section.
+ uint32_t offset; //< The offset in the object file.
+ uint32_t size; //< The size of this section.
+ uint32_t align; //< The alignment.
+ uint32_t relocs; //< The number of relocations.
+ uint64_t flags; //< The flags.
+
+ /**
+ * Construct the object section.
+ */
+ osection (const std::string& name,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t align,
+ uint32_t relocs,
+ uint64_t flags);
+
+ /**
+ * Default constructor.
+ */
+ osection ();
+ };
+
+ /**
+ * Map of object file section offsets keyed by the object file section
+ * index. This is used when adding the external symbols so the symbol's
+ * value can be adjusted by the offset of the section in the RAP section.
+ */
+ typedef std::map < int, osection > osections;
+
+ /**
+ * An ordered container of object section indexes. We need the same
+ * order so the alignments match up with the layout.
+ */
+ typedef std::vector < int > osecindexes;
+
+ /**
+ * Section detail will be written into RAP file
+ */
+ struct section_detail
+ {
+ uint32_t name; //< The offset in the strtable.
+ uint32_t offset; //< The offset in the rap section.
+ uint32_t id; //< The rap id.
+ uint32_t size; //< The size of the section.
+
+ /* Constructor */
+ section_detail (uint32_t name, uint32_t offset, uint32_t id, uint32_t size);
+ };
+
+ /*
+ * A container of section detail
+ */
+ typedef std::list < section_detail > section_details;
+
+ /**
+ * The RAP section data.
+ */
+ struct section
+ {
+ std::string name; //< The name of the section.
+ uint32_t offset; //< The offset of the section.
+ bool rela; //< The relocation record has an addend field.
+ relocations relocs; //< The relocations for this section.
+ osections osecs; //< The object section index.
+ osecindexes osindexes; //< The object section indexes in order.
+
+ /**
+ * Default constructor.
+ */
+ section ();
+
+ /**
+ * Clear the section.
+ */
+ void clear ();
+
+ /**
+ * The size of the section given the offset.
+ */
+ uint32_t size (uint32_t offset = 0) const;
+
+ /**
+ * The alignment of the first section.
+ */
+ uint32_t alignment () const;
+
+ /**
+ * The alignment of the object section given its index.
+ */
+ uint32_t alignment (int index) const;
+
+ /**
+ * Set the offset of this section based on the previous section.
+ */
+ void set_offset (const section& sec);
+
+ /**
+ * Return the object section given the index.
+ */
+ const osection& get_osection (int index) const;
+
+ /**
+ * Output helper function to report the sections in an object file. This
+ * is useful when seeing the flags in the sections.
+ */
+ void output ();
+ };
+
+ /**
+ * A symbol. This matches the symbol structure 'rtems_rtl_obj_sym_t' in the
+ * target code.
+ */
+ struct external
+ {
+ /**
+ * Size of an external in the RAP file.
+ */
+ static const uint32_t rap_size = sizeof (uint32_t) * 3;
+
+ const uint32_t name; //< The string table's name index.
+ const sections sec; //< The section the symbols belongs to.
+ const uint32_t value; //< The offset from the section base.
+ const uint32_t data; //< The ELF st.info field.
+
+ /**
+ * The constructor.
+ */
+ external (const uint32_t name,
+ const sections sec,
+ const uint32_t value,
+ const uint32_t data);
+
+ /**
+ * Copy constructor.
+ */
+ external (const external& orig);
+
+ };
+
+ /**
+ * A container of externals.
+ */
+ typedef std::list < external > externals;
+
+ /**
+ * The specific data for each object we need to collect to create the RAP
+ * format file.
+ */
+ struct object
+ {
+ files::object& obj; //< The object file.
+ files::sections text; //< All executable code.
+ files::sections const_; //< All read only data.
+ files::sections ctor; //< The static constructor table.
+ 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 symtab; //< All exported symbols.
+ files::sections strtab; //< All exported strings.
+ section secs[rap_secs]; //< The sections of interest.
+
+ /**
+ * The constructor. Need to have an object file to create.
+ */
+ object (files::object& obj);
+
+ /**
+ * The copy constructor.
+ */
+ object (const object& orig);
+
+ /**
+ * Find the section type that matches the section index.
+ */
+ sections find (const uint32_t index) const;
+
+ /**
+ * The total number of relocations in the object file.
+ */
+ uint32_t get_relocations () const;
+
+ /**
+ * The total number of relocations for a specific RAP section in the
+ * object file.
+ */
+ uint32_t get_relocations (int sec) const;
+
+ /**
+ * Output the object file details..
+ */
+ void output ();
+
+ private:
+ /**
+ * No default constructor allowed.
+ */
+ object ();
+ };
+
+ /**
+ * A container of objects.
+ */
+ typedef std::list < object > objects;
+
+ /**
+ * The RAP image.
+ */
+ class image
+ {
+ public:
+ /**
+ * Construct the image.
+ */
+ image ();
+
+ /**
+ * Load the layout data from the object files.
+ *
+ * @param app_objects The object files in the application.
+ * @param init The initialisation entry point label.
+ * @param fini The finish entry point label.
+ */
+ void layout (const files::object_list& app_objects,
+ const std::string& init,
+ const std::string& fini);
+
+ /**
+ * Collection the symbols from the object file.
+ *
+ * @param obj The object file to collection the symbol from.
+ */
+ void collect_symbols (object& obj);
+
+ /**
+ * Write the compressed output file. This is the top level write
+ * interface.
+ *
+ * @param comp The compressor.
+ */
+ void write (compress::compressor& comp);
+
+ /**
+ * Write the RAP section to the compressed output file given the object files.
+ * Check to make sure the size in the layout and the size written match.
+ *
+ * @param comp The compressor.
+ * @param sec The RAP setion to write.
+ */
+ void write (compress::compressor& comp, sections sec);
+
+ /**
+ * Write the sections to the compressed output file. The file sections
+ * are used to ensure the alignment. The offset is used to ensure the
+ * alignment of the first section of the object when it is written.
+ *
+ * @param comp The compressor.
+ * @param obj The object file the sections are part of.
+ * @param secs The container of file sections to write.
+ * @param offset The current offset in the RAP section.
+ */
+ void write (compress::compressor& comp,
+ files::object& obj,
+ const files::sections& secs,
+ uint32_t& offset);
+
+ /**
+ * 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);
+
+ /**
+ * Write the details of the files.
+ */
+ void write_details (compress::compressor& comp);
+
+ /**
+ * The total number of relocations for a specific RAP section in the
+ * image.
+ */
+ uint32_t get_relocations (int sec) const;
+
+ /**
+ * Clear the image values.
+ */
+ void clear ();
+
+ /**
+ * Report the RAP section's size.
+ */
+ uint32_t section_size (sections sec) const;
+
+ /**
+ * Find a symbol name in the string table.
+ */
+ std::size_t find_in_strtab (const std::string& symname);
+
+ private:
+
+ objects objs; //< The RAP objects
+ uint32_t sec_size[rap_secs]; //< The sections of interest.
+ uint32_t sec_align[rap_secs]; //< The sections of interest.
+ bool sec_rela[rap_secs]; //< The sections of interest.
+ externals externs; //< The symbols in the image
+ uint32_t symtab_size; //< The size of the symbols.
+ std::string strtab; //< The strings table.
+ uint32_t relocs_size; //< The relocations size.
+ uint32_t init_off; //< The strtab offset to the init label.
+ uint32_t fini_off; //< The strtab offset to the fini label.
+ };
+
+ const char*
+ section_name (int sec)
+ {
+ if (sec < rap_secs)
+ return section_names[sec];
+ throw rld::error ("Invalid section '" + rld::to_string (sec) + "'",
+ "rap::section-name");
+ }
+
+ /**
+ * Update the offset taking into account the alignment.
+ *
+ * @param offset The current offset.
+ * @param size The size to move the offset by.
+ * @param alignment The alignment of the offset.
+ * @return uint32_t The new aligned offset.
+ */
+ uint32_t align_offset (uint32_t offset, uint32_t size, uint32_t alignment)
+ {
+ offset += size;
+
+ if (alignment > 1)
+ {
+ uint32_t mask = alignment - 1;
+ if (offset & mask)
+ {
+ offset &= ~mask;
+ offset += alignment;
+ }
+ }
+
+ return offset;
+ }
+
+ relocation::relocation (const files::relocation& reloc,
+ const uint32_t offset)
+ : offset (reloc.offset + offset),
+ info (reloc.info),
+ addend (reloc.addend),
+ symname (reloc.symname),
+ symtype (reloc.symtype),
+ symsect (reloc.symsect),
+ symvalue (reloc.symvalue),
+ symbinding (reloc.symbinding)
+ {
+ }
+
+ section_detail::section_detail (uint32_t name,
+ uint32_t offset,
+ uint32_t id,
+ uint32_t size)
+ : name (name),
+ offset (offset),
+ id (id),
+ size (size)
+ {
+ }
+
+ osection::osection (const std::string& name,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t align,
+ uint32_t relocs,
+ uint64_t flags)
+ : name (name),
+ offset (offset),
+ size (size),
+ align (align),
+ relocs (relocs),
+ flags (flags)
+ {
+ }
+
+ osection::osection ()
+ : offset (0),
+ size (0),
+ align (0),
+ relocs (0),
+ flags (0)
+ {
+ }
+
+ section::section ()
+ : offset (0),
+ rela (false)
+ {
+ }
+
+ void
+ section::clear ()
+ {
+ offset = 0;
+ rela = false;
+ }
+
+ uint32_t
+ section::size (uint32_t offset_) const
+ {
+ uint32_t end = offset_;
+ if (end == 0)
+ end = offset;
+ for (size_t si = 0; si < osindexes.size (); ++si)
+ {
+ const osection& osec = get_osection (osindexes[si]);
+ end = align_offset (end, 0, osec.align);
+ end += osec.size;
+ }
+ return end - offset;
+ }
+
+ uint32_t
+ section::alignment () const
+ {
+ if (!osindexes.empty ())
+ {
+ const osection& osec = get_osection (osindexes[0]);
+ return osec.align;
+ }
+ return 0;
+ }
+
+ uint32_t
+ section::alignment (int index) const
+ {
+ const osection& osec = get_osection (index);
+ return osec.align;
+ }
+
+ void
+ section::set_offset (const section& sec)
+ {
+ uint32_t align = alignment ();
+ offset = align_offset (sec.offset, sec.size (), align);
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:section::set-offset: " << name
+ << " offset=" << offset
+ << " size=" << size ()
+ << " align=" << align
+ << " sec.offset=" << sec.offset
+ << " sec.size=" << sec.size (sec.offset)
+ << std::endl;
+ }
+
+ const osection&
+ section::get_osection (int index) const
+ {
+ osections::const_iterator osi = osecs.find (index);
+ if (osi == osecs.end ())
+ throw rld::error ("Invalid object seciton index in '" + name +"': index=" +
+ rld::to_string (index),
+ "rap::section");
+ return (*osi).second;
+ }
+
+ /**
+ * Output helper function to report the sections in an object file. This is
+ * useful when seeing the flags in the sections.
+ */
+ void
+ section::output ()
+ {
+ if (!osindexes.empty ())
+ {
+ std::cout << ' ' << name
+ << ": size: " << size (offset)
+ << " offset: " << offset
+ << " rela: " << (rela ? "yes" : "no")
+ << std::endl;
+
+ for (osecindexes::const_iterator osi = osindexes.begin ();
+ osi != osindexes.end ();
+ ++osi)
+ {
+ const osection& osec = get_osection (*osi);
+
+ if (osec.size)
+ {
+ #define SF(f, i, c) if (osec.flags & (f)) flags[i] = c
+
+ std::string flags ("--------------");
+
+ SF (SHF_WRITE, 0, 'W');
+ SF (SHF_ALLOC, 1, 'A');
+ SF (SHF_EXECINSTR, 2, 'E');
+ SF (SHF_MERGE, 3, 'M');
+ SF (SHF_STRINGS, 4, 'S');
+ SF (SHF_INFO_LINK, 5, 'I');
+ SF (SHF_LINK_ORDER, 6, 'L');
+ SF (SHF_OS_NONCONFORMING, 7, 'N');
+ SF (SHF_GROUP, 8, 'G');
+ SF (SHF_TLS, 9, 'T');
+ SF (SHF_AMD64_LARGE, 10, 'a');
+ SF (SHF_ENTRYSECT, 11, 'e');
+ SF (SHF_COMDEF, 12, 'c');
+ SF (SHF_ORDERED, 13, 'O');
+
+ std::cout << " " << std::left
+ << std::setw (15) << osec.name
+ << " " << flags
+ << " size: " << std::setw (5) << osec.size
+ << " align: " << std::setw (3) << osec.align
+ << " relocs: " << std::setw (4) << osec.relocs
+ << " offset: " << std::setw (5) << osec.offset
+ << std::hex
+ << " image: 0x" << offset + osec.offset
+ << std::dec << std::right << std::endl;
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper for for_each to merge the related object sections into the RAP
+ * section.
+ */
+ class section_merge:
+ public std::unary_function < const files::section, void >
+ {
+ public:
+
+ section_merge (object& obj, section& sec);
+
+ ~section_merge ();
+
+ void operator () (const files::section& fsec);
+
+ private:
+
+ object& obj;
+ section& sec;
+ };
+
+ section_merge::section_merge (object& obj, section& sec)
+ : obj (obj),
+ sec (sec)
+ {
+ sec.offset = 0;
+ sec.rela = false;
+ }
+
+ section_merge::~section_merge ()
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:section-merge: " << sec.name
+ << " size=" << sec.size ()
+ << " offset=" << sec.offset
+ << " " << obj.obj.name ().full () << std::endl;
+ }
+
+ void
+ section_merge::operator () (const files::section& fsec)
+ {
+ /*
+ * Align the size up to the next alignment boundary and use that as the
+ * offset for this object file section.
+ */
+ uint32_t offset = align_offset (sec.size (), 0, fsec.alignment);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:section-merge: " << fsec.name
+ << " sec-size=" << sec.size ()
+ << " relocs=" << fsec.relocs.size ()
+ << " offset=" << offset
+ << " fsec.size=" << fsec.size
+ << " fsec.alignment=" << fsec.alignment
+ << " fsec.rela=" << fsec.rela
+ << " " << obj.obj.name ().full () << std::endl;
+
+ /*
+ * Add the object file's section offset to the map. This is needed
+ * to adjust the external symbol offsets.
+ */
+ osection osec (fsec.name,
+ offset,
+ fsec.size,
+ fsec.alignment,
+ fsec.relocs.size (),
+ fsec.flags);
+ sec.osecs[fsec.index] = osec;
+ sec.osindexes.push_back (fsec.index);
+
+ uint32_t rc = 0;
+
+ for (files::relocations::const_iterator fri = fsec.relocs.begin ();
+ fri != fsec.relocs.end ();
+ ++fri, ++rc)
+ {
+ const files::relocation& freloc = *fri;
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << " " << std::setw (2) << sec.relocs.size ()
+ << '/' << std::setw (2) << rc
+ << std::hex << ": reloc.info=0x" << freloc.info << std::dec
+ << " reloc.offset=" << freloc.offset
+ << " reloc.addend=" << freloc.addend
+ << " reloc.symtype=" << freloc.symtype
+ << " reloc.symsect=" << freloc.symsect
+ << " reloc.symbinding=" << freloc.symbinding
+ << std::endl;
+
+ sec.relocs.push_back (relocation (freloc, offset));
+ }
+
+ std::stable_sort (sec.relocs.begin (),
+ sec.relocs.end (),
+ reloc_symname_compare ());
+ std::stable_sort (sec.relocs.begin (),
+ sec.relocs.end (),
+ reloc_offset_compare ());
+
+ if (fsec.rela == true)
+ sec.rela = fsec.rela;
+ }
+
+ external::external (const uint32_t name,
+ const sections sec,
+ const uint32_t value,
+ const uint32_t data)
+ : name (name),
+ sec (sec),
+ value (value),
+ data (data)
+ {
+ }
+
+ external::external (const external& orig)
+ : name (orig.name),
+ sec (orig.sec),
+ value (orig.value),
+ data (orig.data)
+ {
+ }
+
+ object::object (files::object& obj)
+ : obj (obj)
+ {
+ /*
+ * Set up the names of the sections.
+ */
+ for (int s = 0; s < rap_secs; ++s)
+ secs[s].name = section_names[s];
+
+ /*
+ * Get the relocation records. Collect the various section types from the
+ * object file into the RAP sections. Merge those sections into the RAP
+ * sections.
+ */
+
+ obj.open ();
+ try
+ {
+ obj.begin ();
+ obj.load_relocations ();
+ obj.end ();
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+ obj.close ();
+
+ obj.get_sections (text, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
+ obj.get_sections (const_, SHT_PROGBITS, SHF_ALLOC, SHF_WRITE | SHF_EXECINSTR);
+ obj.get_sections (ctor, ".ctors");
+ obj.get_sections (dtor, ".dtors");
+ obj.get_sections (data, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
+ obj.get_sections (bss, SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ obj.get_sections (symtab, SHT_SYMTAB);
+ obj.get_sections (strtab, ".strtab");
+
+ std::for_each (text.begin (), text.end (),
+ section_merge (*this, secs[rap_text]));
+ std::for_each (const_.begin (), const_.end (),
+ section_merge (*this, secs[rap_const]));
+ std::for_each (ctor.begin (), ctor.end (),
+ section_merge (*this, secs[rap_ctor]));
+ std::for_each (dtor.begin (), dtor.end (),
+ section_merge (*this, secs[rap_dtor]));
+ std::for_each (data.begin (), data.end (),
+ section_merge (*this, secs[rap_data]));
+ std::for_each (bss.begin (), bss.end (),
+ section_merge (*this, secs[rap_bss]));
+ }
+
+ object::object (const object& orig)
+ : obj (orig.obj),
+ text (orig.text),
+ const_ (orig.const_),
+ ctor (orig.ctor),
+ dtor (orig.dtor),
+ data (orig.data),
+ bss (orig.bss),
+ symtab (orig.symtab),
+ strtab (orig.strtab)
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ secs[s] = orig.secs[s];
+ }
+
+ sections
+ object::find (const uint32_t index) const
+ {
+ const files::section* sec;
+
+ sec = files::find (text, index);
+ if (sec)
+ return rap_text;
+
+ sec = files::find (const_, index);
+ if (sec)
+ return rap_const;
+
+ sec = files::find (ctor, index);
+ if (sec)
+ return rap_ctor;
+
+ sec = files::find (dtor, index);
+ if (sec)
+ return rap_dtor;
+
+ sec = files::find (data, index);
+ if (sec)
+ return rap_data;
+
+ sec = files::find (bss, index);
+ if (sec)
+ return rap_bss;
+
+ throw rld::error ("Section index '" + rld::to_string (index) +
+ "' not found: " + obj.name ().full (), "rap::object");
+ }
+
+ uint32_t
+ object::get_relocations () const
+ {
+ uint32_t relocs = 0;
+ for (int s = 0; s < rap_secs; ++s)
+ relocs += secs[s].relocs.size ();
+ return relocs;
+ }
+
+ uint32_t
+ object::get_relocations (int sec) const
+ {
+ if ((sec < 0) || (sec >= rap_secs))
+ throw rld::error ("Invalid section index '" + rld::to_string (sec),
+ "rap::relocations");
+ return secs[sec].relocs.size ();
+ }
+
+ void
+ object::output ()
+ {
+ std::cout << "rap:object: " << obj.name ().full () << std::endl;
+ secs[rap_text].output ();
+ secs[rap_const].output ();
+ secs[rap_ctor].output ();
+ secs[rap_dtor].output ();
+ secs[rap_data].output ();
+ if (secs[rap_bss].size ())
+ std::cout << " bss: size: " << secs[rap_bss].size () << std::endl;
+ }
+
+ image::image ()
+ {
+ clear ();
+ }
+
+ void
+ image::layout (const files::object_list& app_objects,
+ const std::string& init,
+ const std::string& fini)
+ {
+ clear ();
+
+ /*
+ * Create the local objects which contain the layout information.
+ */
+ for (files::object_list::const_iterator aoi = app_objects.begin ();
+ aoi != app_objects.end ();
+ ++aoi)
+ {
+ files::object& app_obj = *(*aoi);
+
+ if (!app_obj.valid ())
+ throw rld::error ("Not valid: " + app_obj.name ().full (),
+ "rap::layout");
+
+ objs.push_back (object (app_obj));
+ }
+
+ for (objects::iterator oi = objs.begin (), poi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+
+ /*
+ * 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 ())
+ {
+ object& pobj = *poi;
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ obj.secs[s].set_offset (pobj.secs[s]);
+ sec_size[s] = obj.secs[s].offset + obj.secs[s].size ();
+ sec_align[s] = obj.secs[s].alignment ();
+ if (obj.secs[s].rela == true)
+ sec_rela[s] = obj.secs[s].rela;
+ }
+ ++poi;
+ }
+ else
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ sec_size[s] = obj.secs[s].size ();
+ sec_align[s] = obj.secs[s].alignment ();
+ if (obj.secs[s].rela == true)
+ sec_rela[s] = true;
+ }
+ }
+
+ collect_symbols (obj);
+
+ relocs_size += obj.get_relocations ();
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ obj.output ();
+ }
+
+ init_off = strtab.size () + 1;
+ strtab += '\0';
+ strtab += init;
+
+ fini_off = strtab.size () + 1;
+ strtab += '\0';
+ strtab += fini;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ uint32_t total = (sec_size[rap_text] + sec_size[rap_const] +
+ sec_size[rap_data] + sec_size[rap_bss] +
+ symtab_size + strtab.size() + relocs_size);
+ std::cout << "rap::layout: total:" << total
+ << " text:" << sec_size[rap_text]
+ << " const:" << sec_size[rap_const]
+ << " ctor:" << sec_size[rap_ctor]
+ << " dtor:" << sec_size[rap_dtor]
+ << " data:" << sec_size[rap_data]
+ << " bss:" << sec_size[rap_bss]
+ << " symbols:" << symtab_size << " (" << externs.size () << ')'
+ << " strings:" << strtab.size () + 1
+ << " relocs:" << relocs_size
+ << std::endl;
+ }
+ }
+
+ void
+ image::collect_symbols (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) || (sym.type () == STT_NOTYPE))
+ {
+ if ((sym.binding () == STB_GLOBAL) || (sym.binding () == STB_WEAK))
+ {
+ int symsec = sym.section_index ();
+
+ /* Ignore section index 0 */
+ if (symsec == 0)
+ continue;
+ /* Ignore sparc common section */
+ if ((elf::object_machine_type () == EM_SPARC) && (symsec == 65522))
+ continue;
+
+ sections rap_sec = obj.find (symsec);
+ section& sec = obj.secs[rap_sec];
+ std::size_t name;
+
+ /*
+ * See if the name is already in the string table.
+ */
+ name = find_in_strtab (sym.name ());
+
+ if (name == std::string::npos)
+ {
+ name = strtab.size () + 1;
+ strtab += '\0';
+ strtab += sym.name ();
+ }
+
+ /*
+ * The symbol's value is the symbols value plus the offset of the
+ * object file's section offset in the RAP section.
+ */
+ externs.push_back (external (name,
+ rap_sec,
+ sec.offset + sec.osecs[symsec].offset +
+ sym.value (),
+ sym.info ()));
+
+ symtab_size += external::rap_size;
+ }
+ }
+ }
+ }
+
+ void
+ image::write (compress::compressor& comp)
+ {
+ /*
+ * Start with the machine type so the target can check the applicatiion
+ * is ok and can be loaded. Add the init and fini labels to the string
+ * table and add the references to the string table next. Follow this
+ * with the section details then the string table and symbol table then
+ * finally the relocation records.
+ */
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: machine=" << comp.transferred () << std::endl;
+
+ comp << elf::object_machine_type ()
+ << elf::object_datatype ()
+ << elf::object_class ();
+
+ /*
+ * The init and fini label offsets. Then the symbol table and string
+ * table sizes.
+ */
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: header=" << comp.transferred () << std::endl;
+
+ comp << init_off
+ << fini_off
+ << symtab_size
+ << (uint32_t) strtab.size () + 1
+ << (uint32_t) 0;
+
+ /*
+ * Output file details
+ */
+ if (add_obj_details)
+ {
+ write_details (comp);
+ }
+ else
+ {
+ comp << (uint32_t)0; /* No file details */
+ }
+
+ /*
+ * The sections.
+ */
+ for (int s = 0; s < rap_secs; ++s)
+ comp << sec_size[s]
+ << sec_align[s];
+
+ /*
+ * Output the sections from each object file.
+ */
+ write (comp, rap_text);
+ write (comp, rap_const);
+ write (comp, rap_ctor);
+ write (comp, rap_dtor);
+ write (comp, rap_data);
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: strtab=" << comp.transferred () << std::endl;
+
+ strtab += '\0';
+ comp << strtab;
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: symbols=" << comp.transferred () << std::endl;
+
+ write_externals (comp);
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: relocs=" << comp.transferred () << std::endl;
+
+ write_relocations (comp);
+ }
+
+ /**
+ * Helper for for_each to write out the various sections.
+ */
+ class section_writer:
+ public std::unary_function < object, void >
+ {
+ public:
+
+ section_writer (image& img,
+ compress::compressor& comp,
+ sections sec);
+
+ void operator () (object& obj);
+
+ private:
+
+ image& img;
+ compress::compressor& comp;
+ sections sec;
+ uint32_t offset;
+ };
+
+ section_writer::section_writer (image& img,
+ compress::compressor& comp,
+ sections sec)
+ : img (img),
+ comp (comp),
+ sec (sec),
+ offset (0)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ std::cout << "rap:output: " << section_names[sec]
+ << ": offset=" << comp.transferred ()
+ << " size=" << img.section_size (sec) << std::endl;
+ }
+
+ void
+ section_writer::operator () (object& obj)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:writing: " << section_names[sec] << std::endl;
+
+ switch (sec)
+ {
+ case rap_text:
+ img.write (comp, obj.obj, obj.text, offset);
+ break;
+ case rap_const:
+ img.write (comp, obj.obj, obj.const_, offset);
+ break;
+ case rap_ctor:
+ img.write (comp, obj.obj, obj.ctor, offset);
+ break;
+ case rap_dtor:
+ img.write (comp, obj.obj, obj.dtor, offset);
+ break;
+ case rap_data:
+ img.write (comp, obj.obj, obj.data, offset);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void
+ image::write (compress::compressor& comp, sections sec)
+ {
+ uint32_t image_offset = comp.transferred ();
+
+ std::for_each (objs.begin (), objs.end (),
+ section_writer (*this, comp, sec));
+
+ uint32_t written = comp.transferred () - image_offset;
+
+ if (written != sec_size[sec])
+ {
+ std::string msg = "Image output size does not match layout size: ";
+ msg += section_names[sec];
+ msg += ": layout-size=" + rld::to_string (sec_size[sec]);
+ msg += " image-size=" + rld::to_string (written);
+ throw rld::error (msg, "rap::write");
+ }
+ }
+
+ void
+ image::write (compress::compressor& comp,
+ files::object& obj,
+ const files::sections& secs,
+ uint32_t& offset)
+ {
+ uint32_t size = 0;
+
+ obj.open ();
+
+ try
+ {
+ obj.begin ();
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << "rap:write sections: " << obj.name ().full () << std::endl;
+
+ for (files::sections::const_iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
+ {
+ const files::section& sec = *si;
+ uint32_t unaligned_offset = offset + size;
+
+ offset = align_offset (offset, size, sec.alignment);
+
+ if (offset != unaligned_offset)
+ {
+ char ee = '\xee';
+ for (uint32_t p = 0; p < (offset - unaligned_offset); ++p)
+ comp.write (&ee, 1);
+ }
+
+ comp.write (obj, sec.offset, sec.size);
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << " sec: " << sec.index << ' ' << sec.name
+ << " offset=" << offset
+ << " size=" << sec.size
+ << " align=" << sec.alignment
+ << " padding=" << (offset - unaligned_offset) << std::endl;
+
+ size = sec.size;
+ }
+
+ offset += size;
+
+ if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+ std::cout << " total size=" << offset << std::endl;
+
+ obj.end ();
+ }
+ catch (...)
+ {
+ obj.close ();
+ throw;
+ }
+
+ obj.close ();
+ }
+
+ void
+ image::write_externals (compress::compressor& comp)
+ {
+ int count = 0;
+ for (externals::const_iterator ei = externs.begin ();
+ ei != externs.end ();
+ ++ei, ++count)
+ {
+ const external& ext = *ei;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "rap:externs: " << count
+ << " name=" << &strtab[ext.name] << " (" << ext.name << ')'
+ << " section=" << section_names[ext.sec]
+ << " data=" << ext.data
+ << " value=0x" << std::hex << ext.value << std::dec
+ << std::endl;
+
+ if ((ext.data & 0xffff0000) != 0)
+ throw rld::error ("Data value has data in bits higher than 15",
+ "rap::write-externs");
+
+ comp << (uint32_t) ((ext.sec << 16) | ext.data)
+ << ext.name
+ << ext.value;
+ }
+ }
+
+ void
+ image::write_relocations (compress::compressor& comp)
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ uint32_t count = get_relocations (s);
+ uint32_t sr = 0;
+ uint32_t header;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "rap:relocation: section:" << section_names[s]
+ << " relocs=" << count
+ << " rela=" << (char*) (sec_rela[s] ? "yes" : "no")
+ << std::endl;
+
+ header = count;
+ header |= sec_rela[s] ? RAP_RELOC_RELA : 0;
+
+ comp << header;
+
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+ section& sec = obj.secs[s];
+ relocations& relocs = sec.relocs;
+ uint32_t rc = 0;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << " relocs=" << sec.relocs.size ()
+ << " sec.offset=" << sec.offset
+ << " sec.size=" << sec.size ()
+ << " sec.align=" << sec.alignment ()
+ << " " << obj.obj.name ().full () << std::endl;
+
+ for (relocations::const_iterator ri = relocs.begin ();
+ ri != relocs.end ();
+ ++ri, ++sr, ++rc)
+ {
+ const relocation& reloc = *ri;
+ uint32_t info = GELF_R_TYPE (reloc.info);
+ uint32_t offset;
+ uint32_t addend = reloc.addend;
+ bool write_addend = sec.rela;
+ bool write_symname = false;
+
+ offset = sec.offset + reloc.offset;
+
+ if ((reloc.symtype == STT_SECTION) || (reloc.symbinding == STB_LOCAL))
+ {
+ int rap_symsect = obj.find (reloc.symsect);
+
+ /*
+ * Bit 31 clear, bits 30:8 RAP section index.
+ */
+ info |= rap_symsect << 8;
+
+ addend += (obj.secs[rap_symsect].offset +
+ obj.secs[rap_symsect].osecs[reloc.symsect].offset +
+ reloc.symvalue);
+
+ write_addend = true;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << " " << std::setw (2) << sr
+ << '/' << std::setw (2) << rc
+ <<": rsym: sect=" << section_names[rap_symsect]
+ << " rap_symsect=" << rap_symsect
+ << " sec.offset=" << obj.secs[rap_symsect].offset
+ << " sec.osecs=" << obj.secs[rap_symsect].osecs[reloc.symsect].offset
+ << " (" << obj.obj.get_section (reloc.symsect).name << ')'
+ << " reloc.symsect=" << reloc.symsect
+ << " reloc.symvalue=" << reloc.symvalue
+ << " reloc.addend=" << reloc.addend
+ << " addend=" << addend
+ << std::endl;
+ }
+ else
+ {
+ /*
+ * Bit 31 must be set. Bit 30 determines the type of string and
+ * bits 29:8 the strtab offset or the size of the appended
+ * string.
+ */
+
+ info |= RAP_RELOC_STRING;
+
+ std::size_t size = find_in_strtab (reloc.symname);
+
+ if (size == std::string::npos)
+ {
+ /*
+ * Bit 30 clear, the size of the symbol name.
+ */
+ info |= reloc.symname.size () << 8;
+ write_symname = true;
+ }
+ else
+ {
+ /*
+ * Bit 30 set, the offset in the strtab.
+ */
+ info |= RAP_RELOC_STRING_EMBED | (size << 8);
+ }
+ }
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << " " << std::setw (2) << sr << '/'
+ << std::setw (2) << rc
+ << std::hex << ": reloc: info=0x" << info << std::dec
+ << " offset=" << offset;
+ if (write_addend)
+ std::cout << " addend=" << addend;
+ if ((info & RAP_RELOC_STRING) != 0)
+ {
+ std::cout << " symname=" << reloc.symname;
+ if (write_symname)
+ std::cout << " (appended)";
+ }
+ std::cout << std::hex
+ << " reloc.info=0x" << reloc.info << std::dec
+ << " reloc.offset=" << reloc.offset
+ << " reloc.symtype=" << reloc.symtype
+ << std::endl;
+ }
+
+ comp << info << offset;
+
+ if (write_addend)
+ comp << addend;
+
+ if (write_symname)
+ comp << reloc.symname;
+ }
+ }
+ }
+ }
+
+ void image::write_details (compress::compressor& comp)
+ {
+
+ std::string strtable;
+ uint32_t pos = 0;
+
+ section_details s_details;
+
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "rap:file details" << std::endl
+ << " total " << objs.size () <<" files" << std::endl;
+ }
+
+ comp << (uint32_t)(objs.size ());
+
+ /* rpath for rap file */
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "rap:file rpath=" << rld::rap::rpath << std::endl;
+ }
+
+ comp << (uint32_t)rld::rap::rpath.length ();
+
+ if (rld::rap::rpath.length () > 0)
+ {
+ strtable += rld::rap::rpath;
+ }
+
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+
+ /* obj full name */
+ strtable += obj.obj.name ().full ();
+ strtable += '\0';
+ }
+
+ pos = strtable.length ();
+
+ uint32_t sec_num = 0;
+ for (objects::iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ object& obj = *oi;
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "file:" << obj.obj.name ().full () << std::endl;
+
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ section& sec = obj.secs[s];
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "rap:section: " << sec.name << " "
+ "offset= " << sec.offset << std::endl;
+ }
+
+ for (size_t si = 0; si < sec.osindexes.size (); ++si)
+ {
+ const osection& osec = sec.get_osection (sec.osindexes[si]);
+
+ strtable += osec.name;
+ strtable += '\0';
+
+ /* sec.offset + osec.offset is the offset in the rap section */
+ s_details.push_back (section_detail (pos,
+ sec.offset + osec.offset,
+ s,
+ osec.size));
+
+ pos = strtable.length ();
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "osec.name=" << osec.name << " "
+ << "osec.offset=" << osec.offset << " "
+ << "osec.size=" << osec.size << std::endl;
+ }
+ }
+ }
+
+ /* Output section numbers*/
+ comp << (uint32_t)((s_details.size () - sec_num));
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "sec_num:" << s_details.size () - sec_num << std::endl;
+ sec_num = s_details.size ();
+ }
+
+ comp << (uint32_t)(strtable.size ());
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ std::cout << "total detail size:" << strtable.size () << std::endl;
+
+ comp << strtable;
+
+ for (section_details::const_iterator si = s_details.begin ();
+ si != s_details.end ();
+ ++si)
+ {
+ const section_detail& sec_detail = *si;
+ comp << (uint32_t)(sec_detail.name);
+
+ if (sec_detail.id > 0xf)
+ std::cout << "Out max rap section id 15\n" << std::endl;
+
+ comp << (uint32_t)((sec_detail.id << 28) | sec_detail.offset);
+ comp << (uint32_t)(sec_detail.size);
+ }
+ }
+
+ uint32_t
+ image::get_relocations (int sec) const
+ {
+ if ((sec < 0) || (sec >= rap_secs))
+ throw rld::error ("Invalid section index '" + rld::to_string (sec),
+ "rap::image::relocations");
+
+ uint32_t relocs = 0;
+
+ for (objects::const_iterator oi = objs.begin ();
+ oi != objs.end ();
+ ++oi)
+ {
+ const object& obj = *oi;
+ relocs += obj.get_relocations (sec);
+ }
+
+ return relocs;
+ }
+
+ void
+ image::clear ()
+ {
+ for (int s = 0; s < rap_secs; ++s)
+ {
+ sec_size[s] = 0;
+ sec_align[s] = 0;
+ sec_rela[s] = false;
+ }
+ symtab_size = 0;
+ strtab.clear ();
+ relocs_size = 0;
+ init_off = 0;
+ fini_off = 0;
+ }
+
+ uint32_t
+ image::section_size (sections sec) const
+ {
+ if ((sec < 0) || (sec >= rap_secs))
+ throw rld::error ("Invalid section index '" + rld::to_string (sec),
+ "rap::image::section_size");
+ return sec_size[sec];
+ }
+
+ std::size_t
+ image::find_in_strtab (const std::string& symname)
+ {
+ std::size_t pos = 0;
+ while (pos < strtab.size ())
+ {
+ std::size_t off = strtab.find (symname, pos);
+ if (off == std::string::npos)
+ break;
+ if (::strlen (strtab.c_str () + off) == symname.size ())
+ return off;
+ pos = off + 1;
+ }
+ return std::string::npos;
+ }
+
+ void
+ write (files::image& app,
+ const std::string& init,
+ const std::string& fini,
+ const files::object_list& app_objects,
+ const symbols::table& /* symbols */) /* Add back for incremental
+ * linking */
+ {
+ std::string header;
+
+ header = "RAP,00000000,0002,LZ77,00000000\n";
+ app.write (header.c_str (), header.size ());
+
+ compress::compressor compressor (app, 2 * 1024);
+ image rap;
+
+ rap.layout (app_objects, init, fini);
+ rap.write (compressor);
+
+ compressor.flush ();
+
+ std::ostringstream length;
+
+ length << std::setfill ('0') << std::setw (8)
+ << header.size () + compressor.compressed ();
+
+ header.replace (4, 8, length.str ());
+
+ app.seek (0);
+ app.write (header.c_str (), header.size ());
+
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ int pcent = (compressor.compressed () * 100) / compressor.transferred ();
+ int premand = (((compressor.compressed () * 1000) + 500) /
+ compressor.transferred ()) % 10;
+ std::cout << "rap: objects: " << app_objects.size ()
+ << ", size: " << compressor.compressed ()
+ << ", compression: " << pcent << '.' << premand << '%'
+ << std::endl;
+ }
+ }
+
+ }
+}