Chris Johns ec419a05ee rtemstoolkit/rap: Ignore R_ARM_V4BX relocation records
Note, this removes the detalis needed to alter the instruction for
an ARMv4 instruction set. Currently this type of record is not handled
in the RAP format loader and the RTL loader ignores it.

Close #3396
2018-04-16 11:55:01 +10:00

1727 lines
49 KiB
C++

/*
* 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.
};
/*
* Per machine specific special handling.
*/
bool
machine_symbol_check (const symbols::symbol& sym)
{
int symsec = sym.section_index ();
/*
* Ignore section index 0
*/
if (symsec == 0)
return false;
/*
* Ignore sparc common section
*/
if ((elf::object_machine_type () == EM_SPARC) && (symsec == 65522))
return false;
return true;
}
bool
machine_relocation_check (const files::relocation& reloc)
{
/*
* Drop some ARM relocations.
*/
if (elf::object_machine_type () == EM_ARM)
{
switch (reloc.type)
{
case 40: /* R_ARM_V4BX */
return false;
default:
break;
}
}
return true;
}
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;
bool merge_reloc = machine_relocation_check (freloc);
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << " " << std::setw (2) << sec.relocs.size ()
<< '/' << std::setw (2) << rc << ':'
<< " merge=" << merge_reloc
<< std::hex
<< " reloc.type=" << freloc.type
<< " 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;
if (merge_reloc)
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 ();
/*
* Do not noting if the symbol is reject at the machine level.
*/
if (!machine_symbol_check (sym))
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 (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << " " << std::setw (2) << sr
<< '/' << std::setw (2) << rc << ':'
<< std::hex
<< " reloc.info=0x" << reloc.info
<< std::dec
<< " reloc.offset=" << reloc.offset
<< " reloc.addend=" << reloc.addend
<< " reloc.symtype=" << reloc.symtype
<< " reloc.symsect=" << reloc.symsect
<< " (" << obj.obj.get_section (reloc.symsect).name << ')'
<< " reloc.symvalue=" << reloc.symvalue
<< " reloc.symbinding=" << reloc.symbinding
<< std::endl;
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
<< " 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;
}
}
}
}