blob: dc9445b4bacb2c780d8557694a252114ee3f4430 [file] [log] [blame]
//===- Relocator.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Config/Config.h>
#include <mcld/Fragment/Fragment.h>
#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/Relocator.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/SectionData.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Module.h>
#if HAVE_CXXABI_H
#include <cxxabi.h>
#endif
#include <sstream>
using namespace mcld;
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
std::string demangleSymbol(const std::string& mangled_name) {
#if HAVE_CXXABI_H
// __cxa_demangle needs manually handle the memory release, so we wrap
// it into this helper function.
size_t output_leng;
int status;
char* buffer = abi::__cxa_demangle(mangled_name.c_str(), /*buffer=*/0,
&output_leng, &status);
if (status != 0) { // Failed
return mangled_name;
}
std::string demangled_name(buffer);
free(buffer);
return demangled_name;
#else
return mangled_name;
#endif
}
//===----------------------------------------------------------------------===//
// Relocator
//===----------------------------------------------------------------------===//
Relocator::~Relocator()
{
}
void Relocator::partialScanRelocation(Relocation& pReloc,
Module& pModule,
const LDSection& pSection)
{
// if we meet a section symbol
if (pReloc.symInfo()->type() == ResolveInfo::Section) {
LDSymbol* input_sym = pReloc.symInfo()->outSymbol();
// 1. update the relocation target offset
assert(input_sym->hasFragRef());
uint64_t offset = input_sym->fragRef()->getOutputOffset();
pReloc.target() += offset;
// 2. get output section symbol
// get the output LDSection which the symbol defined in
const LDSection& out_sect =
input_sym->fragRef()->frag()->getParent()->getSection();
ResolveInfo* sym_info =
pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
// set relocation target symbol to the output section symbol's resolveInfo
pReloc.setSymInfo(sym_info);
}
}
void Relocator::issueUndefRef(Relocation& pReloc,
LDSection& pSection,
Input& pInput)
{
FragmentRef::Offset undef_sym_pos = pReloc.targetRef().offset();
std::string sect_name(pSection.name());
sect_name = sect_name.substr(sect_name.find('.', /*pos=*/1)); // Drop .rel(a) prefix
std::string reloc_sym(pReloc.symInfo()->name());
if (reloc_sym.substr(0, 2) == "_Z")
reloc_sym = demangleSymbol(reloc_sym);
std::stringstream ss;
ss << "0x" << std::hex << undef_sym_pos;
std::string undef_sym_pos_hex(ss.str());
if (sect_name.substr(0, 5) != ".text") {
// Function name is only valid for text section
fatal(diag::undefined_reference) << reloc_sym
<< pInput.path()
<< sect_name
<< undef_sym_pos_hex;
return;
}
std::string caller_file_name;
std::string caller_func_name;
for (LDContext::sym_iterator i = pInput.context()->symTabBegin(),
e = pInput.context()->symTabEnd(); i != e; ++i) {
LDSymbol& sym = **i;
if (sym.resolveInfo()->type() == ResolveInfo::File)
caller_file_name = sym.resolveInfo()->name();
if (sym.resolveInfo()->type() == ResolveInfo::Function &&
sym.value() <= undef_sym_pos &&
sym.value() + sym.size() > undef_sym_pos) {
caller_func_name = sym.name();
break;
}
}
if (caller_func_name.substr(0, 2) == "_Z")
caller_func_name = demangleSymbol(caller_func_name);
fatal(diag::undefined_reference_text) << reloc_sym
<< pInput.path()
<< caller_file_name
<< caller_func_name;
}