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