1//===- LinkerConfig.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#include "alone/Support/LinkerConfig.h"
11#include "alone/Support/Log.h"
12
13#include <llvm/Support/Signals.h>
14
15#include <mcld/MC/MCLDDirectory.h>
16#include <mcld/MC/ZOption.h>
17#include <mcld/LD/TextDiagnosticPrinter.h>
18#include <mcld/Support/Path.h>
19#include <mcld/Support/MsgHandling.h>
20#include <mcld/Support/raw_ostream.h>
21
22using namespace alone;
23
24LinkerConfig::LinkerConfig(const std::string &pTriple)
25  : mTriple(pTriple), mSOName(), mTarget(NULL), mLDConfig(NULL),
26    mLDScript(NULL), mDiagLineInfo(NULL), mDiagPrinter(NULL) {
27
28  initializeTarget();
29  initializeLDScript();
30  initializeLDInfo();
31  initializeDiagnostic();
32}
33
34LinkerConfig::~LinkerConfig() {
35  delete mLDConfig;
36
37  if (mDiagPrinter->getNumErrors() != 0) {
38    // If here, the program failed ungracefully. Run the interrupt handlers to
39    // ensure any other cleanups (e.g., files that registered by
40    // RemoveFileOnSignal(...)) getting done before exit.
41    llvm::sys::RunInterruptHandlers();
42  }
43  mDiagPrinter->finish();
44
45  delete mLDScript;
46  delete mDiagLineInfo;
47  delete mDiagPrinter;
48}
49
50bool LinkerConfig::initializeTarget() {
51  std::string error;
52  mTarget = mcld::TargetRegistry::lookupTarget(mTriple, error);
53  if (NULL != mTarget) {
54    return true;
55  } else {
56    ALOGE("Cannot initialize mcld::Target for given triple '%s'! (%s)\n",
57          mTriple.c_str(), error.c_str());
58    return false;
59  }
60}
61
62bool LinkerConfig::initializeLDInfo() {
63  if (NULL != mLDConfig) {
64    ALOGE("Cannot initialize mcld::MCLDInfo for given triple '%s!\n",
65          mTriple.c_str());
66    return false;
67  }
68
69  mLDConfig = new mcld::LinkerConfig(getTriple());
70  mLDConfig->setCodeGenType(mcld::LinkerConfig::Exec);
71
72  struct NameMap {
73    const char* from;
74    const char* to;
75  };
76
77  static const NameMap map[] =
78  {
79    {".text", ".text"},
80    {".rodata", ".rodata"},
81    {".data.rel.ro.local", ".data.rel.ro.local"},
82    {".data.rel.ro", ".data.rel.ro"},
83    {".data", ".data"},
84    {".bss", ".bss"},
85    {".tdata", ".tdata"},
86    {".tbss", ".tbss"},
87    {".init_array", ".init_array"},
88    {".fini_array", ".fini_array"},
89    // TODO: Support DT_INIT_ARRAY for all constructors?
90    {".ctors", ".ctors"},
91    {".dtors", ".dtors"},
92    // FIXME: in GNU ld, if we are creating a shared object .sdata2 and .sbss2
93    // sections would be handled differently.
94    {".sdata2", ".sdata"},
95    {".sbss2", ".sbss"},
96    {".sdata", ".sdata"},
97    {".sbss", ".sbss"},
98    {".lrodata", ".lrodata"},
99    {".ldata", ".ldata"},
100    {".lbss", ".lbss"},
101    {".gcc_except_table", ".gcc_except_table"},
102    {".gnu.linkonce.d.rel.ro.local", ".data.rel.ro.local"},
103    {".gnu.linkonce.d.rel.ro", ".data.rel.ro"},
104    {".gnu.linkonce.r", ".rodata"},
105    {".gnu.linkonce.d", ".data"},
106    {".gnu.linkonce.b", ".bss"},
107    {".gnu.linkonce.sb2", ".sbss"},
108    {".gnu.linkonce.sb", ".sbss"},
109    {".gnu.linkonce.s2", ".sdata"},
110    {".gnu.linkonce.s", ".sdata"},
111    {".gnu.linkonce.wi", ".debug_info"},
112    {".gnu.linkonce.td", ".tdata"},
113    {".gnu.linkonce.tb", ".tbss"},
114    {".gnu.linkonce.t", ".text"},
115    {".gnu.linkonce.lr", ".lrodata"},
116    {".gnu.linkonce.lb", ".lbss"},
117    {".gnu.linkonce.l", ".ldata"},
118  };
119
120  if (mLDConfig->codeGenType() != mcld::LinkerConfig::Object) {
121    const unsigned int map_size =  (sizeof(map) / sizeof(map[0]) );
122    for (unsigned int i = 0; i < map_size; ++i) {
123      bool exist = false;
124      mLDScript->sectionMap().append(map[i].from,
125                                               map[i].to,
126                                               exist);
127    }
128  }
129  return true;
130}
131
132bool LinkerConfig::initializeLDScript() {
133  mLDScript = new mcld::LinkerScript();
134  return true;
135}
136
137bool LinkerConfig::initializeDiagnostic() {
138  // Set up MsgHandler.
139  mDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *mLDConfig);
140
141  mcld::InitializeDiagnosticEngine(*mLDConfig, mDiagPrinter);
142
143  mDiagLineInfo = mTarget->createDiagnosticLineInfo(*mTarget, mTriple);
144
145  mcld::getDiagnosticEngine().setLineInfo(*mDiagLineInfo);
146  return true;
147}
148
149bool LinkerConfig::isShared() const {
150  return (mcld::LinkerConfig::DynObj == mLDConfig->codeGenType());
151}
152
153void LinkerConfig::setShared(bool pEnable) {
154  if (pEnable)
155    mLDConfig->setCodeGenType(mcld::LinkerConfig::DynObj);
156  else
157    mLDConfig->setCodeGenType(mcld::LinkerConfig::Exec);
158  return;
159}
160
161void LinkerConfig::setBsymbolic(bool pEnable) {
162  mLDConfig->options().setBsymbolic(pEnable);
163  return;
164}
165
166void LinkerConfig::setDefineCommon(bool pEnable) {
167  mLDConfig->options().setDefineCommon(pEnable);
168  return;
169}
170
171void LinkerConfig::setSOName(const std::string &pSOName) {
172  mLDConfig->options().setSOName(pSOName);
173  return;
174}
175
176void LinkerConfig::setDyld(const std::string &pDyld) {
177  mLDConfig->options().setDyld(pDyld);
178  return;
179}
180
181void LinkerConfig::setSysRoot(const std::string &pSysRoot) {
182  mLDScript->setSysroot(mcld::sys::fs::Path(pSysRoot));
183  return;
184}
185
186void LinkerConfig::setZOption(unsigned int pOptions) {
187  mcld::ZOption option;
188  if (pOptions & kCombReloc) {
189    option.setKind(mcld::ZOption::CombReloc);
190    mLDConfig->options().addZOption(option);
191  }
192  else {
193    option.setKind(mcld::ZOption::NoCombReloc);
194    mLDConfig->options().addZOption(option);
195  }
196
197  if (pOptions & kDefs) {
198    option.setKind(mcld::ZOption::Defs);
199    mLDConfig->options().addZOption(option);
200  }
201
202  if (pOptions & kExecStack) {
203    option.setKind(mcld::ZOption::ExecStack);
204    mLDConfig->options().addZOption(option);
205  }
206  else {
207    option.setKind(mcld::ZOption::NoExecStack);
208    mLDConfig->options().addZOption(option);
209  }
210
211  if (pOptions & kInitFirst) {
212    option.setKind(mcld::ZOption::InitFirst);
213    mLDConfig->options().addZOption(option);
214  }
215
216  if (pOptions & kInterPose) {
217    option.setKind(mcld::ZOption::InterPose);
218    mLDConfig->options().addZOption(option);
219  }
220
221  if (pOptions & kLoadFltr) {
222    option.setKind(mcld::ZOption::LoadFltr);
223    mLDConfig->options().addZOption(option);
224  }
225
226  if (pOptions & kMulDefs) {
227    option.setKind(mcld::ZOption::MulDefs);
228    mLDConfig->options().addZOption(option);
229  }
230
231  if (pOptions & kNoCopyReloc) {
232    option.setKind(mcld::ZOption::NoCopyReloc);
233    mLDConfig->options().addZOption(option);
234  }
235
236  if (pOptions & kNoDefaultLib) {
237    option.setKind(mcld::ZOption::NoDefaultLib);
238    mLDConfig->options().addZOption(option);
239  }
240
241  if (pOptions & kNoDelete) {
242    option.setKind(mcld::ZOption::NoDelete);
243    mLDConfig->options().addZOption(option);
244  }
245
246  if (pOptions & kNoDLOpen) {
247    option.setKind(mcld::ZOption::NoDLOpen);
248    mLDConfig->options().addZOption(option);
249  }
250
251  if (pOptions & kNoDump) {
252    option.setKind(mcld::ZOption::NoDump);
253    mLDConfig->options().addZOption(option);
254  }
255
256  if (pOptions & kRelro) {
257    option.setKind(mcld::ZOption::Relro);
258    mLDConfig->options().addZOption(option);
259  }
260  else {
261    option.setKind(mcld::ZOption::NoRelro);
262    mLDConfig->options().addZOption(option);
263  }
264
265  if (pOptions & kLazy) {
266    option.setKind(mcld::ZOption::Lazy);
267    mLDConfig->options().addZOption(option);
268  }
269  else {
270    option.setKind(mcld::ZOption::Now);
271    mLDConfig->options().addZOption(option);
272  }
273
274  if (pOptions & kOrigin) {
275    option.setKind(mcld::ZOption::Origin);
276    mLDConfig->options().addZOption(option);
277  }
278}
279
280void LinkerConfig::addWrap(const std::string &pWrapSymbol) {
281  bool exist = false;
282
283  // Add wname -> __wrap_wname.
284  mcld::StringEntry<llvm::StringRef>* to_wrap =
285               mLDScript->renameMap().insert(pWrapSymbol, exist);
286
287  std::string to_wrap_str = "__wrap_" + pWrapSymbol;
288  to_wrap->setValue(to_wrap_str);
289
290  if (exist) {
291    mcld::warning(mcld::diag::rewrap) << pWrapSymbol << to_wrap_str;
292  }
293
294  // Add __real_wname -> wname.
295  std::string from_real_str = "__real_" + pWrapSymbol;
296  mcld::StringEntry<llvm::StringRef>* from_real =
297             mLDScript->renameMap().insert(from_real_str, exist);
298  from_real->setValue(pWrapSymbol);
299
300  if (exist) {
301    mcld::warning(mcld::diag::rewrap) << pWrapSymbol << from_real_str;
302  }
303
304  return;
305}
306
307void LinkerConfig::addPortable(const std::string &pPortableSymbol) {
308  bool exist = false;
309
310  // Add pname -> pname_portable.
311  mcld::StringEntry<llvm::StringRef>* to_port =
312                mLDScript->renameMap().insert(pPortableSymbol, exist);
313
314  std::string to_port_str = pPortableSymbol + "_portable";
315  to_port->setValue(to_port_str);
316
317  if (exist) {
318    mcld::warning(mcld::diag::rewrap) << pPortableSymbol << to_port_str;
319}
320
321  // Add __real_pname -> pname.
322  std::string from_real_str = "__real_" + pPortableSymbol;
323  mcld::StringEntry<llvm::StringRef>* from_real =
324           mLDScript->renameMap().insert(from_real_str, exist);
325
326  from_real->setValue(pPortableSymbol);
327
328  if (exist) {
329    mcld::warning(mcld::diag::rewrap) << pPortableSymbol << from_real_str;
330  }
331
332  return;
333}
334
335void LinkerConfig::addSearchDir(const std::string &pDirPath) {
336  // SearchDirs will remove the created MCLDDirectory.
337  if (!mLDScript->directories().insert(pDirPath)) {
338    mcld::warning(mcld::diag::warn_cannot_open_search_dir) << pDirPath;
339  }
340}
341