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/Linker.h"
18#include "bcc/Support/LinkerConfig.h"
19#include "bcc/Support/Log.h"
20
21#include <llvm/Support/ELF.h>
22
23#include <mcld/Module.h>
24#include <mcld/IRBuilder.h>
25#include <mcld/MC/MCLDInput.h>
26#include <mcld/Linker.h>
27#include <mcld/LD/LDSection.h>
28#include <mcld/LD/LDContext.h>
29#include <mcld/Support/Path.h>
30
31using namespace bcc;
32
33const char* Linker::GetErrorString(enum Linker::ErrorCode pErrCode) {
34  static const char* ErrorString[] = {
35    /* kSuccess */
36    "Successfully compiled.",
37    /* kDoubleConfig */
38    "Configure Linker twice.",
39    /* kDelegateLDInfo */
40    "Cannot get linker information",
41    /* kFindNameSpec */
42    "Cannot find -lnamespec",
43    /* kOpenObjectFile */
44    "Cannot open object file",
45    /* kNotConfig */
46    "Linker::config() is not called",
47    /* kNotSetUpOutput */
48    "Linker::setOutput() is not called before add input files",
49    /* kOpenOutput */
50    "Cannot open output file",
51    /* kReadSections */
52    "Cannot read sections",
53    /* kReadSymbols */
54    "Cannot read symbols",
55    /* kAddAdditionalSymbols */
56    "Cannot add standard and target symbols",
57    /* kMaxErrorCode */
58    "(Unknown error code)"
59  };
60
61  if (pErrCode > kMaxErrorCode) {
62    pErrCode = kMaxErrorCode;
63  }
64
65  return ErrorString[ static_cast<size_t>(pErrCode) ];
66}
67
68//===----------------------------------------------------------------------===//
69// Linker
70//===----------------------------------------------------------------------===//
71Linker::Linker()
72  : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL),
73    mOutputHandler(-1) {
74}
75
76Linker::Linker(const LinkerConfig& pConfig)
77  : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL),
78    mOutputHandler(-1) {
79
80  const std::string &triple = pConfig.getTriple();
81
82  enum ErrorCode err = config(pConfig);
83  if (kSuccess != err) {
84    ALOGE("%s (%s)", GetErrorString(err), triple.c_str());
85    return;
86  }
87
88  return;
89}
90
91Linker::~Linker() {
92  delete mModule;
93  delete mLinker;
94  delete mBuilder;
95}
96
97enum Linker::ErrorCode Linker::extractFiles(const LinkerConfig& pConfig) {
98  mLDConfig = pConfig.getLDConfig();
99  if (mLDConfig == NULL) {
100    return kDelegateLDInfo;
101  }
102  return kSuccess;
103}
104
105enum Linker::ErrorCode Linker::config(const LinkerConfig& pConfig) {
106  if (mLDConfig != NULL) {
107    return kDoubleConfig;
108  }
109
110  extractFiles(pConfig);
111
112  mModule = new mcld::Module(mLDConfig->options().soname());
113
114  mBuilder = new mcld::IRBuilder(*mModule, *mLDConfig);
115
116  mLinker = new mcld::Linker();
117
118  mLinker->config(const_cast<mcld::LinkerConfig&>(*mLDConfig));
119
120  return kSuccess;
121}
122
123enum Linker::ErrorCode Linker::addNameSpec(const std::string &pNameSpec) {
124  mcld::Input* input = mBuilder->ReadInput(pNameSpec);
125  if (NULL == input)
126    return kFindNameSpec;
127  return kSuccess;
128}
129
130/// addObject - Add a object file by the filename.
131enum Linker::ErrorCode Linker::addObject(const std::string &pObjectPath) {
132  mcld::Input* input = mBuilder->ReadInput(pObjectPath, pObjectPath);
133  if (NULL == input)
134    return kOpenObjectFile;
135  return kSuccess;
136}
137
138/// addObject - Add a piece of memory. The memory is of ELF format.
139enum Linker::ErrorCode Linker::addObject(void* pMemory, size_t pSize) {
140  mcld::Input* input = mBuilder->ReadInput("NAN", pMemory, pSize);
141  if (NULL == input)
142    return kOpenMemory;
143  return kSuccess;
144}
145
146enum Linker::ErrorCode Linker::addCode(void* pMemory, size_t pSize) {
147  mcld::Input* input = mBuilder->CreateInput("NAN", "NAN", mcld::Input::Object);
148  mcld::LDSection* sect = mBuilder->CreateELFHeader(*input, ".text",
149                                llvm::ELF::SHT_PROGBITS,
150                                llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
151                                0x1);
152  mcld::SectionData* data = mBuilder->CreateSectionData(*sect);
153  mcld::Fragment* frag = mBuilder->CreateRegion(pMemory, pSize);
154  mBuilder->AppendFragment(*frag, *data);
155  return kSuccess;
156}
157
158enum Linker::ErrorCode Linker::setOutput(const std::string &pPath) {
159  mOutputPath = pPath;
160  return kSuccess;
161}
162
163enum Linker::ErrorCode Linker::setOutput(int pFileHandler) {
164  mOutputHandler = pFileHandler;
165  return kSuccess;
166}
167
168enum Linker::ErrorCode Linker::link() {
169  mLinker->link(*mModule, *mBuilder);
170  if (!mOutputPath.empty()) {
171    mLinker->emit(mOutputPath);
172    return kSuccess;
173  }
174
175  if (-1 != mOutputHandler) {
176    mLinker->emit(mOutputHandler);
177    return kSuccess;
178  }
179  return kNotSetUpOutput;
180}
181
182