rtems-tools/rtemstoolkit/rld-resolver.cpp
2014-11-30 14:37:30 +11:00

259 lines
7.6 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.
*
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <iomanip>
#include <iostream>
#include <sys/stat.h>
#include <rld.h>
#include <rld.h>
namespace rld
{
namespace resolver
{
static files::object*
get_object (files::cache& cache,
const std::string& fullname)
{
files::objects& objects = cache.get_objects ();
files::objects::iterator oi = objects.find (fullname);
if (oi == objects.end ())
return 0;
return (*oi).second;
}
static void
resolve_symbols (files::object_list& dependents,
files::cache& cache,
symbols::table& base_symbols,
symbols::table& symbols,
symbols::symtab& unresolved,
const std::string& fullname)
{
const std::string name = path::basename (fullname);
static int nesting = 0;
++nesting;
/*
* Find each unresolved symbol in the symbol table pointing the
* 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 'urs' is the unresolved symbol and
* 'es' is the exported symbol.
*/
files::object* object = get_object (cache, fullname);
if (object)
{
if (object->resolved () || object->resolving ())
{
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "resolver:resolving: "
<< std::setw (nesting - 1) << ' '
<< name
<< " is resolved or resolving"
<< std::endl;
return;
}
object->resolve_set ();
}
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "resolver:resolving: "
<< std::setw (nesting - 1) << ' '
<< name
<< ", unresolved: "
<< unresolved.size ()
<< std::endl;
files::object_list objects;
for (symbols::symtab::iterator ursi = unresolved.begin ();
ursi != unresolved.end ();
++ursi)
{
symbols::symbol& urs = *((*ursi).second);
if ((urs.binding () != STB_WEAK) && urs.object ())
continue;
symbols::symbol* es = base_symbols.find_global (urs.name ());
bool base = true;
if (rld::verbose () >= RLD_VERBOSE_INFO)
{
std::cout << "resolver:resolve : "
<< std::setw (nesting + 1) << ' '
<< " |- " << urs.name () << std::endl;
}
if (!es)
{
es = symbols.find_global (urs.name ());
if (!es)
{
es = symbols.find_weak (urs.name ());
if (!es)
throw rld::error ("symbol not found: " + urs.name (), name);
}
base = false;
}
symbols::symbol& esym = *es;
if (rld::verbose () >= RLD_VERBOSE_INFO)
{
std::cout << "resolver:resolved : "
<< std::setw (nesting + 1) << ' '
<< " | `--> ";
if (esym.object())
{
std::cout << esym.object()->name ().basename ();
if (esym.object()->resolving ())
std::cout << " (resolving)";
else if (esym.object()->resolved ())
std::cout << " (resolved)";
else if (base)
std::cout << " (base)";
else
std::cout << " (unresolved: " << objects.size () + 1 << ')';
}
else
std::cout << "null";
std::cout << std::endl;
}
if (!base)
{
files::object& eobj = *esym.object ();
urs.set_object (eobj);
if (!eobj.resolved () && !eobj.resolving ())
{
objects.push_back (&eobj);
objects.unique ();
}
}
esym.referenced ();
}
if (object)
{
object->resolve_clear ();
object->resolved_set ();
}
/*
* Recurse into any references object files.
*/
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "resolver:resolved : "
<< std::setw (nesting + 1) << ' '
<< " +-- referenced objects: " << objects.size ()
<< std::endl;
for (files::object_list::iterator oli = objects.begin ();
oli != objects.end ();
++oli)
{
files::object& obj = *(*oli);
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "resolver:resolving: "
<< std::setw (nesting) << ' '
<< "] " << name << " ==> "
<< obj.name ().basename () << std::endl;
resolve_symbols (dependents, cache, base_symbols, symbols,
obj.unresolved_symbols (),
obj.name ().full ());
}
--nesting;
dependents.merge (objects);
dependents.unique ();
}
void
resolve (files::object_list& dependents,
files::cache& cache,
symbols::table& base_symbols,
symbols::table& symbols,
symbols::symtab& undefined)
{
files::object_list objects;
cache.get_objects (objects);
/*
* First resolve any undefined symbols that are forced by the linker or
* the user.
*/
resolver::resolve_symbols (dependents, cache, base_symbols, symbols,
undefined, "undefines");
/*
* Resolve the symbols in the object files.
*/
for (files::object_list::iterator oi = objects.begin ();
oi != objects.end ();
++oi)
{
files::object& object = *(*oi);
if (rld::verbose () >= RLD_VERBOSE_INFO)
std::cout << "resolver:resolving: top: "
<< object.name ().basename () << std::endl;
resolver::resolve_symbols (dependents, cache, base_symbols, symbols,
object.unresolved_symbols (),
object.name ().full ());
}
if (rld::verbose () >= RLD_VERBOSE_INFO)
{
std::cout << "resolver:resolving: dependents: "
<< dependents.size () << std::endl;
int count = 1;
for (files::object_list::iterator di = dependents.begin ();
di != dependents.end ();
++di)
{
files::object& obj = *(*di);
std::cout << std::setw (3) << count++
<< ": " << obj.name ().basename () << std::endl;
}
}
}
}
}