mirror of
https://git.rtems.org/rtems-tools/
synced 2025-05-15 08:27:36 +08:00

When generating the symbol table for loadable modules, include TLS symbols so that the modules can reference them.
490 lines
10 KiB
C++
490 lines
10 KiB
C++
/*
|
|
* 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
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
/**
|
|
* @file
|
|
*
|
|
* @ingroup rtems-ld
|
|
*
|
|
* @brief RTEMS Linker symbols manages the symbols from all the object files.
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <rld.h>
|
|
|
|
#include <libiberty/demangle.h>
|
|
|
|
namespace rld
|
|
{
|
|
namespace symbols
|
|
{
|
|
/**
|
|
* Get the demangled name.
|
|
*/
|
|
bool
|
|
demangle_name (const std::string& name, std::string& demangled)
|
|
{
|
|
bool yes = false;
|
|
if (name.length() == 0)
|
|
demangled = name;
|
|
else
|
|
{
|
|
std::string wrapper = "_GLOBAL__sub_I_";
|
|
size_t offset = 0;
|
|
if (name.compare (0, wrapper.length (), wrapper) == 0)
|
|
offset = wrapper.length ();
|
|
char* demangled_name = ::cplus_demangle (name.c_str () + offset,
|
|
DMGL_ANSI | DMGL_PARAMS | DMGL_TYPES |
|
|
DMGL_RET_POSTFIX);
|
|
if (demangled_name)
|
|
{
|
|
demangled = demangled_name;
|
|
::free (demangled_name);
|
|
yes = true;
|
|
}
|
|
}
|
|
return yes;
|
|
}
|
|
|
|
bool
|
|
is_cplusplus (const std::string& name)
|
|
{
|
|
std::string demangled;
|
|
return symbols::demangle_name (name, demangled);
|
|
}
|
|
|
|
symbol::symbol ()
|
|
: index_ (-1),
|
|
object_ (0),
|
|
references_ (0)
|
|
{
|
|
memset (&esym_, 0, sizeof (esym_));
|
|
}
|
|
|
|
symbol::symbol (int index,
|
|
const std::string& name,
|
|
files::object& object,
|
|
const elf::elf_sym& esym)
|
|
: index_ (index),
|
|
name_ (name),
|
|
object_ (&object),
|
|
esym_ (esym),
|
|
references_ (0)
|
|
{
|
|
if (!object_)
|
|
throw rld_error_at ("object pointer is 0");
|
|
if (!demangle_name (name_, demangled_))
|
|
demangled_ = name_;
|
|
}
|
|
|
|
symbol::symbol (int index,
|
|
const std::string& name,
|
|
const elf::elf_sym& esym)
|
|
: index_ (index),
|
|
name_ (name),
|
|
object_ (0),
|
|
esym_ (esym),
|
|
references_ (0)
|
|
{
|
|
if (!demangle_name (name_, demangled_))
|
|
demangled_ = name_;
|
|
}
|
|
|
|
symbol::symbol (const std::string& name,
|
|
const elf::elf_addr value)
|
|
: index_ (-1),
|
|
name_ (name),
|
|
object_ (0),
|
|
references_ (0)
|
|
{
|
|
memset (&esym_, 0, sizeof (esym_));
|
|
esym_.st_value = value;
|
|
}
|
|
|
|
symbol::symbol (const char* name,
|
|
const elf::elf_addr value)
|
|
: index_ (-1),
|
|
name_ (name),
|
|
object_ (0),
|
|
references_ (0)
|
|
{
|
|
memset (&esym_, 0, sizeof (esym_));
|
|
esym_.st_value = value;
|
|
}
|
|
|
|
int
|
|
symbol::index () const
|
|
{
|
|
return index_;
|
|
}
|
|
|
|
const std::string&
|
|
symbol::name () const
|
|
{
|
|
return name_;
|
|
}
|
|
|
|
const std::string&
|
|
symbol::demangled () const
|
|
{
|
|
return demangled_;
|
|
}
|
|
|
|
bool
|
|
symbol::is_cplusplus () const
|
|
{
|
|
return symbols::is_cplusplus (name_);
|
|
}
|
|
|
|
bool
|
|
symbol::is_local () const
|
|
{
|
|
return binding () == STB_LOCAL;
|
|
}
|
|
|
|
bool
|
|
symbol::is_weak () const
|
|
{
|
|
return binding () == STB_WEAK;
|
|
}
|
|
|
|
bool
|
|
symbol::is_global () const
|
|
{
|
|
return binding () == STB_GLOBAL;
|
|
}
|
|
|
|
int
|
|
symbol::type () const
|
|
{
|
|
return GELF_ST_TYPE (esym_.st_info);
|
|
}
|
|
|
|
int
|
|
symbol::binding () const
|
|
{
|
|
return GELF_ST_BIND (esym_.st_info);
|
|
}
|
|
|
|
int
|
|
symbol::section_index () const
|
|
{
|
|
return esym_.st_shndx;
|
|
}
|
|
|
|
elf::elf_addr
|
|
symbol::value () const
|
|
{
|
|
return esym_.st_value;
|
|
}
|
|
|
|
uint32_t
|
|
symbol::info () const
|
|
{
|
|
return esym_.st_info;
|
|
}
|
|
|
|
rld::files::object*
|
|
symbol::object () const
|
|
{
|
|
return object_;
|
|
}
|
|
|
|
void
|
|
symbol::set_object (rld::files::object& obj)
|
|
{
|
|
object_ = &obj;
|
|
}
|
|
|
|
const elf::elf_sym&
|
|
symbol::esym () const
|
|
{
|
|
return esym_;
|
|
}
|
|
|
|
void
|
|
symbol::referenced ()
|
|
{
|
|
++references_;
|
|
if (object_)
|
|
object_->symbol_referenced ();
|
|
}
|
|
|
|
bool
|
|
symbol::operator< (const symbol& rhs) const
|
|
{
|
|
return name_ < rhs.name_;
|
|
}
|
|
|
|
void
|
|
symbol::output (std::ostream& out) const
|
|
{
|
|
const elf::elf_sym& es = esym ();
|
|
|
|
std::string binding;
|
|
int binding_val = GELF_ST_BIND (es.st_info);
|
|
switch (binding_val)
|
|
{
|
|
case STB_LOCAL:
|
|
binding = "STB_LOCAL ";
|
|
break;
|
|
case STB_GLOBAL:
|
|
binding = "STB_GLOBAL";
|
|
break;
|
|
case STB_WEAK:
|
|
binding = "STB_WEAK ";
|
|
break;
|
|
default:
|
|
if ((binding_val >= STB_LOPROC) && (binding_val <= STB_HIPROC))
|
|
binding = "STB_LOPROC(" + rld::to_string (binding_val) + ")";
|
|
else
|
|
binding = "STB_INVALID(" + rld::to_string (binding_val) + ")";
|
|
break;
|
|
}
|
|
|
|
std::string type;
|
|
int type_val = GELF_ST_TYPE (es.st_info);
|
|
switch (type_val)
|
|
{
|
|
case STT_NOTYPE:
|
|
type = "STT_NOTYPE ";
|
|
break;
|
|
case STT_OBJECT:
|
|
type = "STT_OBJECT ";
|
|
break;
|
|
case STT_FUNC:
|
|
type = "STT_FUNC ";
|
|
break;
|
|
case STT_SECTION:
|
|
type = "STT_SECTION";
|
|
break;
|
|
case STT_FILE:
|
|
type = "STT_FILE ";
|
|
break;
|
|
case STT_TLS:
|
|
type = "STT_TLS ";
|
|
break;
|
|
default:
|
|
if ((type_val >= STT_LOPROC) && (type_val <= STT_HIPROC))
|
|
type = "STT_LOPROC(" + rld::to_string (type_val) + ")";
|
|
else
|
|
type = "STT_INVALID(" + rld::to_string (type_val) + ")";
|
|
break;
|
|
}
|
|
|
|
out << std::setw (8) << index_
|
|
<< ' ' << binding
|
|
<< ' ' << type
|
|
<< ' ' << std::setw(6) << es.st_shndx
|
|
<< " 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
|
|
out << name ();
|
|
|
|
if (object ())
|
|
out << " (" << object ()->name ().basename () << ')';
|
|
}
|
|
|
|
table::table ()
|
|
{
|
|
}
|
|
|
|
table::~table ()
|
|
{
|
|
}
|
|
|
|
void
|
|
table::add_global (symbol& sym)
|
|
{
|
|
globals_[sym.name ()] = &sym;
|
|
}
|
|
|
|
void
|
|
table::add_weak (symbol& sym)
|
|
{
|
|
weaks_[sym.name ()] = &sym;
|
|
}
|
|
|
|
void
|
|
table::add_local (symbol& sym)
|
|
{
|
|
locals_[sym.name ()] = &sym;
|
|
}
|
|
|
|
symbol*
|
|
table::find_global (const std::string& name)
|
|
{
|
|
symtab::iterator sti = globals_.find (name);
|
|
if (sti == globals_.end ())
|
|
return 0;
|
|
return (*sti).second;
|
|
}
|
|
|
|
symbol*
|
|
table::find_weak (const std::string& name)
|
|
{
|
|
symtab::iterator sti = weaks_.find (name);
|
|
if (sti == weaks_.end ())
|
|
return 0;
|
|
return (*sti).second;
|
|
}
|
|
|
|
symbol*
|
|
table::find_local (const std::string& name)
|
|
{
|
|
symtab::iterator sti = locals_.find (name);
|
|
if (sti == locals_.end ())
|
|
return 0;
|
|
return (*sti).second;
|
|
}
|
|
|
|
size_t
|
|
table::size () const
|
|
{
|
|
return globals_.size () + weaks_.size () + locals_.size ();
|
|
}
|
|
|
|
const symtab&
|
|
table::globals () const
|
|
{
|
|
return globals_;
|
|
}
|
|
|
|
const symtab&
|
|
table::weaks () const
|
|
{
|
|
return weaks_;
|
|
}
|
|
|
|
const symtab&
|
|
table::locals () const
|
|
{
|
|
return locals_;
|
|
}
|
|
|
|
void
|
|
table::globals (addrtab& addresses)
|
|
{
|
|
for (symtab::iterator gi = globals_.begin ();
|
|
gi != globals_.end ();
|
|
++gi)
|
|
{
|
|
symbol& sym = *((*gi).second);
|
|
addresses[sym.value ()] = (*gi).second;
|
|
}
|
|
}
|
|
|
|
void
|
|
table::weaks (addrtab& addresses)
|
|
{
|
|
for (symtab::iterator wi = weaks_.begin ();
|
|
wi != weaks_.end ();
|
|
++wi)
|
|
{
|
|
symbol& sym = *((*wi).second);
|
|
addresses[sym.value ()] = (*wi).second;
|
|
}
|
|
}
|
|
|
|
void
|
|
table::locals (addrtab& addresses)
|
|
{
|
|
for (symtab::iterator li = locals_.begin ();
|
|
li != locals_.end ();
|
|
++li)
|
|
{
|
|
symbol& sym = *((*li).second);
|
|
addresses[sym.value ()] = (*li).second;
|
|
}
|
|
}
|
|
|
|
void
|
|
load (bucket& bucket_, table& table_)
|
|
{
|
|
for (bucket::iterator sbi = bucket_.begin ();
|
|
sbi != bucket_.end ();
|
|
++sbi)
|
|
{
|
|
table_.add_global (*sbi);
|
|
}
|
|
}
|
|
|
|
void
|
|
load (bucket& bucket_, symtab& table_)
|
|
{
|
|
for (bucket::iterator sbi = bucket_.begin ();
|
|
sbi != bucket_.end ();
|
|
++sbi)
|
|
{
|
|
symbol& sym = *sbi;
|
|
table_[sym.name ()] = &sym;
|
|
}
|
|
}
|
|
|
|
size_t
|
|
referenced (pointers& symbols)
|
|
{
|
|
size_t used = 0;
|
|
for (pointers::iterator sli = symbols.begin ();
|
|
sli != symbols.end ();
|
|
++sli)
|
|
{
|
|
symbol& sym = *(*sli);
|
|
if (sym.references ())
|
|
++used;
|
|
}
|
|
|
|
return used;
|
|
}
|
|
|
|
void
|
|
output (std::ostream& out, const table& symbols)
|
|
{
|
|
out << "Globals:" << std::endl;
|
|
output (out, symbols.globals ());
|
|
out << "Weaks:" << std::endl;
|
|
output (out, symbols.weaks ());
|
|
out << "Locals:" << std::endl;
|
|
output (out, symbols.locals ());
|
|
}
|
|
|
|
void
|
|
output (std::ostream& out, const symtab& symbols)
|
|
{
|
|
out << " No. Index Scope Type SHNDX Address Size Name" << std::endl;
|
|
int index = 0;
|
|
for (symtab::const_iterator si = symbols.begin ();
|
|
si != symbols.end ();
|
|
++si)
|
|
{
|
|
const symbol& sym = *((*si).second);
|
|
out << std::setw (5) << index << ' ' << sym << std::endl;
|
|
++index;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|