summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2012-11-17 17:34:33 +1100
committerChris Johns <chrisj@rtems.org>2012-11-17 17:34:33 +1100
commit7ee957ca2f579802b4823ad562f05bd27ad425e1 (patch)
tree5f085ca653f2d80496e984b978b556b561127064
parentd68833ada79a4255e95017b44f73dcb21c7a7701 (diff)
Refactor the ELF support to allow ELF write suppport.
The refactoring allows better reuse of the ELF support and cleans up some hacks from the generic file and archive handling improving the separation of the file handling from the file format, ie ELF. The handling of ELF object files and ELF object files inside archives is cleaner. The refactor cleaned up the symbol handling where the symbols now reside in the ELF file object and references are take in symbol pointer containers and symbol table containers. The main purpose of the refactor is to allow support for creating and writing ELF files. Also added an rtems-syms command where special symbol support can be added.
-rw-r--r--rld-elf-types.h25
-rw-r--r--rld-elf.cpp772
-rw-r--r--rld-elf.h383
-rw-r--r--rld-files.cpp214
-rw-r--r--rld-files.h98
-rw-r--r--rld-outputter.cpp44
-rw-r--r--rld-resolver.cpp17
-rw-r--r--rld-symbols.cpp64
-rw-r--r--rld-symbols.h77
-rw-r--r--rld.cpp16
-rw-r--r--rtems-ld.cpp (renamed from main.cpp)55
-rw-r--r--rtems-syms.cpp311
-rw-r--r--wscript38
13 files changed, 1620 insertions, 494 deletions
diff --git a/rld-elf-types.h b/rld-elf-types.h
index 2c9c149..ece0928 100644
--- a/rld-elf-types.h
+++ b/rld-elf-types.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -36,15 +36,18 @@ namespace rld
/**
* Hide the types from libelf we use.
*/
- typedef ::GElf_Word elf_word;
- typedef ::GElf_Addr elf_addr;
- typedef ::GElf_Sym elf_sym;
- typedef ::Elf_Kind elf_kind;
- typedef ::Elf_Scn elf_scn;
- typedef ::GElf_Shdr elf_shdr;
- typedef ::GElf_Ehdr elf_ehdr;
- typedef ::Elf_Data elf_data;
- typedef ::Elf elf;
+ typedef ::GElf_Word elf_word;
+ typedef ::GElf_Xword elf_xword;
+ 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;
}
}
diff --git a/rld-elf.cpp b/rld-elf.cpp
index 8f983b6..30cd4b6 100644
--- a/rld-elf.cpp
+++ b/rld-elf.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011-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
@@ -30,18 +30,23 @@ namespace rld
{
namespace elf
{
- void error (const std::string& where)
+ /**
+ * Throw an ELF error.
+ *
+ * @param where Where the error is raised.
+ */
+ void libelf_error (const std::string& where)
{
- throw rld::error (::elf_errmsg (-1), "elf:" + where);
+ throw rld::error (::elf_errmsg (-1), "libelf:" + where);
}
/**
* We record the first class, machine and .. type of object file we get the
* header of and all header must match. We cannot mix object module types.
*/
- static int elf_object_class = ELFCLASSNONE;
- static int elf_object_data = ELFDATANONE;
- static int elf_object_machinetype = EM_NONE;
+ static unsigned int elf_object_class = ELFCLASSNONE;
+ static unsigned int elf_object_data = ELFDATANONE;
+ static unsigned int elf_object_machinetype = EM_NONE;
/**
* A single place to initialise the libelf library. This must be called
@@ -54,255 +59,656 @@ namespace rld
if (!libelf_initialised)
{
if (::elf_version (EV_CURRENT) == EV_NONE)
- error ("initialisation");
+ libelf_error ("initialisation");
libelf_initialised = true;
}
}
- /**
- * Return the RTEMS target type given the ELF machine type.
- */
- const std::string
- machine_type ()
+ section::section (file& file_, int index_)
+ : file_ (&file_),
+ index_ (index_),
+ scn (0),
+ data_ (0)
{
- struct types_and_labels
- {
- const char* name; //< The RTEMS label.
- int machinetype; //< The machine type.
- };
- types_and_labels types_to_labels[] =
- {
- { "arm", EM_ARM },
- { "avr", EM_AVR },
- { "bfin", EM_BLACKFIN },
- { "h8300", EM_H8_300 },
- { "i386", EM_386 },
- /* { "m32c", EM_M32C }, Not in libelf I imported */
- { "m32r", EM_M32R },
- { "m68k", EM_68K },
- { "m68k", EM_COLDFIRE },
- { "mips", EM_MIPS },
- { "powerpc", EM_PPC },
- { "sh", EM_SH },
- { "sparc", EM_SPARC },
- { "sparc64", EM_SPARC },
- { 0, EM_NONE }
- };
+ memset (&shdr, 0, sizeof (shdr));
- int m = 0;
- while (types_to_labels[m].machinetype != EM_NONE)
+ scn = ::elf_getscn (file_.get_elf (), index_);
+ if (!scn)
+ libelf_error ("elf_getscn: " + file_.name ());
+
+ if (!::gelf_getshdr (scn, &shdr))
+ libelf_error ("gelf_getshdr: " + file_.name ());
+
+ if (shdr.sh_type != SHT_NULL)
{
- if (elf_object_machinetype == types_to_labels[m].machinetype)
- return types_to_labels[m].name;
- ++m;
+ name_ = file_.get_string (shdr.sh_name);
+ data_ = ::elf_getdata (scn, NULL);
+ if (!data_)
+ libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')');
}
-
- std::ostringstream what;
- what << "unknown machine type: " << elf_object_machinetype;
- throw rld::error (what, "machine-type");
}
- section::section (int index,
- std::string& name,
- elf_scn* scn,
- elf_shdr& shdr)
- : index (index),
- name (name),
- scn (scn),
- shdr (shdr)
+ section::section (const section& orig)
+ : file_ (orig.file_),
+ index_ (orig.index_),
+ name_ (orig.name_),
+ scn (orig.scn),
+ shdr (orig.shdr),
+ data_ (orig.data_)
{
- data = ::elf_getdata (scn, NULL);
- if (!data)
- error ("elf_getdata");
}
section::section ()
- : index (-1),
+ : file_ (0),
+ index_ (-1),
scn (0),
- data (0)
+ data_ (0)
{
memset (&shdr, 0, sizeof (shdr));
}
+ int
+ section::index () const
+ {
+ check ();
+ return index_;
+ }
+
+ const std::string&
+ section::name () const
+ {
+ check ();
+ return name_;
+ }
+
+ elf_data*
+ section::data ()
+ {
+ check ();
+ return data_;
+ }
+
+ elf_word
+ section::type () const
+ {
+ check ();
+ return shdr.sh_type;
+ }
+
+ elf_xword
+ section::flags () const
+ {
+ check ();
+ return shdr.sh_flags;
+ }
+
+ elf_addr
+ section::address () const
+ {
+ check ();
+ return shdr.sh_addr;
+ }
+
+ elf_xword
+ section::alignment () const
+ {
+ check ();
+ return shdr.sh_addralign;
+ }
+
+ elf_off
+ section::offset () const
+ {
+ check ();
+ return shdr.sh_offset;
+ }
+
+ elf_word
+ section::link () const
+ {
+ check ();
+ return shdr.sh_link;
+ }
+
+ elf_word
+ section::info () const
+ {
+ check ();
+ return shdr.sh_info;
+ }
+
+ elf_xword
+ section::size () const
+ {
+ check ();
+ return shdr.sh_size;
+ }
+
+ elf_xword
+ section::entry_size () const
+ {
+ check ();
+ return shdr.sh_entsize;
+ }
+
+ int
+ section::entries () const
+ {
+ return size () / entry_size ();
+ }
+
+ void
+ section::check () const
+ {
+ if (!file_ || (index_ < 0))
+ throw rld::error ("Invalid section.", "section:check:");
+ }
+
+ file::file ()
+ : fd_ (-1),
+ archive (false),
+ writable (false),
+ elf_ (0),
+ oclass (0),
+ ident_str (0),
+ ident_size (0)
+ {
+ memset (&ehdr, 0, sizeof (ehdr));
+ memset (&phdr, 0, sizeof (phdr));
+ }
+
+ file::~file ()
+ {
+ end ();
+ }
+
+ void
+ file::begin (const std::string& name__, int fd__, const bool writable_)
+ {
+ begin (name__, fd__, writable_, 0, 0);
+ }
+
+ void
+ file::begin (const std::string& name__, file& archive_, off_t offset)
+ {
+ archive_.check ("begin:archive");
+
+ if (archive_.writable)
+ throw rld::error ("archive is writable", "elf:file:begin");
+
+ begin (name__, archive_.fd_, false, &archive_, offset);
+ }
+
#define rld_archive_fhdr_size (60)
void
- begin (rld::files::image& image)
+ file::begin (const std::string& name__,
+ int fd__,
+ const bool writable_,
+ file* archive_,
+ off_t offset_)
{
- libelf_initialise ();
+ if (fd__ < 0)
+ throw rld::error ("no file descriptor", "elf:file:begin");
/*
* Begin's are not nesting.
*/
- Elf* elf = image.elf ();
- if (elf)
- error ("begin: already done: " + image.name ().full ());
+ if (elf_ || (fd_ >= 0))
+ throw rld::error ("already called", "elf:file:begin");
/*
- * Is this image part of an archive ?
+ * Cannot write directly into archive. Create a file then archive it.
*/
- elf = image.elf (true);
- if (elf)
- {
- ssize_t offset = image.name ().offset () - rld_archive_fhdr_size;
+ if (archive_ && writable_)
+ throw rld::error ("cannot write into archives directly",
+ "elf:file:begin");
- if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
- std::cout << "elf::rand: " << elf << " offset:" << offset
- << ' ' << image.name ().full () << std::endl;
+ libelf_initialise ();
- if (::elf_rand (elf, offset) != offset)
- error ("begin:" + image.name ().full ());
+ /*
+ * Is this image part of an archive ?
+ */
+ if (archive_)
+ {
+ ssize_t offset = offset_ - rld_archive_fhdr_size;
+ if (::elf_rand (archive_->elf_, offset) != offset)
+ libelf_error ("rand: " + archive_->name_);
}
/*
* Note, the elf passed is either the archive or NULL.
*/
- elf = ::elf_begin (image.fd (), ELF_C_READ, elf);
- if (!elf)
- error ("begin:" + image.name ().full ());
+ elf* elf__ = ::elf_begin (fd__,
+ writable_ ? ELF_C_WRITE : ELF_C_READ,
+ archive_ ? archive_->elf_ : 0);
+ if (!elf__)
+ libelf_error ("begin: " + name__);
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
- std::cout << "elf::begin: " << elf
- << ' ' << image.name ().full () << std::endl;
+ std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl;
- image.set_elf (elf);
+ elf_kind ek = ::elf_kind (elf__);
- elf_kind ek = ::elf_kind (elf);
- if (image.name ().is_archive ())
+ /*
+ * If this is inside an archive it must be an ELF file.
+ */
+
+ if (archive_ && (ek != ELF_K_ELF))
+ throw rld::error ("File format in archive not ELF", "elf:file:begin: " + name__);
+ else
{
- if (ek != ELF_K_AR)
- throw rld::error ("File not an ar archive", "libelf:" + image.name ().full ());
+ if (ek == ELF_K_AR)
+ archive = true;
+ else if (ek == ELF_K_ELF)
+ archive = false;
+ else
+ throw rld::error ("File format not ELF or archive",
+ "elf:file:begin: " + name__);
}
- else if (ek != ELF_K_ELF)
- throw rld::error ("File format not ELF", "libelf:" + image.name ().full ());
- /*
- * If an ELF file make sure they all match. On the first file that begins
- * an ELF session record its settings.
- */
- if (ek == ELF_K_ELF)
+ if (!writable_)
{
- int cl = ::gelf_getclass (elf);
-
- if (elf_object_class == ELFCLASSNONE)
- elf_object_class = cl;
- else if (cl != elf_object_class)
- throw rld::error ("Mixed classes not allowed (32bit/64bit).",
- "begin:" + image.name ().full ());
-
- char* ident = elf_getident (elf, NULL);
-
- if (elf_object_data == ELFDATANONE)
- elf_object_data = ident[EI_DATA];
- else if (elf_object_data != ident[EI_DATA])
- throw rld::error ("Mixed data types not allowed (LSB/MSB).",
- "begin:" + image.name ().full ());
+ /*
+ * If an ELF file make sure they all match. On the first file that
+ * begins an ELF session record its settings.
+ */
+ if (ek == ELF_K_ELF)
+ {
+ oclass = ::gelf_getclass (elf__);
+ ident_str = elf_getident (elf__, &ident_size);
+ }
}
+
+ fd_ = fd__;
+ name_ = name__;
+ writable = writable_;
+ elf_ = elf__;
+
+ if (!archive)
+ load_header ();
}
void
- end (rld::files::image& image)
+ file::end ()
{
- ::Elf* elf = image.elf ();
- if (elf)
+ if (elf_)
{
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
- std::cout << "elf::end: " << elf
- << ' ' << image.name ().full () << std::endl;
- ::elf_end (elf);
+ std::cout << "libelf::end: " << elf_
+ << ' ' << name_ << std::endl;
+ ::elf_end (elf_);
}
- image.set_elf (0);
+
+ fd_ = -1;
+ name_.clear ();
+ archive = false;
+ elf_ = 0;
+ oclass = 0;
+ ident_str = 0;
+ ident_size = 0;
+ memset (&ehdr, 0, sizeof (ehdr));
+ memset (&phdr, 0, sizeof (phdr));
+ stab.clear ();
+ secs.clear ();
}
void
- get_header (rld::files::image& image, elf_ehdr& ehdr)
+ file::load_header ()
{
- if (::gelf_getehdr (image.elf (), &ehdr) == NULL)
- error ("get-header:" + image.name ().full ());
-
- if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_REL))
- throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
- "get-header:" + image.name ().full ());
+ check ("get_header");
- if (elf_object_machinetype == EM_NONE)
- elf_object_machinetype = ehdr.e_machine;
- else if (elf_object_machinetype != ehdr.e_machine)
+ if (::gelf_getehdr (elf_, &ehdr) == NULL)
+ error ("get-header");
+ }
+
+ unsigned int
+ file::machinetype () const
+ {
+ check ("machinetype");
+ return ehdr.e_machine;
+ }
+
+ unsigned int
+ file::type () const
+ {
+ check ("type");
+ return ehdr.e_type;
+ }
+
+ unsigned int
+ file::object_class () const
+ {
+ check ("object_class");
+ return oclass;
+ }
+
+ unsigned int
+ file::data_type () const
+ {
+ check ("data_type");
+ if (!ident_str)
+ throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_);
+ return ident_str[EI_DATA];
+ }
+
+ bool
+ file::is_archive () const
+ {
+ check ("is_archive");
+ return archive;
+ }
+
+ bool
+ file::is_executable () const
+ {
+ check ("is_executable");
+ return ehdr.e_type != ET_REL;
+ }
+
+ bool
+ file::is_relocatable() const
+ {
+ check ("is_relocatable");
+ return ehdr.e_type == ET_REL;
+ }
+
+ int
+ file::section_count () const
+ {
+ check ("section_count");
+ return ehdr.e_shnum;
+ }
+
+ void
+ file::load_sections ()
+ {
+ if (secs.empty ())
{
- std::ostringstream oss;
- oss << "get-header:" << image.name ().full ()
- << ": " << elf_object_machinetype << '/' << ehdr.e_machine;
- throw rld::error ("Mixed machine types not supported.", oss.str ());
+ check ("load_sections_headers");
+ for (int sn = 0; sn < section_count (); ++sn)
+ secs.push_back (section (*this, sn));
}
}
void
- get_section_headers (rld::files::object& object,
- sections& secs,
- unsigned int type)
+ file::get_sections (sections& filtered_secs, unsigned int type)
{
- for (int sn = 0; sn < object.sections (); ++sn)
+ load_sections ();
+ filtered_secs.clear ();
+ for (sections::iterator si = secs.begin ();
+ si != secs.end ();
+ ++si)
{
- ::Elf_Scn* scn = ::elf_getscn (object.elf (), sn);
- if (!scn)
- error ("elf_getscn:" + object.name ().full ());
- ::GElf_Shdr shdr;
- if (!::gelf_getshdr (scn, &shdr))
- error ("gelf_getshdr:" + object.name ().full ());
- if (shdr.sh_type == type)
- {
- std::string name = get_string (object,
- object.section_strings (),
- shdr.sh_name);
- secs.push_back (section (sn, name, scn, shdr));
- }
+ if ((type == 0) || ((*si).type () == type))
+ filtered_secs.push_back (*si);
}
}
void
- load_symbol_table (rld::symbols::table& exported,
- rld::files::object& object,
- section& sec,
- bool local,
- bool weak,
- bool global)
- {
- int count = sec.shdr.sh_size / sec.shdr.sh_entsize;
- for (int s = 0; s < count; ++s)
+ file::load_symbols ()
+ {
+ if (symbols.empty ())
{
- GElf_Sym esym;
- if (!::gelf_getsym (sec.data, s, &esym))
- error ("gelf_getsym");
- std::string name = get_string (object, sec.shdr.sh_link, esym.st_name);
- if (!name.empty ())
+ sections symbol_secs;
+
+ get_sections (symbol_secs, SHT_SYMTAB);
+
+ for (sections::iterator si = symbol_secs.begin ();
+ si != symbol_secs.end ();
+ ++si)
{
- int stype = GELF_ST_TYPE (esym.st_info);
- int sbind = GELF_ST_BIND (esym.st_info);
- if (rld::verbose () >= RLD_VERBOSE_TRACE)
- {
- rld::symbols::symbol sym (name, esym);
- std::cout << "elf::symbol: ";
- sym.output (std::cout);
- std::cout << std::endl;
- }
- if ((stype == STT_NOTYPE) && (esym.st_shndx == SHN_UNDEF))
- object.unresolved_symbols ()[name] = rld::symbols::symbol (name, esym);
- else if (((stype == STT_NOTYPE) ||
- (stype == STT_OBJECT) ||
- (stype == STT_FUNC)) &&
- ((local && (sbind == STB_LOCAL)) ||
- (weak && (sbind == STB_WEAK)) ||
- (global && (sbind == STB_GLOBAL))))
+ section& sec = *si;
+ int syms = sec.entries ();
+
+ for (int s = 0; s < syms; ++s)
{
- exported[name] = rld::symbols::symbol (name, object, esym);;
- object.external_symbols ().push_back (&exported[name]);
+ elf_sym esym;
+
+ if (!::gelf_getsym (sec.data (), s, &esym))
+ error ("gelf_getsym");
+
+ std::string name = get_string (sec.link (), esym.st_name);
+
+ if (!name.empty ())
+ {
+ symbols::symbol sym (name, esym);
+
+ if (rld::verbose () >= RLD_VERBOSE_TRACE)
+ {
+ std::cout << "elf::symbol: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
+ }
+
+ symbols.push_back (sym);
+ }
}
}
}
}
void
+ file::get_symbols (symbols::pointers& filtered_syms,
+ bool unresolved,
+ bool local,
+ bool weak,
+ bool global)
+ {
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "elf:get-syms: unresolved:" << unresolved
+ << " local:" << local
+ << " weak:" << weak
+ << " global:" << global
+ << " " << name_
+ << std::endl;
+
+ load_symbols ();
+
+ filtered_syms.clear ();
+
+ for (symbols::bucket::iterator si = symbols.begin ();
+ si != symbols.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *si;
+
+ int stype = sym.type ();
+ int sbind = sym.binding ();
+
+ /*
+ * If wanting unresolved symbols and the type is no-type and the
+ * section is undefined, or, the type is no-type or object or function
+ * and the bind is local and we want local symbols, or the bind is weak
+ * and we want weak symbols, or the bind is global and we want global
+ * symbols then add the filtered symbols container.
+ */
+ bool add = false;
+
+ if ((stype == STT_NOTYPE) && (sym.index () == SHN_UNDEF))
+ {
+ if (unresolved)
+ add = true;
+ }
+ else if (!unresolved)
+ {
+ if (((stype == STT_NOTYPE) ||
+ (stype == STT_OBJECT) ||
+ (stype == STT_FUNC)) &&
+ ((local && (sbind == STB_LOCAL)) ||
+ (weak && (sbind == STB_WEAK)) ||
+ (global && (sbind == STB_GLOBAL))))
+ add = true;
+ }
+
+ if (add)
+ filtered_syms.push_back (&sym);
+ }
+ }
+
+ int
+ file::strings_section () const
+ {
+ check ("strings_sections");
+ return ehdr.e_shstrndx;
+ }
+
+ std::string
+ file::get_string (int section, size_t offset)
+ {
+ check ("get_string");
+ char* s = ::elf_strptr (elf_, section, offset);
+ if (!s)
+ error ("elf_strptr");
+ return s;
+ }
+
+ std::string
+ file::get_string (size_t offset)
+ {
+ check ("get_string");
+ char* s = ::elf_strptr (elf_, strings_section (), offset);
+ if (!s)
+ error ("elf_strptr");
+ return s;
+ }
+
+#if 0
+ void
+ file::set_header (xxx)
+ {
+ elf_ehdr* ehdr_ = ::gelf_newehdr (elf_);
+
+ if (ehdr == NULL)
+ error ("set-header");
+
+ ehdr->xx = xx;
+
+ ::gelf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY);
+ }
+#endif
+
+ elf*
+ file::get_elf ()
+ {
+ return elf_;
+ }
+
+ const std::string&
+ file::name () const
+ {
+ return name_;
+ }
+
+ bool
+ file::is_writable () const
+ {
+ return writable;
+ }
+
+ void
+ file::check (const char* where) const
+ {
+ if (!elf_ || (fd_ < 0))
+ {
+ std::string w = where;
+ throw rld::error ("no elf file or header", "elf:file:" + w);
+ }
+ }
+
+ void
+ file::check_writable (const char* where) const
+ {
+ check (where);
+ if (!writable)
+ {
+ std::string w = where;
+ throw rld::error ("not writable", "elf:file:" + w);
+ }
+ }
+
+ void
+ file::error (const char* where) const
+ {
+ std::string w = where;
+ libelf_error (w + ": " + name_);
+ }
+
+ const std::string
+ machine_type (unsigned int machinetype)
+ {
+ struct types_and_labels
+ {
+ const char* name; //< The RTEMS label.
+ unsigned int machinetype; //< The machine type.
+ };
+ types_and_labels types_to_labels[] =
+ {
+ { "arm", EM_ARM },
+ { "avr", EM_AVR },
+ { "bfin", EM_BLACKFIN },
+ { "h8300", EM_H8_300 },
+ { "i386", EM_386 },
+ /* { "m32c", EM_M32C }, Not in libelf I imported */
+ { "m32r", EM_M32R },
+ { "m68k", EM_68K },
+ { "m68k", EM_COLDFIRE },
+ { "mips", EM_MIPS },
+ { "powerpc", EM_PPC },
+ { "sh", EM_SH },
+ { "sparc", EM_SPARC },
+ { "sparc64", EM_SPARC },
+ { 0, EM_NONE }
+ };
+
+ int m = 0;
+ while (types_to_labels[m].machinetype != EM_NONE)
+ {
+ if (machinetype == types_to_labels[m].machinetype)
+ return types_to_labels[m].name;
+ ++m;
+ }
+
+ std::ostringstream what;
+ what << "unknown machine type: " << elf_object_machinetype;
+ throw rld::error (what, "machine-type");
+ }
+
+ const std::string machine_type ()
+ {
+ return machine_type (elf_object_machinetype);
+ }
+
+ void
+ check_file(const file& file)
+ {
+ if (elf_object_machinetype == EM_NONE)
+ elf_object_machinetype = file.machinetype ();
+ else if (file.machinetype () != elf_object_machinetype)
+ {
+ std::ostringstream oss;
+ oss << "elf:check_file:" << file.name ()
+ << ": " << elf_object_machinetype << '/' << file.machinetype ();
+ throw rld::error ("Mixed machine types not supported.", oss.str ());
+ }
+
+ if (elf_object_class == ELFCLASSNONE)
+ elf_object_class = file.object_class ();
+ else if (file.object_class () != elf_object_class)
+ throw rld::error ("Mixed classes not allowed (32bit/64bit).",
+ "elf:check_file: " + file.name ());
+
+ if (elf_object_data == ELFDATANONE)
+ elf_object_data = file.data_type ();
+ else if (elf_object_data != file.data_type ())
+ throw rld::error ("Mixed data types not allowed (LSB/MSB).",
+ "elf:check_file: " + file.name ());
+ }
+
+#if 0
+ void
load_symbols (rld::symbols::table& symbols,
- rld::files::object& object,
+ rld::files::object& object,
bool local,
bool weak,
bool global)
@@ -314,17 +720,7 @@ namespace rld
++si)
load_symbol_table (symbols, object, *si, local, weak, global);
}
-
- std::string
- get_string (rld::files::object& object,
- int section,
- size_t offset)
- {
- char* s = ::elf_strptr (object.elf (), section, offset);
- if (!s)
- error ("elf_strptr");
- return s;
- }
+#endif
}
}
diff --git a/rld-elf.h b/rld-elf.h
index 763ab55..4f37636 100644
--- a/rld-elf.h
+++ b/rld-elf.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -34,87 +34,360 @@ namespace rld
namespace elf
{
/**
- * Sections.
+ * Forward decl.
*/
- struct section
+ class file;
+
+ /**
+ * An ELF Section.
+ */
+ class section
{
- int index; //< The section header index.
- std::string name; //< The section's name.
- elf_scn* scn; //< ELF private section data.
- elf_shdr shdr; //< The section header.
- elf_data* data; //< The section's data.
-
+ public:
+ /**
+ * Construct the section getting the details.
+ *
+ * @param elf The ELF file this section is part of.
+ * @param index The sections index in the ELF file.
+ */
+ section (file& file_, int index);
+
/**
- * Construct the section and get the data value.
+ * Copy constructor.
*/
- section (int index,
- std::string& name,
- elf_scn* scn,
- elf_shdr& sdhr);
+ section (const section& orig);
/**
* Default constructor.
*/
section ();
+
+ /**
+ * The section's index in the ELF file.
+ *
+ * @return int The section number.
+ */
+ int index () const;
+
+ /**
+ * The name of the section.
+ *
+ * @return const std::string& The section's name.
+ */
+ const std::string& name () const;
+
+ /**
+ * The section's data.
+ */
+ elf_data* data ();
+
+ /**
+ * Get the type of the section.
+ */
+ elf_word type () const;
+
+ /**
+ * The section flags.
+ */
+ elf_xword flags () const;
+
+ /**
+ * In-memory address of the section.
+ */
+ elf_addr address () const;
+
+ /**
+ * Alignment constraint.
+ */
+ elf_xword alignment () const;
+
+ /**
+ * The file offset of the section.
+ */
+ elf_off offset () const;
+
+ /**
+ * The header table link.
+ */
+ elf_word link () const;
+
+ /**
+ * Extra information.
+ */
+ elf_word info () const;
+
+ /**
+ * Size of the section.
+ */
+ elf_xword size () const;
+
+ /**
+ * Size of the entries in the section.
+ */
+ elf_xword entry_size () const;
+
+ /**
+ * Number of entries.
+ */
+ int entries () const;
+
+ private:
+
+ /**
+ * Check the section is acrtual valid.
+ */
+ void check () const;
+
+ file* file_; //< The ELF file.
+ int index_; //< The section header index.
+ std::string name_; //< The section's name.
+ elf_scn* scn; //< ELF private section data.
+ elf_shdr shdr; //< The section header.
+ elf_data* data_; //< The section's data.
};
/**
- * Container of section headers.
+ * Container of ELF sections.
*/
typedef std::list < section > sections;
/**
- * Get the machine type detected in the object files as their headers are read.
+ * An ELF file.
*/
- const std::string machine_type ();
+ class file
+ {
+ public:
+ /**
+ * Construct an ELF file.
+ */
+ file ();
- /**
- * Begin a libelf session with the image.
- */
- void begin (rld::files::image& image);
+ /**
+ * Destruct the ELF file object.
+ */
+ ~file ();
- /**
- * End the libelf session with the image.
- */
- void end (rld::files::image& image);
+ /**
+ * Begin using the ELF file.
+ *
+ * @param name The full name of the file.
+ * @param fd The file descriptor to read or write the file.
+ * @param writable The file is writeable. The default is false.
+ */
+ void begin (const std::string& name, int fd, const bool writable = false);
- /**
- * Get the ELF header.
- */
- void get_header (rld::files::image& image, elf_ehdr& ehdr);
+ /**
+ * Begin using the ELF file in an archive.
+ *
+ * @param name The full name of the file.
+ * @param archive The file that is the archive.
+ * @param offset The offset of the ELF file in the archive.
+ */
+ void begin (const std::string& name, file& archive, off_t offset);
+
+ /**
+ * End using the ELF file.
+ */
+ void end ();
+
+ /**
+ * Load the header. Done automatically.
+ */
+ void load_header ();
+
+ /**
+ * Get the machine type.
+ */
+ unsigned int machinetype () const;
+
+ /**
+ * Get the type of ELF file.
+ */
+ unsigned int type () const;
+
+ /**
+ * Get the class of the object file.
+ */
+ unsigned int object_class () const;
+
+ /**
+ * Get the data type, ie LSB or MSB.
+ */
+ unsigned int data_type () const;
+
+ /**
+ * Is the file an archive format file ?
+ */
+ bool is_archive () const;
+
+ /**
+ * Is the file an executable ?
+ */
+ bool is_executable () const;
+
+ /**
+ * Is the file relocatable ?
+ */
+ bool is_relocatable() const;
+
+ /**
+ * The number of sections in the file.
+ */
+ int section_count () const;
+
+ /**
+ * Load the sections.
+ */
+ void load_sections ();
+
+ /**
+ * Get a filtered container of the sections. The key is the section
+ * type. If the sections are not loaded they are loaded. If the type is 0
+ * all sections are returned.
+ *
+ * @param filtered_secs The container the copy of the filtered sections
+ * are placed in.
+ * @param type The type of sections to filter on. If 0 all sections are
+ * matched.
+ */
+ void get_sections (sections& filtered_secs, unsigned int type);
+
+ /**
+ * Return the index of the string section.
+ */
+ int strings_section () const;
+
+ /**
+ * Get the string from the specified section at the requested offset.
+ *
+ * @param section The section to search for the string.
+ * @param offset The offset in the string section.
+ * @return std::string The string.
+ */
+ std::string get_string (int section, size_t offset);
+
+ /**
+ * Get the string from the ELF header declared string section at the
+ * requested offset.
+ *
+ * @param offset The offset in the string section.
+ * @return std::string The string.
+ */
+ std::string get_string (size_t offset);
+
+ /**
+ * Load the symbols.
+ */
+ void load_symbols ();
+
+ /**
+ * Get a filtered container of symbols given the various types. If the
+ * symbols are not loaded they are loaded.
+ *
+ * @param filter_syms The filtered symbols found in the file. This is a
+ * container of pointers.
+ * @param local Return local symbols.
+ * @param weak Return weak symbols.
+ * @param global Return global symbols.
+ * @param unresolved Return unresolved symbols.
+ */
+ void get_symbols (rld::symbols::pointers& filtered_syms,
+ bool unresolved = false,
+ bool local = false,
+ bool weak = true,
+ bool global = true);
+
+ /**
+ * Get the ELF reference.
+ */
+ elf* get_elf ();
+
+ /**
+ * Get the name of the file.
+ */
+ const std::string& name () const;
+
+ /**
+ * Is the file writable ?
+ */
+ bool is_writable () const;
+
+ private:
+
+ /**
+ * Begin using the ELF file.
+ *
+ * @param name The full name of the file.
+ * @param fd The file descriptor to read or write the file.
+ * @param writable The file is writeable. It cannot be part of an archive.
+ * @param archive The archive's ELF handle or 0 if not an archive.
+ * @param offset The offset of the ELF file in the archive if elf is non-zero.
+ */
+ void begin (const std::string& name,
+ int fd,
+ const bool writable,
+ file* archive,
+ off_t offset);
+
+ /**
+ * Check if the file is usable. Throw an exception if not.
+ *
+ * @param where Where the check is performed.
+ */
+ void check (const char* where) const;
+
+ /**
+ * Check if the file is usable and writable. Throw an exception if not.
+ *
+ * @param where Where the check is performed.
+ */
+ void check_writable (const char* where) const;
+
+ /**
+ * Generate libelf error.
+ *
+ * @param where Where the error is generated.
+ */
+ void error (const char* where) const;
+
+ int fd_; //< The file handle.
+ std::string name_; //< The name of the file.
+ bool archive; //< The ELF file is part of an archive.
+ bool writable; //< The file is writeable.
+ elf* elf_; //< The ELF handle.
+ unsigned int mtype; //< The machine type.
+ unsigned int oclass; //< The object class.
+ const char* ident_str; //< The ELF file's ident string.
+ size_t ident_size; //< The size of the ident.
+ elf_ehdr ehdr; //< The ELF header.
+ elf_phdr phdr; //< The ELF program header.
+ std::string stab; //< The string table.
+ sections secs; //< The sections.
+ rld::symbols::bucket symbols; //< The symbols. All tables point here.
+ };
/**
- * Get the section headers for an object file.
- */
- void get_section_headers (rld::files::object& object,
- sections& secs,
- unsigned int type = SHT_NULL);
-
- /**
- * Load the symbol table with the symbols.
+ * Return the machine type label given the machine type.
+ *
+ * @param machinetype The ELF machine type.
*/
- void load_symbol_table (rld::symbols::table& exported,
- rld::files::object& object,
- section& sec,
- bool local = false,
- bool weak = true,
- bool global = true);
-
+ const std::string machine_type (unsigned int machinetype);
+
/**
- * Load the symbol table with an object's symbols.
+ * Return the global machine type set by the check_file call.
*/
- void load_symbols (rld::symbols::table& symbols,
- rld::files::object& object,
- bool local = false,
- bool weak = true,
- bool global = true);
+ const std::string machine_type ();
/**
- * Get a string.
+ * Check the file against the global machine type, object class and data
+ * type. If this is the first file checked it becomes the default all
+ * others are checked against. This is a simple way to make sure all files
+ * are the same type.
+ *
+ * @param file The check to check.
*/
- std::string get_string (rld::files::object& object,
- int section,
- size_t offset);
+ void check_file(const file& file);
+
}
}
diff --git a/rld-files.cpp b/rld-files.cpp
index d44474b..108f920 100644
--- a/rld-files.cpp
+++ b/rld-files.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -45,7 +45,7 @@ namespace rld
scan_decimal (const uint8_t* string, size_t len)
{
uint64_t value = 0;
-
+
while (len && (*string != ' '))
{
value *= 10;
@@ -104,7 +104,7 @@ namespace rld
joined = path_ + RLD_PATH_SEPARATOR + file_;
else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) &&
(file_[0] == RLD_PATH_SEPARATOR))
- joined = path_ + &file_[1];
+ joined = path_ + &file_[1];
else
joined = path_ + file_;
}
@@ -147,7 +147,7 @@ namespace rld
const std::string& oname,
off_t offset,
size_t size)
- : aname_ (aname),
+ : aname_ (aname),
oname_ (oname),
offset_ (offset),
size_ (size)
@@ -246,8 +246,8 @@ namespace rld
return aname_;
return oname_;
}
-
- const std::string
+
+ const std::string
file::full () const
{
std::string f;
@@ -297,8 +297,7 @@ namespace rld
image::image (file& name)
: name_ (name),
references_ (0),
- fd_ (-1),
- elf_ (0)
+ fd_ (-1)
{
}
@@ -306,15 +305,14 @@ namespace rld
: name_ (path, is_object),
references_ (0),
fd_ (-1),
- elf_ (0),
- symbol_refs (0)
+ symbol_refs (0),
+ writeable (false)
{
}
image::image ()
: references_ (0),
fd_ (-1),
- elf_ (0),
symbol_refs (0)
{
}
@@ -335,26 +333,34 @@ namespace rld
}
void
- image::open (bool writable)
+ image::open (bool writeable_)
{
const std::string path = name_.path ();
if (path.empty ())
- throw rld::error ("No file name", "open" + path);
+ throw rld::error ("No file name", "open:" + path);
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << "image::open: " << name (). full ()
+ << " writable:" << (char*) (writeable_ ? "yes" : "no")
<< " refs:" << references_ + 1 << std::endl;
if (fd_ < 0)
{
- if (writable)
+ writeable = writeable_;
+
+ if (writeable)
fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE);
else
fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY);
if (fd_ < 0)
throw rld::error (::strerror (errno), "open:" + path);
}
+ else
+ {
+ if (writeable_ != writeable)
+ throw rld::error ("Cannot change write status", "open:" + path);
+ }
++references_;
}
@@ -385,7 +391,7 @@ namespace rld
throw rld::error (strerror (errno), "read:" + name ().path ());
return rsize;
}
-
+
ssize_t
image::write (const void* buffer, size_t size)
{
@@ -394,28 +400,28 @@ namespace rld
throw rld::error (strerror (errno), "write:" + name ().path ());
return wsize;
}
-
+
void
image::seek (off_t offset)
{
if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0)
throw rld::error (strerror (errno), "lseek:" + name ().path ());
}
-
+
bool
image::seek_read (off_t offset, uint8_t* buffer, size_t size)
{
seek (offset);
return size == (size_t) read (buffer, size);
}
-
+
bool
image::seek_write (off_t offset, const void* buffer, size_t size)
{
seek (offset);
return size == (size_t) write (buffer, size);
}
-
+
const file&
image::name () const
{
@@ -423,41 +429,35 @@ namespace rld
}
int
- image::references () const
+ image::references () const
{
return references_;
}
size_t
- image::size () const
+ image::size () const
{
return name ().size ();
}
int
- image::fd () const
+ image::fd () const
{
return fd_;
}
- rld::elf::elf*
- image::elf (bool )
+ rld::elf::file&
+ image::elf ()
{
return elf_;
}
void
- image::set_elf (rld::elf::elf* elf)
- {
- elf_ = elf;
- }
-
- void
image::symbol_referenced ()
{
++symbol_refs;
}
-
+
int
image::symbol_references () const
{
@@ -474,6 +474,10 @@ namespace rld
buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
while (size)
{
+ /*
+ * @fixme the reading and writing are not POSIX; sigints could split them.
+ */
+
size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
ssize_t r = ::read (in.fd (), buffer, l);
@@ -545,6 +549,25 @@ namespace rld
close ();
}
+ void
+ archive::begin ()
+ {
+ elf ().begin (name ().full (), fd ());
+
+ /*
+ * Make sure it is an archive.
+ */
+ if (!elf ().is_archive ())
+ throw rld::error ("Not an archive.",
+ "archive-begin:" + name ().full ());
+ }
+
+ void
+ archive::end ()
+ {
+ elf ().end ();
+ }
+
bool
archive::is (const std::string& path) const
{
@@ -580,8 +603,8 @@ namespace rld
/*
* The archive file headers are always aligned to an even address.
*/
- size =
- (scan_decimal (&header[rld_archive_size],
+ size =
+ (scan_decimal (&header[rld_archive_size],
rld_archive_size_size) + 1) & ~1;
/*
@@ -625,15 +648,15 @@ namespace rld
off_t off = offset;
while (extended_file_names == 0)
{
- size_t esize =
+ size_t esize =
(scan_decimal (&header[rld_archive_size],
rld_archive_size_size) + 1) & ~1;
off += esize + rld_archive_fhdr_size;
-
+
if (!read_header (off, &header[0]))
throw rld::error ("No GNU extended file name section found",
"get-names:" + name ().path ());
-
+
if ((header[0] == '/') && (header[1] == '/'))
{
extended_file_names = off + rld_archive_fhdr_size;
@@ -693,7 +716,7 @@ namespace rld
(header[rld_archive_magic + 1] != 0x0a))
throw rld::error ("Invalid header magic numbers at " +
rld::to_string (offset), "read-header:" + name ().path ());
-
+
return true;
}
@@ -725,7 +748,7 @@ namespace rld
uint8_t header[rld_archive_fhdr_size];
memset (header, ' ', sizeof (header));
-
+
size_t len = name.length ();
if (len > rld_archive_fname_size)
len = rld_archive_fname_size;
@@ -756,7 +779,7 @@ namespace rld
* GNU extended filenames.
*/
std::string extended_file_names;
-
+
for (object_list::iterator oi = objects.begin ();
oi != objects.end ();
++oi)
@@ -818,7 +841,7 @@ namespace rld
close ();
throw;
}
-
+
close ();
}
@@ -877,16 +900,34 @@ namespace rld
object::begin ()
{
/*
- * Begin an ELF session and get the ELF header.
+ * Begin a session.
+ */
+ if (archive_)
+ elf ().begin (name ().full (), archive_->elf(), name ().offset ());
+ else
+ elf ().begin (name ().full (), fd ());
+
+ /*
+ * Cannot be an archive.
*/
- rld::elf::begin (*this);
- rld::elf::get_header (*this, ehdr);
+ if (elf ().is_archive ())
+ throw rld::error ("Is an archive not an object file.",
+ "object-begin:" + name ().full ());
+
+ /*
+ * We only support executable or relocatable ELF files.
+ */
+ if (!elf ().is_executable () && !elf ().is_relocatable ())
+ throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
+ "object-begin:" + name ().full ());
+
+ elf::check_file (elf ());
}
void
object::end ()
{
- rld::elf::end (*this);
+ elf ().end ();
}
void
@@ -894,17 +935,58 @@ namespace rld
{
if (rld::verbose () >= RLD_VERBOSE_DETAILS)
std::cout << "object:load-sym: " << name ().full () << std::endl;
- rld::elf::load_symbols (symbols, *this, local);
- }
- std::string
- object::get_string (int section, size_t offset)
- {
- return rld::elf::get_string (*this, section, offset);
+ rld::symbols::pointers syms;
+
+ elf ().get_symbols (syms, false, local);
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "object:load-sym: exported: total "
+ << syms.size () << std::endl;
+
+ for (symbols::pointers::iterator si = syms.begin ();
+ si != syms.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *(*si);
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ {
+ std::cout << "object:load-sym: exported: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
+ }
+
+ sym.set_object (*this);
+ symbols[sym.name ()] = &sym;
+ externals.push_back (&sym);
+ }
+
+ elf ().get_symbols (syms, true);
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ std::cout << "object:load-sym: unresolved: total "
+ << syms.size () << std::endl;
+
+ for (symbols::pointers::iterator si = syms.begin ();
+ si != syms.end ();
+ ++si)
+ {
+ symbols::symbol& sym = *(*si);
+
+ if (rld::verbose () >= RLD_VERBOSE_DETAILS)
+ {
+ std::cout << "object:load-sym: unresolved: ";
+ sym.output (std::cout);
+ std::cout << std::endl;
+ }
+
+ unresolved[sym.name ()] = &sym;
+ }
}
-
+
int
- object::references () const
+ object::references () const
{
if (archive_)
return archive_->references ();
@@ -912,7 +994,7 @@ namespace rld
}
size_t
- object::size () const
+ object::size () const
{
if (archive_)
return archive_->size ();
@@ -920,21 +1002,13 @@ namespace rld
}
int
- object::fd () const
+ object::fd () const
{
if (archive_)
return archive_->fd ();
return image::fd ();
}
- rld::elf::elf*
- object::elf (bool archive__)
- {
- if (archive__ && archive_)
- return archive_->elf ();
- return image::elf ();
- }
-
void
object::symbol_referenced ()
{
@@ -942,13 +1016,14 @@ namespace rld
if (archive_)
archive_->symbol_referenced ();
}
-
+
archive*
object::get_archive ()
{
return archive_;
}
+#if 0
int
object::sections () const
{
@@ -960,6 +1035,7 @@ namespace rld
{
return ehdr.e_shstrndx;
}
+#endif
rld::symbols::table&
object::unresolved_symbols ()
@@ -967,7 +1043,7 @@ namespace rld
return unresolved;
}
- rld::symbols::list&
+ rld::symbols::pointers&
object::external_symbols ()
{
return externals;
@@ -1047,7 +1123,7 @@ namespace rld
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "cache:archive-begin: " << path << std::endl;
ar->open ();
- rld::elf::begin (*ar);
+ ar->begin ();
}
}
}
@@ -1063,7 +1139,7 @@ namespace rld
{
if (rld::verbose () >= RLD_VERBOSE_TRACE)
std::cout << "cache:archive-end: " << path << std::endl;
- rld::elf::end (*ar);
+ ar->end ();
ar->close ();
}
}
@@ -1082,7 +1158,7 @@ namespace rld
for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
archive_end (((*ai).second)->path ());
}
-
+
void
cache::collect_object_files ()
{
@@ -1173,7 +1249,7 @@ namespace rld
{
return archives_;
}
-
+
objects&
cache::get_objects ()
{
diff --git a/rld-files.h b/rld-files.h
index 976f60a..26c7723 100644
--- a/rld-files.h
+++ b/rld-files.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -26,7 +26,7 @@
* handle. A handle is the object file with the specific file descriptor
* created when the archive or object file was opened.
*
- *
+ *
*/
#if !defined (_RLD_FILES_H_)
@@ -67,7 +67,7 @@ namespace rld
* Container list of object files.
*/
typedef std::list < object* > object_list;
-
+
/**
* Split a path from a string with a delimiter to the path container. Add
* only the paths that exist and ignore those that do not.
@@ -78,8 +78,8 @@ namespace rld
/**
* Make a path by joining the parts with required separator.
*/
- void path_join (const std::string& path_,
- const std::string& file_,
+ void path_join (const std::string& path_,
+ const std::string& file_,
std::string& joined);
/**
@@ -91,7 +91,7 @@ namespace rld
* Check the path is a directory.
*/
bool check_directory (const std::string& path);
-
+
/**
* Find the file given a container of paths and file names.
*
@@ -99,7 +99,7 @@ namespace rld
* @param name The name of the file to search for.
* @param search_paths The container of paths to search.
*/
- void find_file (std::string& path,
+ void find_file (std::string& path,
const std::string& name,
paths& search_paths);
@@ -323,15 +323,9 @@ namespace rld
virtual int fd () const;
/**
- * The libelf reference. The ELF image could be in an archive container
- * so set container to true to get the archive's reference.
+ * The ELF reference.
*/
- virtual rld::elf::elf* elf (bool archive = false);
-
- /**
- * Set the libelf reference.
- */
- void set_elf (rld::elf::elf* elf);
+ elf::file& elf ();
/**
* A symbol in the image has been referenced.
@@ -353,21 +347,33 @@ namespace rld
}
/**
- * Is the archive open ?
+ * Is the image open ?
*
- * @retval true The archive is open.
- * @retval false The archive is not open.
+ * @retval true The image is open.
+ * @retval false The image is not open.
*/
bool is_open () const {
return fd () != -1;
}
+ /**
+ * Is the image writable ?
+ *
+ * @retval true The image is writeable.
+ * @retval false The image is not writeable.
+ */
+ bool is_writeable () const {
+ return writeable;
+ }
+
private:
+
file name_; //< The name of the file.
int references_; //< The number of handles open.
int fd_; //< The file descriptor of the archive.
- elf::elf* elf_; //< The libelf reference.
+ elf::file elf_; //< The libelf reference.
int symbol_refs; //< The number of symbols references made.
+ bool writeable; //< The image is writable.
};
/**
@@ -396,6 +402,16 @@ namespace rld
virtual ~archive ();
/**
+ * Begin the ELF session.
+ */
+ void begin ();
+
+ /**
+ * End the ELF session.
+ */
+ void end ();
+
+ /**
* Match the archive name.
*
* @param name The name of the archive to check.
@@ -413,7 +429,7 @@ namespace rld
* Load objects.
*/
void load_objects (objects& objs);
-
+
/**
* Get the name.
*/
@@ -431,6 +447,7 @@ namespace rld
void create (object_list& objects);
private:
+
/**
* Read header.
*/
@@ -441,7 +458,7 @@ namespace rld
*/
void add_object (objects& objs,
const char* name,
- off_t offset,
+ off_t offset,
size_t size);
/**
@@ -528,7 +545,7 @@ namespace rld
/**
* Get the string from the string table.
*/
- std::string get_string (int section, size_t offset);
+// std::string get_string (int section, size_t offset);
/**
* References to the image.
@@ -546,12 +563,6 @@ namespace rld
virtual int fd () const;
/**
- * The libelf reference. The ELF image could be in an archive container
- * so set container to true to get the archive's reference.
- */
- virtual elf::elf* elf (bool archive = false);
-
- /**
* A symbol in the image has been referenced.
*/
virtual void symbol_referenced ();
@@ -562,6 +573,7 @@ namespace rld
*/
archive* get_archive ();
+#if 0
/**
* Number of sections in the object file.
*/
@@ -571,6 +583,7 @@ namespace rld
* Section string index.
*/
int section_strings () const;
+#endif
/**
* Return the unresolved symbol table for this object file.
@@ -580,14 +593,13 @@ namespace rld
/**
* Return the list external symbols.
*/
- rld::symbols::list& external_symbols ();
+ rld::symbols::pointers& external_symbols ();
private:
- archive* archive_; //< Points to the archive if part of an
- // archive.
- elf::elf_ehdr ehdr; //< The ELF header.
- rld::symbols::table unresolved; //< This object's unresolved symbols.
- rld::symbols::list externals; //< This object's external symbols.
+ archive* archive_; //< Points to the archive if part of
+ // an archive.
+ rld::symbols::table unresolved; //< This object's unresolved symbols.
+ rld::symbols::pointers externals; //< This object's external symbols.
/**
* Cannot copy via a copy constructor.
@@ -644,22 +656,22 @@ namespace rld
void add_libraries (paths& paths__);
/**
- * Being an ELF session on an archive.
+ * Being a session on an archive.
*/
void archive_begin (const std::string& path);
/**
- * End an ELF session on an archive.
+ * End a session on an archive.
*/
void archive_end (const std::string& path);
/**
- * Being ELF sessions on all archives.
+ * Being sessions on all archives.
*/
void archives_begin ();
/**
- * End the archive elf sessions.
+ * End the archive sessions.
*/
void archives_end ();
@@ -667,13 +679,13 @@ namespace rld
* Collect the object names and add them to the cache.
*/
void collect_object_files ();
-
+
/**
* Collect the object file names by verifing the paths to the files are
* valid or read the object file names contained in any archives.
*/
void collect_object_files (const std::string& path);
-
+
/**
* Load the symbols into the symbol table.
*
@@ -691,12 +703,12 @@ namespace rld
* Get the archives.
*/
archives& get_archives ();
-
+
/**
* Get the objects inlcuding those in archives.
*/
objects& get_objects ();
-
+
/**
* Get the added objects. Does not include the ones in th archives.
*/
diff --git a/rld-outputter.cpp b/rld-outputter.cpp
index ef18d5d..bdd9dfa 100644
--- a/rld-outputter.cpp
+++ b/rld-outputter.cpp
@@ -68,7 +68,7 @@ namespace rld
ursi != unresolved.begin ();
++ursi)
{
- rld::symbols::symbol& urs = (*ursi).second;
+ rld::symbols::symbol& urs = *((*ursi).second);
++count;
@@ -98,6 +98,8 @@ namespace rld
++oi)
objects.push_back (*oi);
+ objects.unique ();
+
rld::files::archive arch (name);
arch.create (objects);
}
@@ -128,46 +130,6 @@ namespace rld
}
out.close ();
-
-#if 0
- rld::files::object_list objects;
- cache.get_objects (objects);
-
- for (rld::files::object_list::iterator oi = objects.begin ();
- oi != objects.end ();
- ++oi)
- {
- rld::files::object& obj = *(*oi);
-
- if (rld::verbose () >= RLD_VERBOSE_INFO)
- std::cout << " o: " << obj.name ().full () << std::endl;
-
- out << "o:" << obj.name ().basename () << std::endl;
- }
-
- for (rld::files::object_list::iterator oi = dependents.begin ();
- oi != dependents.end ();
- ++oi)
- {
- rld::files::object& obj = *(*oi);
- rld::symbols::table& unresolved = obj.unresolved_symbols ();
-
- if (rld::verbose () >= RLD_VERBOSE_INFO)
- std::cout << " d: " << obj.name ().full () << std::endl;
-
- out << "d:" << obj.name ().basename () << std::endl;
-
- int count = 0;
- for (rld::symbols::table::iterator ursi = unresolved.begin ();
- ursi != unresolved.begin ();
- ++ursi)
- {
- ++count;
- rld::symbols::symbol& urs = (*ursi).second;
- out << " u:" << count << ':' << urs.name () << std::endl;
- }
- }
-#endif
}
}
}
diff --git a/rld-resolver.cpp b/rld-resolver.cpp
index fe75754..60b69ef 100644
--- a/rld-resolver.cpp
+++ b/rld-resolver.cpp
@@ -54,7 +54,7 @@ namespace rld
* unresolved symbol's object file to the file that resolves the
* symbol. Record each object file that is found and when all unresolved
* symbols in this object file have been found iterate over the found
- * object files resolving them. The 'usr' is the unresolved symbol and
+ * object files resolving them. The 'urs' is the unresolved symbol and
* 'es' is the exported symbol.
*/
@@ -66,19 +66,26 @@ namespace rld
<< object.name ().basename ()
<< ", unresolved: "
<< unresolved.size ()
- << ((*unresolved.begin ()).second.object () ? " (resolved)" : "")
+ << (((*unresolved.begin ()).second)->object () ? " (resolved)" : "")
<< std::endl;
rld::files::object_list objects;
for (rld::symbols::table::iterator ursi = unresolved.begin ();
- (ursi != unresolved.end ()) && !(*ursi).second.object ();
+ (ursi != unresolved.end ()) && !((*ursi).second)->object ();
++ursi)
{
- rld::symbols::symbol& urs = (*ursi).second;
+ rld::symbols::symbol& urs = *((*ursi).second);
rld::symbols::table::iterator esi = base_symbols.find (urs.name ());
bool base = true;
+ if (rld::verbose () >= RLD_VERBOSE_INFO)
+ {
+ std::cout << "resolver:resolve : "
+ << std::setw (nesting + 1) << ' '
+ << urs.name () << std::endl;
+ }
+
if (esi == base_symbols.end ())
{
esi = symbols.find (urs.name ());
@@ -88,7 +95,7 @@ namespace rld
base = false;
}
- rld::symbols::symbol& es = (*esi).second;
+ rld::symbols::symbol& es = *((*esi).second);
if (rld::verbose () >= RLD_VERBOSE_INFO)
{
diff --git a/rld-symbols.cpp b/rld-symbols.cpp
index 7c55869..127bb2f 100644
--- a/rld-symbols.cpp
+++ b/rld-symbols.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -57,7 +57,7 @@ namespace rld
}
symbol::symbol (const std::string& name,
- rld::files::object& object,
+ files::object& object,
const elf::elf_sym& esym)
: name_ (name),
object_ (&object),
@@ -104,13 +104,13 @@ namespace rld
esym_.st_value = value;
}
- const std::string&
+ const std::string&
symbol::name () const
{
return name_;
}
- const std::string&
+ const std::string&
symbol::demangled () const
{
return demangled_;
@@ -122,25 +122,43 @@ namespace rld
return (name_[0] == '_') && (name_[1] == 'Z');
}
+ int
+ symbol::type () const
+ {
+ return GELF_ST_TYPE (esym_.st_info);
+ }
+
+ int
+ symbol::binding () const
+ {
+ return GELF_ST_BIND (esym_.st_info);
+ }
+
+ int
+ symbol::index () const
+ {
+ return esym_.st_shndx;
+ }
+
rld::files::object*
symbol::object () const
{
return object_;
}
-
+
void
symbol::set_object (rld::files::object& obj)
{
object_ = &obj;
}
- const elf::elf_sym&
+ const elf::elf_sym&
symbol::esym () const
{
return esym_;
}
- void
+ void
symbol::referenced ()
{
++references_;
@@ -148,7 +166,7 @@ namespace rld
object_->symbol_referenced ();
}
- bool
+ bool
symbol::operator< (const symbol& rhs) const
{
return name_ < rhs.name_;
@@ -207,14 +225,14 @@ namespace rld
break;
}
- out << binding
+ out << binding
<< ' ' << type
- << " 0x" << std::setw (8) << std::setfill ('0') << std::hex
- << es.st_value
+ << " 0x" << std::setw (8) << std::setfill ('0') << std::hex
+ << es.st_value
<< std::dec << std::setfill (' ')
<< ' ' << std::setw (7) << es.st_size
<< ' ';
-
+
if (is_cplusplus ())
out << demangled ();
else
@@ -224,15 +242,27 @@ namespace rld
out << " (" << object ()->name ().basename () << ')';
}
+ void
+ load (bucket& bucket_, table& table_)
+ {
+ for (bucket::iterator sbi = bucket_.begin ();
+ sbi != bucket_.end ();
+ ++sbi)
+ {
+ symbol& sym = *sbi;
+ table_[sym.name ()] = &sym;
+ }
+ }
+
size_t
- referenced (list& symbols)
+ referenced (pointers& symbols)
{
size_t used = 0;
- for (rld::symbols::list::iterator sli = symbols.begin ();
+ for (pointers::iterator sli = symbols.begin ();
sli != symbols.end ();
++sli)
{
- rld::symbols::symbol& sym = *(*sli);
+ symbol& sym = *(*sli);
if (sym.references ())
++used;
}
@@ -249,7 +279,7 @@ namespace rld
si != symbols.end ();
++si)
{
- const symbol& sym = (*si).second;
+ const symbol& sym = *((*si).second);
out << std::setw (5) << index << ' ' << sym << std::endl;
++index;
}
diff --git a/rld-symbols.h b/rld-symbols.h
index ec6938d..f566efe 100644
--- a/rld-symbols.h
+++ b/rld-symbols.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -58,27 +58,27 @@ namespace rld
/**
* Construct an exported symbol with a object file.
*/
- symbol (const std::string& name,
- rld::files::object& object,
+ symbol (const std::string& name,
+ files::object& object,
const elf::elf_sym& esym);
/**
* Construct an unresolved symbol with no object file.
*/
symbol (const std::string& name, const elf::elf_sym& esym);
-
+
/**
* Construct a linker symbol that is internally created.
*/
symbol (const std::string& name,
const elf::elf_addr value);
-
+
/**
* Construct a linker symbol that is internally created.
*/
- symbol (const char* name,
- rld::elf::elf_addr value = 0);
-
+ symbol (const char* name,
+ elf::elf_addr value = 0);
+
/**
* The symbol's name.
*/
@@ -95,20 +95,35 @@ namespace rld
bool is_cplusplus () const;
/**
+ * The symbol's type.
+ */
+ int type () const;
+
+ /**
+ * The symbol's binding, ie local, weak, or global.
+ */
+ int binding () const;
+
+ /**
+ * The synbol's section index.
+ */
+ int index () const;
+
+ /**
* The symbol's object file name.
*/
- rld::files::object* object () const;
+ files::object* object () const;
/**
* Set the symbol's object file name. Used when resolving unresolved
* symbols.
*/
- void set_object (rld::files::object& obj);
+ void set_object (files::object& obj);
/**
* The ELF symbol.
*/
- const ::GElf_Sym& esym () const;
+ const elf::elf_sym& esym () const;
/**
* Return the number of references.
@@ -133,28 +148,39 @@ namespace rld
void output (std::ostream& out) const;
private:
- std::string name_; //< The name of the symbol.
- std::string demangled_; //< If a C++ symbol the demangled name.
- rld::files::object* object_; //< The object file containing the
- // symbol.
- ::GElf_Sym esym_; //< The ELF symbol.
- int references_; //< The number of times if it referenced.
+
+ 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.
+ elf::elf_sym esym_; //< The ELF symbol.
+ int references_; //< The number of times if it referenced.
};
/**
- * List of symbol references.
+ * Container of symbols. A bucket of symbols.
+ */
+ typedef std::list < symbol > bucket;
+
+ /**
+ * References to symbols. Should always point to symbols held in a bucket.
+ */
+ typedef std::list < symbol* > pointers;
+
+ /**
+ * A symbols table is a map container of symbols. Should always point to
+ * symbols held in a bucket.
*/
- typedef std::list < symbol* > list;
+ typedef std::map < std::string, symbol* > table;
/**
- * A symbols table is a map container of symbols.
+ * Load a table from a buckey.
*/
- typedef std::map < std::string, symbol > table;
+ void load (bucket& bucket_, table& table_);
/**
- * Given a list of symbols return how many are referenced.
+ * Given a container of symbols return how many are referenced.
*/
- size_t referenced (list& symbols);
+ size_t referenced (pointers& symbols);
/**
* Output the symbol table.
@@ -166,7 +192,8 @@ namespace rld
/**
* Output stream operator.
*/
-static inline std::ostream& operator<< (std::ostream& out, const rld::symbols::symbol& sym) {
+static inline std::ostream& operator<< (std::ostream& out,
+ const rld::symbols::symbol& sym) {
sym.output (out);
return out;
}
diff --git a/rld.cpp b/rld.cpp
index bd4a90a..997291d 100644
--- a/rld.cpp
+++ b/rld.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2011, 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
@@ -64,7 +64,7 @@ namespace rld
* The output passed on the command line.
*/
static std::string output;
-
+
void
verbose_inc ()
{
@@ -116,7 +116,7 @@ namespace rld
std::cout << "Archive files : " << cache.archive_count () << std::endl;
std::cout << "Object files : " << cache.object_count () << std::endl;
std::cout << "Exported symbols : " << symbols.size () << std::endl;
-
+
std::cout << "Archives:" << std::endl;
cache.output_archive_files (std::cout);
std::cout << "Objects:" << std::endl;
@@ -136,9 +136,9 @@ namespace rld
oli != objects.end ();
++oli)
{
- rld::files::object& object = *(*oli);
- rld::symbols::list& externals = object.external_symbols ();
-
+ rld::files::object& object = *(*oli);
+ rld::symbols::pointers& externals = object.external_symbols ();
+
if (rld::symbols::referenced (externals) != externals.size ())
{
if (first)
@@ -149,7 +149,7 @@ namespace rld
std::cout << ' ' << object.name ().basename () << std::endl;
- for (rld::symbols::list::iterator sli = externals.begin ();
+ for (rld::symbols::pointers::iterator sli = externals.begin ();
sli != externals.end ();
++sli)
{
diff --git a/main.cpp b/rtems-ld.cpp
index 28a405a..f04b8b0 100644
--- a/main.cpp
+++ b/rtems-ld.cpp
@@ -155,24 +155,26 @@ main (int argc, char* argv[])
try
{
- rld::files::cache cache;
- rld::files::cache base;
- rld::files::paths libpaths;
- rld::files::paths libs;
- rld::files::paths objects;
- rld::files::paths libraries;
- rld::symbols::table base_symbols;
- rld::symbols::table symbols;
- rld::symbols::table undefined;
- std::string entry;
- std::string output = "a.out";
- std::string base_name;
- std::string cc_name;
- bool script = false;
- bool standard_libs = true;
- bool exec_prefix_set = false;
- bool map = false;
- bool warnings = false;
+ rld::files::cache cache;
+ rld::files::cache base;
+ rld::files::paths libpaths;
+ rld::files::paths libs;
+ rld::files::paths objects;
+ rld::files::paths libraries;
+ rld::symbols::bucket defines;
+ rld::symbols::bucket undefines;
+ rld::symbols::table base_symbols;
+ rld::symbols::table symbols;
+ rld::symbols::table undefined;
+ std::string entry;
+ std::string output = "a.out";
+ std::string base_name;
+ std::string cc_name;
+ bool script = false;
+ bool standard_libs = true;
+ bool exec_prefix_set = false;
+ bool map = false;
+ bool warnings = false;
libpaths.push_back (".");
@@ -254,11 +256,11 @@ main (int argc, char* argv[])
break;
case 'd':
- symbols[optarg] = rld::symbols::symbol (optarg);
+ defines.push_back (rld::symbols::symbol (optarg));
break;
case 'u':
- undefined[optarg] = rld::symbols::symbol (optarg);
+ undefines.push_back (rld::symbols::symbol (optarg));
break;
case 'b':
@@ -295,6 +297,17 @@ main (int argc, char* argv[])
objects.push_back (*argv++);
/*
+ * Load the symbol table with the defined symbols from the defines bucket.
+ */
+ rld::symbols::load (defines, symbols);
+
+ /*
+ * Load the undefined table with the undefined symbols from the undefines
+ * bucket.
+ */
+ rld::symbols::load (undefines, undefined);
+
+ /*
* Add the object files to the cache.
*/
cache.add (objects);
@@ -397,7 +410,7 @@ main (int argc, char* argv[])
int status;
char* realname;
realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
- std::cerr << "error: std::exception: " << realname << " [";
+ std::cerr << "error: exception: " << realname << " [";
::free (realname);
const std::type_info &ti = typeid (e);
realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
diff --git a/rtems-syms.cpp b/rtems-syms.cpp
new file mode 100644
index 0000000..822e0e6
--- /dev/null
+++ b/rtems-syms.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2011-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_rld
+ *
+ * @brief RTEMS Symbols Main manages opions, sequence of operations and exceptions.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#include <rld.h>
+#include <rld-cc.h>
+#include <rld-outputter.h>
+#include <rld-process.h>
+#include <rld-resolver.h>
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
+/**
+ * RTEMS Linker options. This needs to be rewritten to be like cc where only a
+ * single '-' and long options is present.
+ */
+static struct option rld_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "warn", no_argument, NULL, 'w' },
+ { "lib-path", required_argument, NULL, 'L' },
+ { "lib", required_argument, NULL, 'l' },
+ { "no-stdlibs", no_argument, NULL, 'n' },
+ { "cc", required_argument, NULL, 'C' },
+ { "exec-prefix", required_argument, NULL, 'E' },
+ { "march", required_argument, NULL, 'a' },
+ { "mcpu", required_argument, NULL, 'c' },
+ { NULL, 0, NULL, 0 }
+};
+
+void
+usage (int exit_code)
+{
+ std::cout << "rtems-syms [options] objects" << std::endl
+ << "Options and arguments:" << std::endl
+ << " -h : help (also --help)" << std::endl
+ << " -V : print linker version number and exit (also --version)" << std::endl
+ << " -v : verbose (trace import parts), can be supply multiple times" << std::endl
+ << " to increase verbosity (also --verbose)" << std::endl
+ << " -w : generate warnings (also --warn)" << std::endl
+ << " -L path : path to a library, add multiple for more than" << std::endl
+ << " one path (also --lib-path)" << std::endl
+ << " -l lib : add lib to the libraries searched, add multiple" << std::endl
+ << " for more than one library (also --lib)" << std::endl
+ << " -S : search standard libraries (also --stdlibs)" << std::endl
+ << " -C file : execute file as the target C compiler (also --cc)" << std::endl
+ << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
+ << " -a march : machine architecture (also --march)" << std::endl
+ << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl;
+ ::exit (exit_code);
+}
+
+static void
+fatal_signal (int signum)
+{
+ signal (signum, SIG_DFL);
+
+ rld::process::temporaries.clean_up ();
+
+ /*
+ * Get the same signal again, this time not handled, so its normal effect
+ * occurs.
+ */
+ kill (getpid (), signum);
+}
+
+static void
+setup_signals (void)
+{
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_signal);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_signal);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_signal);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_signal);
+#endif
+#ifdef SIGCHLD
+ signal (SIGCHLD, SIG_DFL);
+#endif
+}
+
+int
+main (int argc, char* argv[])
+{
+ int ec = 0;
+
+ setup_signals ();
+
+ try
+ {
+ rld::files::cache cache;
+ rld::files::paths libpaths;
+ rld::files::paths libs;
+ rld::files::paths objects;
+ rld::files::paths libraries;
+ rld::symbols::table symbols;
+ std::string base_name;
+ std::string cc_name;
+ bool standard_libs = false;
+ bool exec_prefix_set = false;
+ bool warnings = false;
+
+ libpaths.push_back (".");
+
+ while (true)
+ {
+ int opt = ::getopt_long (argc, argv, "hvwVSE:L:l:a:c:C:", rld_opts, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt)
+ {
+ case 'V':
+ std::cout << "rtems-syms (RTEMS Symbols) " << rld::version ()
+ << std::endl;
+ ::exit (0);
+ break;
+
+ case 'v':
+ rld::verbose_inc ();
+ break;
+
+ case 'w':
+ warnings = true;
+ break;
+
+ case 'l':
+ /*
+ * The order is important. It is the search order.
+ */
+ libs.push_back (optarg);
+ break;
+
+ case 'L':
+ if ((optarg[::strlen (optarg) - 1] == '/') ||
+ (optarg[::strlen (optarg) - 1] == '\\'))
+ optarg[::strlen (optarg) - 1] = '\0';
+ libpaths.push_back (optarg);
+ break;
+
+ case 'S':
+ standard_libs = true;
+ break;
+
+ case 'C':
+ if (exec_prefix_set == true)
+ std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
+ rld::cc::cc = optarg;
+ break;
+
+ case 'E':
+ exec_prefix_set = true;
+ rld::cc::exec_prefix = optarg;
+ break;
+
+ case 'a':
+ rld::cc::march = optarg;
+ break;
+
+ case 'c':
+ rld::cc::mcpu = optarg;
+ break;
+
+ case '?':
+ usage (3);
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ std::cout << "RTEMS Symbols " << rld::version () << std::endl;
+
+ /*
+ * If there are no object files there is nothing to link.
+ */
+ if (argc == 0)
+ throw rld::error ("no object files", "options");
+
+ /*
+ * Load the remaining command line arguments into the cache as object
+ * files.
+ */
+ while (argc--)
+ objects.push_back (*argv++);
+
+ /*
+ * Add the object files to the cache.
+ */
+ cache.add (objects);
+
+ /*
+ * Open the cache.
+ */
+ cache.open ();
+
+ /*
+ * If the full path to CC is not provided and the exec-prefix is not set by
+ * the command line see if it can be detected from the object file
+ * types. This must be after we have added the object files because they
+ * are used when detecting.
+ */
+ if (rld::cc::cc.empty () && !exec_prefix_set)
+ rld::cc::exec_prefix = rld::elf::machine_type ();
+
+ /*
+ * Get the standard library paths
+ */
+ rld::cc::get_standard_libpaths (libpaths);
+
+ /*
+ * Get the command line libraries.
+ */
+ rld::files::find_libraries (libraries, libpaths, libs);
+
+ /*
+ * Are we to load standard libraries ?
+ */
+ if (standard_libs)
+ rld::cc::get_standard_libs (libraries, libpaths);
+
+ /*
+ * Load the library to the cache.
+ */
+ cache.add_libraries (libraries);
+
+ /*
+ * Load the symbol table.
+ */
+ cache.load_symbols (symbols);
+
+ rld::map (cache, symbols);
+ }
+ catch (rld::error re)
+ {
+ std::cerr << "error: "
+ << re.where << ": " << re.what
+ << std::endl;
+ ec = 10;
+ }
+ catch (std::exception e)
+ {
+ int status;
+ char* realname;
+ realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
+ std::cerr << "error: exception: " << realname << " [";
+ ::free (realname);
+ const std::type_info &ti = typeid (e);
+ realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
+ std::cerr << realname << "] " << e.what () << std::endl;
+ ::free (realname);
+ ec = 11;
+ }
+ catch (...)
+ {
+ /*
+ * Helps to know if this happens.
+ */
+ std::cout << "error: unhandled exception" << std::endl;
+ ec = 12;
+ }
+
+ return ec;
+}
diff --git a/wscript b/wscript
index 3a993d5..4649c7f 100644
--- a/wscript
+++ b/wscript
@@ -60,7 +60,7 @@ def build(bld):
# Build flags.
#
bld.warningflags = ['-Wall', '-Wextra', '-pedantic']
- bld.optflags = ['-O2']
+ bld.optflags = [] #['-O2']
bld.cflags = ['-pipe', '-g'] + bld.optflags
bld.cxxflags = ['-pipe', '-g'] + bld.optflags
bld.linkflags = ['-g']
@@ -79,19 +79,35 @@ def build(bld):
modules = ['fastlz', 'elf', 'iberty']
#
+ # RLD source.
+ #
+ rld_source = ['rld-elf.cpp',
+ 'rld-files.cpp',
+ 'rld-cc.cpp',
+ 'rld-outputter.cpp',
+ 'rld-process.cpp',
+ 'rld-resolver.cpp',
+ 'rld-symbols.cpp',
+ 'rld.cpp']
+
+ #
# Build the linker.
#
bld.program(target = 'rtems-ld',
- source = ['main.cpp',
- 'pkgconfig.cpp',
- 'rld-elf.cpp',
- 'rld-files.cpp',
- 'rld-cc.cpp',
- 'rld-outputter.cpp',
- 'rld-process.cpp',
- 'rld-resolver.cpp',
- 'rld-symbols.cpp',
- 'rld.cpp'],
+ source = ['rtems-ld.cpp',
+ 'pkgconfig.cpp'] + rld_source,
+ defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
+ includes = ['.'] + bld.includes,
+ cflags = bld.cflags + bld.warningflags,
+ cxxflags = bld.cxxflags + bld.warningflags,
+ linkflags = bld.linkflags,
+ use = modules)
+
+ #
+ # Build the symbols.
+ #
+ bld.program(target = 'rtems-syms',
+ source = ['rtems-syms.cpp'] + rld_source,
defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION],
includes = ['.'] + bld.includes,
cflags = bld.cflags + bld.warningflags,