1//===- SectLinker.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//
10// This file implements the SectLinker class.
11//
12//===----------------------------------------------------------------------===//
13
14#include <mcld/ADT/BinTree.h>
15#include <mcld/CodeGen/SectLinker.h>
16#include <mcld/CodeGen/SectLinkerOption.h>
17#include <mcld/MC/MCLDInputTree.h>
18#include <mcld/MC/MCLDDriver.h>
19#include <mcld/Support/DerivedPositionDependentOptions.h>
20#include <mcld/Support/FileSystem.h>
21#include <mcld/Target/TargetLDBackend.h>
22
23#include <llvm/Module.h>
24#include <llvm/Support/ErrorHandling.h>
25#include <llvm/Support/raw_ostream.h>
26
27#include <algorithm>
28#include <stack>
29#include <string>
30
31using namespace mcld;
32using namespace llvm;
33
34//===----------------------------------------------------------------------===//
35// Forward declarations
36char SectLinker::m_ID = 0;
37static bool CompareOption(const PositionDependentOption* X,
38                          const PositionDependentOption* Y);
39
40//===----------------------------------------------------------------------===//
41// SectLinker
42SectLinker::SectLinker(SectLinkerOption &pOption,
43                       TargetLDBackend& pLDBackend)
44  : MachineFunctionPass(m_ID),
45    m_pOption(&pOption),
46    m_pLDBackend(&pLDBackend),
47    m_pLDDriver(NULL) { }
48
49SectLinker::~SectLinker()
50{
51  delete m_pLDDriver;
52  // FIXME: current implementation can not change the order of delete.
53  //
54  // Instance of TargetLDBackend was created outside and is not managed by
55  // SectLinker. It should not be destroyed here and by SectLinker. However, in
56  // order to follow the LLVM convention - that is, the pass manages all the
57  // objects it used during the processing, we destroy the object of
58  // TargetLDBackend here.
59  delete m_pLDBackend;
60}
61
62bool SectLinker::doInitialization(Module &pM)
63{
64  MCLDInfo &info = m_pOption->info();
65
66  // setup the output
67  info.output().setContext(info.contextFactory().produce(info.output().path()));
68
69  int mode = (Output::Object == info.output().type())? 0544 : 0755;
70  info.output().setMemArea(
71      info.memAreaFactory().produce(info.output().path(),
72                                    O_RDWR | O_CREAT | O_TRUNC,
73                                    mode));
74
75  //   make sure output is openend successfully.
76  if (!info.output().hasMemArea())
77    report_fatal_error("output is not given on the command line\n");
78
79  if (!info.output().memArea()->isGood())
80    report_fatal_error("can not open output file :"+info.output().path().native());
81
82  // let the target override the target-specific parameters
83  addTargetOptions(pM, *m_pOption);
84
85  // ----- convert position dependent options into tree of input files  ----- //
86  PositionDependentOptions &PosDepOpts = m_pOption->pos_dep_options();
87  std::stable_sort(PosDepOpts.begin(), PosDepOpts.end(), CompareOption);
88  initializeInputTree(PosDepOpts);
89
90  // Now, all input arguments are prepared well, send it into MCLDDriver
91  m_pLDDriver = new MCLDDriver(info, *m_pLDBackend);
92
93  return false;
94}
95
96bool SectLinker::doFinalization(Module &pM)
97{
98  const MCLDInfo &info = m_pOption->info();
99
100  // 3. - initialize output's standard segments and sections
101  if (!m_pLDDriver->initMCLinker())
102    return true;
103
104  // 4. - normalize the input tree
105  m_pLDDriver->normalize();
106
107  if (info.options().verbose()) {
108    outs() << "MCLinker (LLVM Sub-project) - ";
109    outs() << MCLDInfo::version();
110    outs() << "\n";
111  }
112
113  if (info.options().trace()) {
114    static int counter = 0;
115    outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n";
116    InputTree::const_dfs_iterator input, inEnd = info.inputs().dfs_end();
117    for (input=info.inputs().dfs_begin(); input!=inEnd; ++input) {
118      outs() << counter++ << " *  " << (*input)->name();
119      switch((*input)->type()) {
120      case Input::Archive:
121        outs() << "\tarchive\t(";
122        break;
123      case Input::Object:
124        outs() << "\tobject\t(";
125        break;
126      case Input::DynObj:
127        outs() << "\tshared\t(";
128        break;
129      case Input::Script:
130        outs() << "\tscript\t(";
131        break;
132      default:
133        report_fatal_error("** Trace a unsupported file. It must be an internal bug!");
134      }
135      outs() << (*input)->path().c_str() << ")\n";
136    }
137  }
138
139  // 5. - check if we can do static linking and if we use split-stack.
140  if (!m_pLDDriver->linkable())
141    return true;
142
143
144  // 6. - read all sections
145  if (!m_pLDDriver->readSections() ||
146      !m_pLDDriver->mergeSections())
147    return true;
148
149  // 7. - read all symbol tables of input files and resolve them
150  if (!m_pLDDriver->readSymbolTables() ||
151      !m_pLDDriver->mergeSymbolTables())
152    return true;
153
154  // 7.a - add standard symbols and target-dependent symbols
155  // m_pLDDriver->addUndefSymbols();
156  if (!m_pLDDriver->addStandardSymbols() ||
157      !m_pLDDriver->addTargetSymbols())
158    return true;
159
160  // 8. - read all relocation entries from input files
161  m_pLDDriver->readRelocations();
162
163  // 9. - pre-layout
164  m_pLDDriver->prelayout();
165
166  // 10. - linear layout
167  m_pLDDriver->layout();
168
169  // 10.b - post-layout
170  m_pLDDriver->postlayout();
171
172  // 11. - finalize symbol value
173  m_pLDDriver->finalizeSymbolValue();
174
175  // 12. - apply relocations
176  m_pLDDriver->relocate();
177
178  // 13. - write out output
179  m_pLDDriver->emitOutput();
180
181  // 14. - post processing
182  m_pLDDriver->postProcessing();
183  return false;
184}
185
186bool SectLinker::runOnMachineFunction(MachineFunction& pF)
187{
188  // basically, linkers do nothing during function is generated.
189  return false;
190}
191
192void SectLinker::initializeInputTree(const PositionDependentOptions &pPosDepOptions) const
193{
194  if (pPosDepOptions.empty())
195    return;
196
197  MCLDInfo &info = m_pOption->info();
198  PositionDependentOptions::const_iterator cur_char = pPosDepOptions.begin();
199  if (1 == pPosDepOptions.size() &&
200      ((*cur_char)->type() != PositionDependentOption::INPUT_FILE &&
201       (*cur_char)->type() != PositionDependentOption::NAMESPEC))
202    return;
203
204  InputTree::Connector *prev_ward = &InputTree::Downward;
205
206  std::stack<InputTree::iterator> returnStack;
207  InputTree::iterator cur_node = info.inputs().root();
208
209  PositionDependentOptions::const_iterator charEnd = pPosDepOptions.end();
210  while (cur_char != charEnd ) {
211    switch ((*cur_char)->type()) {
212    case PositionDependentOption::BITCODE: {
213      // threat bitcode as a script in this version.
214      const BitcodeOption *bitcode_option =
215          static_cast<const BitcodeOption*>(*cur_char);
216      info.inputs().insert(cur_node,
217                           *prev_ward,
218                           bitcode_option->path()->native(),
219                           *(bitcode_option->path()),
220                           Input::Script);
221      info.setBitcode(**cur_node);
222      prev_ward->move(cur_node);
223      prev_ward = &InputTree::Afterward;
224      break;
225    }
226    case PositionDependentOption::INPUT_FILE: {
227      const InputFileOption *input_file_option =
228          static_cast<const InputFileOption*>(*cur_char);
229      info.inputs().insert(cur_node,
230                           *prev_ward,
231                           input_file_option->path()->native(),
232                           *(input_file_option->path()));
233      prev_ward->move(cur_node);
234      prev_ward = &InputTree::Afterward;
235      break;
236    }
237    case PositionDependentOption::NAMESPEC: {
238      sys::fs::Path* path = 0;
239      const NamespecOption *namespec_option =
240          static_cast<const NamespecOption*>(*cur_char);
241      if (info.attrFactory().last().isStatic()) {
242        path = info.options().directories().find(namespec_option->namespec(),
243                                                 Input::Archive);
244      }
245      else {
246        path = info.options().directories().find(namespec_option->namespec(),
247                                                 Input::DynObj);
248      }
249
250      if (0 == path) {
251        llvm::report_fatal_error(std::string("Can't find namespec: ")+
252                                 namespec_option->namespec());
253      }
254      info.inputs().insert(cur_node,
255                           *prev_ward,
256                           namespec_option->namespec(),
257                           *path);
258      prev_ward->move(cur_node);
259      prev_ward = &InputTree::Afterward;
260      break;
261    }
262    case PositionDependentOption::START_GROUP:
263      info.inputs().enterGroup(cur_node, *prev_ward);
264      prev_ward->move(cur_node);
265      returnStack.push(cur_node);
266      prev_ward = &InputTree::Downward;
267      break;
268    case PositionDependentOption::END_GROUP:
269      cur_node = returnStack.top();
270      returnStack.pop();
271      prev_ward = &InputTree::Afterward;
272      break;
273    case PositionDependentOption::WHOLE_ARCHIVE:
274      info.attrFactory().last().setWholeArchive();
275      break;
276    case PositionDependentOption::NO_WHOLE_ARCHIVE:
277      info.attrFactory().last().unsetWholeArchive();
278      break;
279    case PositionDependentOption::AS_NEEDED:
280      info.attrFactory().last().setAsNeeded();
281      break;
282    case PositionDependentOption::NO_AS_NEEDED:
283      info.attrFactory().last().unsetAsNeeded();
284      break;
285    case PositionDependentOption::ADD_NEEDED:
286      info.attrFactory().last().setAddNeeded();
287      break;
288    case PositionDependentOption::NO_ADD_NEEDED:
289      info.attrFactory().last().unsetAddNeeded();
290      break;
291    case PositionDependentOption::BSTATIC:
292      info.attrFactory().last().setStatic();
293      break;
294    case PositionDependentOption::BDYNAMIC:
295      info.attrFactory().last().setDynamic();
296      break;
297    default:
298      report_fatal_error("can not find the type of input file");
299    }
300    ++cur_char;
301  }
302
303  if (!returnStack.empty()) {
304    report_fatal_error("no matched --start-group and --end-group");
305  }
306}
307
308//===----------------------------------------------------------------------===//
309// Non-member functions
310static bool CompareOption(const PositionDependentOption* X,
311                          const PositionDependentOption* Y)
312{
313  return (X->position() < Y->position());
314}
315
316