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#include <mcld/Support/FileHandle.h> 14#include <mcld/MC/InputTree.h> 15#include <mcld/MC/MCLDDriver.h> 16#include <mcld/Support/FileSystem.h> 17#include <mcld/Support/MsgHandling.h> 18#include <mcld/Support/FileHandle.h> 19#include <mcld/Support/raw_ostream.h> 20#include <mcld/Support/MemoryAreaFactory.h> 21#include <mcld/Support/DerivedPositionDependentOptions.h> 22#include <mcld/Target/TargetLDBackend.h> 23#include <mcld/CodeGen/SectLinker.h> 24#include <mcld/CodeGen/SectLinkerOption.h> 25 26#include <llvm/Module.h> 27 28#include <algorithm> 29#include <stack> 30#include <string> 31 32using namespace mcld; 33using namespace llvm; 34 35//===----------------------------------------------------------------------===// 36// Forward declarations 37char SectLinker::m_ID = 0; 38static bool CompareOption(const PositionDependentOption* X, 39 const PositionDependentOption* Y); 40 41//===----------------------------------------------------------------------===// 42// SectLinker 43SectLinker::SectLinker(SectLinkerOption &pOption, 44 TargetLDBackend& pLDBackend) 45 : MachineFunctionPass(m_ID), 46 m_pOption(&pOption), 47 m_pLDBackend(&pLDBackend), 48 m_pLDDriver(NULL), 49 m_pMemAreaFactory(NULL) 50{ 51 m_pMemAreaFactory = new MemoryAreaFactory(32); 52} 53 54SectLinker::~SectLinker() 55{ 56 delete m_pLDDriver; 57 58 // FIXME: current implementation can not change the order of delete. 59 // 60 // Instance of TargetLDBackend was created outside and is not managed by 61 // SectLinker. It should not be destroyed here and by SectLinker. However, in 62 // order to follow the LLVM convention - that is, the pass manages all the 63 // objects it used during the processing, we destroy the object of 64 // TargetLDBackend here. 65 delete m_pLDBackend; 66 67 delete m_pMemAreaFactory; 68} 69 70bool SectLinker::doInitialization(Module &pM) 71{ 72 MCLDInfo &info = m_pOption->info(); 73 74 // ----- convert position dependent options into tree of input files ----- // 75 PositionDependentOptions &PosDepOpts = m_pOption->pos_dep_options(); 76 std::stable_sort(PosDepOpts.begin(), PosDepOpts.end(), CompareOption); 77 initializeInputTree(PosDepOpts); 78 initializeInputOutput(info); 79 // Now, all input arguments are prepared well, send it into MCLDDriver 80 m_pLDDriver = new MCLDDriver(info, *m_pLDBackend, *memAreaFactory()); 81 82 return false; 83} 84 85bool SectLinker::doFinalization(Module &pM) 86{ 87 const MCLDInfo &info = m_pOption->info(); 88 89 // 2. - initialize MCLinker 90 if (!m_pLDDriver->initMCLinker()) 91 return true; 92 93 // 3. - initialize output's standard sections 94 if (!m_pLDDriver->initStdSections()) 95 return true; 96 97 // 4. - normalize the input tree 98 m_pLDDriver->normalize(); 99 100 if (info.options().trace()) { 101 static int counter = 0; 102 mcld::outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n"; 103 InputTree::const_dfs_iterator input, inEnd = info.inputs().dfs_end(); 104 for (input=info.inputs().dfs_begin(); input!=inEnd; ++input) { 105 mcld::outs() << counter++ << " * " << (*input)->name(); 106 switch((*input)->type()) { 107 case Input::Archive: 108 mcld::outs() << "\tarchive\t("; 109 break; 110 case Input::Object: 111 mcld::outs() << "\tobject\t("; 112 break; 113 case Input::DynObj: 114 mcld::outs() << "\tshared\t("; 115 break; 116 case Input::Script: 117 mcld::outs() << "\tscript\t("; 118 break; 119 case Input::External: 120 mcld::outs() << "\textern\t("; 121 break; 122 default: 123 unreachable(diag::err_cannot_trace_file) << (*input)->type() 124 << (*input)->name() 125 << (*input)->path(); 126 } 127 mcld::outs() << (*input)->path() << ")\n"; 128 } 129 } 130 131 // 5. - check if we can do static linking and if we use split-stack. 132 if (!m_pLDDriver->linkable()) 133 return true; 134 135 136 // 6. - merge all sections 137 if (!m_pLDDriver->mergeSections()) 138 return true; 139 140 // 7. - add standard symbols and target-dependent symbols 141 // m_pLDDriver->addUndefSymbols(); 142 if (!m_pLDDriver->addStandardSymbols() || 143 !m_pLDDriver->addTargetSymbols()) 144 return true; 145 146 // 8. - read all relocation entries from input files 147 m_pLDDriver->readRelocations(); 148 149 // 9. - pre-layout 150 m_pLDDriver->prelayout(); 151 152 // 10. - linear layout 153 m_pLDDriver->layout(); 154 155 // 10.b - post-layout (create segment, instruction relaxing) 156 m_pLDDriver->postlayout(); 157 158 // 11. - finalize symbol value 159 m_pLDDriver->finalizeSymbolValue(); 160 161 // 12. - apply relocations 162 m_pLDDriver->relocation(); 163 164 // 13. - write out output 165 m_pLDDriver->emitOutput(); 166 167 // 14. - post processing 168 m_pLDDriver->postProcessing(); 169 return false; 170} 171 172bool SectLinker::runOnMachineFunction(MachineFunction& pF) 173{ 174 // basically, linkers do nothing during function is generated. 175 return false; 176} 177 178void SectLinker::initializeInputOutput(MCLDInfo &pLDInfo) 179{ 180 // ----- initialize output file ----- // 181 FileHandle::Permission perm; 182 if (Output::Object == pLDInfo.output().type()) 183 perm = 0544; 184 else 185 perm = 0755; 186 187 MemoryArea* out_area = memAreaFactory()->produce(pLDInfo.output().path(), 188 FileHandle::ReadWrite, 189 perm); 190 191 if (!out_area->handler()->isGood()) { 192 // make sure output is openend successfully. 193 fatal(diag::err_cannot_open_output_file) << pLDInfo.output().name() 194 << pLDInfo.output().path(); 195 } 196 197 pLDInfo.output().setMemArea(out_area); 198 pLDInfo.output().setContext(pLDInfo.contextFactory().produce()); 199 200 // ----- initialize input files ----- // 201 InputTree::dfs_iterator input, inEnd = pLDInfo.inputs().dfs_end(); 202 for (input = pLDInfo.inputs().dfs_begin(); input!=inEnd; ++input) { 203 // already got type - for example, bitcode 204 if ((*input)->type() == Input::Script || 205 (*input)->type() == Input::Object || 206 (*input)->type() == Input::DynObj || 207 (*input)->type() == Input::Archive) 208 continue; 209 210 MemoryArea *input_memory = 211 memAreaFactory()->produce((*input)->path(), FileHandle::ReadOnly); 212 213 if (input_memory->handler()->isGood()) { 214 (*input)->setMemArea(input_memory); 215 } 216 else { 217 error(diag::err_cannot_open_input) << (*input)->name() << (*input)->path(); 218 return; 219 } 220 221 LDContext *input_context = 222 pLDInfo.contextFactory().produce((*input)->path()); 223 224 (*input)->setContext(input_context); 225 } 226} 227 228void SectLinker::initializeInputTree(const PositionDependentOptions &pPosDepOptions) const 229{ 230 if (pPosDepOptions.empty()) 231 fatal(diag::err_no_inputs); 232 233 MCLDInfo &info = m_pOption->info(); 234 PositionDependentOptions::const_iterator option = pPosDepOptions.begin(); 235 if (1 == pPosDepOptions.size() && 236 ((*option)->type() != PositionDependentOption::INPUT_FILE && 237 (*option)->type() != PositionDependentOption::NAMESPEC) && 238 (*option)->type() != PositionDependentOption::BITCODE) { 239 // if we only have one positional options, and the option is 240 // not an input file, then emit error message. 241 fatal(diag::err_no_inputs); 242 } 243 244 // ----- Input tree insertion algorithm ----- // 245 // The type of the previsou node indicates the direction of the current 246 // insertion. 247 // 248 // root : the parent node who being inserted. 249 // mover : the direcion of current movement. 250 // 251 // for each positional options: 252 // insert the options in current root. 253 // calculate the next movement 254 255 // Initialization 256 InputTree::Mover *move = &InputTree::Downward; 257 InputTree::iterator root = info.inputs().root(); 258 PositionDependentOptions::const_iterator optionEnd = pPosDepOptions.end(); 259 std::stack<InputTree::iterator> returnStack; 260 261 while (option != optionEnd ) { 262 263 switch ((*option)->type()) { 264 /** bitcode **/ 265 case PositionDependentOption::BITCODE: { 266 267 const BitcodeOption *bitcode_option = 268 static_cast<const BitcodeOption*>(*option); 269 270 // threat bitcode as an external IR in this version. 271 info.inputs().insert(root, *move, 272 bitcode_option->path()->native(), 273 *(bitcode_option->path()), 274 Input::External); 275 276 info.setBitcode(**root); 277 278 // move root on the new created node. 279 move->move(root); 280 281 // the next file is appended after bitcode file. 282 move = &InputTree::Afterward; 283 break; 284 } 285 286 /** input object file **/ 287 case PositionDependentOption::INPUT_FILE: { 288 const InputFileOption *input_file_option = 289 static_cast<const InputFileOption*>(*option); 290 291 info.inputs().insert(root, *move, 292 input_file_option->path()->native(), 293 *(input_file_option->path())); 294 295 // move root on the new created node. 296 move->move(root); 297 298 // the next file is appended after object file. 299 move = &InputTree::Afterward; 300 break; 301 } 302 303 /** -lnamespec **/ 304 case PositionDependentOption::NAMESPEC: { 305 sys::fs::Path* path = NULL; 306 const NamespecOption *namespec_option = 307 static_cast<const NamespecOption*>(*option); 308 309 // find out the real path of the namespec. 310 if (info.attrFactory().constraint().isSharedSystem()) { 311 // In the system with shared object support, we can find both archive 312 // and shared object. 313 314 if (info.attrFactory().last().isStatic()) { 315 // with --static, we must search an archive. 316 path = info.options().directories().find(namespec_option->namespec(), 317 Input::Archive); 318 } 319 else { 320 // otherwise, with --Bdynamic, we can find either an archive or a 321 // shared object. 322 path = info.options().directories().find(namespec_option->namespec(), 323 Input::DynObj); 324 } 325 } 326 else { 327 // In the system without shared object support, we only look for an 328 // archive. 329 path = info.options().directories().find(namespec_option->namespec(), 330 Input::Archive); 331 } 332 333 if (NULL == path) 334 fatal(diag::err_cannot_find_namespec) << namespec_option->namespec(); 335 336 info.inputs().insert(root, *move, 337 namespec_option->namespec(), 338 *path); 339 340 // iterate root on the new created node. 341 move->move(root); 342 343 // the file after a namespec must be appended afterward. 344 move = &InputTree::Afterward; 345 break; 346 } 347 348 /** start group **/ 349 case PositionDependentOption::START_GROUP: 350 info.inputs().enterGroup(root, *move); 351 move->move(root); 352 returnStack.push(root); 353 move = &InputTree::Downward; 354 break; 355 /** end group **/ 356 case PositionDependentOption::END_GROUP: 357 root = returnStack.top(); 358 returnStack.pop(); 359 move = &InputTree::Afterward; 360 break; 361 case PositionDependentOption::WHOLE_ARCHIVE: 362 info.attrFactory().last().setWholeArchive(); 363 break; 364 case PositionDependentOption::NO_WHOLE_ARCHIVE: 365 info.attrFactory().last().unsetWholeArchive(); 366 break; 367 case PositionDependentOption::AS_NEEDED: 368 info.attrFactory().last().setAsNeeded(); 369 break; 370 case PositionDependentOption::NO_AS_NEEDED: 371 info.attrFactory().last().unsetAsNeeded(); 372 break; 373 case PositionDependentOption::ADD_NEEDED: 374 info.attrFactory().last().setAddNeeded(); 375 break; 376 case PositionDependentOption::NO_ADD_NEEDED: 377 info.attrFactory().last().unsetAddNeeded(); 378 break; 379 case PositionDependentOption::BSTATIC: 380 info.attrFactory().last().setStatic(); 381 break; 382 case PositionDependentOption::BDYNAMIC: 383 info.attrFactory().last().setDynamic(); 384 break; 385 default: 386 fatal(diag::err_cannot_identify_option) << (*option)->position() 387 << (uint32_t)(*option)->type(); 388 } // end of switch 389 ++option; 390 } // end of while 391 392 if (!returnStack.empty()) { 393 report_fatal_error("no matched --start-group and --end-group"); 394 } 395} 396 397//===----------------------------------------------------------------------===// 398// Non-member functions 399static bool CompareOption(const PositionDependentOption* X, 400 const PositionDependentOption* Y) 401{ 402 return (X->position() < Y->position()); 403} 404 405