1//===- ScriptFile.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#include "mcld/Script/ScriptFile.h"
10
11#include "mcld/ADT/HashEntry.h"
12#include "mcld/ADT/HashTable.h"
13#include "mcld/ADT/StringHash.h"
14#include "mcld/Script/AssertCmd.h"
15#include "mcld/Script/EntryCmd.h"
16#include "mcld/Script/GroupCmd.h"
17#include "mcld/Script/InputCmd.h"
18#include "mcld/Script/Operand.h"
19#include "mcld/Script/OutputArchCmd.h"
20#include "mcld/Script/OutputCmd.h"
21#include "mcld/Script/OutputFormatCmd.h"
22#include "mcld/Script/RpnExpr.h"
23#include "mcld/Script/ScriptCommand.h"
24#include "mcld/Script/SearchDirCmd.h"
25#include "mcld/Script/SectionsCmd.h"
26#include "mcld/Script/StringList.h"
27#include "mcld/Script/StrToken.h"
28#include "mcld/MC/Input.h"
29#include "mcld/MC/InputBuilder.h"
30#include "mcld/Support/MemoryArea.h"
31#include "mcld/InputTree.h"
32
33#include <llvm/Support/Casting.h>
34#include <llvm/Support/ManagedStatic.h>
35
36#include <cassert>
37
38namespace mcld {
39
40typedef HashEntry<std::string, void*, hash::StringCompare<std::string> >
41    ParserStrEntry;
42typedef HashTable<ParserStrEntry,
43                  hash::StringHash<hash::DJB>,
44                  EntryFactory<ParserStrEntry> > ParserStrPool;
45static llvm::ManagedStatic<ParserStrPool> g_ParserStrPool;
46
47//===----------------------------------------------------------------------===//
48// ScriptFile
49//===----------------------------------------------------------------------===//
50ScriptFile::ScriptFile(Kind pKind, Input& pInput, InputBuilder& pBuilder)
51    : m_Kind(pKind),
52      m_Input(pInput),
53      m_Name(pInput.path().native()),
54      m_pInputTree(NULL),
55      m_Builder(pBuilder),
56      m_bHasSectionsCmd(false),
57      m_bInSectionsCmd(false),
58      m_bInOutputSectDesc(false),
59      m_pRpnExpr(NULL),
60      m_pStringList(NULL),
61      m_bAsNeeded(false) {
62  // FIXME: move creation of input tree out of ScriptFile.
63  m_pInputTree = new InputTree();
64}
65
66ScriptFile::~ScriptFile() {
67  for (iterator it = begin(), ie = end(); it != ie; ++it) {
68    if (*it != NULL)
69      delete *it;
70  }
71  if (m_pInputTree != NULL)
72    delete m_pInputTree;
73}
74
75void ScriptFile::dump() const {
76  for (const_iterator it = begin(), ie = end(); it != ie; ++it)
77    (*it)->dump();
78}
79
80void ScriptFile::activate(Module& pModule) {
81  for (const_iterator it = begin(), ie = end(); it != ie; ++it)
82    (*it)->activate(pModule);
83}
84
85void ScriptFile::addEntryPoint(const std::string& pSymbol) {
86  EntryCmd* entry = new EntryCmd(pSymbol);
87
88  if (m_bInSectionsCmd) {
89    assert(!m_CommandQueue.empty());
90    SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
91    sections->push_back(entry);
92  } else {
93    m_CommandQueue.push_back(entry);
94  }
95}
96
97void ScriptFile::addOutputFormatCmd(const std::string& pName) {
98  m_CommandQueue.push_back(new OutputFormatCmd(pName));
99}
100
101void ScriptFile::addOutputFormatCmd(const std::string& pDefault,
102                                    const std::string& pBig,
103                                    const std::string& pLittle) {
104  m_CommandQueue.push_back(new OutputFormatCmd(pDefault, pBig, pLittle));
105}
106
107void ScriptFile::addInputCmd(StringList& pStringList,
108                             ObjectReader& pObjectReader,
109                             ArchiveReader& pArchiveReader,
110                             DynObjReader& pDynObjReader,
111                             const LinkerConfig& pConfig) {
112  m_CommandQueue.push_back(new InputCmd(pStringList,
113                                        *m_pInputTree,
114                                        m_Builder,
115                                        pObjectReader,
116                                        pArchiveReader,
117                                        pDynObjReader,
118                                        pConfig));
119}
120
121void ScriptFile::addGroupCmd(StringList& pStringList,
122                             GroupReader& pGroupReader,
123                             const LinkerConfig& pConfig) {
124  m_CommandQueue.push_back(new GroupCmd(
125      pStringList, *m_pInputTree, m_Builder, pGroupReader, pConfig));
126}
127
128void ScriptFile::addOutputCmd(const std::string& pFileName) {
129  m_CommandQueue.push_back(new OutputCmd(pFileName));
130}
131
132void ScriptFile::addSearchDirCmd(const std::string& pPath) {
133  m_CommandQueue.push_back(new SearchDirCmd(pPath));
134}
135
136void ScriptFile::addOutputArchCmd(const std::string& pArch) {
137  m_CommandQueue.push_back(new OutputArchCmd(pArch));
138}
139
140void ScriptFile::addAssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage) {
141  m_CommandQueue.push_back(new AssertCmd(pRpnExpr, pMessage));
142}
143
144void ScriptFile::addAssignment(const std::string& pSymbolName,
145                               RpnExpr& pRpnExpr,
146                               Assignment::Type pType) {
147  if (m_bInSectionsCmd) {
148    assert(!m_CommandQueue.empty());
149    SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
150    if (m_bInOutputSectDesc) {
151      assert(!sections->empty());
152      OutputSectDesc* output_desc =
153          llvm::cast<OutputSectDesc>(sections->back());
154      output_desc->push_back(new Assignment(Assignment::INPUT_SECTION,
155                                            pType,
156                                            *(SymOperand::create(pSymbolName)),
157                                            pRpnExpr));
158    } else {
159      sections->push_back(new Assignment(Assignment::OUTPUT_SECTION,
160                                         pType,
161                                         *(SymOperand::create(pSymbolName)),
162                                         pRpnExpr));
163    }
164  } else {
165    m_CommandQueue.push_back(new Assignment(Assignment::OUTSIDE_SECTIONS,
166                                            pType,
167                                            *(SymOperand::create(pSymbolName)),
168                                            pRpnExpr));
169  }
170}
171
172bool ScriptFile::hasSectionsCmd() const {
173  return m_bHasSectionsCmd;
174}
175
176void ScriptFile::enterSectionsCmd() {
177  m_bHasSectionsCmd = true;
178  m_bInSectionsCmd = true;
179  m_CommandQueue.push_back(new SectionsCmd());
180}
181
182void ScriptFile::leaveSectionsCmd() {
183  m_bInSectionsCmd = false;
184}
185
186void ScriptFile::enterOutputSectDesc(const std::string& pName,
187                                     const OutputSectDesc::Prolog& pProlog) {
188  assert(!m_CommandQueue.empty());
189  assert(m_bInSectionsCmd);
190  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
191  sections->push_back(new OutputSectDesc(pName, pProlog));
192
193  m_bInOutputSectDesc = true;
194}
195
196void ScriptFile::leaveOutputSectDesc(const OutputSectDesc::Epilog& pEpilog) {
197  assert(!m_CommandQueue.empty());
198  assert(m_bInSectionsCmd);
199  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
200
201  assert(!sections->empty() && m_bInOutputSectDesc);
202  OutputSectDesc* output_desc = llvm::cast<OutputSectDesc>(sections->back());
203  output_desc->setEpilog(pEpilog);
204
205  m_bInOutputSectDesc = false;
206}
207
208void ScriptFile::addInputSectDesc(InputSectDesc::KeepPolicy pPolicy,
209                                  const InputSectDesc::Spec& pSpec) {
210  assert(!m_CommandQueue.empty());
211  assert(m_bInSectionsCmd);
212  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
213
214  assert(!sections->empty() && m_bInOutputSectDesc);
215  OutputSectDesc* output_sect = llvm::cast<OutputSectDesc>(sections->back());
216
217  output_sect->push_back(new InputSectDesc(pPolicy, pSpec, *output_sect));
218}
219
220RpnExpr* ScriptFile::createRpnExpr() {
221  m_pRpnExpr = RpnExpr::create();
222  return m_pRpnExpr;
223}
224
225StringList* ScriptFile::createStringList() {
226  m_pStringList = StringList::create();
227  return m_pStringList;
228}
229
230void ScriptFile::setAsNeeded(bool pEnable) {
231  m_bAsNeeded = pEnable;
232}
233
234const std::string& ScriptFile::createParserStr(const char* pText,
235                                               size_t pLength) {
236  bool exist = false;
237  ParserStrEntry* entry =
238      g_ParserStrPool->insert(std::string(pText, pLength), exist);
239  return entry->key();
240}
241
242void ScriptFile::clearParserStrPool() {
243  g_ParserStrPool->clear();
244}
245
246}  // namespace mcld
247