summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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,