Relocator.cpp revision 551ae4ebd3e9d137ea668fb83ae4a55b8cfba451
1//===- Relocator.cpp ------------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include <mcld/Config/Config.h>
10#include <mcld/Fragment/Fragment.h>
11#include <mcld/LD/LDContext.h>
12#include <mcld/LD/LDSection.h>
13#include <mcld/LD/LDSymbol.h>
14#include <mcld/LD/Relocator.h>
15#include <mcld/LD/ResolveInfo.h>
16#include <mcld/LD/SectionData.h>
17#include <mcld/Support/MsgHandling.h>
18#include <mcld/Module.h>
19#ifdef HAVE_CXXABI_H
20#include <cxxabi.h>
21#endif
22#include <sstream>
23
24using namespace mcld;
25
26//===----------------------------------------------------------------------===//
27// Helper functions
28//===----------------------------------------------------------------------===//
29std::string demangleSymbol(const std::string& mangled_name) {
30#ifdef HAVE_CXXABI_H
31  // __cxa_demangle needs manually handle the memory release, so we wrap
32  // it into this helper function.
33  size_t output_leng;
34  int status;
35  char* buffer = abi::__cxa_demangle(mangled_name.c_str(), /*buffer=*/0,
36                                     &output_leng, &status);
37  if (status != 0) { // Failed
38    return mangled_name;
39  }
40  std::string demangled_name(buffer);
41  free(buffer);
42
43  return demangled_name;
44#else
45  return mangled_name;
46#endif
47}
48
49
50//===----------------------------------------------------------------------===//
51// Relocator
52//===----------------------------------------------------------------------===//
53Relocator::~Relocator()
54{
55}
56
57void Relocator::partialScanRelocation(Relocation& pReloc,
58                                      Module& pModule,
59                                      const LDSection& pSection)
60{
61  // if we meet a section symbol
62  if (pReloc.symInfo()->type() == ResolveInfo::Section) {
63    LDSymbol* input_sym = pReloc.symInfo()->outSymbol();
64
65    // 1. update the relocation target offset
66    assert(input_sym->hasFragRef());
67    uint64_t offset = input_sym->fragRef()->getOutputOffset();
68    pReloc.target() += offset;
69
70    // 2. get output section symbol
71    // get the output LDSection which the symbol defined in
72    const LDSection& out_sect =
73                        input_sym->fragRef()->frag()->getParent()->getSection();
74    ResolveInfo* sym_info =
75                     pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
76    // set relocation target symbol to the output section symbol's resolveInfo
77    pReloc.setSymInfo(sym_info);
78  }
79}
80
81void Relocator::issueUndefRef(Relocation& pReloc,
82                              LDSection& pSection,
83                              Input& pInput)
84{
85  FragmentRef::Offset undef_sym_pos = pReloc.targetRef().offset();
86  std::string sect_name(pSection.name());
87  sect_name = sect_name.substr(sect_name.find('.', /*pos=*/1));  // Drop .rel(a) prefix
88
89  std::string reloc_sym(pReloc.symInfo()->name());
90  if (reloc_sym.substr(0, 2) == "_Z")
91    reloc_sym = demangleSymbol(reloc_sym);
92
93  std::stringstream ss;
94  ss << "0x" << std::hex << undef_sym_pos;
95  std::string undef_sym_pos_hex(ss.str());
96
97  if (sect_name.substr(0, 5) != ".text") {
98    // Function name is only valid for text section
99    fatal(diag::undefined_reference) << reloc_sym
100                                     << pInput.path()
101                                     << sect_name
102                                     << undef_sym_pos_hex;
103    return;
104  }
105
106  std::string caller_file_name;
107  std::string caller_func_name;
108  for (LDContext::sym_iterator i = pInput.context()->symTabBegin(),
109       e = pInput.context()->symTabEnd(); i != e; ++i) {
110    LDSymbol& sym = **i;
111    if (sym.resolveInfo()->type() == ResolveInfo::File)
112      caller_file_name = sym.resolveInfo()->name();
113
114    if (sym.resolveInfo()->type() == ResolveInfo::Function &&
115        sym.value() <= undef_sym_pos &&
116        sym.value() + sym.size() > undef_sym_pos) {
117      caller_func_name = sym.name();
118      break;
119    }
120  }
121
122  if (caller_func_name.substr(0, 2) == "_Z")
123    caller_func_name = demangleSymbol(caller_func_name);
124
125  fatal(diag::undefined_reference_text) << reloc_sym
126                                        << pInput.path()
127                                        << caller_file_name
128                                        << caller_func_name;
129}
130