MCLinker upstream commit e764452.
Change-Id: I5c9ec467ec96a0143e1e67c59365f3b6303e7348
diff --git a/lib/ADT/StringEntry.cpp b/lib/ADT/StringEntry.cpp
new file mode 100644
index 0000000..c853f83
--- /dev/null
+++ b/lib/ADT/StringEntry.cpp
@@ -0,0 +1,48 @@
+//===- StringEntry.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/ADT/StringEntry.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// StringEntry<llvm::StringRef>
+StringEntry<llvm::StringRef>::StringEntry()
+{
+}
+
+StringEntry<llvm::StringRef>::StringEntry(const StringEntry::key_type& pKey)
+{
+}
+
+StringEntry<llvm::StringRef>::StringEntry(const StringEntry<llvm::StringRef>& pCopy)
+{
+ assert("Copy constructor of StringEntry should not be called!");
+}
+
+StringEntry<llvm::StringRef>::~StringEntry()
+{
+ if (!m_Value.empty())
+ free(const_cast<char*>(m_Value.data()));
+}
+
+void StringEntry<llvm::StringRef>::setValue(llvm::StringRef& pVal)
+{
+ char* data = (char*)malloc(pVal.size()+1);
+ strcpy(data, pVal.data());
+ m_Value = llvm::StringRef(data, pVal.size());
+}
+
+void StringEntry<llvm::StringRef>::setValue(const char* pVal)
+{
+ size_t length = strlen(pVal);
+ char* data = (char*)malloc(length+1);
+ strcpy(data, pVal);
+ m_Value = llvm::StringRef(data, length);
+}
+
diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp
index 13efa96..e24596c 100644
--- a/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/lib/CodeGen/LLVMTargetMachine.cpp
@@ -231,10 +231,6 @@
pPM.add(createGCInfoDeleter()); // not in addPassesToMC
break;
}
- case CGFT_ARCFile: {
- assert(0 && "Output to archive file has not been supported yet!");
- break;
- }
case CGFT_EXEFile: {
if (pLinkerOpt == NULL)
return true;
@@ -378,7 +374,7 @@
return true;
pPM.add(printer);
#endif
- TargetLDBackend* ldBackend = getTarget().createLDBackend(*getTarget().get(), m_Triple);
+ TargetLDBackend* ldBackend = getTarget().createLDBackend(m_Triple);
if (0 == ldBackend)
return true;
@@ -410,3 +406,4 @@
pPM.add(funcPass);
return false;
}
+
diff --git a/lib/CodeGen/SectLinker.cpp b/lib/CodeGen/SectLinker.cpp
index 95e9e4f..4f32c4f 100644
--- a/lib/CodeGen/SectLinker.cpp
+++ b/lib/CodeGen/SectLinker.cpp
@@ -10,19 +10,20 @@
// This file implements the SectLinker class.
//
//===----------------------------------------------------------------------===//
-
-#include <mcld/ADT/BinTree.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/MC/MCLDDriver.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/raw_ostream.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/DerivedPositionDependentOptions.h>
+#include <mcld/Target/TargetLDBackend.h>
#include <mcld/CodeGen/SectLinker.h>
#include <mcld/CodeGen/SectLinkerOption.h>
-#include <mcld/MC/MCLDInputTree.h>
-#include <mcld/MC/MCLDDriver.h>
-#include <mcld/Support/DerivedPositionDependentOptions.h>
-#include <mcld/Support/FileSystem.h>
-#include <mcld/Target/TargetLDBackend.h>
#include <llvm/Module.h>
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/Support/raw_ostream.h>
#include <algorithm>
#include <stack>
@@ -44,11 +45,16 @@
: MachineFunctionPass(m_ID),
m_pOption(&pOption),
m_pLDBackend(&pLDBackend),
- m_pLDDriver(NULL) { }
+ m_pLDDriver(NULL),
+ m_pMemAreaFactory(NULL)
+{
+ m_pMemAreaFactory = new MemoryAreaFactory(32);
+}
SectLinker::~SectLinker()
{
delete m_pLDDriver;
+
// FIXME: current implementation can not change the order of delete.
//
// Instance of TargetLDBackend was created outside and is not managed by
@@ -57,36 +63,19 @@
// objects it used during the processing, we destroy the object of
// TargetLDBackend here.
delete m_pLDBackend;
+
+ delete m_pMemAreaFactory;
}
bool SectLinker::doInitialization(Module &pM)
{
MCLDInfo &info = m_pOption->info();
- // setup the output
- info.output().setContext(info.contextFactory().produce(info.output().path()));
-
- int mode = (Output::Object == info.output().type())? 0544 : 0755;
- info.output().setMemArea(
- info.memAreaFactory().produce(info.output().path(),
- O_RDWR | O_CREAT | O_TRUNC,
- mode));
-
- // make sure output is openend successfully.
- if (!info.output().hasMemArea())
- report_fatal_error("output is not given on the command line\n");
-
- if (!info.output().memArea()->isGood())
- report_fatal_error("can not open output file :"+info.output().path().native());
-
- // let the target override the target-specific parameters
- addTargetOptions(pM, *m_pOption);
-
// ----- convert position dependent options into tree of input files ----- //
PositionDependentOptions &PosDepOpts = m_pOption->pos_dep_options();
std::stable_sort(PosDepOpts.begin(), PosDepOpts.end(), CompareOption);
initializeInputTree(PosDepOpts);
-
+ initializeInputOutput(info);
// Now, all input arguments are prepared well, send it into MCLDDriver
m_pLDDriver = new MCLDDriver(info, *m_pLDBackend);
@@ -97,42 +86,45 @@
{
const MCLDInfo &info = m_pOption->info();
- // 3. - initialize output's standard segments and sections
+ // 2. - initialize MCLinker
if (!m_pLDDriver->initMCLinker())
return true;
+ // 3. - initialize output's standard sections
+ if (!m_pLDDriver->initStdSections())
+ return true;
+
// 4. - normalize the input tree
m_pLDDriver->normalize();
- if (info.options().verbose()) {
- outs() << "MCLinker (LLVM Sub-project) - ";
- outs() << MCLDInfo::version();
- outs() << "\n";
- }
-
if (info.options().trace()) {
static int counter = 0;
- outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n";
+ mcld::outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n";
InputTree::const_dfs_iterator input, inEnd = info.inputs().dfs_end();
for (input=info.inputs().dfs_begin(); input!=inEnd; ++input) {
- outs() << counter++ << " * " << (*input)->name();
+ mcld::outs() << counter++ << " * " << (*input)->name();
switch((*input)->type()) {
case Input::Archive:
- outs() << "\tarchive\t(";
+ mcld::outs() << "\tarchive\t(";
break;
case Input::Object:
- outs() << "\tobject\t(";
+ mcld::outs() << "\tobject\t(";
break;
case Input::DynObj:
- outs() << "\tshared\t(";
+ mcld::outs() << "\tshared\t(";
break;
case Input::Script:
- outs() << "\tscript\t(";
+ mcld::outs() << "\tscript\t(";
+ break;
+ case Input::External:
+ mcld::outs() << "\textern\t(";
break;
default:
- report_fatal_error("** Trace a unsupported file. It must be an internal bug!");
+ unreachable(diag::err_cannot_trace_file) << (*input)->type()
+ << (*input)->name()
+ << (*input)->path();
}
- outs() << (*input)->path().c_str() << ")\n";
+ mcld::outs() << (*input)->path() << ")\n";
}
}
@@ -147,8 +139,7 @@
return true;
// 7. - read all symbol tables of input files and resolve them
- if (!m_pLDDriver->readSymbolTables() ||
- !m_pLDDriver->mergeSymbolTables())
+ if (!m_pLDDriver->readSymbolTables())
return true;
// 7.a - add standard symbols and target-dependent symbols
@@ -173,7 +164,7 @@
m_pLDDriver->finalizeSymbolValue();
// 12. - apply relocations
- m_pLDDriver->relocate();
+ m_pLDDriver->relocation();
// 13. - write out output
m_pLDDriver->emitOutput();
@@ -189,86 +180,188 @@
return false;
}
+void SectLinker::initializeInputOutput(MCLDInfo &pLDInfo)
+{
+ // ----- initialize output file ----- //
+ FileHandle::Permission perm;
+ if (Output::Object == pLDInfo.output().type())
+ perm = 0544;
+ else
+ perm = 0755;
+
+ MemoryArea* out_area = memAreaFactory()->produce(pLDInfo.output().path(),
+ FileHandle::ReadWrite,
+ perm);
+
+ if (!out_area->handler()->isGood()) {
+ // make sure output is openend successfully.
+ fatal(diag::err_cannot_open_output_file) << pLDInfo.output().name()
+ << pLDInfo.output().path();
+ }
+
+ pLDInfo.output().setMemArea(out_area);
+ pLDInfo.output().setContext(pLDInfo.contextFactory().produce());
+
+ // ----- initialize input files ----- //
+ InputTree::dfs_iterator input, inEnd = pLDInfo.inputs().dfs_end();
+ for (input = pLDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
+ // already got type - for example, bitcode
+ if ((*input)->type() == Input::Script ||
+ (*input)->type() == Input::Object ||
+ (*input)->type() == Input::DynObj ||
+ (*input)->type() == Input::Archive)
+ continue;
+
+ MemoryArea *input_memory =
+ memAreaFactory()->produce((*input)->path(), FileHandle::ReadOnly);
+
+ if (input_memory->handler()->isGood()) {
+ (*input)->setMemArea(input_memory);
+ }
+ else {
+ error(diag::err_cannot_open_input) << (*input)->name() << (*input)->path();
+ return;
+ }
+
+ LDContext *input_context =
+ pLDInfo.contextFactory().produce((*input)->path());
+
+ (*input)->setContext(input_context);
+ }
+}
+
void SectLinker::initializeInputTree(const PositionDependentOptions &pPosDepOptions) const
{
if (pPosDepOptions.empty())
- return;
+ fatal(diag::err_no_inputs);
MCLDInfo &info = m_pOption->info();
- PositionDependentOptions::const_iterator cur_char = pPosDepOptions.begin();
+ PositionDependentOptions::const_iterator option = pPosDepOptions.begin();
if (1 == pPosDepOptions.size() &&
- ((*cur_char)->type() != PositionDependentOption::INPUT_FILE &&
- (*cur_char)->type() != PositionDependentOption::NAMESPEC))
- return;
+ ((*option)->type() != PositionDependentOption::INPUT_FILE &&
+ (*option)->type() != PositionDependentOption::NAMESPEC) &&
+ (*option)->type() != PositionDependentOption::BITCODE) {
+ // if we only have one positional options, and the option is
+ // not an input file, then emit error message.
+ fatal(diag::err_no_inputs);
+ }
- InputTree::Connector *prev_ward = &InputTree::Downward;
+ // ----- Input tree insertion algorithm ----- //
+ // The type of the previsou node indicates the direction of the current
+ // insertion.
+ //
+ // root : the parent node who being inserted.
+ // mover : the direcion of current movement.
+ //
+ // for each positional options:
+ // insert the options in current root.
+ // calculate the next movement
+ // Initialization
+ InputTree::Mover *move = &InputTree::Downward;
+ InputTree::iterator root = info.inputs().root();
+ PositionDependentOptions::const_iterator optionEnd = pPosDepOptions.end();
std::stack<InputTree::iterator> returnStack;
- InputTree::iterator cur_node = info.inputs().root();
- PositionDependentOptions::const_iterator charEnd = pPosDepOptions.end();
- while (cur_char != charEnd ) {
- switch ((*cur_char)->type()) {
- case PositionDependentOption::BITCODE: {
- // threat bitcode as a script in this version.
- const BitcodeOption *bitcode_option =
- static_cast<const BitcodeOption*>(*cur_char);
- info.inputs().insert(cur_node,
- *prev_ward,
- bitcode_option->path()->native(),
- *(bitcode_option->path()),
- Input::Script);
- info.setBitcode(**cur_node);
- prev_ward->move(cur_node);
- prev_ward = &InputTree::Afterward;
- break;
- }
- case PositionDependentOption::INPUT_FILE: {
- const InputFileOption *input_file_option =
- static_cast<const InputFileOption*>(*cur_char);
- info.inputs().insert(cur_node,
- *prev_ward,
- input_file_option->path()->native(),
- *(input_file_option->path()));
- prev_ward->move(cur_node);
- prev_ward = &InputTree::Afterward;
- break;
- }
+ while (option != optionEnd ) {
+
+ switch ((*option)->type()) {
+ /** bitcode **/
+ case PositionDependentOption::BITCODE: {
+
+ const BitcodeOption *bitcode_option =
+ static_cast<const BitcodeOption*>(*option);
+
+ // threat bitcode as an external IR in this version.
+ info.inputs().insert(root, *move,
+ bitcode_option->path()->native(),
+ *(bitcode_option->path()),
+ Input::External);
+
+ info.setBitcode(**root);
+
+ // move root on the new created node.
+ move->move(root);
+
+ // the next file is appended after bitcode file.
+ move = &InputTree::Afterward;
+ break;
+ }
+
+ /** input object file **/
+ case PositionDependentOption::INPUT_FILE: {
+ const InputFileOption *input_file_option =
+ static_cast<const InputFileOption*>(*option);
+
+ info.inputs().insert(root, *move,
+ input_file_option->path()->native(),
+ *(input_file_option->path()));
+
+ // move root on the new created node.
+ move->move(root);
+
+ // the next file is appended after object file.
+ move = &InputTree::Afterward;
+ break;
+ }
+
+ /** -lnamespec **/
case PositionDependentOption::NAMESPEC: {
- sys::fs::Path* path = 0;
+ sys::fs::Path* path = NULL;
const NamespecOption *namespec_option =
- static_cast<const NamespecOption*>(*cur_char);
- if (info.attrFactory().last().isStatic()) {
+ static_cast<const NamespecOption*>(*option);
+
+ // find out the real path of the namespec.
+ if (info.attrFactory().constraint().isSharedSystem()) {
+ // In the system with shared object support, we can find both archive
+ // and shared object.
+
+ if (info.attrFactory().last().isStatic()) {
+ // with --static, we must search an archive.
+ path = info.options().directories().find(namespec_option->namespec(),
+ Input::Archive);
+ }
+ else {
+ // otherwise, with --Bdynamic, we can find either an archive or a
+ // shared object.
+ path = info.options().directories().find(namespec_option->namespec(),
+ Input::DynObj);
+ }
+ }
+ else {
+ // In the system without shared object support, we only look for an
+ // archive.
path = info.options().directories().find(namespec_option->namespec(),
Input::Archive);
}
- else {
- path = info.options().directories().find(namespec_option->namespec(),
- Input::DynObj);
- }
- if (0 == path) {
- llvm::report_fatal_error(std::string("Can't find namespec: ")+
- namespec_option->namespec());
- }
- info.inputs().insert(cur_node,
- *prev_ward,
+ if (NULL == path)
+ fatal(diag::err_cannot_find_namespec) << namespec_option->namespec();
+
+ info.inputs().insert(root, *move,
namespec_option->namespec(),
*path);
- prev_ward->move(cur_node);
- prev_ward = &InputTree::Afterward;
+
+ // iterate root on the new created node.
+ move->move(root);
+
+ // the file after a namespec must be appended afterward.
+ move = &InputTree::Afterward;
break;
}
+
+ /** start group **/
case PositionDependentOption::START_GROUP:
- info.inputs().enterGroup(cur_node, *prev_ward);
- prev_ward->move(cur_node);
- returnStack.push(cur_node);
- prev_ward = &InputTree::Downward;
+ info.inputs().enterGroup(root, *move);
+ move->move(root);
+ returnStack.push(root);
+ move = &InputTree::Downward;
break;
+ /** end group **/
case PositionDependentOption::END_GROUP:
- cur_node = returnStack.top();
+ root = returnStack.top();
returnStack.pop();
- prev_ward = &InputTree::Afterward;
+ move = &InputTree::Afterward;
break;
case PositionDependentOption::WHOLE_ARCHIVE:
info.attrFactory().last().setWholeArchive();
@@ -295,10 +388,11 @@
info.attrFactory().last().setDynamic();
break;
default:
- report_fatal_error("can not find the type of input file");
- }
- ++cur_char;
- }
+ fatal(diag::err_cannot_identify_option) << (*option)->position()
+ << (uint32_t)(*option)->type();
+ } // end of switch
+ ++option;
+ } // end of while
if (!returnStack.empty()) {
report_fatal_error("no matched --start-group and --end-group");
diff --git a/lib/LD/BSDArchiveReader.cpp b/lib/LD/BSDArchiveReader.cpp
index 1264824..079153b 100644
--- a/lib/LD/BSDArchiveReader.cpp
+++ b/lib/LD/BSDArchiveReader.cpp
@@ -6,9 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInput.h"
-#include "mcld/MC/MCLDInputTree.h"
-#include "mcld/LD/BSDArchiveReader.h"
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/LD/BSDArchiveReader.h>
using namespace mcld;
diff --git a/lib/LD/CIE.cpp b/lib/LD/CIE.cpp
new file mode 100644
index 0000000..c2f4317
--- /dev/null
+++ b/lib/LD/CIE.cpp
@@ -0,0 +1,23 @@
+//===- CIE.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/CIE.h>
+
+using namespace mcld;
+
+//==========================
+// CIE
+
+CIE::CIE(MemoryRegion& pRegion, uint8_t pFDEEncode)
+ : MCRegionFragment(pRegion), m_FDEEncoding(pFDEEncode) {
+}
+
+CIE::~CIE()
+{
+}
diff --git a/lib/LD/DWARFLineInfo.cpp b/lib/LD/DWARFLineInfo.cpp
new file mode 100644
index 0000000..63c588d
--- /dev/null
+++ b/lib/LD/DWARFLineInfo.cpp
@@ -0,0 +1,15 @@
+//===- DWARFLineInfo.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DWARFLineInfo.h>
+
+using namespace mcld;
+
+//==========================
+// DWARFLineInfo
+
diff --git a/lib/LD/Diagnostic.cpp b/lib/LD/Diagnostic.cpp
new file mode 100644
index 0000000..5175ebd
--- /dev/null
+++ b/lib/LD/Diagnostic.cpp
@@ -0,0 +1,173 @@
+//===- Diagnostic.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/Diagnostic.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/ADT/Twine.h>
+#include <ctype.h>
+#include <algorithm>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// Diagnostic
+Diagnostic::Diagnostic(DiagnosticEngine& pEngine)
+ : m_Engine(pEngine) {
+}
+
+Diagnostic::~Diagnostic()
+{
+}
+
+// format - format this diagnostic into string, subsituting the formal
+// arguments. The result is appended at on the pOutStr.
+void Diagnostic::format(std::string& pOutStr) const
+{
+ // we've not implemented DWARF LOC messages yet. So, keep pIsLoC false
+ llvm::StringRef desc = m_Engine.infoMap().getDescription(getID(), false);
+
+ format(desc.begin(), desc.end(), pOutStr);
+}
+
+const char* Diagnostic::findMatch(char pVal,
+ const char* pBegin, const char* pEnd ) const
+{
+ unsigned int depth = 0;
+ for (; pBegin != pEnd; ++pBegin) {
+ if (0 == depth && *pBegin == pVal)
+ return pBegin;
+ if (0 != depth && *pBegin == '}')
+ --depth;
+
+ if ('%' == *pBegin) {
+ ++pBegin;
+ if (pBegin == pEnd)
+ break;
+
+ if (!isdigit(*pBegin) && !ispunct(*pBegin)) {
+ ++pBegin;
+ while (pBegin != pEnd && !isdigit(*pBegin) && *pBegin != '{')
+ ++pBegin;
+
+ if (pBegin == pEnd)
+ break;
+ if ('{' == *pBegin)
+ ++depth;
+ }
+ }
+ } // end of for
+ return pEnd;
+}
+
+// format - format the given formal string, subsituting the formal
+// arguments. The result is appended at on the pOutStr.
+void Diagnostic::format(const char* pBegin, const char* pEnd,
+ std::string& pOutStr) const
+{
+ const char* cur_char = pBegin;
+ while (cur_char != pEnd) {
+ if ('%' != *cur_char) {
+ const char* new_end = std::find(cur_char, pEnd, '%');
+ pOutStr.append(cur_char, new_end);
+ cur_char = new_end;
+ continue;
+ }
+ else if (ispunct(cur_char[1])) {
+ pOutStr.push_back(cur_char[1]); // %% -> %.
+ cur_char += 2;
+ continue;
+ }
+
+ // skip the %.
+ ++cur_char;
+
+ const char* modifier = NULL, *argument = NULL;
+ size_t modifier_len = 0, argument_len = 0;
+
+ // we get a modifier
+ if (!isdigit(*cur_char)) {
+ modifier = cur_char;
+ while (*cur_char == '-' || (*cur_char >= 'a' && *cur_char <= 'z'))
+ ++cur_char;
+ modifier_len = cur_char - modifier;
+
+ // we get an argument
+ if ('{' == *cur_char) {
+ ++cur_char; // skip '{'
+ argument = cur_char;
+ cur_char = findMatch('}', cur_char, pEnd);
+
+ if (cur_char == pEnd) {
+ // DIAG's format error
+ llvm::report_fatal_error(llvm::Twine("Mismatched {} in the diagnostic: ") +
+ llvm::Twine(getID()));
+ }
+
+ argument_len = cur_char - argument;
+ ++cur_char; // skip '}'
+ }
+ }
+ if (!isdigit(*cur_char)) {
+ llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
+ llvm::Twine(getID()) + llvm::Twine(": ") +
+ llvm::Twine(pBegin) +
+ llvm::Twine("\nNo given arugment number:\n"));
+ }
+
+ unsigned int arg_no = *cur_char - '0';
+ ++cur_char; // skip argument number
+
+ DiagnosticEngine::ArgumentKind kind = getArgKind(arg_no);
+ switch (kind) {
+ case DiagnosticEngine::ak_std_string: {
+ if (0 != modifier_len) {
+ llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
+ llvm::Twine(getID()) +
+ llvm::Twine(": ") + llvm::Twine(pBegin) +
+ llvm::Twine("\nNo modifiers for strings yet\n"));
+ }
+ const std::string& str = getArgStdStr(arg_no);
+ pOutStr.append(str.begin(), str.end());
+ break;
+ }
+ case DiagnosticEngine::ak_c_string: {
+ if (0 != modifier_len) {
+ llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
+ llvm::Twine(getID()) +
+ llvm::Twine(": ") + llvm::Twine(pBegin) +
+ llvm::Twine("\nNo modifiers for strings yet\n"));
+ }
+ const char* str = getArgCStr(arg_no);
+ if (NULL == str)
+ str = "(null)";
+ pOutStr.append(str);
+ break;
+ }
+ case DiagnosticEngine::ak_sint: {
+ int val = getArgSInt(arg_no);
+ llvm::raw_string_ostream(pOutStr) << val;
+ break;
+ }
+ case DiagnosticEngine::ak_uint: {
+ unsigned int val = getArgUInt(arg_no);
+ llvm::raw_string_ostream(pOutStr) << val;
+ break;
+ }
+ case DiagnosticEngine::ak_bool: {
+ bool val = getArgBool(arg_no);
+ if (val)
+ pOutStr.append("true");
+ else
+ pOutStr.append("false");
+ break;
+ }
+ } // end of switch
+ } // end of while
+}
+
diff --git a/lib/LD/DiagnosticEngine.cpp b/lib/LD/DiagnosticEngine.cpp
new file mode 100644
index 0000000..11dbe1b
--- /dev/null
+++ b/lib/LD/DiagnosticEngine.cpp
@@ -0,0 +1,58 @@
+//===- DiagnosticEngine.cpp -----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticEngine.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/MC/MCLDInfo.h>
+
+using namespace mcld;
+
+//==========================
+// DiagnosticEngine
+DiagnosticEngine::DiagnosticEngine(const MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter,
+ bool pShouldOwnPrinter)
+ : m_LDInfo(pLDInfo),
+ m_pLineInfo(pLineInfo),
+ m_pPrinter(pPrinter),
+ m_InfoMap(pLDInfo),
+ m_OwnPrinter(pShouldOwnPrinter) {
+ if (NULL == m_pPrinter) {
+ m_pPrinter = new DiagnosticPrinter(); // Dumb printer
+ m_OwnPrinter = true;
+ }
+}
+
+DiagnosticEngine::~DiagnosticEngine()
+{
+ if (m_OwnPrinter && m_pPrinter != NULL)
+ delete m_pPrinter;
+
+ if (NULL != m_pLineInfo)
+ delete m_pLineInfo;
+}
+
+void DiagnosticEngine::setPrinter(DiagnosticPrinter& pPrinter,
+ bool pShouldOwnPrinter)
+{
+ if (m_OwnPrinter && m_pPrinter != NULL)
+ delete m_pPrinter;
+ m_pPrinter = &pPrinter;
+ m_OwnPrinter = pShouldOwnPrinter;
+}
+
+// emit - process current diagnostic.
+bool DiagnosticEngine::emit()
+{
+ bool emitted = m_InfoMap.process(*this);
+ m_State.reset();
+ return emitted;
+}
+
diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp
new file mode 100644
index 0000000..b9a6fa9
--- /dev/null
+++ b/lib/LD/DiagnosticInfos.cpp
@@ -0,0 +1,149 @@
+//===- DiagnosticInfo.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/DataTypes.h>
+
+#include <mcld/ADT/SizeTraits.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/LD/Diagnostic.h>
+#include <mcld/LD/DiagnosticInfos.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+
+using namespace mcld;
+
+namespace {
+
+struct DiagStaticInfo
+{
+public:
+ uint16_t ID;
+ DiagnosticEngine::Severity Severity;
+ uint16_t DescriptionLen;
+ const char* DescriptionStr;
+
+public:
+ llvm::StringRef getDescription() const
+ { return llvm::StringRef(DescriptionStr, DescriptionLen); }
+
+ bool operator<(const DiagStaticInfo& pRHS) const
+ { return (ID < pRHS.ID); }
+};
+
+} // namespace anonymous
+
+static const DiagStaticInfo DiagCommonInfo[] = {
+#define DIAG(ENUM, CLASS, ADDRDESC, LOCDESC) \
+ { diag::ENUM, CLASS, STR_SIZE(ADDRDESC, uint16_t), ADDRDESC },
+#include "mcld/LD/DiagCommonKinds.inc"
+#include "mcld/LD/DiagReaders.inc"
+#include "mcld/LD/DiagSymbolResolutions.inc"
+#include "mcld/LD/DiagRelocations.inc"
+#include "mcld/LD/DiagLayouts.inc"
+#include "mcld/LD/DiagGOTPLT.inc"
+#undef DIAG
+ { 0, DiagnosticEngine::None, 0, 0}
+};
+
+static const unsigned int DiagCommonInfoSize =
+ sizeof(DiagCommonInfo)/sizeof(DiagCommonInfo[0])-1;
+
+static const DiagStaticInfo DiagLoCInfo[] = {
+#define DIAG(ENUM, CLASS, ADDRDESC, LOCDESC) \
+ { diag::ENUM, CLASS, STR_SIZE(LOCDESC, uint16_t), LOCDESC },
+#include "mcld/LD/DiagReaders.inc"
+#include "mcld/LD/DiagSymbolResolutions.inc"
+#include "mcld/LD/DiagRelocations.inc"
+#include "mcld/LD/DiagLayouts.inc"
+#include "mcld/LD/DiagGOTPLT.inc"
+#undef DIAG
+ { 0, DiagnosticEngine::None, 0, 0}
+};
+
+static const unsigned int DiagLoCInfoSize =
+ sizeof(DiagLoCInfo)/sizeof(DiagLoCInfo[0])-1;
+
+
+static const DiagStaticInfo* getDiagInfo(unsigned int pID, bool pInLoC = false)
+{
+ const DiagStaticInfo* static_info = (pInLoC)?DiagLoCInfo:DiagCommonInfo;
+ unsigned int info_size = (pInLoC)?DiagLoCInfoSize:DiagCommonInfoSize;
+
+ DiagStaticInfo key = { static_cast<uint16_t>(pID), DiagnosticEngine::None, 0, 0 };
+ const DiagStaticInfo *result = std::lower_bound(static_info, static_info + info_size, key);
+
+ if (result == (static_info + info_size) || result->ID != pID)
+ return NULL;
+
+ return result;
+}
+
+//===----------------------------------------------------------------------===//
+// DiagnosticInfos
+DiagnosticInfos::DiagnosticInfos(const MCLDInfo& pLDInfo)
+ : m_LDInfo(pLDInfo) {
+}
+
+DiagnosticInfos::~DiagnosticInfos()
+{
+}
+
+llvm::StringRef DiagnosticInfos::getDescription(unsigned int pID, bool pInLoC) const
+{
+ return getDiagInfo(pID, pInLoC)->getDescription();
+}
+
+bool DiagnosticInfos::process(DiagnosticEngine& pEngine) const
+{
+ Diagnostic info(pEngine);
+
+ unsigned int ID = info.getID();
+
+ // we are not implement LineInfo, so keep pIsLoC false.
+ const DiagStaticInfo* static_info = getDiagInfo(ID);
+
+ DiagnosticEngine::Severity severity = static_info->Severity;
+
+ switch (ID) {
+ case diag::multiple_definitions: {
+ if (m_LDInfo.options().hasMulDefs()) {
+ severity = DiagnosticEngine::Ignore;
+ }
+ break;
+ }
+ case diag::undefined_reference: {
+ // we have not implement --unresolved-symbols=method yet. So far, MCLinker
+ // provides the easier --allow-shlib-undefined and --no-undefined (i.e. -z defs)
+ switch(m_LDInfo.output().type()) {
+ case Output::Object:
+ if (m_LDInfo.options().isNoUndefined())
+ severity = DiagnosticEngine::Error;
+ else
+ severity = DiagnosticEngine::Ignore;
+ break;
+ case Output::DynObj:
+ if (m_LDInfo.options().isNoUndefined() || !m_LDInfo.options().isAllowShlibUndefined())
+ severity = DiagnosticEngine::Error;
+ else
+ severity = DiagnosticEngine::Ignore;
+ break;
+ case Output::Exec:
+ severity = DiagnosticEngine::Error;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ } // end of switch
+
+ // finally, report it.
+ pEngine.getPrinter()->handleDiagnostic(severity, info);
+ return true;
+}
+
diff --git a/lib/LD/DiagnosticLineInfo.cpp b/lib/LD/DiagnosticLineInfo.cpp
new file mode 100644
index 0000000..d3c9190
--- /dev/null
+++ b/lib/LD/DiagnosticLineInfo.cpp
@@ -0,0 +1,15 @@
+//===- DiagnosticLineInfo.cpp ---------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticLineInfo.h>
+
+using namespace mcld;
+
+//==========================
+// DiagnosticLineInfo
+
diff --git a/lib/LD/DiagnosticPrinter.cpp b/lib/LD/DiagnosticPrinter.cpp
new file mode 100644
index 0000000..7bbf473
--- /dev/null
+++ b/lib/LD/DiagnosticPrinter.cpp
@@ -0,0 +1,34 @@
+//===- DiagnosticPrinter.cpp ----------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticPrinter.h>
+
+using namespace mcld;
+
+//==========================
+// DiagnosticPrinter
+DiagnosticPrinter::DiagnosticPrinter()
+ : m_NumErrors(0), m_NumWarnings(0) {
+}
+
+DiagnosticPrinter::~DiagnosticPrinter()
+{
+ clear();
+}
+
+/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+/// capturing it to a log as needed.
+void DiagnosticPrinter::handleDiagnostic(DiagnosticEngine::Severity pSeverity,
+ const Diagnostic& pInfo)
+{
+ if (pSeverity == DiagnosticEngine::Warning)
+ ++m_NumWarnings;
+ else if (pSeverity <= DiagnosticEngine::Error)
+ ++m_NumErrors;
+}
+
diff --git a/lib/LD/ELFDynObjFileFormat.cpp b/lib/LD/ELFDynObjFileFormat.cpp
index 77034eb..30183cc 100644
--- a/lib/LD/ELFDynObjFileFormat.cpp
+++ b/lib/LD/ELFDynObjFileFormat.cpp
@@ -6,11 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
#include <mcld/LD/ELFDynObjFileFormat.h>
#include <mcld/LD/LDFileFormat.h>
#include <mcld/LD/LDSection.h>
#include <mcld/MC/MCLinker.h>
-#include <llvm/Support/ELF.h>
#include <mcld/Target/GNULDBackend.h>
using namespace mcld;
@@ -77,5 +77,10 @@
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
f_Backend.bitclass() / 8);
+ f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
+ LDFileFormat::EhFrameHdr,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x4);
}
diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp
index 12e6d7c..de36104 100644
--- a/lib/LD/ELFDynObjReader.cpp
+++ b/lib/LD/ELFDynObjReader.cpp
@@ -69,9 +69,13 @@
MemoryRegion* region = pInput.memArea()->request(0, hdr_size);
uint8_t* ELF_hdr = region->start();
- bool result = m_pELFReader->readSectionHeaders(pInput, m_Linker, ELF_hdr);
+ bool shdr_result = m_pELFReader->readSectionHeaders(pInput, m_Linker, ELF_hdr);
pInput.memArea()->release(region);
- return result;
+
+ // read .dynamic to get the correct SONAME
+ bool dyn_result = m_pELFReader->readDynamic(pInput);
+
+ return (shdr_result && dyn_result);
}
/// readSymbols
@@ -80,9 +84,20 @@
assert(pInput.hasMemArea());
LDSection* symtab_shdr = pInput.context()->getSection(".dynsym");
+ if (NULL == symtab_shdr) {
+ note(diag::note_has_no_symtab) << pInput.name()
+ << pInput.path()
+ << ".dynsym";
+ return true;
+ }
+
LDSection* strtab_shdr = symtab_shdr->getLink();
- if (NULL == symtab_shdr || NULL == strtab_shdr)
+ if (NULL == strtab_shdr) {
+ fatal(diag::fatal_cannot_read_strtab) << pInput.name()
+ << pInput.path()
+ << ".dynsym";
return false;
+ }
MemoryRegion* symtab_region = pInput.memArea()->request(symtab_shdr->offset(),
symtab_shdr->size());
diff --git a/lib/LD/ELFDynObjWriter.cpp b/lib/LD/ELFDynObjWriter.cpp
index 21cd8e4..cabc9e9 100644
--- a/lib/LD/ELFDynObjWriter.cpp
+++ b/lib/LD/ELFDynObjWriter.cpp
@@ -58,7 +58,10 @@
switch(sect->kind()) {
case LDFileFormat::Regular:
case LDFileFormat::Relocation:
- case LDFileFormat::Target: {
+ case LDFileFormat::Target:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
region = pOutput.memArea()->request(sect->offset(), sect->size());
if (NULL == region) {
llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section[") +
@@ -72,11 +75,10 @@
case LDFileFormat::Null:
case LDFileFormat::NamePool:
case LDFileFormat::BSS:
- case LDFileFormat::Debug:
case LDFileFormat::Note:
case LDFileFormat::MetaData:
- case LDFileFormat::Exception:
case LDFileFormat::Version:
+ case LDFileFormat::EhFrameHdr:
// ignore these sections
continue;
default: {
@@ -91,7 +93,12 @@
// write out sections with data
switch(sect->kind()) {
- case LDFileFormat::Regular: {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ // FIXME: if optimization of exception handling sections is enabled,
+ // then we should emit these sections by the other way.
emitSectionData(m_Linker.getLayout(), *sect, *region);
break;
}
@@ -99,11 +106,16 @@
emitRelocation(m_Linker.getLayout(), pOutput, *sect, *region);
break;
case LDFileFormat::Target:
- target().emitSectionData(pOutput, *sect, m_Linker.getLDInfo(), *region);
+ target().emitSectionData(pOutput,
+ *sect,
+ m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ *region);
break;
default:
continue;
}
+
} // end of for loop
if (32 == target().bitclass()) {
@@ -116,6 +128,8 @@
target(),
pOutput);
+ emitELF32ProgramHeader(pOutput, target());
+
emitELF32SectionHeader(pOutput, m_Linker);
}
else if (64 == target().bitclass()) {
@@ -128,11 +142,13 @@
target(),
pOutput);
+ emitELF64ProgramHeader(pOutput, target());
+
emitELF64SectionHeader(pOutput, m_Linker);
}
else
return make_error_code(errc::not_supported);
-
+ pOutput.memArea()->clear();
return llvm::make_error_code(llvm::errc::success);
}
diff --git a/lib/LD/ELFExecFileFormat.cpp b/lib/LD/ELFExecFileFormat.cpp
index f10d764..8ae0de0 100644
--- a/lib/LD/ELFExecFileFormat.cpp
+++ b/lib/LD/ELFExecFileFormat.cpp
@@ -6,8 +6,81 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <llvm/Support/ELF.h>
#include <mcld/LD/ELFExecFileFormat.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
#include <mcld/MC/MCLinker.h>
+#include <mcld/Target/GNULDBackend.h>
using namespace mcld;
+void ELFExecFileFormat::initObjectType(MCLinker& pLinker)
+{
+ // FIXME: make sure ELF executable files has these sections.
+ f_pDynSymTab = &pLinker.getOrCreateOutputSectHdr(".dynsym",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_DYNSYM,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pDynStrTab = &pLinker.getOrCreateOutputSectHdr(".dynstr",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_STRTAB,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pInterp = &pLinker.getOrCreateOutputSectHdr(".interp",
+ LDFileFormat::Note,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x1);
+ f_pHashTab = &pLinker.getOrCreateOutputSectHdr(".hash",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_HASH,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pDynamic = &pLinker.getOrCreateOutputSectHdr(".dynamic",
+ LDFileFormat::NamePool,
+ llvm::ELF::SHT_DYNAMIC,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pRelaDyn = &pLinker.getOrCreateOutputSectHdr(".rela.dyn",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_RELA,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelaPlt = &pLinker.getOrCreateOutputSectHdr(".rela.plt",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_RELA,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelDyn = &pLinker.getOrCreateOutputSectHdr(".rel.dyn",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pRelPlt = &pLinker.getOrCreateOutputSectHdr(".rel.plt",
+ LDFileFormat::Relocation,
+ llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC,
+ f_Backend.bitclass() / 8);
+ f_pGOT = &pLinker.getOrCreateOutputSectHdr(".got",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pPLT = &pLinker.getOrCreateOutputSectHdr(".plt",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
+ f_Backend.bitclass() / 8);
+ f_pGOTPLT = &pLinker.getOrCreateOutputSectHdr(".got.plt",
+ LDFileFormat::Target,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
+ f_Backend.bitclass() / 8);
+ f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
+ LDFileFormat::EhFrameHdr,
+ llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC,
+ 0x4);
+}
diff --git a/lib/LD/ELFExecWriter.cpp b/lib/LD/ELFExecWriter.cpp
new file mode 100644
index 0000000..7438180
--- /dev/null
+++ b/lib/LD/ELFExecWriter.cpp
@@ -0,0 +1,157 @@
+//===- ELFExecWriter.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/ELFExecWriter.h>
+#include <mcld/LD/LDSymbol.h>
+#include <mcld/Target/GNULDBackend.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/MCLDOutput.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLinker.h>
+#include <llvm/Support/ELF.h>
+#include <vector>
+
+using namespace llvm;
+using namespace mcld;
+
+
+//==========================
+// ELFExecWriter
+ELFExecWriter::ELFExecWriter(GNULDBackend& pBackend, MCLinker& pLinker)
+ : ExecWriter(pBackend),
+ ELFWriter(pBackend),
+ m_Backend(pBackend),
+ m_Linker(pLinker) {
+
+}
+
+ELFExecWriter::~ELFExecWriter()
+{
+}
+
+llvm::error_code ELFExecWriter::writeExecutable(Output& pOutput)
+{
+ // write out the interpreter section: .interp
+ target().emitInterp(pOutput, m_Linker.getLDInfo());
+
+ // Write out name pool sections: .dynsym, .dynstr, .hash
+ target().emitDynNamePools(pOutput,
+ m_Linker.getOutputSymbols(),
+ m_Linker.getLayout(),
+ m_Linker.getLDInfo());
+
+ // Write out name pool sections: .symtab, .strtab
+ target().emitRegNamePools(pOutput,
+ m_Linker.getOutputSymbols(),
+ m_Linker.getLayout(),
+ m_Linker.getLDInfo());
+
+ // Write out regular ELF sections
+ unsigned int secIdx = 0;
+ unsigned int secEnd = pOutput.context()->numOfSections();
+ for (secIdx = 0; secIdx < secEnd; ++secIdx) {
+ LDSection* sect = pOutput.context()->getSection(secIdx);
+ MemoryRegion* region = NULL;
+ // request output region
+ switch(sect->kind()) {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Relocation:
+ case LDFileFormat::Target:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ region = pOutput.memArea()->request(sect->offset(), sect->size());
+ if (NULL == region) {
+ llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section[") +
+ llvm::Twine(secIdx) +
+ llvm::Twine("] - `") +
+ sect->name() +
+ llvm::Twine("'.\n"));
+ }
+ break;
+ }
+ case LDFileFormat::Null:
+ case LDFileFormat::NamePool:
+ case LDFileFormat::BSS:
+ case LDFileFormat::Note:
+ case LDFileFormat::MetaData:
+ case LDFileFormat::Version:
+ case LDFileFormat::EhFrameHdr:
+ // ignore these sections
+ continue;
+ default: {
+ llvm::errs() << "WARNING: unsupported section kind: "
+ << sect->kind()
+ << " of section "
+ << sect->name()
+ << ".\n";
+ continue;
+ }
+ }
+
+ // write out sections with data
+ switch(sect->kind()) {
+ case LDFileFormat::Regular:
+ case LDFileFormat::Debug:
+ case LDFileFormat::GCCExceptTable:
+ case LDFileFormat::EhFrame: {
+ // FIXME: if optimization of exception handling sections is enabled,
+ // then we should emit these sections by the other way.
+ emitSectionData(m_Linker.getLayout(), *sect, *region);
+ break;
+ }
+ case LDFileFormat::Relocation:
+ emitRelocation(m_Linker.getLayout(), pOutput, *sect, *region);
+ break;
+ case LDFileFormat::Target:
+ target().emitSectionData(pOutput,
+ *sect,
+ m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ *region);
+ break;
+ default:
+ continue;
+ }
+ } // end of for loop
+
+ if (32 == target().bitclass()) {
+ // Write out ELF header
+ // Write out section header table
+ emitELF32ShStrTab(pOutput, m_Linker);
+
+ writeELF32Header(m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ target(),
+ pOutput);
+
+ emitELF32ProgramHeader(pOutput, target());
+
+ emitELF32SectionHeader(pOutput, m_Linker);
+ }
+ else if (64 == target().bitclass()) {
+ // Write out ELF header
+ // Write out section header table
+ emitELF64ShStrTab(pOutput, m_Linker);
+
+ writeELF64Header(m_Linker.getLDInfo(),
+ m_Linker.getLayout(),
+ target(),
+ pOutput);
+
+ emitELF64ProgramHeader(pOutput, target());
+
+ emitELF64SectionHeader(pOutput, m_Linker);
+ }
+ else
+ return make_error_code(errc::not_supported);
+
+ pOutput.memArea()->clear();
+ return llvm::make_error_code(llvm::errc::success);
+}
+
diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp
index 9394e44..f1c39cb 100644
--- a/lib/LD/ELFFileFormat.cpp
+++ b/lib/LD/ELFFileFormat.cpp
@@ -57,7 +57,8 @@
f_pJCR(NULL),
f_pNoteABITag(NULL),
f_pStab(NULL),
- f_pStabStr(NULL) {
+ f_pStabStr(NULL),
+ f_pStack(NULL) {
}
@@ -186,7 +187,7 @@
f_pDataRelRo = &pLinker.getOrCreateOutputSectHdr(".data.rel.ro",
LDFileFormat::Regular,
llvm::ELF::SHT_PROGBITS,
- llvm::ELF::SHF_ALLOC,
+ llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pDtors = &pLinker.getOrCreateOutputSectHdr(".dtors",
LDFileFormat::Regular,
@@ -194,20 +195,15 @@
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
0x1);
f_pEhFrame = &pLinker.getOrCreateOutputSectHdr(".eh_frame",
- LDFileFormat::Exception,
+ LDFileFormat::EhFrame,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
- 0x1);
- f_pEhFrameHdr = &pLinker.getOrCreateOutputSectHdr(".eh_frame_hdr",
- LDFileFormat::Exception,
- llvm::ELF::SHT_PROGBITS,
- llvm::ELF::SHF_ALLOC,
- 0x1);
+ 0x4);
f_pGCCExceptTable = &pLinker.getOrCreateOutputSectHdr(".gcc_except_table",
- LDFileFormat::Exception,
+ LDFileFormat::GCCExceptTable,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
- 0x1);
+ 0x4);
f_pGNUVersion = &pLinker.getOrCreateOutputSectHdr(".gnu.version",
LDFileFormat::Version,
llvm::ELF::SHT_GNU_versym,
diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp
index abc3d30..1ea81e2 100644
--- a/lib/LD/ELFObjectReader.cpp
+++ b/lib/LD/ELFObjectReader.cpp
@@ -8,13 +8,13 @@
//===----------------------------------------------------------------------===//
#include <llvm/Support/ELF.h>
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/ELFObjectReader.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/MC/MCLDInput.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCRegionFragment.h>
#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MsgHandling.h>
#include <string>
#include <cassert>
@@ -99,7 +99,14 @@
(*section)->getInfo());
bool exist = false;
- signatures().insert(signature->name(), exist);
+ if (0 == std::strlen(signature->name()) &&
+ ResolveInfo::Section == signature->type()) {
+ // if the signature is a section symbol in input object, we use the
+ // section name as group signature.
+ signatures().insert((*section)->name(), exist);
+ } else {
+ signatures().insert(signature->name(), exist);
+ }
if (exist) {
// if this is not the first time we see this group signature, then
@@ -132,28 +139,32 @@
break;
}
/** normal sections **/
- // FIXME: support Debug, Exception and Version Kinds
- case LDFileFormat::Debug:
- case LDFileFormat::Exception:
+ // FIXME: support Version Kinds
case LDFileFormat::Version:
/** Fall through **/
case LDFileFormat::Regular:
case LDFileFormat::Note:
+ case LDFileFormat::Debug:
case LDFileFormat::MetaData: {
if (!m_pELFReader->readRegularSection(pInput, m_Linker, **section))
- llvm::report_fatal_error(
- llvm::Twine("can not read regular section `") +
- (*section)->name() +
- llvm::Twine("'.\n"));
+ fatal(diag::err_cannot_read_section) << (*section)->name();
+ break;
+ }
+ case LDFileFormat::EhFrame: {
+ if (!m_pELFReader->readEhFrame(pInput, m_Linker, **section))
+ fatal(diag::err_cannot_read_section) <<(*section)->name();
+ break;
+ }
+ case LDFileFormat::GCCExceptTable: {
+ //if (!m_pELFReader->readExceptionSection(pInput, m_Linker, **section))
+ if (!m_pELFReader->readRegularSection(pInput, m_Linker, **section))
+ fatal(diag::err_cannot_read_section) << (*section)->name();
break;
}
/** target dependent sections **/
case LDFileFormat::Target: {
if (!m_pELFReader->readTargetSection(pInput, m_Linker, **section))
- llvm::report_fatal_error(
- llvm::Twine("can not read target dependentsection `") +
- (*section)->name() +
- llvm::Twine("'.\n"));
+ fatal(diag::err_cannot_read_target_section) << (*section)->name();
break;
}
/** BSS sections **/
@@ -179,7 +190,14 @@
case LDFileFormat::Null:
case LDFileFormat::NamePool:
continue;
-
+ // warning
+ case LDFileFormat::EhFrameHdr:
+ default: {
+ warning(diag::warn_illegal_input_section) << (*section)->name()
+ << pInput.name()
+ << pInput.path();
+ break;
+ }
}
} // end of for all sections
@@ -192,9 +210,20 @@
assert(pInput.hasMemArea());
LDSection* symtab_shdr = pInput.context()->getSection(".symtab");
+ if (NULL == symtab_shdr) {
+ note(diag::note_has_no_symtab) << pInput.name()
+ << pInput.path()
+ << ".symtab";
+ return true;
+ }
+
LDSection* strtab_shdr = symtab_shdr->getLink();
- if (NULL == symtab_shdr || NULL == strtab_shdr)
+ if (NULL == strtab_shdr) {
+ fatal(diag::fatal_cannot_read_strtab) << pInput.name()
+ << pInput.path()
+ << ".symtab";
return false;
+ }
MemoryRegion* symtab_region = pInput.memArea()->request(symtab_shdr->offset(),
symtab_shdr->size());
diff --git a/lib/LD/ELFReader.cpp b/lib/LD/ELFReader.cpp
index 1fd2a13..6aacc08 100644
--- a/lib/LD/ELFReader.cpp
+++ b/lib/LD/ELFReader.cpp
@@ -7,15 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ELF.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ELF.h>
#include <llvm/Support/Host.h>
#include <mcld/MC/MCLinker.h>
-#include <mcld/Support/MemoryArea.h>
-#include <mcld/Support/MemoryRegion.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/Target/GNULDBackend.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <cstring>
using namespace mcld;
@@ -28,16 +29,22 @@
{
// name rules
llvm::StringRef name(pName);
- if (llvm::StringRef::npos != name.find(".debug"))
+ if (name.startswith(".debug") ||
+ name.startswith(".zdebug") ||
+ name.startswith(".gnu.linkonce.wi.") ||
+ name.startswith(".line") ||
+ name.startswith(".stab"))
return LDFileFormat::Debug;
if (name.startswith(".comment"))
return LDFileFormat::MetaData;
if (name.startswith(".interp") || name.startswith(".dynamic"))
return LDFileFormat::Note;
- if (name.startswith(".eh_frame") ||
- name.startswith(".eh_frame_hdr") ||
- name.startswith(".gcc_except_table"))
- return LDFileFormat::Exception;
+ if (name.startswith(".eh_frame"))
+ return LDFileFormat::EhFrame;
+ if (name.startswith(".eh_frame_hdr"))
+ return LDFileFormat::EhFrameHdr;
+ if (name.startswith(".gcc_except_table"))
+ return LDFileFormat::GCCExceptTable;
// type rules
switch(pType) {
@@ -74,8 +81,7 @@
(pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) ||
(pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER))
return LDFileFormat::Target;
- llvm::report_fatal_error(llvm::Twine("unsupported ELF section type: ") +
- llvm::Twine(pType) + llvm::Twine(".\n"));
+ fatal(diag::err_unsupported_section) << pName << pType;
}
return LDFileFormat::MetaData;
}
@@ -141,13 +147,9 @@
LDSection* sect_hdr = pInput.context()->getSection(pShndx);
- if (NULL == sect_hdr) {
- llvm::report_fatal_error(llvm::Twine("section[") +
- llvm::Twine(pShndx) +
- llvm::Twine("] is invalid in file `") +
- pInput.path().native() +
- llvm::Twine("'.\n"));
- }
+ if (NULL == sect_hdr)
+ unreachable(diag::unreachable_invalid_section_idx) << pShndx
+ << pInput.path().native();
MCFragmentRef* result = pLinker.getLayout().getFragmentRef(*sect_hdr, pOffset);
return result;
@@ -186,3 +188,17 @@
return 0x0;
}
+bool ELFReaderIF::readEhFrame(Input& pInput,
+ MCLinker& pLinker,
+ LDSection& pInputSectHdr) const
+{
+ LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
+ pInputSectHdr.kind(),
+ pInputSectHdr.type(),
+ pInputSectHdr.flag());
+
+ size_t size = pLinker.addEhFrame(pInputSectHdr, *pInput.memArea());
+
+ out_sect.setSize(out_sect.size() + size);
+ return true;
+}
diff --git a/lib/LD/ELFSegment.cpp b/lib/LD/ELFSegment.cpp
index a08641b..dbefbc5 100644
--- a/lib/LD/ELFSegment.cpp
+++ b/lib/LD/ELFSegment.cpp
@@ -19,7 +19,8 @@
uint64_t pPaddr,
uint64_t pFilesz,
uint64_t pMemsz,
- uint64_t pAlign)
+ uint64_t pAlign,
+ uint64_t pMaxSectAlign)
: m_Type(pType),
m_Flag(pFlag),
m_Offset(pOffset),
@@ -27,7 +28,8 @@
m_Paddr(pPaddr),
m_Filesz(pFilesz),
m_Memsz(pMemsz),
- m_Align(pAlign) {
+ m_Align(pAlign),
+ m_MaxSectionAlign(pMaxSectAlign) {
}
ELFSegment::~ELFSegment()
diff --git a/lib/LD/ELFSegmentFactory.cpp b/lib/LD/ELFSegmentFactory.cpp
index d8ad3cc..af0f588 100644
--- a/lib/LD/ELFSegmentFactory.cpp
+++ b/lib/LD/ELFSegmentFactory.cpp
@@ -25,16 +25,40 @@
/// produce - produce an empty ELF segment information.
/// this function will create an ELF segment
/// @param pType - p_type in ELF program header
-ELFSegment* ELFSegmentFactory::produce(uint32_t pType)
+ELFSegment* ELFSegmentFactory::produce(uint32_t pType, uint32_t pFlag)
{
ELFSegment* segment = allocate();
- new (segment) ELFSegment(pType);
+ new (segment) ELFSegment(pType, pFlag);
return segment;
}
-/// destroy - destruct the ELF segment
-void ELFSegmentFactory::destroy(ELFSegment*& pSegment)
+ELFSegment*
+ELFSegmentFactory::find(uint32_t pType, uint32_t pFlagSet, uint32_t pFlagClear)
{
- deallocate(pSegment);
+ iterator segment, segEnd = end();
+ for (segment = begin(); segment != segEnd; ++segment) {
+ if ((*segment).type() == pType &&
+ ((*segment).flag() & pFlagSet) == pFlagSet &&
+ ((*segment).flag() & pFlagClear) == 0x0) {
+ return &(*segment);
+ }
+ }
+ return NULL;
+}
+
+const ELFSegment*
+ELFSegmentFactory::find(uint32_t pType,
+ uint32_t pFlagSet,
+ uint32_t pFlagClear) const
+{
+ const_iterator segment, segEnd = end();
+ for (segment = begin(); segment != segEnd; ++segment) {
+ if ((*segment).type() == pType &&
+ ((*segment).flag() & pFlagSet) == pFlagSet &&
+ ((*segment).flag() & pFlagClear) == 0x0) {
+ return &(*segment);
+ }
+ }
+ return NULL;
}
diff --git a/lib/LD/ELFWriter.cpp b/lib/LD/ELFWriter.cpp
index a94fd5c..2f2d898 100644
--- a/lib/LD/ELFWriter.cpp
+++ b/lib/LD/ELFWriter.cpp
@@ -18,6 +18,8 @@
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/Layout.h>
+#include <mcld/LD/ELFSegment.h>
+#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/Target/GNULDBackend.h>
#include <cstdlib>
#include <cstring>
@@ -146,7 +148,7 @@
&& (pOutput.type() != Output::Object)
&& (pOutput.type() != Output::DynObj));
- const LDSymbol* entry_symbol = pLDInfo.getStrSymPool().findSymbol(entry_name);
+ const LDSymbol* entry_symbol = pLDInfo.getNamePool().findSymbol(entry_name);
// found the symbol
if (NULL != entry_symbol) {
@@ -244,6 +246,70 @@
}
}
+
+/// emitELF32ProgramHeader - emit Elf32_Phdr
+void ELFWriter::emitELF32ProgramHeader(Output& pOutput,
+ const GNULDBackend& pBackend) const
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(Elf32_Ehdr);
+ phdr_size = sizeof(Elf32_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ pBackend.numOfSegments() * phdr_size);
+
+ Elf32_Phdr* phdr = (Elf32_Phdr*)region->start();
+
+ // Iterate the elf segment table in GNULDBackend
+ size_t index = 0;
+ ELFSegmentFactory::const_iterator seg = pBackend.elfSegmentTable().begin(),
+ segEnd = pBackend.elfSegmentTable().end();
+ for (; seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
+ }
+}
+
+/// emitELF64ProgramHeader - emit ElfR64Phdr
+void ELFWriter::emitELF64ProgramHeader(Output& pOutput,
+ const GNULDBackend& pBackend) const
+{
+ assert(pOutput.hasMemArea());
+
+ uint64_t start_offset, phdr_size;
+
+ start_offset = sizeof(Elf64_Ehdr);
+ phdr_size = sizeof(Elf64_Phdr);
+ // Program header must start directly after ELF header
+ MemoryRegion *region = pOutput.memArea()->request(start_offset,
+ pBackend.numOfSegments() * phdr_size);
+ Elf64_Phdr* phdr = (Elf64_Phdr*)region->start();
+
+ // Iterate the elf segment table in GNULDBackend
+ size_t index = 0;
+ ELFSegmentFactory::const_iterator seg = pBackend.elfSegmentTable().begin(),
+ segEnd = pBackend.elfSegmentTable().end();
+ for (; seg != segEnd; ++seg, ++index) {
+ phdr[index].p_type = (*seg).type();
+ phdr[index].p_flags = (*seg).flag();
+ phdr[index].p_offset = (*seg).offset();
+ phdr[index].p_vaddr = (*seg).vaddr();
+ phdr[index].p_paddr = (*seg).paddr();
+ phdr[index].p_filesz = (*seg).filesz();
+ phdr[index].p_memsz = (*seg).memsz();
+ phdr[index].p_align = (*seg).align();
+ }
+}
+
/// emitELF32ShStrTab - emit section string table
void ELFWriter::emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const
{
diff --git a/lib/LD/EhFrame.cpp b/lib/LD/EhFrame.cpp
new file mode 100644
index 0000000..76af403
--- /dev/null
+++ b/lib/LD/EhFrame.cpp
@@ -0,0 +1,373 @@
+//===- EhFrame.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrame.h>
+#include <mcld/MC/MCLinker.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Target/TargetLDBackend.h>
+#include <llvm/Support/Dwarf.h>
+#include <llvm/Support/Host.h>
+
+using namespace mcld;
+
+//==========================
+// EhFrame
+EhFrame::EhFrame()
+ : m_fCanRecognizeAll(true) {
+}
+
+EhFrame::~EhFrame()
+{
+}
+
+uint64_t EhFrame::readEhFrame(Layout& pLayout,
+ const TargetLDBackend& pBackend,
+ llvm::MCSectionData& pSD,
+ LDSection& pSection,
+ MemoryArea& pArea)
+{
+ MemoryRegion* region = pArea.request(pSection.offset(),
+ pSection.size());
+ // an empty .eh_frame
+ if (NULL == region) {
+ note(diag::note_ehframe) << "an empty eh_frame";
+ return 0;
+ }
+
+ ConstAddress eh_start = region->start();
+ ConstAddress eh_end = region->end();
+ ConstAddress p = eh_start;
+
+ // read the Length filed
+ uint32_t len = readVal(p, pBackend.isLittleEndian());
+
+ // This CIE is a terminator if the Length field is 0, return 0 to handled it
+ // as an ordinary input.
+ if (0 == len) {
+ note(diag::note_ehframe) << "a terminator";
+ pArea.release(region);
+ return 0;
+ }
+
+ if (0xffffffff == len) {
+ debug(diag::debug_eh_unsupport) << "64-bit eh_frame";
+ pArea.release(region);
+ m_fCanRecognizeAll = false;
+ return 0;
+ }
+
+ // record the order of the CIE and FDE fragments
+ FragListType frag_list;
+
+ while (p < eh_end) {
+
+ if (eh_end - p < 4) {
+ debug(diag::debug_eh_unsupport) << "CIE or FDE size smaller than 4";
+ m_fCanRecognizeAll = false;
+ break;
+ }
+ // read the Length field
+ len = readVal(p, pBackend.isLittleEndian());
+ p += 4;
+
+ // the zero length entry should be the end of the section
+ if (0 == len) {
+ if (p < eh_end) {
+ debug(diag::debug_eh_unsupport) << "Non-end entry with zero length";
+ m_fCanRecognizeAll = false;
+ }
+ break;
+ }
+ if (0xffffffff == len) {
+ debug(diag::debug_eh_unsupport) << "64-bit eh_frame";
+ m_fCanRecognizeAll = false;
+ break;
+ }
+
+ if (eh_end - p < 4) {
+ debug(diag::debug_eh_unsupport) <<
+ "CIE:ID field / FDE: CIE Pointer field";
+ m_fCanRecognizeAll = false;
+ break;
+ }
+
+ // compute the section offset of this entry
+ uint32_t ent_offset = static_cast<uint32_t>(p - eh_start - 4);
+
+ // get the MemoryRegion for this entry
+ MemoryRegion* ent_region = pArea.request(pSection.offset() + ent_offset,
+ len + 4);
+
+ // create and add a CIE or FDE entry
+ uint32_t id = readVal(p, pBackend.isLittleEndian());
+ // CIE
+ if (0 == id) {
+ if (!addCIE(*ent_region, pBackend, frag_list)) {
+ m_fCanRecognizeAll = false;
+ pArea.release(ent_region);
+ break;
+ }
+ }
+
+ // FDE
+ else {
+ if (!addFDE(*ent_region, pBackend, frag_list)) {
+ m_fCanRecognizeAll = false;
+ pArea.release(ent_region);
+ break;
+ }
+ }
+ p += len;
+ }
+
+ if (!m_fCanRecognizeAll) {
+ pArea.release(region);
+ deleteFragments(frag_list, pArea);
+ return 0;
+ }
+
+ // append all CIE and FDE fragments to Layout after we successfully read
+ // this eh_frame
+ size_t section_size = 0;
+ for (FragListType::iterator it = frag_list.begin();
+ it != frag_list.end(); ++it)
+ section_size += pLayout.appendFragment(**it, pSD, pSection.align());
+
+ pArea.release(region);
+ return section_size;
+}
+
+bool EhFrame::addCIE(MemoryRegion& pRegion,
+ const TargetLDBackend& pBackend,
+ FragListType& pFragList)
+{
+ ConstAddress cie_start = pRegion.start();
+ ConstAddress cie_end = pRegion.end();
+ ConstAddress p = cie_start;
+
+ // skip the Length (4 byte) and CIE ID (4 byte) fields
+ p += 8;
+
+ // the version should be 1
+ if (1 != *p) {
+ debug(diag::debug_eh_unsupport) << "CIE version";
+ return false;
+ }
+ ++p;
+
+ // get the Augumentation String
+ ConstAddress aug_str = p;
+ ConstAddress aug_str_end = static_cast<ConstAddress>(
+ memchr(p, '\0', cie_end - p));
+
+ // skip the Augumentation String field
+ p = aug_str_end + 1;
+
+ // skip the Code Alignment Factor
+ if (!skipLEB128(&p, cie_end)) {
+ debug(diag::debug_eh_unsupport) << "unrecognized Code Alignment Factor";
+ return false;
+ }
+ // skip the Data Alignment Factor
+ if (!skipLEB128(&p, cie_end)) {
+ debug(diag::debug_eh_unsupport) << "unrecognized Data Alignment Factor";
+ return false;
+ }
+ // skip the Return Address Register
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "unrecognized Return Address Register";
+ return false;
+ }
+ ++p;
+
+ // the Augmentation String start with 'eh' is a CIE from gcc before 3.0,
+ // in LSB Core Spec 3.0RC1. We do not support it.
+ if (aug_str[0] == 'e' && aug_str[1] == 'h') {
+ debug(diag::debug_eh_unsupport) << "augmentation string `eh`";
+ return false;
+ }
+
+ // parse the Augmentation String to get the FDE encodeing if 'z' existed
+ std::string aug_str_data;
+ uint8_t fde_encoding = llvm::dwarf::DW_EH_PE_absptr;
+ if (*aug_str == 'z') {
+
+ aug_str_data += *aug_str;
+ ++aug_str;
+
+ // skip the Augumentation Data Length
+ if (!skipLEB128(&p, cie_end)) {
+ debug(diag::debug_eh_unsupport) <<
+ "unrecognized Augmentation Data Length";
+ return false;
+ }
+
+ while (aug_str != aug_str_end) {
+ switch (*aug_str) {
+ default:
+ debug(diag::debug_eh_unsupport) << "augmentation string";
+ return false;
+
+ // LDSA encoding (1 byte)
+ case 'L':
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `L`";
+ return false;
+ }
+ ++p;
+ break;
+
+ // Two arguments, the first one represents the encoding of the second
+ // argument (1 byte). The second one is the address of personality
+ // routine.
+ case 'P': {
+ // the first argument
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ uint8_t per_encode = *p;
+ ++p;
+ // get the length of the second argument
+ uint32_t per_length = 0;
+ if (0x60 == (per_encode & 0x60)) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ switch (per_encode & 7) {
+ default:
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ case llvm::dwarf::DW_EH_PE_udata2:
+ per_length = 2;
+ break;
+ case llvm::dwarf::DW_EH_PE_udata4:
+ per_length = 4;
+ break;
+ case llvm::dwarf::DW_EH_PE_udata8:
+ per_length = 8;
+ break;
+ case llvm::dwarf::DW_EH_PE_absptr:
+ per_length = pBackend.bitclass() / 8;
+ break;
+ }
+ // skip the alignment
+ if (llvm::dwarf::DW_EH_PE_aligned == (per_encode & 0xf0)) {
+ uint32_t per_align = p - cie_end;
+ per_align += per_length - 1;
+ per_align &= ~(per_length -1);
+ if (static_cast<uint32_t>(cie_end - p) < per_align) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ p += per_align;
+ }
+ // skip the second argument
+ if (static_cast<uint32_t>(cie_end - p) < per_length) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `P`";
+ return false;
+ }
+ p += per_length;
+ }
+ break;
+
+ // FDE encoding (1 byte)
+ case 'R':
+ if (cie_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "augmentation string `R`";
+ return false;
+ }
+ fde_encoding = *p;
+ switch (fde_encoding & 7) {
+ case llvm::dwarf::DW_EH_PE_udata2:
+ case llvm::dwarf::DW_EH_PE_udata4:
+ case llvm::dwarf::DW_EH_PE_udata8:
+ case llvm::dwarf::DW_EH_PE_absptr:
+ break;
+ default:
+ debug(diag::debug_eh_unsupport) << "FDE encoding";
+ return false;
+ }
+ ++p;
+ break;
+ } // end switch
+ aug_str_data += *aug_str;
+ ++aug_str;
+ } // end while
+ }
+
+ note(diag::note_eh_cie) << pRegion.size()
+ << aug_str_data
+ << (fde_encoding & 7);
+
+ // create and push back the CIE entry
+ CIE* entry = new CIE(pRegion, fde_encoding);
+ m_CIEs.push_back(entry);
+ pFragList.push_back(static_cast<llvm::MCFragment*>(entry));
+ return true;
+}
+
+bool EhFrame::addFDE(MemoryRegion& pRegion,
+ const TargetLDBackend& pBackend,
+ FragListType& pFragList)
+{
+ ConstAddress fde_start = pRegion.start();
+ ConstAddress fde_end = pRegion.end();
+ ConstAddress p = fde_start;
+
+ // skip the Length (4 byte) and CIE Pointer (4 byte) fields
+ p += 8;
+
+ // get the entry offset of the PC Begin
+ if (fde_end - p < 1) {
+ debug(diag::debug_eh_unsupport) << "FDE PC Begin";
+ return false;
+ }
+ FDE::Offset pc_offset = static_cast<FDE::Offset>(p - fde_start);
+
+ note(diag::note_eh_fde) << pRegion.size() << pc_offset;
+ // create and push back the FDE entry
+ FDE* entry = new FDE(pRegion, **(m_CIEs.end() -1), pc_offset);
+ m_FDEs.push_back(entry);
+ pFragList.push_back(static_cast<llvm::MCFragment*>(entry));
+ return true;
+}
+
+uint32_t EhFrame::readVal(ConstAddress pAddr, bool pIsTargetLittleEndian)
+{
+ const uint32_t* p = reinterpret_cast<const uint32_t*>(pAddr);
+ uint32_t val = *p;
+
+ // byte swapping if the host and target have different endian
+ if (llvm::sys::isLittleEndianHost() != pIsTargetLittleEndian)
+ val = bswap32(val);
+ return val;
+}
+
+bool EhFrame::skipLEB128(ConstAddress* pp, ConstAddress pend)
+{
+ for (ConstAddress p = *pp; p < pend; ++p) {
+ if (0 == (*p & 0x80)) {
+ *pp = p + 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+void EhFrame::deleteFragments(FragListType& pList, MemoryArea& pArea)
+{
+ MCRegionFragment* frag = NULL;
+ for (FragListType::iterator it = pList.begin(); it != pList.end(); ++it) {
+ frag = static_cast<MCRegionFragment*>(*it);
+ pArea.release(&(frag->getRegion()));
+ delete *it;
+ }
+ pList.clear();
+}
+
diff --git a/lib/LD/EhFrameHdr.cpp b/lib/LD/EhFrameHdr.cpp
new file mode 100644
index 0000000..8806af4
--- /dev/null
+++ b/lib/LD/EhFrameHdr.cpp
@@ -0,0 +1,49 @@
+//===- EhFrameHdr.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrameHdr.h>
+
+using namespace mcld;
+
+//==========================
+// EhFrameHdr
+EhFrameHdr::EhFrameHdr(const EhFrame& pEhFrameData,
+ const LDSection& pEhFrameSect,
+ LDSection& pEhFrameHdrSect)
+ : m_EhFrameData(pEhFrameData),
+ m_EhFrameSect(pEhFrameSect),
+ m_EhFrameHdrSect(pEhFrameHdrSect)
+{
+}
+
+EhFrameHdr::~EhFrameHdr()
+{
+}
+
+/// @ref lsb core generic 4.1
+/// .eh_frame_hdr section format
+/// uint8_t : version
+/// uint8_t : eh_frame_ptr_enc
+/// uint8_t : fde_count_enc
+/// uint8_t : table_enc
+/// uint32_t : eh_frame_ptr
+/// uint32_t : fde_count
+/// __________________________ when fde_count > 0
+/// <uint32_t, uint32_t>+ : binary search table
+
+/// sizeOutput - base on the fde count to size output
+void EhFrameHdr::sizeOutput()
+{
+ size_t size = 12;
+ if (m_EhFrameData.canRecognizeAllEhFrame()) {
+ size_t fde_count = m_EhFrameData.getFDECount();
+ size += 8 * fde_count;
+ }
+ m_EhFrameHdrSect.setSize(size);
+}
+
diff --git a/lib/LD/ExecWriter.cpp b/lib/LD/ExecWriter.cpp
new file mode 100644
index 0000000..d66cd17
--- /dev/null
+++ b/lib/LD/ExecWriter.cpp
@@ -0,0 +1,16 @@
+//===- ExecWriter.cpp ---------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "mcld/LD/ExecWriter.h"
+#include "mcld/Target/TargetLDBackend.h"
+#include "mcld/MC/MCLDInput.h"
+
+using namespace mcld;
+
+//==========================
+// ExecWriter
diff --git a/lib/LD/FDE.cpp b/lib/LD/FDE.cpp
new file mode 100644
index 0000000..b70f7e1
--- /dev/null
+++ b/lib/LD/FDE.cpp
@@ -0,0 +1,24 @@
+//===- FDE.cpp ------------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/FDE.h>
+
+using namespace mcld;
+
+//==========================
+// FDE
+
+FDE::FDE(MemoryRegion& pRegion, const CIE& pCIE, Offset pPCBeginOffset)
+ : MCRegionFragment(pRegion), m_CIE(pCIE), m_PCBeginOffset(pPCBeginOffset) {
+}
+
+FDE::~FDE()
+{
+}
+
diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp
index 3fa00b8..0a64752 100644
--- a/lib/LD/GNUArchiveReader.cpp
+++ b/lib/LD/GNUArchiveReader.cpp
@@ -6,42 +6,35 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInfo.h"
-#include "mcld/MC/MCLDInput.h"
-#include "mcld/MC/MCLDInputTree.h"
-#include "mcld/LD/GNUArchiveReader.h"
+#include <mcld/MC/MCLDInfo.h>
+#include <mcld/MC/MCLDInput.h>
+#include <mcld/MC/InputTree.h>
+#include <mcld/LD/GNUArchiveReader.h>
+#include <mcld/Support/FileSystem.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/ADT/SizeTraits.h>
-#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/system_error.h>
+#include <llvm/Support/Host.h>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>
-using namespace std;
using namespace mcld;
-typedef size_t sectionSizeTy;
typedef uint32_t elfWord;
-/// Archive Header, Magic number, etc..
-const unsigned archiveMagicSize = 8;
-const char archiveMagic[archiveMagicSize] = { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' };
-const char thinArchiveMagic[archiveMagicSize] = { '!', '<', 't', 'h', 'i', 'n', '>', '\n' };
-const char archiveFinalMagic[2] = { '`', '\n' };
+/// Archive Header, Magic number
+const char GNUArchiveReader::ArchiveMagic[ArchiveMagicSize] = { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' };
+const char GNUArchiveReader::ThinArchiveMagic[ArchiveMagicSize] = { '!', '<', 't', 'h', 'i', 'n', '>', '\n' };
+const char GNUArchiveReader::HeaderFinalMagic[HeaderFinalMagicSize] = { '`', '\n' };
-struct GNUArchiveReader::ArchiveMemberHeader
-{
- char name[16];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char finalMagic[2];
-};
struct GNUArchiveReader::SymbolTableEntry
{
@@ -49,13 +42,6 @@
std::string name;
};
-inline void endian_swap(unsigned int& x)
-{
- x = (x>>24) |
- ((x<<8) & 0x00FF0000) |
- ((x>>8) & 0x0000FF00) |
- (x<<24);
-}
/// convert string to size_t
@@ -73,22 +59,25 @@
/// Public API
bool GNUArchiveReader::isMyFormat(Input &pInput) const
{
- llvm::OwningPtr<llvm::MemoryBuffer> mapFile;
- llvm::MemoryBuffer::getFile(pInput.path().c_str(), mapFile);
- const char* pFile = mapFile->getBufferStart();
+ assert(pInput.hasMemArea());
+
+ MemoryRegion *region = pInput.memArea()->request(0, ArchiveMagicSize);
+ if (!region)
+ llvm::report_fatal_error("can't request MemoryRegion for archive magic");
+
+ const char *p_buffer = reinterpret_cast<char *> (region->getBuffer());
/// check archive format.
- if(mapFile->getBufferSize() <= archiveMagicSize)
+ if (memcmp(p_buffer, ArchiveMagic, ArchiveMagicSize) != 0
+ && memcmp(p_buffer, ThinArchiveMagic, ArchiveMagicSize) != 0) {
return false;
- bool isThinArchive = memcmp(pFile, thinArchiveMagic, archiveMagicSize) == 0;
- if(!isThinArchive && memcmp(pFile, archiveMagic, archiveMagicSize) != 0)
- return false;
+ }
return true;
}
LDReader::Endian GNUArchiveReader::endian(Input& pFile) const
{
- return m_endian;
+ return LDReader::BigEndian;
}
InputTree *GNUArchiveReader::readArchive(Input &pInput)
@@ -103,62 +92,59 @@
InputTree *GNUArchiveReader::setupNewArchive(Input &pInput,
size_t off)
{
- llvm::OwningPtr<llvm::MemoryBuffer> mapFile;
- if(llvm::MemoryBuffer::getFile(pInput.path().c_str(), mapFile))
- {
- assert(0 && "GNUArchiveReader:can't map a file to MemoryBuffer\n");
- return NULL;
- }
+ assert(pInput.hasMemArea());
+ MemoryRegion *region = pInput.memArea()->request(off, ArchiveMagicSize);
+
+ if (!region)
+ llvm::report_fatal_error("can't request MemoryRegion for archive magic");
+
+ const char *pFile = reinterpret_cast<char *> (region->getBuffer());
+
+ /// check archive format.
+ bool isThinArchive;
+ isThinArchive = memcmp(pFile, ThinArchiveMagic, ArchiveMagicSize) == 0;
+ if(!isThinArchive && memcmp(pFile, ArchiveMagic, ArchiveMagicSize) != 0)
+ llvm::report_fatal_error("Fail : archive magic number is not matched");
InputTree *resultTree = new InputTree(m_pLDInfo.inputFactory());
std::vector<SymbolTableEntry> symbolTable;
std::string archiveMemberName;
std::string extendedName;
- bool isThinArchive;
- const char *pFile = mapFile->getBufferStart();
- /// check archive format.
- if(mapFile->getBufferSize() <= archiveMagicSize)
- return NULL;
- else
- {
- isThinArchive = memcmp(pFile, thinArchiveMagic, archiveMagicSize) == 0;
- if(!isThinArchive && memcmp(pFile, archiveMagic, archiveMagicSize) != 0)
- return NULL;
- }
-
- off += archiveMagicSize ;
- size_t symbolTableSize = parseMemberHeader(mapFile, off, &archiveMemberName,
+ off += ArchiveMagicSize ;
+ size_t symbolTableSize = readMemberHeader(*pInput.memArea(), off, &archiveMemberName,
NULL, extendedName);
/// read archive symbol table
if(archiveMemberName.empty())
{
- readSymbolTable(mapFile, symbolTable,
- off+sizeof(GNUArchiveReader::ArchiveMemberHeader), symbolTableSize);
- off = off + sizeof(GNUArchiveReader::ArchiveMemberHeader) + symbolTableSize;
+ readSymbolTable(*pInput.memArea(), symbolTable,
+ off+sizeof(ArchiveMemberHeader), symbolTableSize);
+ off = off + sizeof(ArchiveMemberHeader) + symbolTableSize;
}
else
{
- assert(0 && "fatal error : need symbol table\n");
+ llvm::report_fatal_error("fatal error : need symbol table\n");
return NULL;
}
if((off&1) != 0)
++off;
- size_t extendedSize = parseMemberHeader(mapFile, off, &archiveMemberName,
+ size_t extendedSize = readMemberHeader(*pInput.memArea(), off, &archiveMemberName,
NULL, extendedName);
/// read long Name table if exist
if(archiveMemberName == "/")
{
- off += sizeof(GNUArchiveReader::ArchiveMemberHeader);
- pFile += off;
- extendedName.assign(pFile,extendedSize);
+ off += sizeof(ArchiveMemberHeader);
+ MemoryRegion *extended_name_region = pInput.memArea()->request(off, extendedSize);
+ pFile = reinterpret_cast<char *>(extended_name_region->getBuffer());
+ extendedName.assign(pFile, extendedSize);
+
}
/// traverse all the archive members
InputTree::iterator node = resultTree->root();
- set<string> haveSeen;
+ std::set<std::string> haveSeen;
for(unsigned i=0 ; i<symbolTable.size() ; ++i)
{
/// We shall get each member at this archive.
@@ -166,7 +152,7 @@
/// the original InputTree, resultTree.
off_t nestedOff = 0;
- parseMemberHeader(mapFile, symbolTable[i].fileOffset, &archiveMemberName,
+ readMemberHeader(*pInput.memArea(), symbolTable[i].fileOffset, &archiveMemberName,
&nestedOff, extendedName);
if(haveSeen.find(archiveMemberName)==haveSeen.end())
@@ -191,8 +177,13 @@
continue;
}
-
- /// create the real path
+
+ /// TODO:(Duo)
+ /// adjust the relative pathname
+ /// For example
+ /// thin archive pathname : "/usr/lib/thin.a"
+ /// Member name : "member.a"
+ /// pathname after adjust : "/usr/lib/member.a"
sys::fs::RealPath realPath(archiveMemberName);
if(nestedOff > 0)
{
@@ -237,20 +228,20 @@
/// "filename.o/ " - regular file with short name
/// "/5566 " - name at offset 5566 at long name table
-size_t GNUArchiveReader::parseMemberHeader(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+size_t GNUArchiveReader::readMemberHeader(MemoryArea &pArea,
off_t off,
std::string *p_Name,
off_t *p_NestedOff,
std::string &p_ExtendedName)
{
- const char *pFile = mapFile->getBufferStart();
- pFile += off;
+ MemoryRegion *region = pArea.request(off, sizeof(ArchiveMemberHeader));
+ const char *pFile = reinterpret_cast<char *>(region->getBuffer());
const ArchiveMemberHeader *header = reinterpret_cast<const ArchiveMemberHeader *>(pFile);
/// check magic number of member header
- if(memcmp(header->finalMagic, archiveFinalMagic, sizeof archiveFinalMagic))
+ if(memcmp(header->finalMagic, HeaderFinalMagic, sizeof HeaderFinalMagic))
{
- assert(0 && "archive member header magic number false");
+ llvm::report_fatal_error("archive member header magic number false");
return 0;
}
@@ -259,7 +250,7 @@
size_t memberSize = stringToType<size_t>(sizeString);
if(memberSize == 0)
{
- assert(0 && "member Size Error");
+ llvm::report_fatal_error("member Size Error");
return 0;
}
@@ -270,7 +261,7 @@
size_t nameLen = ((nameEnd == NULL) ? 0 : (nameEnd - header->name));
if((nameLen <= 0) || (nameLen >= sizeof(header->name)))
{
- assert(0 && "header name format error\n");
+ llvm::report_fatal_error("header name format error\n");
return 0;
}
p_Name->assign(header->name, nameLen);
@@ -302,7 +293,7 @@
|| extendedNameOff < 0
|| static_cast<size_t>(extendedNameOff) >= p_ExtendedName.size())
{
- assert(0 && "extended name");
+ llvm::report_fatal_error("extended name");
return 0;
}
@@ -311,7 +302,7 @@
if(nameEnd[-1] != '/'
|| static_cast<size_t>(nameEnd-name) > p_ExtendedName.size())
{
- assert(0 && "p_ExtendedName substring is not end with / \n");
+ llvm::report_fatal_error("p_ExtendedName substring is not end with / \n");
return 0;
}
p_Name->assign(name, nameEnd-name-1);
@@ -322,35 +313,40 @@
return memberSize;
}
-void GNUArchiveReader::readSymbolTable(llvm::OwningPtr<llvm::MemoryBuffer> &mapFile,
+void GNUArchiveReader::readSymbolTable(MemoryArea &pArea,
std::vector<SymbolTableEntry> &pSymbolTable,
off_t start,
size_t size)
{
- const char *startPtr = mapFile->getBufferStart() + start;
- const elfWord *p_Word = reinterpret_cast<const elfWord *>(startPtr);
+ MemoryRegion *region = pArea.request(start, size);
+ const char *pFile = reinterpret_cast<char *>(region->getBuffer());
+ const elfWord *p_Word = reinterpret_cast<const elfWord *>(pFile);
unsigned int symbolNum = *p_Word;
/// Portable Issue on Sparc platform
/// Intel, ARM and Mips are littel-endian , Sparc is little-endian after verion 9
/// symbolNum in symbol table is always big-endian
- if(m_endian == LDReader::LittleEndian)
- endian_swap(symbolNum);
+ if(llvm::sys::isLittleEndianHost())
+ symbolNum = bswap32(symbolNum);
++p_Word;
const char *p_Name = reinterpret_cast<const char *>(p_Word + symbolNum);
- pSymbolTable.resize(symbolNum);
for(unsigned int i=0 ; i<symbolNum ; ++i)
{
- /// assign member offset
+ SymbolTableEntry entry;
+ /// member offset
unsigned int memberOffset = *p_Word;
- endian_swap(memberOffset);
- pSymbolTable[i].fileOffset = static_cast<off_t>(memberOffset);
+ if(llvm::sys::isLittleEndianHost())
+ memberOffset = bswap32(memberOffset);
+ entry.fileOffset = static_cast<off_t>(memberOffset);
++p_Word;
- /// assign member name
+ /// member name
off_t nameEnd = strlen(p_Name) + 1;
- pSymbolTable[i].name.assign(p_Name, nameEnd);
+ entry.name.assign(p_Name, nameEnd);
p_Name += nameEnd;
+ /// the symbol is found in symbol pool
+ if (m_pLDInfo.getNamePool().findSymbol(entry.name))
+ pSymbolTable.push_back(entry);
}
}
diff --git a/lib/LD/InputSymbolTable.cpp b/lib/LD/InputSymbolTable.cpp
deleted file mode 100644
index e34679c..0000000
--- a/lib/LD/InputSymbolTable.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//===- InputSymbolTable.cpp -----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/InputSymbolTable.h"
-#include <vector>
-
-using namespace mcld;
-
-//==========================
-// InputSymbolTable
-
-InputSymbolTable::InputSymbolTable(StrSymPool &pStrSymPool,
- size_t pNumOfSymbols,
- StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable)
- : SymbolTableIF(pStrSymPool)
-{
- f_StrSymPool.addIndirectClient(*this);
-
- f_pCategorySet->at(CategorySet::Entire).reserve(pNumOfSymbols);
-
- f_pCategorySet->at(CategorySet::Entire).interpose(&pEntireStringTable);
- f_pCategorySet->at(CategorySet::Dynamic).interpose(&pDynamicStringTable);
-}
-
-void InputSymbolTable::doInsertSymbol(LDSymbol *pSym)
-{
- f_pCategorySet->insertSymbolPointer(pSym);
-}
-
-void InputSymbolTable::doMerge(const SymbolTableIF &pSymTab)
-{
- if (this == &pSymTab)
- return;
- for (size_t i = 0; i < CategorySet::NumOfCategories; ++i)
- f_pCategorySet->at(i).insert(f_pCategorySet->at(i).end(),
- pSymTab.begin(i),
- pSymTab.end(i));
-}
-
-InputSymbolTable::~InputSymbolTable()
-{
-}
diff --git a/lib/LD/Layout.cpp b/lib/LD/Layout.cpp
index 9328d74..bc91cee 100644
--- a/lib/LD/Layout.cpp
+++ b/lib/LD/Layout.cpp
@@ -8,14 +8,14 @@
//===----------------------------------------------------------------------===//
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/ADT/SizeTraits.h>
#include <mcld/LD/Layout.h>
+#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDFileFormat.h>
+#include <mcld/LD/LDSection.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCLDInfo.h>
-#include <mcld/LD/LDSection.h>
-#include <mcld/LD/LDContext.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/TargetLDBackend.h>
#include <cassert>
@@ -132,16 +132,6 @@
}
else {
range_list = m_SDRangeMap[&pSD];
-#ifdef MCLD_DEBUG
- RangeList::iterator rangeIter, rangeEnd = range_list->end();
- for (rangeIter = range_list->begin(); rangeIter != rangeEnd; ++rangeIter) {
- if (&pInputHdr == rangeIter->header) {
- llvm::report_fatal_error(llvm::Twine("Trying to map the same LDSection: ") +
- pInputHdr.name() +
- llvm::Twine(" into the different ranges.\n"));
- }
- }
-#endif
}
// make a range and push it into the range list
@@ -425,9 +415,7 @@
// range not found
if (range == rangeEnd) {
- llvm::report_fatal_error(llvm::Twine("section ") +
- pInputSection.name() +
- llvm::Twine(" never be in the range list.\n"));
+ fatal(diag::err_section_not_laid_out) << pInputSection.name();
}
return getFragmentRef(*range, pOffset);
@@ -481,7 +469,7 @@
llvm::Twine(" never be in the range list.\n"));
}
- return getFragmentRef(*range, target_offset);
+ return getFragmentRef(*range, pBigOffset);
}
uint64_t Layout::getOutputOffset(const llvm::MCFragment& pFrag)
@@ -516,7 +504,8 @@
}
void Layout::sortSectionOrder(const Output& pOutput,
- const TargetLDBackend& pBackend)
+ const TargetLDBackend& pBackend,
+ const MCLDInfo& pInfo)
{
typedef std::pair<LDSection*, unsigned int> SectOrder;
typedef std::vector<SectOrder > SectListTy;
@@ -525,7 +514,7 @@
for (size_t index = 0; index < m_SectionOrder.size(); ++index)
sect_list.push_back(std::make_pair(
m_SectionOrder[index],
- pBackend.getSectionOrder(pOutput, *m_SectionOrder[index])));
+ pBackend.getSectionOrder(pOutput, *m_SectionOrder[index], pInfo)));
// simple insertion sort should be fine for general cases such as so and exec
for (unsigned int i = 1; i < sect_list.size(); ++i) {
@@ -545,7 +534,9 @@
}
}
-bool Layout::layout(Output& pOutput, const TargetLDBackend& pBackend)
+bool Layout::layout(Output& pOutput,
+ const TargetLDBackend& pBackend,
+ const MCLDInfo& pInfo)
{
// determine what sections in output context will go into final output, and
// push the needed sections into m_SectionOrder for later processing
@@ -558,10 +549,12 @@
switch (sect->kind()) {
// ignore if there is no SectionData for certain section kinds
case LDFileFormat::Regular:
- case LDFileFormat::Note:
case LDFileFormat::Target:
case LDFileFormat::MetaData:
case LDFileFormat::BSS:
+ case LDFileFormat::Debug:
+ case LDFileFormat::EhFrame:
+ case LDFileFormat::GCCExceptTable:
if (0 != sect->size()) {
if (NULL != sect->getSectionData() &&
!sect->getSectionData()->getFragmentList().empty()) {
@@ -581,6 +574,8 @@
// ignore if section size is 0
case LDFileFormat::NamePool:
case LDFileFormat::Relocation:
+ case LDFileFormat::Note:
+ case LDFileFormat::EhFrameHdr:
if (0 != sect->size())
m_SectionOrder.push_back(sect);
break;
@@ -590,47 +585,22 @@
;
}
break;
- case LDFileFormat::Debug:
- if (0 != sect->size()) {
- m_SectionOrder.push_back(sect);
- llvm::errs() << "WARNING: DWRAF debugging has not been fully supported yet.\n"
- << "section `" << sect->name() << "'.\n";
- }
- break;
- case LDFileFormat::Exception:
- if (0 != sect->size()) {
- llvm::errs() << "WARNING: Exception handling has not been fully supported yet.\n"
- << "section `" << sect->name() << "'.\n";
- if (NULL != sect->getSectionData() &&
- !sect->getSectionData()->getFragmentList().empty()) {
- // make sure that all fragments are valid
- llvm::MCFragment& frag =
- sect->getSectionData()->getFragmentList().back();
- setFragmentLayoutOrder(&frag);
- setFragmentLayoutOffset(&frag);
- }
- m_SectionOrder.push_back(sect);
- }
- break;
case LDFileFormat::Version:
if (0 != sect->size()) {
m_SectionOrder.push_back(sect);
- llvm::errs() << "WARNING: Symbolic versioning has not been fully supported yet.\n"
- << "section `" << sect->name() << "'.\n";
+ warning(diag::warn_unsupported_symbolic_versioning) << sect->name();
}
break;
default:
- llvm::report_fatal_error(llvm::Twine("Unsupported section kind of `") +
- sect->name() +
- llvm::Twine("': ") +
- llvm::Twine(sect->kind()) +
- llvm::Twine(".\n"));
+ if (0 != sect->size()) {
+ error(diag::err_unsupported_section) << sect->name() << sect->kind();
+ }
break;
}
}
// perform sorting on m_SectionOrder to get a ordering for final layout
- sortSectionOrder(pOutput, pBackend);
+ sortSectionOrder(pOutput, pBackend, pInfo);
// Backend defines the section start offset for section 1.
uint64_t offset = pBackend.sectionStartOffset();
diff --git a/lib/LD/MsgHandler.cpp b/lib/LD/MsgHandler.cpp
new file mode 100644
index 0000000..96310a2
--- /dev/null
+++ b/lib/LD/MsgHandler.cpp
@@ -0,0 +1,52 @@
+//===- MsgHandler.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/MsgHandler.h>
+#include <mcld/LD/DiagnosticEngine.h>
+
+using namespace mcld;
+
+MsgHandler::MsgHandler(DiagnosticEngine& pEngine)
+ : m_Engine(pEngine), m_NumArgs(0) {
+}
+
+MsgHandler::~MsgHandler()
+{
+ emit();
+}
+
+bool MsgHandler::emit()
+{
+ flushCounts();
+ return m_Engine.emit();
+}
+
+void MsgHandler::addString(llvm::StringRef pStr) const
+{
+ assert(m_NumArgs < DiagnosticEngine::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ m_Engine.state().ArgumentKinds[m_NumArgs] = DiagnosticEngine::ak_std_string;
+ m_Engine.state().ArgumentStrs[m_NumArgs++] = pStr.data();
+}
+
+void MsgHandler::addString(const std::string& pStr) const
+{
+ assert(m_NumArgs < DiagnosticEngine::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ m_Engine.state().ArgumentKinds[m_NumArgs] = DiagnosticEngine::ak_std_string;
+ m_Engine.state().ArgumentStrs[m_NumArgs++] = pStr;
+}
+
+void MsgHandler::addTaggedVal(intptr_t pValue, DiagnosticEngine::ArgumentKind pKind) const
+{
+ assert(m_NumArgs < DiagnosticEngine::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ m_Engine.state().ArgumentKinds[m_NumArgs] = pKind;
+ m_Engine.state().ArgumentVals[m_NumArgs++] = pValue;
+}
+
diff --git a/lib/LD/StrSymPool.cpp b/lib/LD/NamePool.cpp
similarity index 69%
rename from lib/LD/StrSymPool.cpp
rename to lib/LD/NamePool.cpp
index abe3fb7..1247057 100644
--- a/lib/LD/StrSymPool.cpp
+++ b/lib/LD/NamePool.cpp
@@ -1,4 +1,4 @@
-//===- StrSymPool.cpp -----------------------------------------------------===//
+//===- NamePool.cpp -------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,27 +6,24 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
-#include "mcld/LD/StrSymPool.h"
-#include "mcld/LD/Resolver.h"
#include <llvm/Support/raw_ostream.h>
+#include <mcld/LD/NamePool.h>
+#include <mcld/LD/Resolver.h>
using namespace mcld;
//==========================
-// StrSymPool
-StrSymPool::StrSymPool(const Resolver& pResolver, StrSymPool::size_type pSize)
- : m_pResolver(pResolver.clone()), m_Table(pSize) {
+// NamePool
+NamePool::NamePool(const Resolver& pResolver, NamePool::size_type pSize)
+ : m_pResolver(&pResolver), m_Table(pSize) {
}
-StrSymPool::~StrSymPool()
+NamePool::~NamePool()
{
- if (0 != m_pResolver)
- delete m_pResolver;
}
/// createSymbol - create a symbol
-ResolveInfo* StrSymPool::createSymbol(const llvm::StringRef& pName,
+ResolveInfo* NamePool::createSymbol(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
@@ -48,7 +45,7 @@
/// insertSymbol - insert a symbol and resolve it immediately
/// @return the pointer of resolved ResolveInfo
/// @return is the symbol existent?
-void StrSymPool::insertSymbol(const llvm::StringRef& pName,
+void NamePool::insertSymbol(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
@@ -98,69 +95,49 @@
// symbol resolution
bool override = false;
unsigned int action = Resolver::LastAction;
- switch(m_pResolver->resolve(*old_symbol, *new_symbol, override)) {
- case Resolver::Success: {
- pResult.info = old_symbol;
- pResult.existent = true;
- pResult.overriden = override;
- break;
- }
- case Resolver::Warning: {
- llvm::errs() << "WARNING: " << m_pResolver->mesg() << "\n";
- m_pResolver->clearMesg();
- pResult.info = old_symbol;
- pResult.existent = true;
- pResult.overriden = override;
- break;
- }
- case Resolver::Abort: {
- llvm::report_fatal_error(m_pResolver->mesg());
- pResult.info = old_symbol;
- pResult.existent = true;
- pResult.overriden = override;
- break;
- }
- default: {
- m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult);
- break;
- }
+ if (m_pResolver->resolve(*old_symbol, *new_symbol, override)) {
+ pResult.info = old_symbol;
+ pResult.existent = true;
+ pResult.overriden = override;
}
+ else
+ m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult);
return;
}
-llvm::StringRef StrSymPool::insertString(const llvm::StringRef& pString)
+llvm::StringRef NamePool::insertString(const llvm::StringRef& pString)
{
bool exist = false;
ResolveInfo* resolve_info = m_Table.insert(pString, exist);
return llvm::StringRef(resolve_info->name(), resolve_info->nameSize());
}
-void StrSymPool::reserve(StrSymPool::size_type pSize)
+void NamePool::reserve(NamePool::size_type pSize)
{
m_Table.rehash(pSize);
}
-StrSymPool::size_type StrSymPool::capacity() const
+NamePool::size_type NamePool::capacity() const
{
return (m_Table.numOfBuckets() - m_Table.numOfEntries());
}
/// findInfo - find the resolved ResolveInfo
-ResolveInfo* StrSymPool::findInfo(const llvm::StringRef& pName)
+ResolveInfo* NamePool::findInfo(const llvm::StringRef& pName)
{
Table::iterator iter = m_Table.find(pName);
return iter.getEntry();
}
/// findInfo - find the resolved ResolveInfo
-const ResolveInfo* StrSymPool::findInfo(const llvm::StringRef& pName) const
+const ResolveInfo* NamePool::findInfo(const llvm::StringRef& pName) const
{
Table::const_iterator iter = m_Table.find(pName);
return iter.getEntry();
}
/// findSymbol - find the resolved output LDSymbol
-LDSymbol* StrSymPool::findSymbol(const llvm::StringRef& pName)
+LDSymbol* NamePool::findSymbol(const llvm::StringRef& pName)
{
ResolveInfo* info = findInfo(pName);
if (NULL == info)
@@ -169,7 +146,7 @@
}
/// findSymbol - find the resolved output LDSymbol
-const LDSymbol* StrSymPool::findSymbol(const llvm::StringRef& pName) const
+const LDSymbol* NamePool::findSymbol(const llvm::StringRef& pName) const
{
const ResolveInfo* info = findInfo(pName);
if (NULL == info)
diff --git a/lib/LD/OutputSymbolTable.cpp b/lib/LD/OutputSymbolTable.cpp
deleted file mode 100644
index a17a211..0000000
--- a/lib/LD/OutputSymbolTable.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- OutputSymbolTable.cpp ----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/OutputSymbolTable.h"
-
-using namespace mcld;
-
-//==========================
-// OutputSymbolTable
-
-
-OutputSymbolTable::OutputSymbolTable(StrSymPool &pStrSymPool,
- size_t pNumOfSymbols,
- StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable)
- : SymbolTableIF(pStrSymPool)
-{
- f_StrSymPool.addDirectClient(*this);
-
- f_pCategorySet->at(CategorySet::Entire).reserve(pNumOfSymbols);
-
- f_pCategorySet->at(CategorySet::Entire).interpose(&pEntireStringTable);
- f_pCategorySet->at(CategorySet::Dynamic).interpose(&pDynamicStringTable);
-}
-
-void OutputSymbolTable::doInsertSymbol(LDSymbol *sym)
-{
- // OutputSymbolTable didn't have any real containers,
- // so no need to do anything.
-}
-
-void OutputSymbolTable::doMerge(const SymbolTableIF &pSymTab)
-{
- // OutputSymbolTable didn't have any real containers,
- // so no need to do anything.
-}
diff --git a/lib/LD/Relocation.cpp b/lib/LD/Relocation.cpp
index 73db39b..0b84ad0 100644
--- a/lib/LD/Relocation.cpp
+++ b/lib/LD/Relocation.cpp
@@ -40,7 +40,7 @@
Relocation::Address Relocation::symValue() const
{
- if(m_pSymInfo->type() == ResolveInfo::Section &&
+ if (m_pSymInfo->type() == ResolveInfo::Section &&
m_pSymInfo->outSymbol()->hasFragRef()) {
return llvm::cast<LDSection>(
m_pSymInfo->outSymbol()->fragRef()->frag()->getParent()->getSection()).addr();
diff --git a/lib/LD/Resolver.cpp b/lib/LD/Resolver.cpp
index 0f7f06e..aa39b13 100644
--- a/lib/LD/Resolver.cpp
+++ b/lib/LD/Resolver.cpp
@@ -6,28 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/LD/Resolver.h"
-#include <cassert>
+#include <mcld/LD/Resolver.h>
using namespace mcld;
//==========================
// Resolver
-Resolver::Resolver()
- : m_Mesg() {
-}
-
-Resolver::Resolver(const Resolver& pCopy)
- : m_Mesg(pCopy.m_Mesg) {
-}
-
Resolver::~Resolver()
{
- m_Mesg.clear();
-}
-
-void Resolver::clearMesg()
-{
- m_Mesg.clear();
}
diff --git a/lib/LD/SectionMap.cpp b/lib/LD/SectionMap.cpp
index d81dfdd..9d32391 100644
--- a/lib/LD/SectionMap.cpp
+++ b/lib/LD/SectionMap.cpp
@@ -12,9 +12,8 @@
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// SectionMap
-
SectionMap::SectionMap()
{
}
@@ -38,13 +37,11 @@
// if still no matching, just let a output seciton has the same input name
if (it == end())
return pInput;
-
return (*it).outputStr;
}
bool SectionMap::push_back(const std::string& pInput,
- const std::string& pOutput,
- const uint64_t pOffset)
+ const std::string& pOutput)
{
// Now only check if the mapping exists in the map already
// TODO: handle the cases such as overriding the exist mapping and drawing
@@ -57,7 +54,6 @@
struct Mapping mapping = {
pInput,
pOutput,
- pOffset,
};
m_SectMap.push_back(mapping);
return true;
diff --git a/lib/LD/SectionMerger.cpp b/lib/LD/SectionMerger.cpp
index f6aef9e..f3a5b65 100644
--- a/lib/LD/SectionMerger.cpp
+++ b/lib/LD/SectionMerger.cpp
@@ -18,7 +18,7 @@
SectionMerger::SectionMerger(SectionMap& pSectionMap, LDContext& pContext)
: m_SectionNameMap(pSectionMap),
m_Output(pContext),
- m_LDSectionMap(pSectionMap.size())
+ m_LDSectionMap()
{
}
diff --git a/lib/LD/StaticResolver.cpp b/lib/LD/StaticResolver.cpp
index 3ba49e2..09cbc11 100644
--- a/lib/LD/StaticResolver.cpp
+++ b/lib/LD/StaticResolver.cpp
@@ -8,28 +8,19 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/StaticResolver.h>
#include <mcld/LD/LDSymbol.h>
-#include <cassert>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
-
//==========================
// StaticResolver
-StaticResolver::StaticResolver()
-{
-}
-
StaticResolver::~StaticResolver()
{
}
-StaticResolver::StaticResolver(const StaticResolver& pCopy)
- : Resolver(pCopy) {
-}
-
-unsigned int StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
- const ResolveInfo& __restrict__ pNew,
- bool &pOverride)
+bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
+ const ResolveInfo& __restrict__ pNew,
+ bool &pOverride) const
{
/* The state table itself.
@@ -41,13 +32,13 @@
static const enum LinkAction link_action[LAST_ORD][LAST_ORD] =
{
/* new\old U w_U d_U wd_U D w_D d_D wd_D C w_C, Cs, Is */
- /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUNDW, NOACT, NOACT, NOACT, REFC },
- /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUND, DUNDW, NOACT, NOACT, NOACT, REFC },
+ /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUND, NOACT, NOACT, NOACT, REFC },
+ /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUNDW, DUNDW, NOACT, NOACT, NOACT, REFC },
/* d_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
/* wd_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
/* D */ {DEF, DEF, DEF, DEF, MDEF, DEF, DEF, DEF, CDEF, CDEF, CDEF, MDEF },
/* w_D */ {DEFW, DEFW, DEFW, DEFW, NOACT, NOACT, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT},
- /* d_D */ {DEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF },
+ /* d_D */ {MDEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF },
/* wd_D */ {MDEFWD, MDEFWD, DEFWD, DEFWD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT},
/* C */ {COM, COM, COM, COM, CREF, COM, COM, COM, MBIG, COM, BIG, REFC },
/* w_C */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
@@ -71,26 +62,23 @@
unsigned int col = getOrdinate(pOld);
bool cycle = false;
- unsigned int result = Resolver::Success;
pOverride = false;
ResolveInfo* old = &pOld;
LinkAction action;
do {
- result = Resolver::Success;
cycle = false;
action = link_action[row][col];
switch(action) {
case FAIL: { /* abort. */
- m_Mesg = std::string("internal error [StaticResolver.cpp:loc 86].\n") +
- std::string("Please report to `[email protected]'.\n");
- result = Resolver::Abort;
- break;
+ fatal(diag::fail_sym_resolution)
+ << __FILE__ << __LINE__
+ << "[email protected]";
+ return false;
}
case NOACT: { /* no action. */
pOverride = false;
old->overrideVisibility(pNew);
- result = Resolver::Success;
break;
}
case UND: /* override by symbol undefined symbol. */
@@ -102,7 +90,6 @@
case COM: { /* override by symbol common defined. */
pOverride = true;
old->override(pNew);
- result = Resolver::Success;
break;
}
case MDEFD: /* mark symbol dynamic defined. */
@@ -110,31 +97,22 @@
uint32_t binding = old->binding();
old->override(pNew);
old->setBinding(binding);
- m_Mesg = std::string("symbol `") +
- old->name() +
- std::string("' uses the type, dynamic, size and type in the dynamic symbol.");
+ ignore(diag::mark_dynamic_defined) << old->name();
pOverride = true;
- result = Resolver::Warning;
break;
}
case DUND:
case DUNDW: {
- if (old->binding() == ResolveInfo::Weak &&
- pNew.binding() != ResolveInfo::Weak) {
- old->setBinding(pNew.binding());
- }
+ old->override(pNew);
old->overrideVisibility(pNew);
+ old->setDynamic();
pOverride = false;
- result = Resolver::Success;
break;
}
case CREF: { /* Possibly warn about common reference to defined symbol. */
// A common symbol does not override a definition.
- m_Mesg = std::string("common '") +
- pNew.name() +
- std::string("' overriden by previous definition.");
+ ignore(diag::comm_refer_to_define) << old->name();
pOverride = false;
- result = Resolver::Warning;
break;
}
case CDEF: { /* redefine existing common symbol. */
@@ -142,12 +120,9 @@
// definition overrides.
//
// NOTE: m_Mesg uses 'name' instead of `name' for being compatible to GNU ld.
- m_Mesg = std::string("definition of '") +
- old->name() +
- std::string("' is overriding common.");
+ ignore(diag::redefine_common) << old->name();
old->override(pNew);
pOverride = true;
- result = Resolver::Warning;
break;
}
case BIG: { /* override by symbol common using largest size. */
@@ -156,7 +131,6 @@
old->overrideAttributes(pNew);
old->overrideVisibility(pNew);
pOverride = true;
- result = Resolver::Success;
break;
}
case MBIG: { /* mark common symbol by larger size. */
@@ -164,22 +138,15 @@
old->setSize(pNew.size());
old->overrideVisibility(pNew);
pOverride = false;
- result = Resolver::Success;
break;
}
case CIND: { /* mark indirect symbol from existing common symbol. */
- m_Mesg = std::string("indirect symbol `") +
- pNew.name()+
- std::string("' point to a common symbol.\n");
- result = Resolver::Warning;
+ ignore(diag::indirect_refer_to_common) << old->name();
}
/* Fall through */
case IND: { /* override by indirect symbol. */
- if (0 == pNew.link()) {
- m_Mesg = std::string("indirect symbol `") +
- pNew.name() +
- std::string("' point to a inexistent symbol.");
- result = Resolver::Abort;
+ if (NULL == pNew.link()) {
+ fatal(diag::indirect_refer_to_inexist) << pNew.name();
break;
}
@@ -203,18 +170,12 @@
}
/* Fall through */
case MDEF: { /* multiple definition error. */
- m_Mesg = std::string("multiple definitions of `") +
- pNew.name() +
- std::string("'.");
- result = Resolver::Abort;
+ error(diag::multiple_definitions) << pNew.name();
break;
}
case REFC: { /* Mark indirect symbol referenced and then CYCLE. */
- if (0 == old->link()) {
- m_Mesg = std::string("indirect symbol `") +
- old->name() +
- std::string("' point to a inexistent symbol.");
- result = Resolver::Abort;
+ if (NULL == old->link()) {
+ fatal(diag::indirect_refer_to_inexist) << old->name();
break;
}
@@ -223,8 +184,12 @@
cycle = true;
break;
}
+ default: {
+ error(diag::undefined_situation) << action << old->name() << pNew.name();
+ return false;
+ }
} // end of the big switch (action)
} while(cycle);
- return result;
+ return true;
}
diff --git a/lib/LD/SymbolTableFactory.cpp b/lib/LD/SymbolTableFactory.cpp
deleted file mode 100644
index 180a4a9..0000000
--- a/lib/LD/SymbolTableFactory.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- SymbolTableFactory.cpp ---------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "mcld/LD/SymbolTableFactory.h"
-
-using namespace mcld;
-
-//==========================
-// SymbolTableFactory
-
-SymbolTableFactory::SymbolTableFactory(size_t pNumOfSymbolTables,
- StrSymPool& pStrSymPool)
- : m_StrSymPool(pStrSymPool),
- m_InputFactory(pNumOfSymbolTables),
- m_OutputFactory(pNumOfSymbolTables)
-{
-}
-
-SymbolTableFactory::~SymbolTableFactory()
-{
-}
-
-SymbolTableIF *SymbolTableFactory::
-createInputTable(StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable,
- size_t pReserve)
-{
- InputSymbolTable *inputSymTab = m_InputFactory.allocate();
- new (inputSymTab) InputSymbolTable(m_StrSymPool,
- pReserve,
- pEntireStringTable,
- pDynamicStringTable);
- return inputSymTab;
-}
-
-SymbolTableIF *SymbolTableFactory::
-createOutputTable(StringTable &pEntireStringTable,
- StringTable &pDynamicStringTable,
- size_t pReserve)
-{
- OutputSymbolTable *outputSymTab = m_OutputFactory.allocate();
- new (outputSymTab) OutputSymbolTable(m_StrSymPool,
- pReserve,
- pEntireStringTable,
- pDynamicStringTable);
- return outputSymTab;
-}
diff --git a/lib/LD/TextDiagnosticPrinter.cpp b/lib/LD/TextDiagnosticPrinter.cpp
new file mode 100644
index 0000000..466d16d
--- /dev/null
+++ b/lib/LD/TextDiagnosticPrinter.cpp
@@ -0,0 +1,167 @@
+//===- TextDiagnosticPrinter.cpp ------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/TextDiagnosticPrinter.h>
+#include <mcld/MC/MCLDInfo.h>
+#include <llvm/Support/Signals.h>
+#include <string>
+
+using namespace mcld;
+
+static const enum llvm::raw_ostream::Colors UnreachableColor = llvm::raw_ostream::RED;
+static const enum llvm::raw_ostream::Colors FatalColor = llvm::raw_ostream::YELLOW;
+static const enum llvm::raw_ostream::Colors ErrorColor = llvm::raw_ostream::RED;
+static const enum llvm::raw_ostream::Colors WarningColor = llvm::raw_ostream::MAGENTA;
+static const enum llvm::raw_ostream::Colors DebugColor = llvm::raw_ostream::CYAN;
+static const enum llvm::raw_ostream::Colors NoteColor = llvm::raw_ostream::GREEN;
+static const enum llvm::raw_ostream::Colors IgnoreColor = llvm::raw_ostream::BLUE;
+
+// Used for changing only the bold attribute.
+static const enum llvm::raw_ostream::Colors SavedColor = llvm::raw_ostream::SAVEDCOLOR;
+
+//===----------------------------------------------------------------------===//
+// TextDiagnosticPrinter
+TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream& pOStream,
+ const MCLDInfo& pLDInfo)
+ : m_OStream(pOStream), m_LDInfo(pLDInfo), m_pInput(NULL) {
+}
+
+TextDiagnosticPrinter::~TextDiagnosticPrinter()
+{
+}
+
+/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+/// capturing it to a log as needed.
+void
+TextDiagnosticPrinter::handleDiagnostic(DiagnosticEngine::Severity pSeverity,
+ const Diagnostic& pInfo)
+{
+ DiagnosticPrinter::handleDiagnostic(pSeverity, pInfo);
+
+ std::string out_string;
+ pInfo.format(out_string);
+
+ switch (pSeverity) {
+ case DiagnosticEngine::Unreachable: {
+ m_OStream.changeColor(UnreachableColor, true);
+ m_OStream << "Unreachable: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Fatal: {
+ m_OStream.changeColor(FatalColor, true);
+ m_OStream << "Fatal: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Error: {
+ m_OStream.changeColor(ErrorColor, true);
+ m_OStream << "Error: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Warning: {
+ m_OStream.changeColor(WarningColor, true);
+ m_OStream << "Warning: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ break;
+ }
+ case DiagnosticEngine::Debug: {
+ // show debug message only if verbose >= 0
+ if (0 <= m_LDInfo.options().verbose()) {
+ m_OStream.changeColor(DebugColor, true);
+ m_OStream << "Debug: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ }
+ break;
+ }
+ case DiagnosticEngine::Note: {
+ // show ignored message only if verbose >= 1
+ if (1 <= m_LDInfo.options().verbose()) {
+ m_OStream.changeColor(NoteColor, true);
+ m_OStream << "Note: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ }
+ break;
+ }
+ case DiagnosticEngine::Ignore: {
+ // show ignored message only if verbose >= 2
+ if (2 <= m_LDInfo.options().verbose()) {
+ m_OStream.changeColor(IgnoreColor, true);
+ m_OStream << "Ignore: ";
+ m_OStream.resetColor();
+ m_OStream << out_string << "\n";
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (pSeverity) {
+ case DiagnosticEngine::Unreachable: {
+ m_OStream << "\n\n";
+ m_OStream.changeColor(llvm::raw_ostream::YELLOW);
+ m_OStream << "You encounter a bug of MCLinker, please report to:\n"
+ << " [email protected]\n";
+ m_OStream.resetColor();
+ }
+ /** fall through **/
+ case DiagnosticEngine::Fatal: {
+ // If we reached here, we are failing ungracefully. Run the interrupt handlers
+ // to make sure any special cleanups get done, in particular that we remove
+ // files registered with RemoveFileOnSignal.
+ llvm::sys::RunInterruptHandlers();
+ exit(1);
+ break;
+ }
+ case DiagnosticEngine::Error: {
+ int16_t error_limit = m_LDInfo.options().maxErrorNum();
+ if ((error_limit != -1) &&
+ (getNumErrors() > static_cast<unsigned>(error_limit))) {
+ m_OStream << "\n\n";
+ m_OStream.changeColor(llvm::raw_ostream::YELLOW);
+ m_OStream << "too many error messages (>" << error_limit << ")...\n";
+ m_OStream.resetColor();
+ llvm::sys::RunInterruptHandlers();
+ exit(1);
+ }
+ break;
+ }
+ case DiagnosticEngine::Warning: {
+ int16_t warning_limit = m_LDInfo.options().maxWarnNum();
+ if ((warning_limit != -1) &&
+ (getNumWarnings() > static_cast<unsigned>(warning_limit))) {
+ m_OStream << "\n\n";
+ m_OStream.changeColor(llvm::raw_ostream::YELLOW);
+ m_OStream << "too many warning messages (>" << warning_limit << ")...\n";
+ m_OStream.resetColor();
+ llvm::sys::RunInterruptHandlers();
+ exit(1);
+ }
+ }
+ default:
+ break;
+ }
+}
+
+void TextDiagnosticPrinter::beginInput(const Input& pInput, const MCLDInfo& pLDInfo)
+{
+ m_pInput = &pInput;
+}
+
+void TextDiagnosticPrinter::endInput()
+{
+ m_pInput = NULL;
+}
diff --git a/lib/MC/ContextFactory.cpp b/lib/MC/ContextFactory.cpp
index d32ea8b..5b698c7 100644
--- a/lib/MC/ContextFactory.cpp
+++ b/lib/MC/ContextFactory.cpp
@@ -33,3 +33,10 @@
return result;
}
+LDContext* ContextFactory::produce()
+{
+ LDContext* result = allocate();
+ new (result) LDContext();
+ return result;
+}
+
diff --git a/lib/MC/MCLDInputTree.cpp b/lib/MC/InputTree.cpp
similarity index 70%
rename from lib/MC/MCLDInputTree.cpp
rename to lib/MC/InputTree.cpp
index b423988..a1d1449 100644
--- a/lib/MC/MCLDInputTree.cpp
+++ b/lib/MC/InputTree.cpp
@@ -1,4 +1,4 @@
-//===- MCLDInputTree.cpp --------------------------------------------------===//
+//===- InputTree.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDInputTree.h"
-#include "mcld/MC/InputFactory.h"
+#include <mcld/MC/InputTree.h>
+#include <mcld/MC/InputFactory.h>
using namespace mcld;
@@ -24,15 +24,15 @@
{
}
-InputTree& InputTree::merge(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector,
+InputTree& InputTree::merge(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover,
InputTree& pTree)
{
if (this == &pTree)
return *this;
if (!pTree.empty()) {
- pConnector.connect(pPosition, iterator(pTree.m_Root.node.right));
+ pMover.connect(pRoot, iterator(pTree.m_Root.node.right));
BinaryTreeBase<Input>::m_Root.summon(
pTree.BinaryTreeBase<Input>::m_Root);
BinaryTreeBase<Input>::m_Root.delegate(pTree.m_Root);
@@ -41,33 +41,33 @@
return *this;
}
-InputTree& InputTree::insert(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector,
+InputTree& InputTree::insert(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover,
const std::string& pNamespec,
const sys::fs::Path& pPath,
unsigned int pType)
{
BinaryTree<Input>::node_type* node = createNode();
node->data = m_FileFactory.produce(pNamespec, pPath, pType);
- pConnector.connect(pPosition, iterator(node));
+ pMover.connect(pRoot, iterator(node));
return *this;
}
-InputTree& InputTree::enterGroup(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector)
+InputTree& InputTree::enterGroup(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover)
{
NodeBase* node = createNode();
- pConnector.connect(pPosition, iterator(node));
+ pMover.connect(pRoot, iterator(node));
return *this;
}
-InputTree& InputTree::insert(InputTree::iterator pPosition,
- const InputTree::Connector& pConnector,
+InputTree& InputTree::insert(InputTree::iterator pRoot,
+ const InputTree::Mover& pMover,
const mcld::Input& pInput)
{
BinaryTree<Input>::node_type* node = createNode();
node->data = const_cast<mcld::Input*>(&pInput);
- pConnector.connect(pPosition, iterator(node));
+ pMover.connect(pRoot, iterator(node));
return *this;
}
diff --git a/lib/MC/MCLDAttribute.cpp b/lib/MC/MCLDAttribute.cpp
index a361691..f7b7e47 100644
--- a/lib/MC/MCLDAttribute.cpp
+++ b/lib/MC/MCLDAttribute.cpp
@@ -6,40 +6,40 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDAttribute.h"
-#include "mcld/MC/AttributeFactory.h"
+#include <mcld/MC/MCLDAttribute.h>
+#include <mcld/MC/AttributeFactory.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
//==========================
// AttrConstraint
-bool AttrConstraint::isLegal(const Attribute& pAttr, std::string &pErrMesg) const
+bool AttrConstraint::isLegal(const Attribute& pAttr) const
{
if (!isWholeArchive() && pAttr.isWholeArchive()) {
- pErrMesg = std::string("Target does not support --whole-archive");
+ error(diag::err_unsupported_whole_archive);
return false;
}
if (!isAsNeeded() && pAttr.isAsNeeded()) {
- pErrMesg = std::string("Target does not support --as-needed");
+ error(diag::err_unsupported_as_needed);
return false;
}
if (!isAddNeeded() && pAttr.isAddNeeded()) {
- pErrMesg = std::string("Target does not support --add-needed");
+ error(diag::err_unsupported_add_needed);
return false;
}
if (isStaticSystem() && pAttr.isDynamic()) {
- pErrMesg = std::string("Target does not support --Bdynamic");
+ error(diag::err_unsupported_Bdynamic);
return false;
}
- // FIXME: may be it's legal, but ignored by GNU ld.
if (isStaticSystem() && pAttr.isAsNeeded()) {
- pErrMesg = std::string("Can't enable --as-needed on a target which does not support dynamic linking");
- return false;
+ warning(diag::err_enable_as_needed_on_static_system);
+ return true;
}
// FIXME: may be it's legal, but ignored by GNU ld.
if (pAttr.isAsNeeded() && pAttr.isStatic()) {
- pErrMesg = std::string("Can't mix --static with --as-needed");
- return false;
+ warning(diag::err_mix_static_as_needed);
+ return true;
}
return true;
}
diff --git a/lib/MC/MCLDDriver.cpp b/lib/MC/MCLDDriver.cpp
index 5e89097..a86983d 100644
--- a/lib/MC/MCLDDriver.cpp
+++ b/lib/MC/MCLDDriver.cpp
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/MC/InputTree.h>
#include <mcld/MC/MCLinker.h>
-#include <mcld/MC/MCLDInputTree.h>
#include <mcld/MC/MCLDDriver.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/ArchiveReader.h>
@@ -15,10 +15,12 @@
#include <mcld/LD/DynObjReader.h>
#include <mcld/LD/ObjectWriter.h>
#include <mcld/LD/DynObjWriter.h>
+#include <mcld/LD/ExecWriter.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/RealPath.h>
+#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/Target/TargetLDBackend.h>
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MsgHandling.h>
using namespace llvm;
using namespace mcld;
@@ -26,91 +28,83 @@
MCLDDriver::MCLDDriver(MCLDInfo& pLDInfo, TargetLDBackend& pLDBackend)
: m_LDInfo(pLDInfo),
m_LDBackend(pLDBackend),
- m_pLinker(0) {
+ m_pLinker(NULL) {
+
}
MCLDDriver::~MCLDDriver()
{
- if (0 != m_pLinker)
+ if (NULL != m_pLinker)
delete m_pLinker;
+
}
-void MCLDDriver::normalize() {
-
+void MCLDDriver::normalize()
+{
+ // ----- set up inputs ----- //
InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
for (input = m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
- // already got type - for example, bitcode
+ // already got type - for example, bitcode or external OIR (object
+ // intermediate representation)
if ((*input)->type() == Input::Script ||
(*input)->type() == Input::Object ||
(*input)->type() == Input::DynObj ||
- (*input)->type() == Input::Archive)
+ (*input)->type() == Input::Archive ||
+ (*input)->type() == Input::External)
continue;
-
- MemoryArea *input_memory =
- m_LDInfo.memAreaFactory().produce((*input)->path(), O_RDONLY);
- if ((input_memory != NULL) && input_memory->isGood()) {
- (*input)->setMemArea(input_memory);
- }
- else {
- llvm::report_fatal_error("can not open file: " + (*input)->path().native());
- return;
- }
-
// is a relocatable object file
if (m_LDBackend.getObjectReader()->isMyFormat(**input)) {
(*input)->setType(Input::Object);
- (*input)->setContext(m_LDInfo.contextFactory().produce((*input)->path()));
m_LDBackend.getObjectReader()->readObject(**input);
}
// is a shared object file
else if (m_LDBackend.getDynObjReader()->isMyFormat(**input)) {
(*input)->setType(Input::DynObj);
- (*input)->setContext(m_LDInfo.contextFactory().produce((*input)->path()));
- (*input)->setSOName((*input)->path().native());
m_LDBackend.getDynObjReader()->readDSO(**input);
}
// is an archive
else if (m_LDBackend.getArchiveReader()->isMyFormat(*(*input))) {
(*input)->setType(Input::Archive);
- mcld::InputTree* archive_member = m_LDBackend.getArchiveReader()->readArchive(**input);
- if(!archive_member) {
- llvm::report_fatal_error("wrong format archive" + (*input)->path().string());
+ mcld::InputTree* archive_member =
+ m_LDBackend.getArchiveReader()->readArchive(**input);
+ if(NULL == archive_member) {
+ error(diag::err_empty_input) << (*input)->name() << (*input)->path();
return;
}
m_LDInfo.inputs().merge<InputTree::Inclusive>(input, *archive_member);
}
else {
- llvm::report_fatal_error(llvm::Twine("can not recognize file format: ") +
- (*input)->path().native() +
- llvm::Twine("\nobject format or target machine is wrong\n"));
+ fatal(diag::err_unrecognized_input_file) << (*input)->path()
+ << m_LDInfo.triple().str();
}
- }
+ } // end of for
}
-
bool MCLDDriver::linkable() const
{
+ // check we have input and output files
+ if (m_LDInfo.inputs().empty()) {
+ error(diag::err_no_inputs);
+ return false;
+ }
+
// check all attributes are legal
mcld::AttributeFactory::const_iterator attr, attrEnd = m_LDInfo.attrFactory().end();
for (attr=m_LDInfo.attrFactory().begin(); attr!=attrEnd; ++attr) {
- std::string error_code;
- if (!m_LDInfo.attrFactory().constraint().isLegal((**attr), error_code)) {
- report_fatal_error(error_code);
+ if (!m_LDInfo.attrFactory().constraint().isLegal((**attr))) {
return false;
}
}
-
- bool hasDynObj = false;
// can not mix -static with shared objects
mcld::InputTree::const_bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
- if ((*input)->type() == mcld::Input::DynObj ) {
- hasDynObj = true;
+ if ((*input)->type() == mcld::Input::DynObj) {
if((*input)->attribute()->isStatic()) {
- report_fatal_error("Can't link shared object with -static option");
+ error(diag::err_mixed_shared_static_objects)
+ << (*input)->name() << (*input)->path();
return false;
}
}
@@ -127,7 +121,6 @@
if (0 == m_pLinker)
m_pLinker = new MCLinker(m_LDBackend,
m_LDInfo,
- *m_LDInfo.output().context(),
m_SectionMap);
// initialize the readers and writers
@@ -137,16 +130,32 @@
!m_LDBackend.initObjectReader(*m_pLinker) ||
!m_LDBackend.initDynObjReader(*m_pLinker) ||
!m_LDBackend.initObjectWriter(*m_pLinker) ||
- !m_LDBackend.initDynObjWriter(*m_pLinker))
+ !m_LDBackend.initDynObjWriter(*m_pLinker) ||
+ !m_LDBackend.initExecWriter(*m_pLinker))
return false;
+ // initialize RelocationFactory
+ m_LDBackend.initRelocFactory(*m_pLinker);
+ return true;
+}
+
+/// initStdSections - initialize standard sections
+bool MCLDDriver::initStdSections()
+{
/// initialize section mapping for standard format, target-dependent section,
/// (and user-defined mapping)
if (!m_SectionMap.initStdSectionMap() ||
!m_LDBackend.initTargetSectionMap(m_SectionMap))
return false;
- // initialize standard segments and sections
+ /// A technical debt. We need to initialize section map here because
+ /// we do not separate output file and temporary data structure. So far,
+ /// MCLinker directly use output file's LDContext as the temporary data
+ /// structure. We will create a new data structure mcld::Module to collect
+ /// all temporary data structures togather.
+ m_pLinker->initSectionMap();
+
+ // initialize standard sections
switch (m_LDInfo.output().type()) {
case Output::DynObj: {
// intialize standard and target-dependent sections
@@ -174,12 +183,9 @@
}
} // end of switch
- // initialize target-dependent segments and sections
+ // initialize target-dependent sections
m_LDBackend.initTargetSections(*m_pLinker);
- // initialize RelocationFactory
- m_LDBackend.initRelocFactory(*m_pLinker);
-
return true;
}
@@ -226,25 +232,13 @@
return true;
}
-/// mergeSymbolTables - merge the symbol tables of input files into the
-/// output's symbol table.
-bool MCLDDriver::mergeSymbolTables()
-{
- mcld::InputTree::dfs_iterator input, inEnd = m_LDInfo.inputs().dfs_end();
- for (input=m_LDInfo.inputs().dfs_begin(); input!=inEnd; ++input) {
- if (!m_pLinker->mergeSymbolTable(**input))
- return false;
- }
- return true;
-}
-
/// addStandardSymbols - shared object and executable files need some
/// standard symbols
/// @return if there are some input symbols with the same name to the
/// standard symbols, return false
bool MCLDDriver::addStandardSymbols()
{
- return m_LDBackend.initStandardSymbols(*m_pLinker);
+ return m_LDBackend.initStandardSymbols(*m_pLinker, m_LDInfo.output());
}
/// addTargetSymbols - some targets, such as MIPS and ARM, need some
@@ -253,7 +247,7 @@
/// target symbols, return false
bool MCLDDriver::addTargetSymbols()
{
- m_LDBackend.initTargetSymbols(*m_pLinker);
+ m_LDBackend.initTargetSymbols(*m_pLinker, m_LDInfo.output());
return true;
}
@@ -284,6 +278,11 @@
m_LDBackend.allocateCommonSymbols(m_LDInfo, *m_pLinker);
+ /// check program interpreter - computer the name size of the runtime dyld
+ /// FIXME: check if we are doing static linking!
+ if (m_LDInfo.output().type() == Output::Exec)
+ m_LDBackend.sizeInterp(m_LDInfo.output(), m_LDInfo);
+
/// measure NamePools - compute the size of name pool sections
/// In ELF, will compute the size of.symtab, .strtab, .dynsym, .dynstr,
/// and .hash sections.
@@ -314,16 +313,6 @@
return true;
}
-/// relocate - applying relocation entries and create relocation
-/// section in the output files
-/// Create relocation section, asking TargetLDBackend to
-/// read the relocation information into RelocationEntry
-/// and push_back into the relocation section
-bool MCLDDriver::relocate()
-{
- return m_pLinker->applyRelocations();
-}
-
/// finalizeSymbolValue - finalize the resolved symbol value.
/// Before relocate(), after layout(), MCLinker should correct value of all
/// symbol.
@@ -332,6 +321,16 @@
return m_pLinker->finalizeSymbols();
}
+/// relocate - applying relocation entries and create relocation
+/// section in the output files
+/// Create relocation section, asking TargetLDBackend to
+/// read the relocation information into RelocationEntry
+/// and push_back into the relocation section
+bool MCLDDriver::relocation()
+{
+ return m_pLinker->applyRelocations();
+}
+
/// emitOutput - emit the output file.
bool MCLDDriver::emitOutput()
{
@@ -342,10 +341,9 @@
case Output::DynObj:
m_LDBackend.getDynObjWriter()->writeDynObj(m_LDInfo.output());
return true;
- /** TODO: open the executable file writer **/
- // case Output::Exec:
- // m_LDBackend.getExecWriter()->writeObject(m_LDInfo.output());
- // return true;
+ case Output::Exec:
+ m_LDBackend.getExecWriter()->writeExecutable(m_LDInfo.output());
+ return true;
}
return false;
}
@@ -354,5 +352,9 @@
bool MCLDDriver::postProcessing()
{
m_pLinker->syncRelocationResult();
+
+ m_LDBackend.postProcessing(m_LDInfo.output(),
+ m_LDInfo,
+ *m_pLinker);
return true;
}
diff --git a/lib/MC/MCLDInfo.cpp b/lib/MC/MCLDInfo.cpp
index 3cd0838..7ac154c 100644
--- a/lib/MC/MCLDInfo.cpp
+++ b/lib/MC/MCLDInfo.cpp
@@ -6,12 +6,14 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#include <mcld/Config/Config.h>
#include <mcld/MC/MCLDInfo.h>
-#include <mcld/Support/FileSystem.h>
#include <mcld/MC/InputFactory.h>
#include <mcld/MC/AttributeFactory.h>
#include <mcld/MC/ContextFactory.h>
-#include <mcld/Config/Config.h>
+#include <mcld/LD/NamePool.h>
+#include <mcld/LD/StaticResolver.h>
+#include <mcld/Support/FileSystem.h>
#include <string>
using namespace mcld;
@@ -22,16 +24,17 @@
size_t pAttrNum,
size_t pInputNum)
: m_Options(),
- m_pBitcode(0),
- m_Triple(pTripleString),
- m_pStrSymPool(0)
+ m_Scripts(),
+ m_pBitcode(NULL),
+ m_Triple(pTripleString)
{
m_pAttrFactory = new AttributeFactory(pAttrNum);
m_pCntxtFactory = new ContextFactory(pInputNum);
- m_pMemAreaFactory = new MemoryAreaFactory(pInputNum);
m_pInputFactory = new InputFactory(pInputNum, *m_pAttrFactory);
m_pInputTree = new InputTree(*m_pInputFactory);
m_pOutput = new mcld::Output();
+ m_pResolver = new StaticResolver();
+ m_pNamePool = new NamePool(*m_pResolver, 1024);
}
MCLDInfo::~MCLDInfo()
@@ -39,9 +42,10 @@
delete m_pOutput;
delete m_pAttrFactory;
delete m_pCntxtFactory;
- delete m_pMemAreaFactory;
delete m_pInputFactory;
delete m_pInputTree;
+ delete m_pResolver;
+ delete m_pNamePool;
}
void MCLDInfo::setBitcode(const Input& pInput)
@@ -63,5 +67,5 @@
const char* MCLDInfo::version()
{
- return mcld::internal::version;
+ return MCLD_VERSION;
}
diff --git a/lib/MC/MCLDOptions.cpp b/lib/MC/MCLDOptions.cpp
index ae07f26..47dbc35 100644
--- a/lib/MC/MCLDOptions.cpp
+++ b/lib/MC/MCLDOptions.cpp
@@ -6,13 +6,59 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/MC/MCLDOptions.h"
-#include "mcld/MC/MCLDInput.h"
+#include <mcld/MC/MCLDOptions.h>
+#include <mcld/MC/MCLDInput.h>
using namespace mcld;
-//==========================
-// MCLDOptions
+//===----------------------------------------------------------------------===//
+// ScriptOptions
+ScriptOptions::ScriptOptions()
+{
+}
+
+ScriptOptions::~ScriptOptions()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// GeneralOptions
+GeneralOptions::GeneralOptions()
+ : m_pDefaultBitcode(NULL),
+ m_Verbose(-1),
+ m_MaxErrorNum(-1),
+ m_MaxWarnNum(-1),
+ m_ExecStack(Unknown),
+ m_CommPageSize(0x0),
+ m_MaxPageSize(0x0),
+ m_bCombReloc(true),
+ m_bNoUndefined(false),
+ m_bInitFirst(false),
+ m_bInterPose(false),
+ m_bLoadFltr(false),
+ m_bMulDefs(false),
+ m_bNoCopyReloc(false),
+ m_bNoDefaultLib(false),
+ m_bNoDelete(false),
+ m_bNoDLOpen(false),
+ m_bNoDump(false),
+ m_bRelro(false),
+ m_bNow(false),
+ m_bOrigin(false),
+ m_bTrace(false),
+ m_Bsymbolic(false),
+ m_Bgroup(false),
+ m_bPIE(false),
+ m_bColor(true),
+ m_bAllowShlibUndefined(true),
+ m_bCreateEhFrameHdr(false)
+{
+}
+
+GeneralOptions::~GeneralOptions()
+{
+}
+
bool GeneralOptions::hasDefaultLDScript() const
{
return true;
@@ -32,3 +78,75 @@
m_Sysroot.assign(pSysroot);
}
+void GeneralOptions::addZOption(const ZOption& pOption)
+{
+ switch (pOption.kind()) {
+ case ZOption::CombReloc:
+ m_bCombReloc = true;
+ break;
+ case ZOption::NoCombReloc:
+ m_bCombReloc = false;
+ break;
+ case ZOption::Defs:
+ m_bNoUndefined = true;
+ break;
+ case ZOption::ExecStack:
+ m_ExecStack = YES;
+ break;
+ case ZOption::NoExecStack:
+ m_ExecStack = NO;
+ break;
+ case ZOption::InitFirst:
+ m_bInitFirst = true;
+ break;
+ case ZOption::InterPose:
+ m_bInterPose = true;
+ break;
+ case ZOption::LoadFltr:
+ m_bLoadFltr = true;
+ break;
+ case ZOption::MulDefs:
+ m_bMulDefs = true;
+ break;
+ case ZOption::NoCopyReloc:
+ m_bNoCopyReloc = true;
+ break;
+ case ZOption::NoDefaultLib:
+ m_bNoDefaultLib = true;
+ break;
+ case ZOption::NoDelete:
+ m_bNoDelete = true;
+ break;
+ case ZOption::NoDLOpen:
+ m_bNoDLOpen = true;
+ break;
+ case ZOption::NoDump:
+ m_bNoDump = true;
+ break;
+ case ZOption::NoRelro:
+ m_bRelro = false;
+ break;
+ case ZOption::Relro:
+ m_bRelro = true;
+ break;
+ case ZOption::Lazy:
+ m_bNow = false;
+ break;
+ case ZOption::Now:
+ m_bNow = true;
+ break;
+ case ZOption::Origin:
+ m_bOrigin = true;
+ break;
+ case ZOption::CommPageSize:
+ m_CommPageSize = pOption.pageSize();
+ break;
+ case ZOption::MaxPageSize:
+ m_MaxPageSize = pOption.pageSize();
+ break;
+ case ZOption::Unknown:
+ default:
+ assert(false && "Not a recognized -z option.");
+ break;
+ }
+}
diff --git a/lib/MC/MCLinker.cpp b/lib/MC/MCLinker.cpp
index e5327e8..4b9c50f 100644
--- a/lib/MC/MCLinker.cpp
+++ b/lib/MC/MCLinker.cpp
@@ -10,7 +10,6 @@
// This file implements the MCLinker class
//
//===----------------------------------------------------------------------===//
-
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCLDInput.h>
#include <mcld/MC/MCLDInfo.h>
@@ -20,7 +19,10 @@
#include <mcld/LD/LDSectionFactory.h>
#include <mcld/LD/SectionMap.h>
#include <mcld/LD/RelocationFactory.h>
+#include <mcld/LD/EhFrame.h>
+#include <mcld/LD/EhFrameHdr.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/TargetLDBackend.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/raw_ostream.h>
@@ -30,25 +32,22 @@
/// Constructor
MCLinker::MCLinker(TargetLDBackend& pBackend,
MCLDInfo& pInfo,
- LDContext& pContext,
- SectionMap& pSectionMap,
- const Resolver& pResolver)
+ SectionMap& pSectionMap)
: m_Backend(pBackend),
- m_Info(pInfo),
- m_Output(pContext),
+ m_LDInfo(pInfo),
m_SectionMap(pSectionMap),
m_LDSymbolFactory(128),
m_LDSectHdrFactory(10), // the average number of sections. (assuming 10.)
m_LDSectDataFactory(10),
- m_SectionMerger(pSectionMap, pContext),
- m_StrSymPool(pResolver, 128)
+ m_pSectionMerger(NULL)
{
- m_Info.setNamePool(m_StrSymPool);
}
/// Destructor
MCLinker::~MCLinker()
{
+ if (NULL != m_pSectionMerger)
+ delete m_pSectionMerger;
}
/// addSymbolFromObject - add a symbol from object file and resolve it
@@ -70,7 +69,7 @@
if (pBinding == ResolveInfo::Local) {
// if the symbol is a local symbol, create a LDSymbol for input, but do not
// resolve them.
- resolved_result.info = m_StrSymPool.createSymbol(pName,
+ resolved_result.info = m_LDInfo.getNamePool().createSymbol(pName,
false,
pType,
pDesc,
@@ -85,8 +84,9 @@
}
else {
// if the symbol is not local, insert and resolve it immediately
- m_StrSymPool.insertSymbol(pName, false, pType, pDesc, pBinding, pSize,
- pVisibility, &old_info, resolved_result);
+ m_LDInfo.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
+ pSize, pVisibility,
+ &old_info, resolved_result);
}
// the return ResolveInfo should not NULL
@@ -188,7 +188,8 @@
// insert symbol and resolve it immediately
// resolved_result is a triple <resolved_info, existent, override>
Resolver::Result resolved_result;
- m_StrSymPool.insertSymbol(pName, true, pType, pDesc, pBinding, pSize, pVisibility,
+ m_LDInfo.getNamePool().insertSymbol(pName, true, pType, pDesc,
+ pBinding, pSize, pVisibility,
NULL, resolved_result);
// the return ResolveInfo should not NULL
@@ -238,14 +239,15 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
LDSymbol* output_sym = NULL;
if (NULL == info) {
// the symbol is not in the pool, create a new one.
// create a ResolveInfo
Resolver::Result result;
- m_StrSymPool.insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, pSize, pVisibility,
- NULL, result);
+ m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc,
+ pBinding, pSize, pVisibility,
+ NULL, result);
assert(!result.existent);
// create a output LDSymbol
@@ -307,7 +309,7 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
if (NULL == info || !info->isUndef()) {
// only undefined symbol can make a reference.
@@ -361,8 +363,9 @@
// Result is <info, existent, override>
Resolver::Result result;
ResolveInfo old_info;
- m_StrSymPool.insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, pSize, pVisibility,
- &old_info, result);
+ m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, pBinding,
+ pSize, pVisibility,
+ &old_info, result);
LDSymbol* output_sym = result.info->outSymbol();
bool has_output_sym = (NULL != output_sym);
@@ -403,7 +406,7 @@
MCFragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
- ResolveInfo* info = m_StrSymPool.findInfo(pName);
+ ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
if (NULL == info || !info->isUndef()) {
// only undefined symbol can make a reference
@@ -427,20 +430,22 @@
uint32_t pType,
uint32_t pFlag)
{
+ assert(m_LDInfo.output().hasContext());
+
// for user such as reader, standard/target fromat
LDSection* result =
m_LDSectHdrFactory.produce(pName, pKind, pType, pFlag);
// check if we need to create a output section for output LDContext
std::string sect_name = m_SectionMap.getOutputSectName(pName);
- LDSection* output_sect = m_Output.getSection(sect_name);
+ LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name);
if (NULL == output_sect) {
// create a output section and push it into output LDContext
output_sect =
m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
- m_Output.getSectionTable().push_back(output_sect);
- m_SectionMerger.addMapping(pName, output_sect);
+ m_LDInfo.output().context()->getSectionTable().push_back(output_sect);
+ m_pSectionMerger->addMapping(pName, output_sect);
}
return *result;
}
@@ -453,17 +458,19 @@
uint32_t pFlag,
uint32_t pAlign)
{
+ assert(m_LDInfo.output().hasContext());
+
// check if we need to create a output section for output LDContext
std::string sect_name = m_SectionMap.getOutputSectName(pName);
- LDSection* output_sect = m_Output.getSection(sect_name);
+ LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name);
if (NULL == output_sect) {
// create a output section and push it into output LDContext
output_sect =
m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
output_sect->setAlign(pAlign);
- m_Output.getSectionTable().push_back(output_sect);
- m_SectionMerger.addMapping(pName, output_sect);
+ m_LDInfo.output().context()->getSectionTable().push_back(output_sect);
+ m_pSectionMerger->addMapping(pName, output_sect);
}
return *output_sect;
}
@@ -481,7 +488,7 @@
// try to get one from output LDSection
LDSection* output_sect =
- m_SectionMerger.getOutputSectHdr(pSection.name());
+ m_pSectionMerger->getOutputSectHdr(pSection.name());
assert(NULL != output_sect);
@@ -509,8 +516,17 @@
const LDSymbol& pSym,
ResolveInfo& pResolveInfo,
MCFragmentRef& pFragmentRef,
+ const LDSection& pSection,
Relocation::Address pAddend)
{
+ // FIXME: we should dicard sections and symbols first instead
+ // if the symbol is in the discarded input section, then we also need to
+ // discard this relocation.
+ if (pSym.fragRef() == NULL &&
+ pResolveInfo.type() == ResolveInfo::Section &&
+ pResolveInfo.desc() == ResolveInfo::Undefined)
+ return NULL;
+
Relocation* relocation = m_Backend.getRelocFactory()->produce(pType,
pFragmentRef,
pAddend);
@@ -519,9 +535,11 @@
m_RelocationList.push_back(relocation);
- m_Backend.scanRelocation(*relocation, pSym, *this, m_Info,
- m_Info.output());
+ m_Backend.scanRelocation(*relocation, pSym, *this, m_LDInfo,
+ m_LDInfo.output(), pSection);
+ if (pResolveInfo.isUndef() && !pResolveInfo.isDyn() && !pResolveInfo.isWeak())
+ fatal(diag::undefined_reference) << pResolveInfo.name();
return relocation;
}
@@ -531,7 +549,7 @@
for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) {
llvm::MCFragment* frag = (llvm::MCFragment*)relocIter;
- static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_Info);
+ static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_LDInfo);
}
return true;
}
@@ -539,9 +557,8 @@
void MCLinker::syncRelocationResult()
{
- m_Info.output().memArea()->clean();
- MemoryRegion* region = m_Info.output().memArea()->request(0,
- m_Info.output().memArea()->size());
+ MemoryRegion* region = m_LDInfo.output().memArea()->request(0,
+ m_LDInfo.output().memArea()->handler()->size());
uint8_t* data = region->getBuffer();
@@ -580,13 +597,19 @@
}
} // end of for
- m_Info.output().memArea()->sync();
+ m_LDInfo.output().memArea()->clear();
}
+void MCLinker::initSectionMap()
+{
+ assert(m_LDInfo.output().hasContext());
+ if (NULL == m_pSectionMerger)
+ m_pSectionMerger = new SectionMerger(m_SectionMap, *m_LDInfo.output().context());
+}
bool MCLinker::layout()
{
- return m_Layout.layout(m_Info.output(), m_Backend);
+ return m_Layout.layout(m_LDInfo.output(), m_Backend, m_LDInfo);
}
bool MCLinker::finalizeSymbols()
@@ -594,18 +617,9 @@
SymbolCategory::iterator symbol, symEnd = m_OutputSymbols.end();
for (symbol = m_OutputSymbols.begin(); symbol != symEnd; ++symbol) {
- if (0x0 != (*symbol)->resolveInfo()->reserved()) {
- // if the symbol is target reserved, target backend is responsible
- // for finalizing the value.
- // if target backend does not know this symbol, it will return false
- // and we have to take over the symbol.
- if (m_Backend.finalizeSymbol(**symbol))
- continue;
- }
-
if ((*symbol)->resolveInfo()->isAbsolute() ||
(*symbol)->resolveInfo()->type() == ResolveInfo::File) {
- // absolute symbols and symbols with function type should have
+ // absolute symbols or symbols with function type should have
// zero value
(*symbol)->setValue(0x0);
continue;
@@ -623,7 +637,8 @@
}
}
- return true;
+ // finialize target-dependent symbols
+ return m_Backend.finalizeSymbols(*this, m_LDInfo.output());
}
bool MCLinker::shouldForceLocal(const ResolveInfo& pInfo) const
@@ -633,7 +648,7 @@
// 2. The symbol is with Hidden or Internal visibility.
// 3. The symbol should be global or weak. Otherwise, local symbol is local.
// 4. The symbol is defined or common
- if (m_Info.output().type() != Output::Object &&
+ if (m_LDInfo.output().type() != Output::Object &&
(pInfo.visibility() == ResolveInfo::Hidden ||
pInfo.visibility() == ResolveInfo::Internal) &&
(pInfo.isGlobal() || pInfo.isWeak()) &&
@@ -642,3 +657,44 @@
return false;
}
+/// addEhFrame - add an exception handling section
+/// @param pSection - the input section
+/// @param pArea - the memory area which pSection is within.
+uint64_t MCLinker::addEhFrame(LDSection& pSection, MemoryArea& pArea)
+{
+ uint64_t size = 0;
+
+ // get the SectionData of this eh_frame
+ llvm::MCSectionData& sect_data = getOrCreateSectData(pSection);
+
+ // parse the eh_frame if the option --eh-frame-hdr is given
+ if (m_LDInfo.options().hasEhFrameHdr()) {
+ EhFrame* ehframe = m_Backend.getEhFrame();
+ assert(NULL != ehframe);
+ if (ehframe->canRecognizeAllEhFrame()) {
+ size = ehframe->readEhFrame(m_Layout, m_Backend, sect_data, pSection,
+ pArea);
+ // zero size indicate that this is an empty section or we can't recognize
+ // this eh_frame, handle it as a regular section.
+ if (0 != size)
+ return size;
+ }
+ }
+
+ // handle eh_frame as a regular section
+ MemoryRegion* region = pArea.request(pSection.offset(),
+ pSection.size());
+
+ llvm::MCFragment* frag = NULL;
+ if (NULL == region) {
+ // If the input section's size is zero, we got a NULL region.
+ // use a virtual fill fragment
+ frag = new llvm::MCFillFragment(0x0, 0, 0);
+ }
+ else
+ frag = new MCRegionFragment(*region);
+
+ size = m_Layout.appendFragment(*frag, sect_data, pSection.align());
+ return size;
+}
+
diff --git a/lib/MC/README b/lib/MC/README
deleted file mode 100644
index f020b50..0000000
--- a/lib/MC/README
+++ /dev/null
@@ -1,8 +0,0 @@
-MCLDStreamer is similar to MCObjectStreamer
-MCLinker is similar to MCAssembler
-MCLDWriter is similar to MCObjectWriter
-
-MCELFObjectReader parses ELF object files
-to MCInst classes
-
-
diff --git a/lib/MC/SearchDirs.cpp b/lib/MC/SearchDirs.cpp
index 0d21e46..40d625b 100644
--- a/lib/MC/SearchDirs.cpp
+++ b/lib/MC/SearchDirs.cpp
@@ -6,16 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/ADT/Twine.h>
-
-#include "mcld/MC/SearchDirs.h"
-#include "mcld/Support/FileSystem.h"
-#include "mcld/MC/MCLDDirectory.h"
+#include <mcld/MC/SearchDirs.h>
+#include <mcld/MC/MCLDDirectory.h>
+#include <mcld/Support/FileSystem.h>
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// Non-member functions
static void SpecToFilename(const std::string& pSpec, std::string& pFile)
{
@@ -23,7 +20,7 @@
pFile += pSpec;
}
-//==========================
+//===----------------------------------------------------------------------===//
// SearchDirs
SearchDirs::SearchDirs()
{
@@ -47,6 +44,8 @@
mcld::sys::fs::Path* SearchDirs::find(const std::string& pNamespec, mcld::Input::Type pType)
{
+ assert(Input::DynObj == pType || Input::Archive == pType);
+
std::string file;
SpecToFilename(pNamespec, file);
// for all MCLDDirectorys
@@ -64,11 +63,10 @@
return entry.path();
}
}
-
++entry;
}
}
-
+ /** Fall through **/
case Input::Archive : {
entry = (*mcld_dir)->begin();
enEnd = (*mcld_dir)->end();
@@ -78,15 +76,12 @@
return entry.path();
}
++entry;
- }
- }
- default: {
- llvm::report_fatal_error(llvm::Twine("SearchDir can not recoginize namespec: `") +
- pNamespec +
- llvm::Twine("'."));
- }
- }
- }
- return 0;
+ }
+ }
+ default:
+ break;
+ } // end of switch
+ } // end of while
+ return NULL;
}
diff --git a/lib/MC/ZOption.cpp b/lib/MC/ZOption.cpp
new file mode 100644
index 0000000..a58562d
--- /dev/null
+++ b/lib/MC/ZOption.cpp
@@ -0,0 +1,25 @@
+//===- ZOption.cpp --------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/MC/ZOption.h>
+
+using namespace mcld;
+
+//==========================
+// ZOption
+
+ZOption::ZOption()
+ : m_Kind(Unknown),
+ m_PageSize(0x0)
+{
+}
+
+ZOption::~ZOption()
+{
+}
+
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 57b82df..cc15e37 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -6,12 +6,16 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/CommandLine.h"
+#include <mcld/Support/CommandLine.h>
#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/ErrorHandling.h>
using namespace llvm;
using namespace llvm::cl;
+using namespace mcld;
+
//--------------------------------------------------
// parser<mcld::sys::fs::Path>
//
@@ -82,3 +86,81 @@
// do nothing
}
+//--------------------------------------------------
+// parser<mcld::ZOption>
+//
+bool parser<mcld::ZOption>::parse(llvm::cl::Option &O,
+ llvm::StringRef ArgName,
+ llvm::StringRef Arg,
+ mcld::ZOption &Val)
+{
+ if (0 == Arg.compare("combreloc"))
+ Val.setKind(ZOption::CombReloc);
+ else if (0 == Arg.compare("nocombreloc"))
+ Val.setKind(ZOption::NoCombReloc);
+ else if (0 == Arg.compare("defs"))
+ Val.setKind(ZOption::Defs);
+ else if (0 == Arg.compare("execstack"))
+ Val.setKind(ZOption::ExecStack);
+ else if (0 == Arg.compare("noexecstack"))
+ Val.setKind(ZOption::NoExecStack);
+ else if (0 == Arg.compare("initfirst"))
+ Val.setKind(ZOption::InitFirst);
+ else if (0 == Arg.compare("interpose"))
+ Val.setKind(ZOption::InterPose);
+ else if (0 == Arg.compare("loadfltr"))
+ Val.setKind(ZOption::LoadFltr);
+ else if (0 == Arg.compare("muldefs"))
+ Val.setKind(ZOption::MulDefs);
+ else if (0 == Arg.compare("nocopyreloc"))
+ Val.setKind(ZOption::NoCopyReloc);
+ else if (0 == Arg.compare("nodefaultlib"))
+ Val.setKind(ZOption::NoDefaultLib);
+ else if (0 == Arg.compare("nodelete"))
+ Val.setKind(ZOption::NoDelete);
+ else if (0 == Arg.compare("nodlopen"))
+ Val.setKind(ZOption::NoDLOpen);
+ else if (0 == Arg.compare("nodump"))
+ Val.setKind(ZOption::NoDump);
+ else if (0 == Arg.compare("relro"))
+ Val.setKind(ZOption::Relro);
+ else if (0 == Arg.compare("norelro"))
+ Val.setKind(ZOption::NoRelro);
+ else if (0 == Arg.compare("lazy"))
+ Val.setKind(ZOption::Lazy);
+ else if (0 == Arg.compare("now"))
+ Val.setKind(ZOption::Now);
+ else if (0 == Arg.compare("origin"))
+ Val.setKind(ZOption::Origin);
+ else if (Arg.startswith("common-page-size=")) {
+ Val.setKind(ZOption::CommPageSize);
+ long long unsigned size = 0;
+ Arg.drop_front(17).getAsInteger(0, size);
+ Val.setPageSize(static_cast<uint64_t>(size));
+ } else if (Arg.startswith("max-page-size=")) {
+ Val.setKind(ZOption::MaxPageSize);
+ long long unsigned size = 0;
+ Arg.drop_front(14).getAsInteger(0, size);
+ Val.setPageSize(static_cast<uint64_t>(size));
+ }
+
+ if (ZOption::Unknown == Val.kind())
+ llvm::report_fatal_error(llvm::Twine("unknown -z option: `") +
+ Arg +
+ llvm::Twine("'\n"));
+ return false;
+}
+
+void parser<mcld::ZOption>::printOptionDiff(const llvm::cl::Option &O,
+ const mcld::ZOption &V,
+ parser<mcld::ZOption>::OptVal Default,
+ size_t GlobalWidth) const
+{
+ // TODO
+}
+
+void parser<mcld::ZOption>::anchor()
+{
+ // do nothing
+}
+
diff --git a/lib/Support/Directory.cpp b/lib/Support/Directory.cpp
index 211b42a..78bb761 100644
--- a/lib/Support/Directory.cpp
+++ b/lib/Support/Directory.cpp
@@ -32,7 +32,7 @@
: m_Path(),
m_FileStatus(),
m_SymLinkStatus(),
- m_Handler(NULL),
+ m_Handler(0),
m_Cache(),
m_CacheFull(false) {
}
@@ -43,7 +43,7 @@
: m_Path(pPath),
m_FileStatus(st),
m_SymLinkStatus(symlink_st),
- m_Handler(NULL),
+ m_Handler(0),
m_Cache(),
m_CacheFull(false) {
if (m_Path.native() == ".")
@@ -56,7 +56,7 @@
: m_Path(pCopy.m_Path),
m_FileStatus(pCopy.m_FileStatus),
m_SymLinkStatus(pCopy.m_SymLinkStatus),
- m_Handler(NULL),
+ m_Handler(0),
m_Cache(),
m_CacheFull(false) {
mcld::sys::fs::detail::open_dir(*this);
diff --git a/lib/Support/FileHandle.cpp b/lib/Support/FileHandle.cpp
new file mode 100644
index 0000000..f6b898c
--- /dev/null
+++ b/lib/Support/FileHandle.cpp
@@ -0,0 +1,332 @@
+//===- FileHandle.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/FileSystem.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// FileHandle
+FileHandle::FileHandle()
+ : m_Path(),
+ m_Handler(-1),
+ m_Size(0),
+ m_State(GoodBit),
+ m_OpenMode(NotOpen) {
+}
+
+FileHandle::~FileHandle()
+{
+ if (isOpened())
+ close();
+}
+
+inline static int oflag(FileHandle::OpenMode pMode)
+{
+ int result = 0x0;
+ if (FileHandle::Unknown == pMode)
+ return result;
+
+ if (FileHandle::ReadWrite == (pMode & FileHandle::ReadWrite))
+ result |= O_RDWR;
+ else if (pMode & FileHandle::ReadOnly)
+ result |= O_RDONLY;
+ else if (pMode & FileHandle::WriteOnly)
+ result |= O_WRONLY;
+
+ if (pMode & FileHandle::Append)
+ result |= O_APPEND;
+
+ if (pMode & FileHandle::Create)
+ result |= O_CREAT;
+
+ if (pMode & FileHandle::Truncate)
+ result |= O_TRUNC;
+
+ return result;
+}
+
+inline static bool get_size(int pHandler, unsigned int &pSize)
+{
+ struct ::stat file_stat;
+ if (-1 == ::fstat(pHandler, &file_stat)) {
+ pSize = 0;
+ return false;
+ }
+ pSize = file_stat.st_size;
+ return true;
+}
+
+bool FileHandle::open(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode)
+{
+ if (isOpened() || Unknown == pMode) {
+ setState(BadBit);
+ return false;
+ }
+
+ m_OpenMode = pMode;
+ m_Handler = ::open(pPath.native().c_str(), oflag(pMode));
+ m_Path = pPath;
+ if (-1 == m_Handler) {
+ m_OpenMode = NotOpen;
+ setState(FailBit);
+ return false;
+ }
+
+ if (!get_size(m_Handler, m_Size)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::open(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode,
+ FileHandle::Permission pPerm)
+{
+ if (isOpened() || Unknown == pMode) {
+ setState(BadBit);
+ return false;
+ }
+
+ m_OpenMode = pMode;
+ m_Handler = sys::fs::detail::open(pPath, oflag(pMode), (int)pPerm);
+ m_Path = pPath;
+ if (-1 == m_Handler) {
+ m_OpenMode = NotOpen;
+ setState(FailBit);
+ return false;
+ }
+
+ if (!get_size(m_Handler, m_Size)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode)
+{
+ if (isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ m_Handler = pFD;
+ m_OpenMode = pMode;
+ m_State = GoodBit;
+
+ if (!get_size(m_Handler, m_Size)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::close()
+{
+ if (!isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (-1 == ::close(m_Handler)) {
+ setState(FailBit);
+ return false;
+ }
+
+ m_Path.native().clear();
+ m_Size = 0;
+ m_OpenMode = NotOpen;
+ cleanState();
+ return true;
+}
+
+bool FileHandle::truncate(size_t pSize)
+{
+ if (!isOpened() || !isWritable()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (-1 == sys::fs::detail::ftruncate(m_Handler, pSize)) {
+ setState(FailBit);
+ return false;
+ }
+
+ m_Size = pSize;
+ return true;
+}
+
+bool FileHandle::read(void* pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+ if (!isOpened() || !isReadable()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (0 == pLength)
+ return true;
+
+ ssize_t read_bytes = sys::fs::detail::pread(m_Handler,
+ pMemBuffer,
+ pLength,
+ pStartOffset);
+
+ if (-1 == read_bytes) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::write(const void* pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+ if (!isOpened() || !isWritable()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (0 == pLength)
+ return true;
+
+
+ ssize_t write_bytes = sys::fs::detail::pwrite(m_Handler,
+ pMemBuffer,
+ pLength,
+ pStartOffset);
+
+ if (-1 == write_bytes) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+#include <iostream>
+using namespace std;
+
+bool FileHandle::mmap(void*& pMemBuffer, size_t pStartOffset, size_t pLength)
+{
+ if (!isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (0 == pLength)
+ return true;
+
+ int prot, flag;
+ if (isReadable() && !isWritable()) {
+ // read-only
+ prot = PROT_READ;
+ flag = MAP_FILE | MAP_PRIVATE;
+ }
+ else if (!isReadable() && isWritable()) {
+ // write-only
+ prot = PROT_WRITE;
+ flag = MAP_FILE | MAP_SHARED;
+ }
+ else if (isReadWrite()) {
+ // read and write
+ prot = PROT_READ | PROT_WRITE;
+ flag = MAP_FILE | MAP_SHARED;
+ }
+ else {
+ // can not read/write
+ setState(BadBit);
+ return false;
+ }
+
+ pMemBuffer = ::mmap(NULL, pLength, prot, flag, m_Handler, pStartOffset);
+
+ if (MAP_FAILED == pMemBuffer) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+bool FileHandle::munmap(void* pMemBuffer, size_t pLength)
+{
+ if (!isOpened()) {
+ setState(BadBit);
+ return false;
+ }
+
+ if (-1 == ::munmap(pMemBuffer, pLength)) {
+ setState(FailBit);
+ return false;
+ }
+
+ return true;
+}
+
+void FileHandle::setState(FileHandle::IOState pState)
+{
+ m_State |= pState;
+}
+
+void FileHandle::cleanState(FileHandle::IOState pState)
+{
+ m_State = pState;
+}
+
+bool FileHandle::isOpened() const
+{
+ if (-1 != m_Handler && m_OpenMode != NotOpen && isGood())
+ return true;
+
+ return false;
+}
+
+// Assume Unknown OpenMode is readable
+bool FileHandle::isReadable() const
+{
+ return (m_OpenMode & ReadOnly);
+}
+
+// Assume Unknown OpenMode is writable
+bool FileHandle::isWritable() const
+{
+ return (m_OpenMode & WriteOnly);
+}
+
+// Assume Unknown OpenMode is both readable and writable
+bool FileHandle::isReadWrite() const
+{
+ return (FileHandle::ReadWrite == (m_OpenMode & FileHandle::ReadWrite));
+}
+
+bool FileHandle::isGood() const
+{
+ return !(m_State & (BadBit | FailBit));
+}
+
+bool FileHandle::isBad() const
+{
+ return (m_State & BadBit);
+}
+
+bool FileHandle::isFailed() const
+{
+ return (m_State & (BadBit | FailBit));
+}
+
diff --git a/lib/Support/FileSystem.cpp b/lib/Support/FileSystem.cpp
index d3366c0..fb2633d 100644
--- a/lib/Support/FileSystem.cpp
+++ b/lib/Support/FileSystem.cpp
@@ -9,10 +9,6 @@
#include "mcld/Support/FileSystem.h"
#include "mcld/Support/Path.h"
-#if defined(ANDROID)
-#include <llvm/Config/config.h>
-#endif
-
using namespace mcld::sys::fs;
@@ -22,12 +18,12 @@
//===--------------------------------------------------------------------===//
// non-member functions
-// Include the truly platform-specific parts.
-#if defined(LLVM_ON_UNIX)
+// Include the truly platform-specific parts.
+#if defined(MCLD_ON_UNIX)
#include "Unix/FileSystem.inc"
-#include "Unix/PathV3.inc"
-#endif
-#if defined(LLVM_ON_WIN32)
+#include "Unix/PathV3.inc"
+#endif
+#if defined(MCLD_ON_WIN32)
#include "Windows/FileSystem.inc"
-#include "Windows/PathV3.inc"
-#endif
+#include "Windows/PathV3.inc"
+#endif
diff --git a/lib/Support/HandleToArea.cpp b/lib/Support/HandleToArea.cpp
new file mode 100644
index 0000000..f580e64
--- /dev/null
+++ b/lib/Support/HandleToArea.cpp
@@ -0,0 +1,94 @@
+//===- HandleToArea.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/HandleToArea.h>
+#include <mcld/Support/MemoryArea.h>
+#include <llvm/ADT/StringRef.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// HandleToArea
+bool HandleToArea::push_back(FileHandle* pHandle, MemoryArea* pArea)
+{
+ if (NULL == pHandle || NULL == pArea)
+ return false;
+
+ Bucket bucket;
+ bucket.hash_value = HashFunction()(
+ llvm::StringRef(pHandle->path().native().c_str(),
+ pHandle->path().native().size()));
+
+ bucket.handle = pHandle;
+ bucket.area = pArea;
+ m_AreaMap.push_back(bucket);
+ return true;
+}
+
+bool HandleToArea::erase(MemoryArea* pArea)
+{
+ if (NULL == pArea || NULL == pArea->handler())
+ return false;
+
+ return erase(pArea->handler()->path());
+}
+
+bool HandleToArea::erase(const sys::fs::Path& pPath)
+{
+ unsigned int hash_value = HashFunction()(
+ llvm::StringRef(pPath.native().c_str(),
+ pPath.native().size()));
+
+ HandleToAreaMap::iterator bucket, bEnd = m_AreaMap.end();
+ for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
+ if (bucket->hash_value == hash_value && bucket->handle->path() == pPath) {
+ // found
+ m_AreaMap.erase(bucket);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+HandleToArea::Result HandleToArea::findFirst(const sys::fs::Path& pPath)
+{
+ unsigned int hash_value = HashFunction()(llvm::StringRef(pPath.native().c_str(),
+ pPath.native().size()));
+
+ HandleToAreaMap::iterator bucket, bEnd = m_AreaMap.end();
+
+ for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
+ if (bucket->hash_value == hash_value) {
+ if (bucket->handle->path() == pPath) {
+ return Result(bucket->handle, bucket->area);
+ }
+ }
+ }
+
+ return Result(NULL, NULL);
+}
+
+HandleToArea::ConstResult HandleToArea::findFirst(const sys::fs::Path& pPath) const
+{
+ unsigned int hash_value = HashFunction()(llvm::StringRef(pPath.native().c_str(),
+ pPath.native().size()));
+
+ HandleToAreaMap::const_iterator bucket, bEnd = m_AreaMap.end();
+
+ for (bucket = m_AreaMap.begin(); bucket != bEnd; ++bucket) {
+ if (bucket->hash_value == hash_value) {
+ if (bucket->handle->path() == pPath) {
+ return ConstResult(bucket->handle, bucket->area);
+ }
+ }
+ }
+
+ return ConstResult(NULL, NULL);
+}
+
diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp
index f388e94..78a9d36 100644
--- a/lib/Support/MemoryArea.cpp
+++ b/lib/Support/MemoryArea.cpp
@@ -6,164 +6,31 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
-#include <llvm/ADT/Twine.h>
-
#include <mcld/Support/RegionFactory.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/FileSystem.h>
-
-#include <cerrno>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
//===--------------------------------------------------------------------===//
// MemoryArea
-MemoryArea::MemoryArea(RegionFactory& pRegionFactory)
- : m_RegionFactory(pRegionFactory),
- m_FileDescriptor(-1),
- m_FileSize(0),
- m_AccessFlags(ReadOnly),
- m_State(BadBit) {
+
+// MemoryArea - special constructor
+// This constructor is used for *SPECIAL* situation. I'm sorry I can not
+// reveal what is the special situation.
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse)
+ : m_RegionFactory(pRegionFactory), m_pFileHandle(NULL) {
+ m_SpaceList.push_back(&pUniverse);
+}
+
+MemoryArea::MemoryArea(RegionFactory& pRegionFactory, FileHandle& pFileHandle)
+ : m_RegionFactory(pRegionFactory), m_pFileHandle(&pFileHandle) {
}
MemoryArea::~MemoryArea()
{
- // truncate the file to real size
- if (isWritable())
- truncate(m_FileSize);
-
- unmap();
-}
-
-void MemoryArea::truncate(size_t pLength)
-{
- if (!isWritable())
- return;
-
- if (-1 == ::ftruncate(m_FileDescriptor, static_cast<off_t>(pLength))) {
- llvm::report_fatal_error(llvm::Twine("Cannot truncate `") +
- m_FilePath.native() +
- llvm::Twine("' to size: ") +
- llvm::Twine(pLength) +
- llvm::Twine(".\n"));
- }
-}
-
-void MemoryArea::map(const sys::fs::Path& pPath, int pFlags)
-{
- m_AccessFlags = pFlags;
- m_FilePath = pPath;
- m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags);
-
- if (-1 == m_FileDescriptor) {
- m_State |= FailBit;
- }
- else {
- struct stat st;
- int stat_result = ::stat(m_FilePath.native().c_str(), &st);
- if (0x0 == stat_result) {
- m_FileSize = static_cast<size_t>(st.st_size);
- m_State = GoodBit;
- }
- else {
- m_FileSize = 0x0;
- m_State |= FailBit;
- m_State |= BadBit;
- }
- }
-}
-
-void MemoryArea::map(const sys::fs::Path& pPath, int pFlags, int pMode)
-{
- m_AccessFlags = pFlags;
- m_FilePath = pPath;
- m_FileDescriptor = ::open(m_FilePath.c_str(), m_AccessFlags, pMode);
-
- if (-1 == m_FileDescriptor) {
- m_State |= FailBit;
- }
- else {
- struct stat st;
- int stat_result = ::stat(m_FilePath.native().c_str(), &st);
- if (0x0 == stat_result) {
- m_FileSize = static_cast<size_t>(st.st_size);
- m_State = GoodBit;
- }
- else {
- m_FileSize = 0x0;
- m_State |= FailBit;
- m_State |= BadBit;
- }
- }
-}
-
-void MemoryArea::unmap()
-{
- if (isMapped()) {
- if (-1 == ::close(m_FileDescriptor))
- m_State |= FailBit;
- else {
- m_FileDescriptor = -1;
- m_AccessFlags = ReadOnly;
- }
- }
-}
-
-bool MemoryArea::isMapped() const
-{
- return (-1 != m_FileDescriptor);
-}
-
-bool MemoryArea::isGood() const
-{
- return 0x0 == (m_State & (BadBit | FailBit));
-}
-
-bool MemoryArea::isBad() const
-{
- return 0x0 != (m_State & BadBit);
-}
-
-bool MemoryArea::isFailed() const
-{
- return 0x0 != (m_State & FailBit);
-}
-
-bool MemoryArea::isEOF() const
-{
- return 0x0 != (m_State & EOFBit);
-}
-
-bool MemoryArea::isReadable() const
-{
- return (((m_AccessFlags & AccessMask) == ReadOnly) ||
- ((m_AccessFlags & AccessMask) == ReadWrite));
-}
-
-bool MemoryArea::isWritable() const
-{
- return (((m_AccessFlags & AccessMask) == WriteOnly) ||
- ((m_AccessFlags & AccessMask) == ReadWrite));
-}
-
-int MemoryArea::rdstate() const
-{
- return m_State;
-}
-
-void MemoryArea::setState(MemoryArea::IOState pState)
-{
- m_State |= pState;
-}
-
-void MemoryArea::clear(MemoryArea::IOState pState)
-{
- m_State = pState;
}
// The layout of MemorySpace in the virtual memory space
@@ -185,242 +52,100 @@
//
MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
{
- if (!isMapped() || !isGood())
- return NULL;
-
- if (0x0 == pLength)
- return NULL;
-
- if (!isWritable() && (pOffset + pLength) > m_FileSize)
- return NULL;
-
- if (isWritable() && (pOffset + pLength) > m_FileSize) {
- // If the memory area is writable, user can expand the size of file by
- // request a region larger than the file.
- // MemoryArea should enlarge the file if the requested region is larger
- // than the file.
- m_FileSize = page_boundary(pOffset + pLength + 1);
- truncate(m_FileSize);
- }
-
Space* space = find(pOffset, pLength);
- MemoryArea::Address r_start = 0;
if (NULL == space) {
- // the space does not exist, create a new space.
- space = new Space(this, pOffset, pLength);
+
+ // not found
+ if (NULL == m_pFileHandle) {
+ // if m_pFileHandle is NULL, clients delegate us an universal Space and
+ // we never remove it. In that way, space can not be NULL.
+ unreachable(diag::err_out_of_range_region);
+ }
+
+ space = Space::createSpace(*m_pFileHandle, pOffset, pLength);
m_SpaceList.push_back(space);
- switch(space->type = policy(pOffset, pLength)) {
- case Space::MMAPED: {
- int mm_prot, mm_flag;
- if (isWritable()) {
- mm_prot = PROT_READ | PROT_WRITE;
- mm_flag = MAP_FILE | MAP_SHARED;
- }
- else {
- mm_prot = PROT_READ;
- mm_flag = MAP_FILE | MAP_PRIVATE;
- }
-
- space->file_offset = page_offset(pOffset);
-
- // The space's size may be larger than filesize.
- space->size = page_boundary(pLength + pOffset + 1 - space->file_offset);
- space->data = (Address) ::mmap(NULL,
- space->size,
- mm_prot, mm_flag,
- m_FileDescriptor,
- space->file_offset);
-
- if (space->data == MAP_FAILED) {
- llvm::report_fatal_error(llvm::Twine("cannot open memory map file :") +
- m_FilePath.native() +
- llvm::Twine(" (") +
- sys::fs::detail::strerror(errno) +
- llvm::Twine(").\n"));
- }
-
- r_start = space->data + (pOffset - space->file_offset);
- break;
- }
- case Space::ALLOCATED_ARRAY: {
- // space->offset and space->size are set in constructor. We only need
- // to set up data.
- space->data = new unsigned char[pLength];
- r_start = space->data;
- if ((m_AccessFlags & AccessMask) != WriteOnly) {
- // Read data from the backend file.
- if (!read(*space)) {
- llvm::report_fatal_error(llvm::Twine("Failed to read data from ") +
- m_FilePath.native() +
- llvm::Twine(" (") +
- sys::fs::detail::strerror(errno) +
- llvm::Twine(") at offset ") +
- llvm::Twine(pOffset) +
- llvm::Twine(" lenght ") +
- llvm::Twine(pLength) + llvm::Twine(".\n"));
- }
- }
- break;
- } // case
- default: {
- llvm::report_fatal_error("unhandled space type\n");
- }
- } // switch
}
- else { // found
- off_t distance = pOffset - space->file_offset;
- r_start = space->data + distance;
- }
+
+ // adjust r_start
+ off_t distance = pOffset - space->start();
+ void* r_start = space->memory() + distance;
// now, we have a legal space to hold the new MemoryRegion
- return m_RegionFactory.produce(space, r_start, pLength);
+ return m_RegionFactory.produce(*space, r_start, pLength);
}
// release - release a MemoryRegion
void MemoryArea::release(MemoryRegion* pRegion)
{
- if (!isMapped() || !isGood())
+ if (NULL == pRegion)
return;
Space *space = pRegion->parent();
m_RegionFactory.destruct(pRegion);
- if (0 == space->region_num) {
- write(*space);
- m_SpaceList.remove(*space);
- release(space);
+ if (0 == space->numOfRegions()) {
+
+ if (NULL != m_pFileHandle) {
+ // if m_pFileHandle is NULL, clients delegate us an universal Space and
+ // we never remove it. Otherwise, we have to synchronize and release
+ // Space.
+ if (m_pFileHandle->isWritable()) {
+ // synchronize writable space before we release it.
+ Space::syncSpace(space, *m_pFileHandle);
+ }
+ Space::releaseSpace(space, *m_pFileHandle);
+ }
+ m_SpaceList.erase(space);
}
}
-void MemoryArea::clean()
+// clear - release all MemoryRegions
+void MemoryArea::clear()
{
- m_RegionFactory.clear();
+ if (NULL == m_pFileHandle)
+ return;
- SpaceList::iterator sIter, sEnd = m_SpaceList.end();
- for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
- write(*sIter);
- release(sIter);
+ if (m_pFileHandle->isWritable()) {
+ SpaceList::iterator space, sEnd = m_SpaceList.end();
+ for (space = m_SpaceList.begin(); space != sEnd; ++space) {
+ Space::syncSpace(space, *m_pFileHandle);
+ Space::releaseSpace(space, *m_pFileHandle);
+ }
}
+ else {
+ SpaceList::iterator space, sEnd = m_SpaceList.end();
+ for (space = m_SpaceList.begin(); space != sEnd; ++space)
+ Space::releaseSpace(space, *m_pFileHandle);
+ }
+
m_SpaceList.clear();
}
-void MemoryArea::sync()
+//===--------------------------------------------------------------------===//
+// SpaceList methods
+Space* MemoryArea::find(size_t pOffset, size_t pLength)
{
SpaceList::iterator sIter, sEnd = m_SpaceList.end();
for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
- write(*sIter);
- }
-}
-
-MemoryArea::Space* MemoryArea::find(size_t pOffset, size_t pLength)
-{
- SpaceList::iterator sIter, sEnd = m_SpaceList.end();
- for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
- if (sIter->file_offset <= pOffset &&
- (pOffset+pLength) <= (sIter->file_offset+sIter->size) ) { // within
+ if (sIter->start() <= pOffset &&
+ (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
+ // within
return sIter;
}
}
return NULL;
}
-void MemoryArea::release(MemoryArea::Space* pSpace)
+const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
{
- switch (pSpace->type) {
- case Space::ALLOCATED_ARRAY: {
- delete [] pSpace->data;
- break;
- }
- case Space::MMAPED: {
- ::munmap(pSpace->data, pSpace->size);
- break;
- }
- default:
- break;
- }
-}
-
-MemoryArea::Space::Type MemoryArea::policy(off_t pOffset, size_t pLength)
-{
- const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
- if (pLength < threshold)
- return Space::ALLOCATED_ARRAY;
- else
- return Space::MMAPED;
-}
-
-ssize_t MemoryArea::readToBuffer(sys::fs::detail::Address pBuf,
- size_t pSize, size_t pOffset) {
- assert(((m_AccessFlags & AccessMask) != WriteOnly) &&
- "Write-only file cannot be read!");
-
- ssize_t read_bytes = sys::fs::detail::pread(m_FileDescriptor, pBuf,
- pSize, pOffset);
- if (static_cast<size_t>(read_bytes) != pSize) {
- // Some error occurred during pread().
- if (read_bytes < 0) {
- m_State |= FailBit;
- }
- else if (static_cast<size_t>(read_bytes) < pSize) {
- m_State |= EOFBit;
- if ((m_AccessFlags & AccessMask) != ReadWrite) {
- // Files which is not read-write are not allowed read beyonds the EOF
- // marker.
- m_State |= BadBit;
- }
- }
- else {
- m_State |= BadBit;
+ SpaceList::const_iterator sIter, sEnd = m_SpaceList.end();
+ for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
+ if (sIter->start() <= pOffset &&
+ (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
+ // within
+ return sIter;
}
}
- return read_bytes;
-}
-
-bool MemoryArea::read(Space& pSpace) {
- if (!isGood() || !isReadable())
- return false;
-
- if (pSpace.type == Space::ALLOCATED_ARRAY) {
- readToBuffer(pSpace.data, pSpace.size, pSpace.file_offset);
- return isGood();
- }
- else {
- // Data associated with mmap()'ed space is already at the position the
- // pSpace points to.
- assert((pSpace.type == Space::MMAPED) && "Unknown type of Space!");
- return true;
- }
-}
-
-
-void MemoryArea::write(const Space& pSpace)
-{
- if (!isMapped() || !isGood() || !isWritable())
- return;
-
- switch(pSpace.type) {
- case Space::MMAPED: {
- if(-1 == ::msync(pSpace.data, pSpace.size, MS_SYNC))
- m_State |= FailBit;
- return;
- }
- case Space::ALLOCATED_ARRAY: {
- ssize_t write_bytes = sys::fs::detail::pwrite(m_FileDescriptor,
- pSpace.data,
- pSpace.size,
- pSpace.file_offset);
- if (0 > write_bytes) {
- m_State |= FailBit;
- return;
- }
- if (0 == write_bytes && 0 != pSpace.size)
- m_State |= BadBit;
- if ( pSpace.size > static_cast<size_t>(write_bytes) )
- m_State |= EOFBit;
- return;
- }
- default:
- return;
- }
+ return NULL;
}
diff --git a/lib/Support/MemoryAreaFactory.cpp b/lib/Support/MemoryAreaFactory.cpp
index 1f7e523..3da07d5 100644
--- a/lib/Support/MemoryAreaFactory.cpp
+++ b/lib/Support/MemoryAreaFactory.cpp
@@ -6,15 +6,18 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/MemoryAreaFactory.h"
-#include "mcld/Support/RegionFactory.h"
+#include <mcld/Support/MemoryAreaFactory.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/SystemUtils.h>
+#include <mcld/Support/Space.h>
using namespace mcld;
-//==========================
+//===----------------------------------------------------------------------===//
// MemoryAreaFactory
MemoryAreaFactory::MemoryAreaFactory(size_t pNum)
- : UniqueGCFactoryBase<sys::fs::Path, MemoryArea, 0>(pNum) {
+ : GCFactory<MemoryArea, 0>(pNum) {
// For each loaded file, MCLinker must load ELF header, section header,
// symbol table, and string table. So, we set the size of chunk quadruple
// larger than the number of input files.
@@ -23,30 +26,91 @@
MemoryAreaFactory::~MemoryAreaFactory()
{
+ HandleToArea::iterator rec, rEnd = m_HandleToArea.end();
+ for (rec = m_HandleToArea.begin(); rec != rEnd; ++rec) {
+ if (rec->handle->isOpened()) {
+ rec->handle->close();
+ }
+ delete rec->handle;
+ }
+
delete m_pRegionFactory;
}
-MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags)
+MemoryArea*
+MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode)
{
- MemoryArea* result = find(pPath);
- if (0 == result) {
- result = allocate();
- new (result) MemoryArea(*m_pRegionFactory);
- result->map(pPath, pFlags);
- f_KeyMap.insert(std::make_pair(pPath, result));
+ HandleToArea::Result map_result = m_HandleToArea.findFirst(pPath);
+ if (NULL == map_result.area) {
+ // can not found
+ FileHandle* handler = new FileHandle();
+ if (!handler->open(pPath, pMode)) {
+ error(diag::err_cannot_open_file) << pPath
+ << sys::strerror(handler->error());
+ }
+
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *handler);
+
+ m_HandleToArea.push_back(handler, result);
+ return result;
}
+
+ return map_result.area;
+}
+
+MemoryArea*
+MemoryAreaFactory::produce(const sys::fs::Path& pPath,
+ FileHandle::OpenMode pMode,
+ FileHandle::Permission pPerm)
+{
+ HandleToArea::Result map_result = m_HandleToArea.findFirst(pPath);
+ if (NULL == map_result.area) {
+ // can not found
+ FileHandle* handler = new FileHandle();
+ if (!handler->open(pPath, pMode, pPerm)) {
+ error(diag::err_cannot_open_file) << pPath
+ << sys::strerror(handler->error());
+ }
+
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *handler);
+
+ m_HandleToArea.push_back(handler, result);
+ return result;
+ }
+
+ return map_result.area;
+}
+
+void MemoryAreaFactory::destruct(MemoryArea* pArea)
+{
+ m_HandleToArea.erase(pArea);
+ pArea->clear();
+ pArea->handler()->close();
+ destroy(pArea);
+ deallocate(pArea);
+}
+
+MemoryArea*
+MemoryAreaFactory::create(void* pMemBuffer, size_t pSize)
+{
+ Space* space = new Space(Space::EXTERNAL, pMemBuffer, pSize);
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *space);
return result;
}
-MemoryArea* MemoryAreaFactory::produce(const sys::fs::Path& pPath, int pFlags, mode_t pMode)
+MemoryArea*
+MemoryAreaFactory::create(int pFD, FileHandle::OpenMode pMode)
{
- MemoryArea* result = find(pPath);
- if (0 == result) {
- result = allocate();
- new (result) MemoryArea(*m_pRegionFactory);
- result->map(pPath, pFlags, pMode);
- f_KeyMap.insert(std::make_pair(pPath, result));
- }
+ FileHandle* handler = new FileHandle();
+ handler->delegate(pFD, pMode);
+
+ MemoryArea* result = allocate();
+ new (result) MemoryArea(*m_pRegionFactory, *handler);
+
return result;
}
diff --git a/lib/Support/MemoryRegion.cpp b/lib/Support/MemoryRegion.cpp
index 3a35f4e..32e790b 100644
--- a/lib/Support/MemoryRegion.cpp
+++ b/lib/Support/MemoryRegion.cpp
@@ -12,23 +12,13 @@
//==========================
// MemoryRegion
-MemoryRegion::MemoryRegion(MemoryArea::Space *pParentSpace,
- const MemoryRegion::Address pVMAStart,
+MemoryRegion::MemoryRegion(Space& pParent,
+ MemoryRegion::Address pVMAStart,
size_t pSize)
- : m_pParentSpace(pParentSpace), m_VMAStart(pVMAStart), m_Length(pSize) {
- m_pParentSpace->region_num++;
+ : m_Parent(pParent), m_VMAStart(pVMAStart), m_Length(pSize) {
}
MemoryRegion::~MemoryRegion()
{
- drift();
-}
-
-void MemoryRegion::drift()
-{
- if (NULL == m_pParentSpace)
- return;
- m_pParentSpace->region_num--;
- m_pParentSpace = NULL;
}
diff --git a/lib/Support/MsgHandling.cpp b/lib/Support/MsgHandling.cpp
new file mode 100644
index 0000000..5b45289
--- /dev/null
+++ b/lib/Support/MsgHandling.cpp
@@ -0,0 +1,74 @@
+//===- MsgHandling.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/LD/DiagnosticEngine.h>
+#include <mcld/LD/DiagnosticLineInfo.h>
+#include <mcld/LD/DiagnosticPrinter.h>
+#include <mcld/LD/MsgHandler.h>
+#include <mcld/Support/MsgHandling.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// DiagnosticInitializer
+class DiagnosticInitializer : public llvm::ManagedStaticBase
+{
+public:
+ DiagnosticEngine* initialize(const MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter)
+ {
+ RegisterManagedStatic(NULL, llvm::object_deleter<DiagnosticEngine>::call);
+ if (llvm::llvm_is_multithreaded()) {
+ llvm::llvm_acquire_global_lock();
+ void* tmp = NULL;
+ if (NULL != pPrinter)
+ tmp = new DiagnosticEngine(pLDInfo, pLineInfo, pPrinter, false);
+ else
+ tmp = new DiagnosticEngine(pLDInfo, pLineInfo, NULL, false);
+
+ TsanHappensBefore(this);
+ llvm::sys::MemoryFence();
+ TsanIgnoreWritesBegin();
+ Ptr = tmp;
+ TsanIgnoreWritesEnd();
+ llvm::llvm_release_global_lock();
+ }
+ else {
+ if (NULL != pPrinter)
+ Ptr = new DiagnosticEngine(pLDInfo, pLineInfo, pPrinter, false);
+ else
+ Ptr = new DiagnosticEngine(pLDInfo, pLineInfo, NULL, false);
+ }
+ return static_cast<DiagnosticEngine*>(Ptr);
+ }
+};
+
+static DiagnosticInitializer g_DiagInitializer;
+static DiagnosticEngine* g_pDiagnosticEngine = NULL;
+
+void mcld::InitializeDiagnosticEngine(const mcld::MCLDInfo& pLDInfo,
+ DiagnosticLineInfo* pLineInfo,
+ DiagnosticPrinter* pPrinter)
+{
+ if (NULL == g_pDiagnosticEngine) {
+ g_pDiagnosticEngine = g_DiagInitializer.initialize(pLDInfo,
+ pLineInfo,
+ pPrinter);
+ }
+}
+
+DiagnosticEngine& mcld::getDiagnosticEngine()
+{
+ assert(NULL != g_pDiagnosticEngine &&
+ "mcld::InitializeDiagnostics() is not called");
+ return *g_pDiagnosticEngine;
+}
+
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index ffb449f..8cc384d 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -11,11 +11,8 @@
#include <llvm/ADT/StringRef.h>
#include <locale>
-#include <stdio.h>
#include <string.h>
-#include <iostream>
-
using namespace mcld;
using namespace mcld::sys::fs;
@@ -119,7 +116,7 @@
Path::StringType::size_type Path::m_append_separator_if_needed()
{
if (!m_PathName.empty() &&
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
*(m_PathName.end()-1) != colon &&
#endif
!is_separator(*(m_PathName.end()-1))) {
@@ -171,7 +168,7 @@
bool mcld::sys::fs::is_separator(char value)
{
return (value == separator
-#ifdef LLVM_ON_WIN32
+#if defined(MCLD_ON_WIN32)
|| value == preferred_separator
#endif
);
diff --git a/lib/Support/RegionFactory.cpp b/lib/Support/RegionFactory.cpp
index e87d389..ddce433 100644
--- a/lib/Support/RegionFactory.cpp
+++ b/lib/Support/RegionFactory.cpp
@@ -6,8 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/RegionFactory.h"
-#include "mcld/Support/MemoryArea.h"
+#include <mcld/Support/RegionFactory.h>
+#include <mcld/Support/MemoryArea.h>
+#include <mcld/Support/Space.h>
using namespace mcld;
@@ -21,18 +22,19 @@
{
}
-MemoryRegion* RegionFactory::produce(MemoryArea::Space* pSpace,
- const sys::fs::detail::Address pVMAStart,
- size_t pSize)
+MemoryRegion* RegionFactory::produce(Space& pSpace, void* pVMAStart, size_t pSize)
{
MemoryRegion* result = Alloc::allocate();
- new (result) MemoryRegion(pSpace, pVMAStart, pSize);
+ new (result) MemoryRegion(pSpace,
+ static_cast<const MemoryRegion::Address>(pVMAStart),
+ pSize);
+ pSpace.addRegion(*result);
return result;
}
void RegionFactory::destruct(MemoryRegion* pRegion)
{
- pRegion->drift();
+ pRegion->parent()->removeRegion(*pRegion);
destroy(pRegion);
deallocate(pRegion);
}
diff --git a/lib/Support/Space.cpp b/lib/Support/Space.cpp
new file mode 100644
index 0000000..4024da1
--- /dev/null
+++ b/lib/Support/Space.cpp
@@ -0,0 +1,179 @@
+//===- Space.cpp ----------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/Space.h>
+#include <mcld/Support/FileHandle.h>
+#include <mcld/Support/MsgHandling.h>
+#include <cstdlib>
+#include <unistd.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// constant data
+static const off_t PageSize = getpagesize();
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+//
+// low address A page high address
+// |--------------------|------------------|
+// ^ page_offset ^ pFileOffset ^ page_boundary
+
+// Given a file offset, return the page offset.
+// return the first page boundary \b before pFileOffset
+inline static off_t page_offset(off_t pFileOffset)
+{ return pFileOffset & ~ (PageSize - 1); }
+
+// page_boundary - Given a file size, return the size to read integral pages.
+// return the first page boundary \b after pFileOffset
+inline static off_t page_boundary(off_t pFileOffset)
+{ return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
+
+inline static Space::Type policy(off_t pOffset, size_t pLength)
+{
+ const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
+ if (pLength < threshold)
+ return Space::ALLOCATED_ARRAY;
+ else
+ return Space::MMAPED;
+}
+
+//===----------------------------------------------------------------------===//
+// Space
+Space::Space()
+ : m_Data(NULL), m_StartOffset(0), m_Size(0),
+ m_RegionCount(0), m_Type(UNALLOCATED) {
+}
+
+Space::Space(Space::Type pType, void* pMemBuffer, size_t pSize)
+ : m_Data(static_cast<Address>(pMemBuffer)), m_StartOffset(0), m_Size(pSize),
+ m_RegionCount(0), m_Type(pType)
+{
+}
+
+Space::~Space()
+{
+ // do nothing. m_Data is deleted by @ref releaseSpace
+}
+
+Space* Space::createSpace(FileHandle& pHandler,
+ size_t pStart, size_t pSize)
+{
+ Type type;
+ void* memory;
+ Space* result = NULL;
+ size_t start, size = 0, total_offset;
+ switch(type = policy(pStart, pSize)) {
+ case ALLOCATED_ARRAY: {
+ // adjust total_offset, start and size
+ total_offset = pStart + pSize;
+ start = pStart;
+ if (total_offset > pHandler.size()) {
+ if (pHandler.isWritable()) {
+ size = pSize;
+ pHandler.truncate(total_offset);
+ }
+ else if (pHandler.size() > start)
+ size = pHandler.size() - start;
+ else {
+ // create a space out of a read-only file.
+ fatal(diag::err_cannot_read_small_file) << pHandler.path()
+ << pHandler.size()
+ << start << size;
+ }
+ }
+ else
+ size = pSize;
+
+ // malloc
+ memory = (void*)malloc(size);
+ if (!pHandler.read(memory, start, size))
+ error(diag::err_cannot_read_file) << pHandler.path() << start << size;
+
+ break;
+ }
+ case MMAPED: {
+ // adjust total_offset, start and size
+ total_offset = page_boundary(pStart + pSize);
+ start = page_offset(pStart);
+ if (total_offset > pHandler.size()) {
+ if (pHandler.isWritable()) {
+ size = page_boundary((pStart - start) + pSize);
+ pHandler.truncate(total_offset);
+ }
+ else if (pHandler.size() > start)
+ size = pHandler.size() - start;
+ else {
+ // create a space out of a read-only file.
+ fatal(diag::err_cannot_read_small_file) << pHandler.path()
+ << pHandler.size()
+ << start << size;
+ }
+ }
+ else
+ size = page_boundary((pStart - start) + pSize);
+
+ // mmap
+ if (!pHandler.mmap(memory, start, size))
+ error(diag::err_cannot_mmap_file) << pHandler.path() << start << size;
+
+ break;
+ }
+ default:
+ break;
+ } // end of switch
+
+ result = new Space(type, memory, size);
+ result->setStart(start);
+ return result;
+}
+
+void Space::releaseSpace(Space* pSpace, FileHandle& pHandler)
+{
+ if (NULL == pSpace)
+ return;
+
+ switch(pSpace->type()) {
+ case ALLOCATED_ARRAY:
+ free(pSpace->memory());
+ break;
+ case MMAPED:
+ if (!pHandler.munmap(pSpace->memory(), pSpace->size()))
+ error(diag::err_cannot_munmap_file) << pHandler.path();
+ break;
+ default: // external and unallocated memory buffers
+ break;
+ } // end of switch
+}
+
+void Space::syncSpace(Space* pSpace, FileHandle& pHandler)
+{
+ if (NULL == pSpace || !pHandler.isWritable())
+ return;
+
+ switch(pSpace->type()) {
+ case Space::ALLOCATED_ARRAY: {
+ if (!pHandler.write(pSpace->memory(),
+ pSpace->start(),
+ pSpace->size())) {
+ error(diag::err_cannot_write_file) << pHandler.path()
+ << pSpace->start()
+ << pSpace->size();
+ }
+ return;
+ }
+ case Space::MMAPED:
+ default: {
+ // system will eventually write bakc the memory after
+ // calling ::munmap
+ return;
+ }
+ } // end of switch
+}
+
diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp
new file mode 100644
index 0000000..5dfea36
--- /dev/null
+++ b/lib/Support/SystemUtils.cpp
@@ -0,0 +1,20 @@
+//===- SystemUtils.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/SystemUtils.h>
+
+using namespace mcld::sys;
+
+//===----------------------------------------------------------------------===//
+// Non-member functions
+#if defined(MCLD_ON_UNIX)
+#include "Unix/System.inc"
+#endif
+#if defined(MCLD_ON_WIN32)
+#include "Windows/System.inc"
+#endif
diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp
index 246cbe8..8bfa235 100644
--- a/lib/Support/TargetRegistry.cpp
+++ b/lib/Support/TargetRegistry.cpp
@@ -6,13 +6,11 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/TargetRegistry.h"
+#include <mcld/Support/TargetRegistry.h>
mcld::TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
-/* ** */
-
void mcld::TargetRegistry::RegisterTarget(mcld::Target &T)
{
s_TargetList.push_back(&T);
@@ -34,7 +32,7 @@
const mcld::Target *mcld::TargetRegistry::lookupTarget(const std::string &pTriple,
std::string &pError)
{
- const llvm::Target* target = llvm::TargetRegistry::lookupTarget( pTriple, pError );
+ const llvm::Target* target = llvm::TargetRegistry::lookupTarget(pTriple, pError);
if (!target)
return 0;
return lookupTarget( *target );
diff --git a/lib/Support/Unix/FileSystem.inc b/lib/Support/Unix/FileSystem.inc
index 6499d66..ce6d0df 100644
--- a/lib/Support/Unix/FileSystem.inc
+++ b/lib/Support/Unix/FileSystem.inc
@@ -9,6 +9,7 @@
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fcntl.h>
namespace mcld{
@@ -23,19 +24,29 @@
std::string assembly_extension = ".s";
std::string bitcode_extension = ".bc";
-size_t pread(int pFD, Address pBuf, size_t pCount, off_t pOffset)
+int open(const Path& pPath, int pOFlag)
{
- return ::pread(pFD, (void*) pBuf, pCount, pOffset);
+ return ::open(pPath.native().c_str(), pOFlag);
}
-size_t pwrite(int pFD, const Address pBuf, size_t pCount, off_t pOffset)
+int open(const Path& pPath, int pOFlag, int pPerm)
{
- return ::pwrite(pFD, (const void*) pBuf, pCount, pOffset);
+ return ::open(pPath.native().c_str(), pOFlag, pPerm);
}
-char *strerror(int errnum)
+ssize_t pread(int pFD, void* pBuf, size_t pCount, size_t pOffset)
{
- return ::strerror(errnum);
+ return ::pread(pFD, pBuf, pCount, pOffset);
+}
+
+ssize_t pwrite(int pFD, const void* pBuf, size_t pCount, size_t pOffset)
+{
+ return ::pwrite(pFD, pBuf, pCount, pOffset);
+}
+
+int ftruncate(int pFD, size_t pLength)
+{
+ return ::ftruncate(pFD, pLength);
}
} // namespace of detail
diff --git a/lib/Support/Unix/PathV3.inc b/lib/Support/Unix/PathV3.inc
index 2e8e6d0..68b0c36 100644
--- a/lib/Support/Unix/PathV3.inc
+++ b/lib/Support/Unix/PathV3.inc
@@ -282,7 +282,7 @@
{
if (pDir.m_Handler)
closedir(reinterpret_cast<DIR *>(pDir.m_Handler));
- pDir.m_Handler = NULL;
+ pDir.m_Handler = 0;
}
void get_pwd(std::string& pPWD)
diff --git a/lib/Support/Unix/System.inc b/lib/Support/Unix/System.inc
new file mode 100644
index 0000000..716aaa2
--- /dev/null
+++ b/lib/Support/Unix/System.inc
@@ -0,0 +1,24 @@
+//===- System.inc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+
+char *strerror(int errnum)
+{
+ return ::strerror(errnum);
+}
+
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/Windows/System.inc b/lib/Support/Windows/System.inc
new file mode 100644
index 0000000..bfd75ee
--- /dev/null
+++ b/lib/Support/Windows/System.inc
@@ -0,0 +1,19 @@
+//===- System.inc ---------------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace mcld{
+namespace sys{
+
+} // namespace of sys
+} // namespace of mcld
+
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
new file mode 100644
index 0000000..2453c2c
--- /dev/null
+++ b/lib/Support/raw_ostream.cpp
@@ -0,0 +1,95 @@
+//===- raw_ostream.cpp ----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Support/raw_ostream.h>
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// raw_ostream
+mcld::raw_fd_ostream::raw_fd_ostream(const char *pFilename,
+ std::string &pErrorInfo,
+ unsigned int pFlags,
+ const MCLDInfo* pLDInfo)
+ : llvm::raw_fd_ostream(pFilename, pErrorInfo, pFlags), m_pLDInfo(pLDInfo) {
+}
+
+mcld::raw_fd_ostream::raw_fd_ostream(int pFD,
+ bool pShouldClose,
+ bool pUnbuffered,
+ const MCLDInfo* pLDInfo)
+ : llvm::raw_fd_ostream(pFD, pShouldClose, pUnbuffered), m_pLDInfo(pLDInfo) {
+}
+
+mcld::raw_fd_ostream::~raw_fd_ostream()
+{
+}
+
+void mcld::raw_fd_ostream::setLDInfo(const MCLDInfo& pLDInfo)
+{
+ m_pLDInfo = &pLDInfo;
+}
+
+llvm::raw_ostream &
+mcld::raw_fd_ostream::changeColor(enum llvm::raw_ostream::Colors pColor,
+ bool pBold,
+ bool pBackground)
+{
+ if (!is_displayed())
+ return *this;
+ return llvm::raw_fd_ostream::changeColor(pColor, pBold, pBackground);
+}
+
+llvm::raw_ostream& mcld::raw_fd_ostream::resetColor()
+{
+ if (!is_displayed())
+ return *this;
+ return llvm::raw_fd_ostream::resetColor();
+}
+
+// FIXME: migrate to newer LLVM
+/**
+llvm::raw_ostream& mcld::raw_fd_ostream::reverseColor()
+{
+ if (!is_displayed())
+ return *this;
+ return llvm::raw_ostream::reverseColor();
+}
+**/
+
+bool mcld::raw_fd_ostream::is_displayed() const
+{
+ if (NULL == m_pLDInfo)
+ return llvm::raw_fd_ostream::is_displayed();
+
+ return m_pLDInfo->options().color();
+}
+
+//===----------------------------------------------------------------------===//
+// outs(), errs(), nulls()
+//===----------------------------------------------------------------------===//
+mcld::raw_fd_ostream& mcld::outs() {
+ // Set buffer settings to model stdout behavior.
+ // Delete the file descriptor when the program exists, forcing error
+ // detection. If you don't want this behavior, don't use outs().
+ static mcld::raw_fd_ostream S(STDOUT_FILENO, true, NULL);
+ return S;
+}
+
+mcld::raw_fd_ostream& mcld::errs() {
+ // Set standard error to be unbuffered by default.
+ static mcld::raw_fd_ostream S(STDERR_FILENO, false, true, NULL);
+ return S;
+}
+
+void mcld::InitializeOStreams(const MCLDInfo& pLDInfo)
+{
+ outs().setLDInfo(pLDInfo);
+ errs().setLDInfo(pLDInfo);
+}
+
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
index b833151..53e4795 100644
--- a/lib/Target/ARM/ARM.h
+++ b/lib/Target/ARM/ARM.h
@@ -9,15 +9,17 @@
#ifndef MCLD_ARM_H
#define MCLD_ARM_H
#include <string>
-#include "mcld/Target/TargetMachine.h"
+#include <mcld/Target/TargetMachine.h>
namespace mcld {
class TargetLDBackend;
extern mcld::Target TheARMTarget;
+extern mcld::Target TheThumbTarget;
TargetLDBackend *createARMLDBackend(const llvm::Target&, const std::string&);
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.cpp b/lib/Target/ARM/ARMAndroidSectLinker.cpp
deleted file mode 100644
index a704cfa..0000000
--- a/lib/Target/ARM/ARMAndroidSectLinker.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- ARMAndroidSectLinker.cpp -------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARMAndroidSectLinker.h"
-
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-ARMAndroidSectLinker::ARMAndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : AndroidSectLinker(pOption,
- pLDBackend) {
- MCLDInfo &info = pOption.info();
- // set up target-dependent constraints of attributes
- info.attrFactory().constraint().disableWholeArchive();
- info.attrFactory().constraint().disableAsNeeded();
- info.attrFactory().constraint().setSharedSystem();
-
- // set up the predefined attributes
- info.attrFactory().predefined().unsetWholeArchive();
- info.attrFactory().predefined().setDynamic();
-
-}
-
-ARMAndroidSectLinker::~ARMAndroidSectLinker()
-{
-}
-
diff --git a/lib/Target/ARM/ARMAndroidSectLinker.h b/lib/Target/ARM/ARMAndroidSectLinker.h
deleted file mode 100644
index 8a47a94..0000000
--- a/lib/Target/ARM/ARMAndroidSectLinker.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//===- ARMAndroidSectLinker.h ---------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ARM_ANDROIDSECTLINKER_H
-#define ARM_ANDROIDSECTLINKER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/Target/AndroidSectLinker.h>
-
-namespace mcld
-{
-
-class MCLDInfo;
-
-/** \class ARMAndroidSectLinker
- * \brief ARMAndroidSectLinker sets up the environment for linking.
- *
- * \see
- * \author Anders Cheng <[email protected]>
- */
-class ARMAndroidSectLinker : public AndroidSectLinker
-{
-public:
- ARMAndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- ~ARMAndroidSectLinker();
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/lib/Target/ARM/ARMDiagnostic.cpp b/lib/Target/ARM/ARMDiagnostic.cpp
new file mode 100644
index 0000000..1ecf7df
--- /dev/null
+++ b/lib/Target/ARM/ARMDiagnostic.cpp
@@ -0,0 +1,39 @@
+//===- ARMDiagnostic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/DWARFLineInfo.h>
+#include "ARM.h"
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// ARMDiagnostic
+
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createARMDiagnostic - the help function to create corresponding ARMDiagnostic
+//
+DiagnosticLineInfo* createARMDiagLineInfo(const llvm::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//==========================
+// InitializeARMDiagnostic
+extern "C" void LLVMInitializeARMDiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheARMTarget, createARMDiagLineInfo);
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheThumbTarget, createARMDiagLineInfo);
+}
+
diff --git a/lib/Target/ARM/ARMELFArchiveReader.h b/lib/Target/ARM/ARMELFArchiveReader.h
index b60a12d..2fa9ce2 100644
--- a/lib/Target/ARM/ARMELFArchiveReader.h
+++ b/lib/Target/ARM/ARMELFArchiveReader.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef ARMELFARCHIVEREADER_H
-#define ARMELFARCHIVEREADER_H
+#ifndef MCLD_ARM_ELF_ARCHIVE_READER_H
+#define MCLD_ARM_ELF_ARCHIVE_READER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/lib/Target/ARM/ARMELFSectLinker.h b/lib/Target/ARM/ARMELFSectLinker.h
index 7493d59..ab626b9 100644
--- a/lib/Target/ARM/ARMELFSectLinker.h
+++ b/lib/Target/ARM/ARMELFSectLinker.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef ARM_ELFSECTLINKER_H
-#define ARM_ELFSECTLINKER_H
+#ifndef ARM_ELF_SECTION_LINKER_H
+#define ARM_ELF_SECTION_LINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h
index 1bf82f5..f42b940 100644
--- a/lib/Target/ARM/ARMFixupKinds.h
+++ b/lib/Target/ARM/ARMFixupKinds.h
@@ -41,9 +41,9 @@
// instruction.
fixup_t2_adr_pcrel_12,
// fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch
- // instructions.
+ // instructions.
fixup_arm_condbranch,
- // fixup_arm_uncondbranch - 24-bit PC relative relocation for
+ // fixup_arm_uncondbranch - 24-bit PC relative relocation for
// branch instructions. (unconditional)
fixup_arm_uncondbranch,
// fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct
diff --git a/lib/Target/ARM/ARMGOT.cpp b/lib/Target/ARM/ARMGOT.cpp
index 37d8e6b..7430203 100644
--- a/lib/Target/ARM/ARMGOT.cpp
+++ b/lib/Target/ARM/ARMGOT.cpp
@@ -9,7 +9,7 @@
#include "ARMGOT.h"
#include <mcld/LD/LDFileFormat.h>
#include <mcld/Support/MemoryRegion.h>
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -33,7 +33,7 @@
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
+ fatal(diag::fail_allocate_memory) << "GOT0";
m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
}
@@ -43,9 +43,7 @@
iterator ie = m_SectionData.end();
for (int i = 1; i < ARMGOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
-
+ assert((it != ie) && "Generation of GOT0 entries is incomplete!");
++it;
}
@@ -69,7 +67,7 @@
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + ARMGOTEntrySize);
}
@@ -82,7 +80,7 @@
got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
if (!got_entry)
- llvm::report_fatal_error("Allocating new memory for GOT failed!");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + getEntrySize());
@@ -182,3 +180,4 @@
}
return result;
}
+
diff --git a/lib/Target/ARM/ARMGOT.h b/lib/Target/ARM/ARMGOT.h
index 4667421..90f0f53 100644
--- a/lib/Target/ARM/ARMGOT.h
+++ b/lib/Target/ARM/ARMGOT.h
@@ -89,3 +89,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp
index fe57fd6..e0f5dcf 100644
--- a/lib/Target/ARM/ARMLDBackend.cpp
+++ b/lib/Target/ARM/ARMLDBackend.cpp
@@ -9,7 +9,6 @@
#include <llvm/ADT/Triple.h>
#include <llvm/ADT/Twine.h>
#include <llvm/Support/ELF.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/SectionMap.h>
#include <mcld/MC/MCLDInfo.h>
@@ -17,6 +16,7 @@
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCRegionFragment.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <cstring>
@@ -42,17 +42,17 @@
ARMGNULDBackend::~ARMGNULDBackend()
{
- if (m_pRelocFactory)
+ if (NULL != m_pRelocFactory)
delete m_pRelocFactory;
- if(m_pGOT)
+ if (NULL != m_pGOT)
delete m_pGOT;
- if(m_pPLT)
+ if (NULL != m_pPLT)
delete m_pPLT;
- if(m_pRelDyn)
+ if (NULL != m_pRelDyn)
delete m_pRelDyn;
- if(m_pRelPLT)
+ if (NULL != m_pRelPLT)
delete m_pRelPLT;
- if(m_pDynamic)
+ if (NULL != m_pDynamic)
delete m_pDynamic;
}
@@ -85,12 +85,12 @@
// FIXME: Currently we set exidx and extab to "Exception" and directly emit
// them from input
m_pEXIDX = &pLinker.getOrCreateOutputSectHdr(".ARM.exidx",
- LDFileFormat::Exception,
+ LDFileFormat::Target,
llvm::ELF::SHT_ARM_EXIDX,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_LINK_ORDER,
bitclass() / 8);
m_pEXTAB = &pLinker.getOrCreateOutputSectHdr(".ARM.extab",
- LDFileFormat::Exception,
+ LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC,
0x1);
@@ -101,7 +101,7 @@
0x1);
}
-void ARMGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+void ARMGNULDBackend::initTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
@@ -122,7 +122,7 @@
MCLinker& pLinker)
{
// when building shared object, the .got section is must.
- if(pOutput.type() == Output::DynObj && (NULL == m_pGOT)) {
+ if (pOutput.type() == Output::DynObj && (NULL == m_pGOT)) {
createARMGOT(pLinker, pOutput);
}
}
@@ -131,11 +131,7 @@
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // emit program headers
- if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
- emitProgramHdrs(pLinker.getLDInfo().output());
-
- ELFFileFormat *file_format = getOutputFormat(pOutput);
+ const ELFFileFormat *file_format = getOutputFormat(pOutput);
// apply PLT
if (file_format->hasPLT()) {
@@ -177,11 +173,6 @@
return *m_pDynamic;
}
-bool ARMGNULDBackend::isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const
-{
- return (pOutput.type() == Output::DynObj);
-}
-
void ARMGNULDBackend::createARMGOT(MCLinker& pLinker, const Output& pOutput)
{
// get .got LDSection and create MCSectionData
@@ -191,7 +182,7 @@
m_pGOT = new ARMGOT(got, pLinker.getOrCreateSectData(got));
// define symbol _GLOBAL_OFFSET_TABLE_ when .got create
- if( m_pGOTSymbol != NULL ) {
+ if (m_pGOTSymbol != NULL) {
pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
false,
@@ -249,62 +240,73 @@
8);
}
-ELFFileFormat* ARMGNULDBackend::getOutputFormat(const Output& pOutput) const
+void ARMGNULDBackend::addCopyReloc(ResolveInfo& pSym)
{
- switch (pOutput.type()) {
- case Output::DynObj:
- return getDynObjFileFormat();
- case Output::Exec:
- return getExecFileFormat();
- // FIXME: We do not support building .o now
- case Output::Object:
- default:
- llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
- llvm::Twine(pOutput.type()));
- return NULL;
+ bool exist;
+ Relocation& rel_entry = *m_pRelDyn->getEntry(pSym, false, exist);
+ rel_entry.setType(llvm::ELF::R_ARM_COPY);
+ assert(pSym.outSymbol()->hasFragRef());
+ rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
+ rel_entry.setSymInfo(&pSym);
+}
+
+LDSymbol& ARMGNULDBackend::defineSymbolforCopyReloc(MCLinker& pLinker,
+ const ResolveInfo& pSym)
+{
+ // For a symbol needing copy relocation, define a copy symbol in the BSS
+ // section and all other reference to this symbol should refer to this
+ // copy.
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == pSym.type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
}
-}
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
-bool ARMGNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- return (Output::DynObj == pOutput.type() &&
- ResolveInfo::Function == pSym.type() &&
- (pSym.isDyn() || pSym.isUndef() ||
- isSymbolPreemptible(pSym, pLDInfo, pOutput)));
-}
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(
+ *bss_sect_hdr);
-bool ARMGNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const
-{
- if(pSym.isUndef() && (Output::Exec == pOutput.type()))
- return false;
- if(pSym.isAbsolute())
- return false;
- if(Output::DynObj == pOutput.type() && isAbsReloc)
- return true;
- if(pSym.isDyn() || pSym.isUndef())
- return true;
+ // Determine the alignment by the symbol value
+ // FIXME: here we use the largest alignment
+ uint32_t addralign = bitclass() / 8;
- return false;
-}
+ // allocate space in BSS for the copy symbol
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, pSym.size());
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ addralign);
+ bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
-bool ARMGNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- if(pSym.other() != ResolveInfo::Default)
- return false;
+ // change symbol binding to Global if it's a weak symbol
+ ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
+ if (binding == ResolveInfo::Weak)
+ binding = ResolveInfo::Global;
- if(Output::DynObj != pOutput.type())
- return false;
+ // Define the copy symbol in the bss section and resolve it
+ LDSymbol* cpy_sym = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ pSym.name(),
+ false,
+ (ResolveInfo::Type)pSym.type(),
+ ResolveInfo::Define,
+ binding,
+ pSym.size(), // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*frag, 0x0),
+ (ResolveInfo::Visibility)pSym.other());
- if(pLDInfo.options().Bsymbolic())
- return false;
-
- return true;
+ return *cpy_sym;
}
/// checkValidReloc - When we attempt to generate a dynamic relocation for
@@ -314,7 +316,7 @@
const Output& pOutput) const
{
// If not building a PIC object, no relocation type is invalid
- if (!isPIC(pLDInfo, pOutput))
+ if (!isOutputPIC(pOutput, pLDInfo))
return;
switch(pReloc.type()) {
@@ -331,13 +333,8 @@
break;
default:
- llvm::report_fatal_error(llvm::Twine("Attempt to generate unsupported") +
- llvm::Twine(" relocation type ") +
- llvm::Twine((int)pReloc.type()) +
- llvm::Twine(" for symbol '") +
- llvm::Twine(pReloc.symInfo()->name()) +
- llvm::Twine("', recompile with -fPIC")
- );
+ error(diag::non_pic_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
break;
}
}
@@ -347,7 +344,7 @@
const Layout& pLayout) const
{
// Update value keep in addend if we meet a section symbol
- if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ if (pReloc.symInfo()->type() == ResolveInfo::Section) {
pReloc.setAddend(pLayout.getOutputOffset(
*pInputSym.fragRef()) + pReloc.addend());
}
@@ -368,6 +365,8 @@
// Set R_ARM_TARGET1 to R_ARM_ABS32
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET1 should be set by option --target1-rel
+ // or --target1-rel
case llvm::ELF::R_ARM_TARGET1:
pReloc.setType(llvm::ELF::R_ARM_ABS32);
case llvm::ELF::R_ARM_ABS32:
@@ -375,13 +374,13 @@
// If buiding PIC object (shared library or PIC executable),
// a dynamic relocations with RELATIVE type to this location is needed.
// Reserve an entry in .rel.dyn
- if(isPIC(pLDInfo, pOutput)) {
- // create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (isOutputPIC(pOutput, pLDInfo)) {
+ //create .rel.dyn section if not exist
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ rsym->setReserved(rsym->reserved() | ReserveRel);
}
return;
}
@@ -395,53 +394,41 @@
case llvm::ELF::R_ARM_MOVT_ABS:
case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
case llvm::ELF::R_ARM_THM_MOVT_ABS: {
- // Update value keep in relocation place if we meet a section symbol
- if(rsym->type() == ResolveInfo::Section) {
- pReloc.target() = pLinker.getLayout().getOutputOffset(
- *pInputSym.fragRef()) + pReloc.target();
- }
-
- // If building PIC object (shared library or PIC executable),
- // a dynamic relocation for this location is needed.
- // Reserve an entry in .rel.dyn
- if(isPIC(pLDInfo, pOutput)) {
- checkValidReloc(pReloc, pLDInfo, pOutput);
- // create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
- createARMRelDyn(pLinker, pOutput);
- m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ // PIC code should not contain these kinds of relocation
+ if (isOutputPIC(pOutput, pLDInfo)) {
+ error(diag::non_pic_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
}
return;
}
case llvm::ELF::R_ARM_GOTOFF32:
case llvm::ELF::R_ARM_GOTOFF12: {
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
return;
}
// Set R_ARM_TARGET2 to R_ARM_GOT_PREL
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET2 should be set by option --target2
case llvm::ELF::R_ARM_TARGET2:
pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
case llvm::ELF::R_ARM_GOT_BREL:
case llvm::ELF::R_ARM_GOT_PREL: {
// A GOT entry is needed for these relocation type.
// return if we already create GOT for this symbol
- if(rsym->reserved() & 0x6u)
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
return;
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
m_pGOT->reserveEntry();
// If building PIC object, a dynamic relocation with
// type RELATIVE is needed to relocate this GOT entry.
// Reserve an entry in .rel.dyn
- if(isPIC(pLDInfo, pOutput)) {
+ if (isOutputPIC(pOutput, pLDInfo)) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set GOTRel bit
@@ -456,12 +443,9 @@
case llvm::ELF::R_ARM_BASE_PREL: {
// FIXME: Currently we only support R_ARM_BASE_PREL against
// symbol _GLOBAL_OFFSET_TABLE_
- if(rsym != m_pGOTSymbol->resolveInfo()) {
- llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
- llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
- llvm::Twine(rsym->name()) +
- llvm::Twine(".'"));
- }
+ if (rsym != m_pGOTSymbol->resolveInfo())
+ fatal(diag::base_relocation) << (int)pReloc.type() << rsym->name()
+ << "[email protected]";
return;
}
case llvm::ELF::R_ARM_COPY:
@@ -470,9 +454,7 @@
case llvm::ELF::R_ARM_RELATIVE: {
// These are relocation type for dynamic linker, shold not
// appear in object file.
- llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
- llvm::Twine((int)pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
}
default: {
@@ -494,6 +476,8 @@
// Set R_ARM_TARGET1 to R_ARM_ABS32
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET1 should be set by option --target1-rel
+ // or --target1-rel
case llvm::ELF::R_ARM_TARGET1:
pReloc.setType(llvm::ELF::R_ARM_ABS32);
case llvm::ELF::R_ARM_ABS32:
@@ -509,14 +493,14 @@
case llvm::ELF::R_ARM_ABS32_NOI: {
// Absolute relocation type, symbol may needs PLT entry or
// dynamic relocation entry
- if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ if (symbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
// create plt for this symbol if it does not have one
- if(!(rsym->reserved() & 0x8u)){
+ if (!(rsym->reserved() & ReservePLT)){
// Create .got section if it doesn't exist
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createARMPLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -525,19 +509,27 @@
m_pPLT->reserveEntry();
m_pRelPLT->reserveEntry(*m_pRelocFactory);
// set PLT bit
- rsym->setReserved(rsym->reserved() | 0x8u);
+ rsym->setReserved(rsym->reserved() | ReservePLT);
}
}
- if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
- checkValidReloc(pReloc, pLDInfo, pOutput);
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, true)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
}
return;
}
@@ -545,19 +537,20 @@
case llvm::ELF::R_ARM_GOTOFF32:
case llvm::ELF::R_ARM_GOTOFF12: {
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
return;
}
case llvm::ELF::R_ARM_BASE_PREL:
- // FIXME: Currently we only support R_ARM_BASE_PREL against
+ case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
+ case llvm::ELF::R_ARM_THM_MOVW_BREL:
+ case llvm::ELF::R_ARM_THM_MOVT_BREL:
+ // FIXME: Currently we only support these relocations against
// symbol _GLOBAL_OFFSET_TABLE_
- if(rsym != m_pGOTSymbol->resolveInfo()) {
- llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
- llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
- llvm::Twine(rsym->name()) +
- llvm::Twine(".'"));
+ if (rsym != m_pGOTSymbol->resolveInfo()) {
+ fatal(diag::base_relocation) << (int)pReloc.type() << rsym->name()
+ << "[email protected]";
}
case llvm::ELF::R_ARM_REL32:
case llvm::ELF::R_ARM_LDR_PC_G0:
@@ -599,19 +592,25 @@
case llvm::ELF::R_ARM_LDC_SB_G2:
case llvm::ELF::R_ARM_MOVW_BREL_NC:
case llvm::ELF::R_ARM_MOVT_BREL:
- case llvm::ELF::R_ARM_MOVW_BREL:
- case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
- case llvm::ELF::R_ARM_THM_MOVT_BREL:
- case llvm::ELF::R_ARM_THM_MOVW_BREL: {
+ case llvm::ELF::R_ARM_MOVW_BREL: {
// Relative addressing relocation, may needs dynamic relocation
- if(isSymbolNeedsDynRel(*rsym, pOutput, false)) {
- checkValidReloc(pReloc, pLDInfo, pOutput);
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, false)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | 0x1u);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ checkValidReloc(pReloc, pLDInfo, pOutput);
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
}
return;
}
@@ -631,22 +630,22 @@
// A PLT entry is needed when building shared library
// return if we already create plt for this symbol
- if(rsym->reserved() & 0x8u)
+ if (rsym->reserved() & ReservePLT)
return;
// if symbol is defined in the ouput file and it's not
// preemptible, no need plt
- if(rsym->isDefine() && !rsym->isDyn() &&
+ if (rsym->isDefine() && !rsym->isDyn() &&
!isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
return;
}
// Create .got section if it doesn't exist
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createARMPLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -655,12 +654,13 @@
m_pPLT->reserveEntry();
m_pRelPLT->reserveEntry(*m_pRelocFactory);
// set PLT bit
- rsym->setReserved(rsym->reserved() | 0x8u);
+ rsym->setReserved(rsym->reserved() | ReservePLT);
return;
}
// Set R_ARM_TARGET2 to R_ARM_GOT_PREL
// Ref: GNU gold 1.11 arm.cc, line 9892
+ // FIXME: R_ARM_TARGET2 should be set by option --target2
case llvm::ELF::R_ARM_TARGET2:
pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
case llvm::ELF::R_ARM_GOT_BREL:
@@ -668,25 +668,25 @@
case llvm::ELF::R_ARM_GOT_PREL: {
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if(rsym->reserved() & 0x6u)
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
return;
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createARMGOT(pLinker, pOutput);
m_pGOT->reserveEntry();
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rel.dyn
- if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ if (Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createARMRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set GOTRel bit
- rsym->setReserved(rsym->reserved() | 0x4u);
+ rsym->setReserved(rsym->reserved() | GOTRel);
return;
}
// set GOT bit
- rsym->setReserved(rsym->reserved() | 0x2u);
+ rsym->setReserved(rsym->reserved() | ReserveGOT);
return;
}
@@ -696,9 +696,7 @@
case llvm::ELF::R_ARM_RELATIVE: {
// These are relocation type for dynamic linker, shold not
// appear in object file.
- llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
- llvm::Twine((int)pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
}
default: {
@@ -711,12 +709,21 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput)
+ const Output& pOutput,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) {
+ if (rsym->isLocal()) {
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+ }
+ return;
+ }
+
// Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
// entries should be created.
// FIXME: Below judgements concern only .so is generated as output
@@ -724,14 +731,14 @@
// A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
// is needed
- if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
- if(rsym == m_pGOTSymbol->resolveInfo()) {
+ if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
+ if (rsym == m_pGOTSymbol->resolveInfo()) {
createARMGOT(pLinker, pOutput);
}
}
// rsym is local
- if(rsym->isLocal())
+ if (rsym->isLocal())
scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
// rsym is external
@@ -743,25 +750,54 @@
uint64_t ARMGNULDBackend::emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const
{
assert(pRegion.size() && "Size of MemoryRegion is zero!");
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
- if (&pSection == m_pAttributes) {
- // FIXME: Currently Emitting .ARM.attributes directly from the input file.
+ if (&pSection == m_pAttributes ||
+ &pSection == m_pEXIDX ||
+ &pSection == m_pEXTAB) {
+ // FIXME: Currently Emitting .ARM.attributes, .ARM.exidx, and .ARM.extab
+ // directly from the input file.
const llvm::MCSectionData* sect_data = pSection.getSectionData();
- assert(sect_data &&
- "Emit .ARM.attribute failed, MCSectionData doesn't exist!");
-
- uint8_t* start =
- llvm::cast<MCRegionFragment>(
- sect_data->getFragmentList().front()).getRegion().start();
-
- memcpy(pRegion.start(), start, pRegion.size());
+ llvm::MCSectionData::const_iterator frag_iter, frag_end = sect_data->end();
+ uint8_t* out_offset = pRegion.start();
+ for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) {
+ size_t size = computeFragmentSize(pLayout, *frag_iter);
+ switch(frag_iter->getKind()) {
+ case llvm::MCFragment::FT_Region: {
+ const MCRegionFragment& region_frag =
+ llvm::cast<MCRegionFragment>(*frag_iter);
+ const uint8_t* start = region_frag.getRegion().start();
+ memcpy(out_offset, start, size);
+ break;
+ }
+ case llvm::MCFragment::FT_Align: {
+ llvm::MCAlignFragment& align_frag =
+ llvm::cast<llvm::MCAlignFragment>(*frag_iter);
+ uint64_t count = size / align_frag.getValueSize();
+ switch (align_frag.getValueSize()) {
+ case 1u:
+ std::memset(out_offset, align_frag.getValue(), count);
+ break;
+ default:
+ llvm::report_fatal_error(
+ "unsupported value size for align fragment emission yet.\n");
+ break;
+ } // end switch
+ break;
+ }
+ default:
+ llvm::report_fatal_error("unsupported fragment type.\n");
+ break;
+ } // end switch
+ out_offset += size;
+ } // end for
return pRegion.size();
- }
+ } // end if
if (&pSection == &(file_format->getPLT())) {
assert(NULL != m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
@@ -774,116 +810,15 @@
uint64_t result = m_pGOT->emit(pRegion);
return result;
}
-
- llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
- pSection.name() +
- llvm::Twine("'.\n"));
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "[email protected]";
return 0x0;
}
/// finalizeSymbol - finalize the symbol value
-/// If the symbol's reserved field is not zero, MCLinker will call back this
-/// function to ask the final value of the symbol
-bool ARMGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+bool ARMGNULDBackend::finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
- return false;
-}
-
-/// allocateCommonSymbols - allocate common symbols in the corresponding
-/// sections.
-/// @refer Google gold linker: common.cc: 214
-bool
-ARMGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
-{
- SymbolCategory& symbol_list = pLinker.getOutputSymbols();
-
- if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
- return true;
-
- // addralign := max value of all common symbols
- uint64_t addralign = 0x0;
-
- // Due to the visibility, some common symbols may be forcefully local.
- SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
- }
-
- // global common symbols.
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
-
- // FIXME: If the order of common symbols is defined, then sort common symbols
- // com_sym = symbol_list.commonBegin();
- // std::sort(com_sym, com_end, some kind of order);
-
- // get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
- ".tbss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
- else {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
-
- // get or create corresponding BSS MCSectionData
- assert(NULL != bss_sect_hdr);
- llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
-
- // allocate all common symbols
- uint64_t offset = bss_sect_hdr->size();
-
- // allocate all local common symbols
- com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
- }
-
- // allocate all global common symbols
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
-
- bss_sect_hdr->setSize(offset);
- symbol_list.changeCommonsToGlobal();
return true;
}
@@ -910,9 +845,20 @@
llvm::MCSectionData& sect_data = pLinker.getOrCreateSectData(pInputSectHdr);
- new MCRegionFragment(*region, §_data);
+ llvm::MCFragment* frag = NULL;
+ if (NULL == region) {
+ // If the input section's size is zero, we got a NULL region.
+ // use a virtual fill fragment
+ frag = new llvm::MCFillFragment(0x0, 0, 0);
+ }
+ else
+ frag = new MCRegionFragment(*region);
- out_sect.setSize(out_sect.size() + pInputSectHdr.size());
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ sect_data,
+ pInputSectHdr.align());
+
+ out_sect.setSize(out_sect.size() + size);
return true;
}
@@ -966,16 +912,25 @@
unsigned int
ARMGNULDBackend::getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
- if (&pSectHdr == &file_format->getGOT())
+ if (&pSectHdr == &file_format->getGOT()) {
+ if (pInfo.options().hasNow())
+ return SHO_RELRO_LAST;
return SHO_DATA;
+ }
if (&pSectHdr == &file_format->getPLT())
return SHO_PLT;
+ if (&pSectHdr == m_pEXIDX || &pSectHdr == m_pEXTAB) {
+ // put ARM.exidx and ARM.extab in the same order of .eh_frame
+ return SHO_EXCEPTION;
+ }
+
return SHO_UNDEFINED;
}
@@ -1014,4 +969,6 @@
extern "C" void LLVMInitializeARMLDBackend() {
// Register the linker backend
mcld::TargetRegistry::RegisterTargetLDBackend(TheARMTarget, createARMLDBackend);
+ mcld::TargetRegistry::RegisterTargetLDBackend(TheThumbTarget, createARMLDBackend);
}
+
diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h
index 27acdf1..3e46cd7 100644
--- a/lib/Target/ARM/ARMLDBackend.h
+++ b/lib/Target/ARM/ARMLDBackend.h
@@ -86,7 +86,7 @@
void initTargetSections(MCLinker& pLinker);
/// initTargetSymbols - initialize target dependent symbols in output.
- void initTargetSymbols(MCLinker& pLinker);
+ void initTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// initRelocFactory - create and initialize RelocationFactory
bool initRelocFactory(const MCLinker& pLinker);
@@ -104,7 +104,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput);
+ const Output& pOutput,
+ const LDSection& pSection);
uint32_t machine() const
{ return llvm::ELF::EM_ARM; }
@@ -127,6 +128,9 @@
unsigned int bitclass() const
{ return 32; }
+ uint64_t defaultTextSegmentAddr() const
+ { return 0x8000; }
+
/// doPreLayout - Backend can do any needed modification before layout
void doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
@@ -160,11 +164,13 @@
/// @param pOutput - the output file
/// @param pSection - the given LDSection
/// @param pInfo - all options in the command line.
+ /// @param pLayout - for comouting the size of fragment
/// @param pRegion - the region to write out data
/// @return the size of the table in the file.
uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const;
ARMGOT& getGOT();
@@ -185,29 +191,17 @@
/// getTargetSectionOrder - compute the layout order of ARM target sections
unsigned int getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
- /// finalizeSymbol - finalize the symbol value
- /// If the symbol's reserved field is not zero, MCLinker will call back this
- /// function to ask the final value of the symbol
- bool finalizeSymbol(LDSymbol& pSymbol) const;
-
- /// allocateCommonSymbols - allocate common symbols in the corresponding
- /// sections.
- bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
+ /// finalizeTargetSymbols - finalize the symbol value
+ bool finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// readSection - read target dependent sections
bool readSection(Input& pInput,
MCLinker& pLinker,
LDSection& pInputSectHdr);
-public:
- bool isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
-
- bool isPIC(const MCLDInfo& pLDInfo, const Output& pOutput) const;
-
private:
void scanLocalReloc(Relocation& pReloc,
const LDSymbol& pInputSym,
@@ -221,19 +215,20 @@
const MCLDInfo& pLDInfo,
const Output& pOutput);
- bool isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
-
- bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const;
-
-
void checkValidReloc(Relocation& pReloc,
const MCLDInfo& pLDInfo,
const Output& pOutput) const;
+ /// addCopyReloc - add a copy relocation into .rel.dyn for pSym
+ /// @param pSym - A resolved copy symbol that defined in BSS section
+ void addCopyReloc(ResolveInfo& pSym);
+
+ /// defineSymbolforCopyReloc - allocate a space in BSS section and
+ /// and force define the copy of pSym to BSS section
+ /// @return the output LDSymbol of the copy symbol
+ LDSymbol& defineSymbolforCopyReloc(MCLinker& pLinker,
+ const ResolveInfo& pSym);
+
/// updateAddend - update addend value of the relocation if the
/// the target symbol is a section symbol. Addend is the offset
/// in the section. This value should be updated after section
@@ -251,8 +246,6 @@
void createARMRelDyn(MCLinker& pLinker, const Output& pOutput);
- ELFFileFormat* getOutputFormat(const Output& pOutput) const;
-
private:
RelocationFactory* m_pRelocFactory;
ARMGOT* m_pGOT;
@@ -294,3 +287,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMPLT.cpp b/lib/Target/ARM/ARMPLT.cpp
index b3461d0..5528ef7 100644
--- a/lib/Target/ARM/ARMPLT.cpp
+++ b/lib/Target/ARM/ARMPLT.cpp
@@ -9,8 +9,8 @@
#include "ARMGOT.h"
#include "ARMPLT.h"
#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -65,7 +65,7 @@
plt1_entry = new (std::nothrow) ARMPLT1(&m_SectionData);
if (!plt1_entry)
- llvm::report_fatal_error("Allocating new memory for ARMPLT1 failed!");
+ fatal(diag::fail_allocate_memory) << "ARMPLT1";
m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
@@ -167,7 +167,7 @@
data = static_cast<uint32_t*>(malloc(plt0->getEntrySize()));
if (!data)
- llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+ fatal(diag::fail_allocate_memory) << "plt0";
memcpy(data, arm_plt0, plt0->getEntrySize());
data[4] = offset;
@@ -204,7 +204,7 @@
Out = static_cast<uint32_t*>(malloc(plt1->getEntrySize()));
if (!Out)
- llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+ fatal(diag::fail_allocate_memory) << "plt1";
// Offset is the distance between the last PLT entry and the associated
// GOT entry.
@@ -247,3 +247,4 @@
}
return result;
}
+
diff --git a/lib/Target/ARM/ARMPLT.h b/lib/Target/ARM/ARMPLT.h
index 11d0bd0..f55aaa3 100644
--- a/lib/Target/ARM/ARMPLT.h
+++ b/lib/Target/ARM/ARMPLT.h
@@ -84,3 +84,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFactory.cpp b/lib/Target/ARM/ARMRelocationFactory.cpp
index 2763b3b..4911658 100644
--- a/lib/Target/ARM/ARMRelocationFactory.cpp
+++ b/lib/Target/ARM/ARMRelocationFactory.cpp
@@ -8,11 +8,12 @@
//===--------------------------------------------------------------------===//
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/ELF.h>
+#include <llvm/Support/Host.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/Layout.h>
+#include <mcld/Support/MsgHandling.h>
#include "ARMRelocationFactory.h"
#include "ARMRelocationFunctions.h"
@@ -38,10 +39,8 @@
{
Relocation::Type type = pRelocation.type();
if (type > 130) { // 131-255 doesn't noted in ARM spec
- llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
- "To symbol `") +
- pRelocation.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)type
+ << pRelocation.symInfo()->name();
return;
}
@@ -70,29 +69,18 @@
return;
}
if (Overflow == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' causes overflow. on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_overflow) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
-
if (BadReloc == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' encounters unexpected opcode. "
- "on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_badreloc) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
if (Unsupport == result) {
- llvm::report_fatal_error(llvm::Twine("Encounter unsupported relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ fatal(diag::unsupported_relocation) << type
+ << "[email protected]";
return;
}
}
@@ -106,7 +94,7 @@
// Set thumb bit if
// - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
RelocationFactory::DWord thumbBit =
- ((pReloc.symInfo()->desc() != ResolveInfo::Undefined) &&
+ ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
(pReloc.symInfo()->type() == ResolveInfo::Function) &&
((pReloc.symValue() & 0x1) != 0))?
1:0;
@@ -144,11 +132,11 @@
const ARMRelocationFactory& pFactory)
{
// if symbol is dynamic or undefine or preemptible
- if(pSym.isDyn() ||
- pSym.isUndef() ||
- pFactory.getTarget().isSymbolPreemptible(pSym,
- pLDInfo,
- pLDInfo.output()))
+ if (pSym.isDyn() ||
+ pSym.isUndef() ||
+ pFactory.getTarget().isSymbolPreemptible(pSym,
+ pLDInfo,
+ pLDInfo.output()))
return false;
return true;
}
@@ -176,7 +164,7 @@
Relocation& rel_entry =
*ld_backend.getRelDyn().getEntry(*rsym, true, exist);
assert(!exist && "GOT entry not exist, but DynRel entry exist!");
- if( rsym->isLocal() ||
+ if ( rsym->isLocal() ||
helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
// Initialize got entry to target symbol address
got_entry.setContent(pReloc.symValue());
@@ -192,7 +180,7 @@
rel_entry.targetRef().assign(got_entry);
}
else {
- llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "GOT";
}
}
return got_entry;
@@ -239,7 +227,7 @@
rel_entry.setSymInfo(rsym);
}
else {
- llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "PLT";
}
}
return plt_entry;
@@ -279,7 +267,7 @@
rel_entry.setType(pType);
rel_entry.targetRef() = pReloc.targetRef();
- if(pType == llvm::ELF::R_ARM_RELATIVE)
+ if (pType == llvm::ELF::R_ARM_RELATIVE)
rel_entry.setSymInfo(0);
else
rel_entry.setSymInfo(rsym);
@@ -307,13 +295,17 @@
static ARMRelocationFactory::DWord
helper_extract_thumb_movw_movt_addend(ARMRelocationFactory::DWord pTarget)
{
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. We'd better have a thumb instruction type.
+ // Consider the endianness problem, get the target data value from lower
+ // and upper 16 bits
+ ARMRelocationFactory::DWord val =
+ (*(reinterpret_cast<uint16_t*>(&pTarget)) << 16) |
+ *(reinterpret_cast<uint16_t*>(&pTarget) + 1);
+
// imm16: [19-16][26][14-12][7-0]
- return helper_sign_extend((((pTarget >> 4) & 0xf000U) |
- ((pTarget >> 15) & 0x0800U) |
- ((pTarget >> 4) & 0x0700U) |
- (pTarget & 0x00ffU)),
+ return helper_sign_extend((((val >> 4) & 0xf000U) |
+ ((val >> 15) & 0x0800U) |
+ ((val >> 4) & 0x0700U) |
+ (val & 0x00ffU)),
16);
}
@@ -321,15 +313,19 @@
helper_insert_val_thumb_movw_movt_inst(ARMRelocationFactory::DWord pTarget,
ARMRelocationFactory::DWord pImm)
{
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. We'd better have a thumb instruction type.
+ ARMRelocationFactory::DWord val;
// imm16: [19-16][26][14-12][7-0]
pTarget &= 0xfbf08f00U;
pTarget |= (pImm & 0xf000U) << 4;
pTarget |= (pImm & 0x0800U) << 15;
pTarget |= (pImm & 0x0700U) << 4;
pTarget |= (pImm & 0x00ffU);
- return pTarget;
+
+ // Consider the endianness problem, write back data from lower and
+ // upper 16 bits
+ val = (*(reinterpret_cast<uint16_t*>(&pTarget)) << 16) |
+ *(reinterpret_cast<uint16_t*>(&pTarget) + 1);
+ return val;
}
static ARMRelocationFactory::DWord
@@ -408,13 +404,27 @@
ARMRelocationFactory::DWord A = pReloc.target() + pReloc.addend();
ARMRelocationFactory::DWord S = pReloc.symValue();
- if(rsym->isLocal() && (rsym->reserved() & 0x1u)) {
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ pReloc.target() = (S + A) | T;
+ return ARMRelocationFactory::OK;
+ }
+
+ // A local symbol may need REL Type dynamic relocation
+ if (rsym->isLocal() && (rsym->reserved() & ARMGNULDBackend::ReserveRel)) {
helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
pReloc.target() = (S + A) | T ;
return ARMRelocationFactory::OK;
}
- else if(!rsym->isLocal()) {
- if(rsym->reserved() & 0x8u) {
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0 ; // PLT is not thumb
pReloc.target() = (S + A) | T;
@@ -422,8 +432,8 @@
// If we generate a dynamic relocation (except R_ARM_RELATIVE)
// for a place, we should not perform static relocation on it
// in order to keep the addend store in the place correct.
- if(rsym->reserved() & 0x1u) {
- if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ if (rsym->reserved() & ARMGNULDBackend::ReserveRel) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
}
else {
@@ -433,6 +443,7 @@
}
}
+
// perform static relocation
pReloc.target() = (S + A) | T;
return ARMRelocationFactory::OK;
@@ -481,7 +492,8 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ if (!(pReloc.symInfo()->reserved() &
+ (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
return ARMRelocationFactory::BadReloc;
}
ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
@@ -497,7 +509,8 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- if(!(pReloc.symInfo()->reserved() & 0x6u)) {
+ if (!(pReloc.symInfo()->reserved() &
+ (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
return ARMRelocationFactory::BadReloc;
}
ARMRelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent);
@@ -515,18 +528,23 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- // TODO: Some issue have not been considered, e.g. thumb, overflow?
+ // TODO: Some issue have not been considered:
+ // 1. Add stub when switching mode or jump target too far
+ // 2. We assume the blx is available
// If target is undefined weak symbol, we only need to jump to the
- // next instruction unless it has PLT entry.
- if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ // next instruction unless it has PLT entry. Rewrite instruction
+ // to NOP.
+ if (pReloc.symInfo()->isWeak() &&
+ pReloc.symInfo()->isUndef() &&
+ !pReloc.symInfo()->isDyn() &&
!(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
// change target to NOP : mov r0, r0
pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
return ARMRelocationFactory::OK;
}
- ARMRelocationFactory::Address S; // S dependent on exist PLT or not.
+ ARMRelocationFactory::Address S; // S depends on PLT exists or not.
ARMRelocationFactory::DWord T = getThumbBit(pReloc);
ARMRelocationFactory::DWord A =
helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26)
@@ -534,16 +552,23 @@
ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
S = pReloc.symValue();
- if( pReloc.symInfo()->reserved() & 0x8u) {
+ if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0; // PLT is not thumb.
}
- ARMRelocationFactory::DWord X = ((S + A) | T) - P;
-
- if (X & 0x03u) { // Lowest two bit is not zero.
- llvm::report_fatal_error("Target is thumb, need stub!");
+ // If the jump target is thumb instruction, switch mode is needed, rewrite
+ // the instruction to BLX
+ if (T != 0) {
+ // cannot rewrite R_ARM_JUMP24 instruction to blx
+ assert((pReloc.type() != llvm::ELF::R_ARM_JUMP24)&&
+ "Invalid instruction to rewrite to blx for switching mode.");
+ pReloc.target() = (pReloc.target() & 0xffffff) |
+ 0xfa000000 |
+ (((S + A - P) & 2) << 23);
}
+
+ ARMRelocationFactory::DWord X = ((S + A) | T) - P;
// Check X is 24bit sign int. If not, we should use stub or PLT before apply.
assert(!helper_check_signed_overflow(X, 26) && "Jump or Call target too far!");
// Make sure the Imm is 0. Result Mask.
@@ -552,29 +577,25 @@
}
// R_ARM_THM_CALL: ((S + A) | T) - P
+// R_ARM_THM_JUMP24: (((S + A) | T) - P)
ARMRelocationFactory::Result thm_call(Relocation& pReloc,
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
// If target is undefined weak symbol, we only need to jump to the
- // next instruction unless it has PLT entry.
- if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
+ // next instruction unless it has PLT entry. Rewrite instruction
+ // to NOP.
+ if (pReloc.symInfo()->isWeak() &&
+ pReloc.symInfo()->isUndef() &&
+ !pReloc.symInfo()->isDyn() &&
!(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
pReloc.target() = (0xe000U << 16) | 0xbf00U;
return ARMRelocationFactory::OK;
}
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. Here is an ugly solution. We'd better have a thumb
- // instruction type.
- //uint16_t upper16 = *(
- // reinterpret_cast<uint16_t*>(&pReloc.target())
- // ),
- // lower16 = *(
- // reinterpret_cast<uint16_t*>(&pReloc.target()) + 1
- // );
- ARMRelocationFactory::DWord upper16 = ((pReloc.target() & 0xffff0000U) >> 16),
- lower16 = (pReloc.target() & 0xffffU);
+ // get lower and upper 16 bit instructions from relocation targetData
+ uint16_t upper16 = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
+ uint16_t lower16 = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
ARMRelocationFactory::DWord T = getThumbBit(pReloc);
ARMRelocationFactory::DWord A = helper_thumb32_branch_offset(upper16,
@@ -582,44 +603,52 @@
ARMRelocationFactory::Address P = pReloc.place(pParent.getLayout());
ARMRelocationFactory::Address S;
- S = pReloc.symValue();
// if symbol has plt
- if( pReloc.symInfo()->reserved() & 0x8u) {
+ if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0; // PLT is not thumb.
}
-
- // TODO: If the target is not thumb, we should rewrite instruction to BLX.
-
- ARMRelocationFactory::DWord X = ((S + A) | T) - P;
- X >>= 1;
-
- // FIXME: Check bit size is 24(thumb2) or 22?
- if (helper_check_signed_overflow(X, 24)) {
- assert(!"Offset is too far. We need stub or PLT for it.");
- return ARMRelocationFactory::Overflow;
+ else {
+ S = pReloc.symValue();
}
- // For a BLX instruction, make sure that the relocation is rounded up
- // to a word boundary. This follows the semantics of the instruction
- // which specifies that bit 1 of the target address will come from bit
- // 1 of the base address.
- if ((X & 0x5000U) == 0x4000U) {
- X = (X + 2) & ~0x3U;
+ S = S + A;
+
+ // FIXME: check if we can use BLX instruction (check from .ARM.attribute
+ // CPU ARCH TAG, which should be ARMv5 or above)
+
+ // If the jump target is not thumb, switch mode is needed, rewrite
+ // instruction to BLX
+ if (T == 0) {
+ // for BLX, select bit 1 from relocation base address to jump target
+ // address
+ S = helper_bit_select(S, P, 0x2);
+ // rewrite instruction to BLX
+ lower16 &= ~0x1000U;
+ }
+ else {
+ // otherwise, the instruction should be BL
+ lower16 |= 0x1000U;
+ }
+
+ ARMRelocationFactory::DWord X = (S | T) - P;
+
+ // TODO: check if we need stub when building non-shared object,
+ // overflow or switch-mode.
+
+ // FIXME: Check bit size is 24(thumb2) or 22?
+ if (helper_check_signed_overflow(X, 25)) {
+ assert(!"Offset is too far. We need stub or PLT for it.");
+ return ARMRelocationFactory::Overflow;
}
upper16 = helper_thumb32_branch_upper(upper16, X);
lower16 = helper_thumb32_branch_lower(lower16, X);
- // TODO: By the rsloader experience: If we use 32bit, we need to consider
- // endianness problem. Here is an ugly solution. We'd better have a thumb
- // instruction type.
- //*(reinterpret_cast<uint16_t*>(&preloc.target())) = upper16;
- //*(reinterpret_cast<uint16_t*>(&preloc.target()) + 1) = lower16;
- pReloc.target() = (upper16 << 16);
- pReloc.target() |= lower16;
+ *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper16;
+ *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower16;
- return ARMRelocationFactory::OK;
+ return ARMRelocationFactory::OK;
}
// R_ARM_MOVW_ABS_NC: (S + A) | T
@@ -634,11 +663,19 @@
helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
- T = 0 ; // PLT is not thumb
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0 ; // PLT is not thumb
+ }
}
+
X = (S + A) | T ;
// perform static relocation
pReloc.target() = (S + A) | T;
@@ -683,9 +720,16 @@
helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ }
}
X = S + A;
@@ -725,20 +769,22 @@
helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
- T = 0; // PLT is not thumb
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ T = 0; // PLT is not thumb
+ }
}
X = (S + A) | T;
- // check 16-bit overflow
- if (helper_check_signed_overflow(X, 16)) {
- return ARMRelocationFactory::Overflow;
- } else {
- pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
- X);
- return ARMRelocationFactory::OK;
- }
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
}
// R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
@@ -756,13 +802,30 @@
X = ((S + A) | T) - P;
// check 16-bit overflow
- if (helper_check_signed_overflow(X, 16)) {
- return ARMRelocationFactory::Overflow;
- } else {
- pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
- X);
- return ARMRelocationFactory::OK;
- }
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
+}
+
+// R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S)
+// R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S)
+ARMRelocationFactory::Result thm_movw_brel(Relocation& pReloc,
+ const MCLDInfo& pLDInfo,
+ ARMRelocationFactory& pParent)
+{
+ ARMRelocationFactory::Address S = pReloc.symValue();
+ ARMRelocationFactory::DWord T = getThumbBit(pReloc);
+ ARMRelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+ ARMRelocationFactory::DWord A =
+ helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
+ ARMRelocationFactory::DWord X;
+
+ X = ((S + A) | T) - P;
+
+ // check 16-bit overflow
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ X);
+ return ARMRelocationFactory::OK;
}
// R_ARM_THM_MOVT_ABS: S + A
@@ -776,10 +839,18 @@
helper_extract_thumb_movw_movt_addend(pReloc.target()) + pReloc.addend();
ARMRelocationFactory::DWord X;
- // use plt
- if(rsym->reserved() & 0x8u) {
- S = helper_PLT(pReloc, pParent);
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ // use plt
+ if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ }
}
+
X = S + A;
X >>= 16;
@@ -794,6 +865,7 @@
}
// R_ARM_THM_MOVT_PREL: S + A - P
+// R_ARM_THM_MOVT_BREL: S + A - B(S)
ARMRelocationFactory::Result thm_movt_prel(Relocation& pReloc,
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
@@ -806,15 +878,9 @@
X = S + A - P;
X >>= 16;
-
- // check 16-bit overflow
- if (helper_check_signed_overflow(X, 16)) {
- return ARMRelocationFactory::Overflow;
- } else {
- pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
+ pReloc.target() = helper_insert_val_thumb_movw_movt_inst(pReloc.target(),
X);
- return ARMRelocationFactory::OK;
- }
+ return ARMRelocationFactory::OK;
}
// R_ARM_PREL31: (S + A) | T
@@ -830,14 +896,14 @@
S = pReloc.symValue();
// if symbol has plt
- if( pReloc.symInfo()->reserved() & 0x8u) {
+ if ( pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
T = 0; // PLT is not thumb.
}
ARMRelocationFactory::DWord X = (S + A) | T ;
pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
- if(helper_check_signed_overflow(X, 31))
+ if (helper_check_signed_overflow(X, 31))
return ARMRelocationFactory::Overflow;
return ARMRelocationFactory::OK;
}
@@ -849,7 +915,6 @@
const MCLDInfo& pLDInfo,
ARMRelocationFactory& pParent)
{
- llvm::report_fatal_error("We don't support TLS relocation yet.");
return ARMRelocationFactory::Unsupport;
}
diff --git a/lib/Target/ARM/ARMRelocationFactory.h b/lib/Target/ARM/ARMRelocationFactory.h
index 0426100..636dbee 100644
--- a/lib/Target/ARM/ARMRelocationFactory.h
+++ b/lib/Target/ARM/ARMRelocationFactory.h
@@ -56,3 +56,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/ARMRelocationFunctions.h b/lib/Target/ARM/ARMRelocationFunctions.h
index 10d27a4..bb6e727 100644
--- a/lib/Target/ARM/ARMRelocationFunctions.h
+++ b/lib/Target/ARM/ARMRelocationFunctions.h
@@ -27,6 +27,7 @@
DECL_ARM_APPLY_RELOC_FUNC(movt_prel) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movw_abs_nc) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movw_prel_nc) \
+DECL_ARM_APPLY_RELOC_FUNC(thm_movw_brel) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movt_abs) \
DECL_ARM_APPLY_RELOC_FUNC(thm_movt_prel) \
DECL_ARM_APPLY_RELOC_FUNC(prel31) \
@@ -66,7 +67,7 @@
{ &call, 27, "R_ARM_PLT32" }, \
{ &call, 28, "R_ARM_CALL" }, \
{ &call, 29, "R_ARM_JUMP24" }, \
- { &unsupport, 30, "R_ARM_THM_JUMP24" }, \
+ { &thm_call, 30, "R_ARM_THM_JUMP24" }, \
{ &unsupport, 31, "R_ARM_BASE_ABS" }, \
{ &unsupport, 32, "R_ARM_ALU_PCREL_7_0" }, \
{ &unsupport, 33, "R_ARM_ALU_PCREL_15_8" }, \
@@ -123,9 +124,9 @@
{ &unsupport, 84, "R_ARM_MOVW_BREL_NC" }, \
{ &unsupport, 85, "R_ARM_MOVT_BREL" }, \
{ &unsupport, 86, "R_ARM_MOVW_BREL" }, \
- { &unsupport, 87, "R_ARM_THM_MOVW_BREL_NC" }, \
- { &unsupport, 88, "R_ARM_THM_MOVT_BREL" }, \
- { &unsupport, 89, "R_ARM_THM_MOVW_BREL" }, \
+ { &thm_movw_brel, 87, "R_ARM_THM_MOVW_BREL_NC" }, \
+ { &thm_movt_prel, 88, "R_ARM_THM_MOVT_BREL" }, \
+ { &thm_movw_brel, 89, "R_ARM_THM_MOVW_BREL" }, \
{ &unsupport, 90, "R_ARM_TLS_GOTDESC" }, \
{ &unsupport, 91, "R_ARM_TLS_CALL" }, \
{ &unsupport, 92, "R_ARM_TLS_DESCSEQ" }, \
diff --git a/lib/Target/ARM/ARMSectLinker.cpp b/lib/Target/ARM/ARMSectLinker.cpp
index 16d2126..06dba05 100644
--- a/lib/Target/ARM/ARMSectLinker.cpp
+++ b/lib/Target/ARM/ARMSectLinker.cpp
@@ -9,7 +9,6 @@
#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include "ARM.h"
-#include "ARMAndroidSectLinker.h"
#include "ARMELFSectLinker.h"
@@ -32,8 +31,7 @@
}
// For now, use Android SectLinker directly
- return new ARMAndroidSectLinker(pOption,
- pLDBackend);
+ return new ARMELFSectLinker(pOption, pLDBackend);
}
} // namespace of mcld
@@ -43,4 +41,6 @@
extern "C" void LLVMInitializeARMSectLinker() {
// Register the linker frontend
mcld::TargetRegistry::RegisterSectLinker(TheARMTarget, createARMSectLinker);
+ mcld::TargetRegistry::RegisterSectLinker(TheThumbTarget, createARMSectLinker);
}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
index 3cb7793..54e1b3d 100644
--- a/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -15,6 +15,7 @@
extern "C" void LLVMInitializeARMLDTarget() {
// Register createTargetMachine function pointer to mcld::Target
mcld::RegisterTargetMachine<mcld::ARMBaseTargetMachine> X(mcld::TheARMTarget);
+ mcld::RegisterTargetMachine<mcld::ARMBaseTargetMachine> Y(mcld::TheThumbTarget);
}
mcld::ARMBaseTargetMachine::ARMBaseTargetMachine(llvm::TargetMachine& pPM,
@@ -30,3 +31,4 @@
{
delete m_pLDInfo;
}
+
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
index 419826c..19f8aa2 100644
--- a/lib/Target/ARM/ARMTargetMachine.h
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -37,3 +37,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/ARM/README b/lib/Target/ARM/README
index 2110344..ea88bfe 100644
--- a/lib/Target/ARM/README
+++ b/lib/Target/ARM/README
@@ -1,2 +1,2 @@
-ARMLDBackend stands like ARMAsmBackend. It's a backend of linker,
+ARMLDBackend stands like ARMAsmBackend. It's a backend of linker,
and all target-dependent behavior and data are here.
diff --git a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
index 7e6a41a..4f2f815 100644
--- a/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
+++ b/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
@@ -12,10 +12,12 @@
namespace mcld {
mcld::Target TheARMTarget;
+mcld::Target TheThumbTarget;
extern "C" void LLVMInitializeARMLDTargetInfo() {
// register into mcld::TargetRegistry
mcld::RegisterTarget X(TheARMTarget, "arm" );
+ mcld::RegisterTarget Y(TheThumbTarget, "thumb" );
}
} // namespace of mcld
diff --git a/lib/Target/AndroidSectLinker.cpp b/lib/Target/AndroidSectLinker.cpp
deleted file mode 100644
index 8f3acbf..0000000
--- a/lib/Target/AndroidSectLinker.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- AndroidSectLinker.cpp ----------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include <mcld/Target/AndroidSectLinker.h>
-
-#include <llvm/Support/ErrorHandling.h>
-#include <mcld/MC/MCLDDirectory.h>
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-//==========================
-// AndroidSectLinker
-
-AndroidSectLinker::AndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : SectLinker(pOption, pLDBackend) {
-}
-
-AndroidSectLinker::~AndroidSectLinker()
-{
- // SectLinker will delete m_pLDBackend and m_pLDDriver;
-}
-
-void AndroidSectLinker::addTargetOptions(llvm::Module &pM,
- SectLinkerOption &pOption)
-{
- // ----- Set up General Options ----- //
- MCLDInfo &info = pOption.info();
- MCLDDirectory search_path("=/system/lib");
- search_path.setSysroot(info.options().sysroot());
- if (exists(search_path.path()) && is_directory(search_path.path()))
- info.options().directories().add(search_path);
- else {
- // FIXME: need a warning function
- llvm::errs() << "WARNING: can not open search directory: `-L" << search_path.name() << "'.\n";
- }
-}
-
diff --git a/lib/Target/ELFDynamic.cpp b/lib/Target/ELFDynamic.cpp
index b863ab1..cb7c435 100644
--- a/lib/Target/ELFDynamic.cpp
+++ b/lib/Target/ELFDynamic.cpp
@@ -84,7 +84,6 @@
++m_Idx;
}
-
/// reserveEntries - reserve entries
void ELFDynamic::reserveEntries(const MCLDInfo& pLDInfo,
const ELFFileFormat& pFormat)
@@ -146,6 +145,28 @@
reserveOne(llvm::ELF::DT_RELASZ); // DT_RELASZ
reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT
}
+
+ if (pLDInfo.options().hasOrigin() ||
+ pLDInfo.options().Bsymbolic() ||
+ pLDInfo.options().hasNow()) {
+ // TODO: add checks for DF_TEXTREL and DF_STATIC_TLS
+ reserveOne(llvm::ELF::DT_FLAGS); // DT_FLAGS
+ }
+
+ if (pLDInfo.options().hasNow() ||
+ pLDInfo.options().hasLoadFltr() ||
+ pLDInfo.options().hasOrigin() ||
+ pLDInfo.options().hasInterPose() ||
+ pLDInfo.options().hasNoDefaultLib() ||
+ pLDInfo.options().hasNoDump() ||
+ pLDInfo.options().Bgroup() ||
+ ((pLDInfo.output().type() == Output::DynObj) &&
+ (pLDInfo.options().hasNoDelete() ||
+ pLDInfo.options().hasInitFirst() ||
+ pLDInfo.options().hasNoDLOpen()))) {
+ reserveOne(llvm::ELF::DT_FLAGS_1); // DT_FLAGS_1
+ }
+
reserveOne(llvm::ELF::DT_NULL); // for DT_NULL
}
@@ -217,6 +238,44 @@
applyOne(llvm::ELF::DT_RELAENT, m_pEntryFactory->relaSize()); // DT_RELAENT
}
+ uint64_t dt_flags = 0x0;
+ if (pInfo.options().hasOrigin())
+ dt_flags |= llvm::ELF::DF_ORIGIN;
+ if (pInfo.options().Bsymbolic())
+ dt_flags |= llvm::ELF::DF_SYMBOLIC;
+ if (pInfo.options().hasNow())
+ dt_flags |= llvm::ELF::DF_BIND_NOW;
+ // TODO: add checks for DF_TEXTREL and DF_STATIC_TLS
+ if (0x0 != dt_flags) {
+ applyOne(llvm::ELF::DT_FLAGS, dt_flags); // DT_FLAGS
+ }
+
+ uint64_t dt_flags_1 = 0x0;
+ if (pInfo.options().hasNow())
+ dt_flags_1 |= llvm::ELF::DF_1_NOW;
+ if (pInfo.options().hasLoadFltr())
+ dt_flags_1 |= llvm::ELF::DF_1_LOADFLTR;
+ if (pInfo.options().hasOrigin())
+ dt_flags_1 |= llvm::ELF::DF_1_ORIGIN;
+ if (pInfo.options().hasInterPose())
+ dt_flags_1 |= llvm::ELF::DF_1_INTERPOSE;
+ if (pInfo.options().hasNoDefaultLib())
+ dt_flags_1 |= llvm::ELF::DF_1_NODEFLIB;
+ if (pInfo.options().hasNoDump())
+ dt_flags_1 |= llvm::ELF::DF_1_NODUMP;
+ if (pInfo.options().Bgroup())
+ dt_flags_1 |= llvm::ELF::DF_1_GROUP;
+ if (pInfo.output().type() == Output::DynObj) {
+ if (pInfo.options().hasNoDelete())
+ dt_flags_1 |= llvm::ELF::DF_1_NODELETE;
+ if (pInfo.options().hasInitFirst())
+ dt_flags_1 |= llvm::ELF::DF_1_INITFIRST;
+ if (pInfo.options().hasNoDLOpen())
+ dt_flags_1 |= llvm::ELF::DF_1_NOOPEN;
+ }
+ if (0x0 != dt_flags_1)
+ applyOne(llvm::ELF::DT_FLAGS_1, dt_flags_1); // DT_FLAGS_1
+
applyOne(llvm::ELF::DT_NULL, 0x0); // for DT_NULL
}
diff --git a/lib/Target/ELFSectLinker.cpp b/lib/Target/ELFSectLinker.cpp
new file mode 100644
index 0000000..b95ed0b
--- /dev/null
+++ b/lib/Target/ELFSectLinker.cpp
@@ -0,0 +1,25 @@
+//===- ELFSectLinker.cpp ------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <mcld/Target/ELFSectLinker.h>
+#include <mcld/CodeGen/SectLinkerOption.h>
+
+using namespace mcld;
+
+//==========================
+// ELFSectLinker
+ELFSectLinker::ELFSectLinker(SectLinkerOption &pOption,
+ TargetLDBackend &pLDBackend)
+ : SectLinker(pOption, pLDBackend) {
+}
+
+ELFSectLinker::~ELFSectLinker()
+{
+ // SectLinker will delete m_pLDBackend and m_pLDDriver;
+}
+
diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp
index b82af73..9fff9e3 100644
--- a/lib/Target/GNULDBackend.cpp
+++ b/lib/Target/GNULDBackend.cpp
@@ -11,12 +11,14 @@
#include <mcld/Target/GNULDBackend.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLDOutput.h>
-#include <mcld/MC/MCLDInputTree.h>
+#include <mcld/MC/InputTree.h>
#include <mcld/MC/SymbolCategory.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/Layout.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/MC/MCLinker.h>
#include <string>
#include <cstring>
#include <cassert>
@@ -26,36 +28,57 @@
//===----------------------------------------------------------------------===//
// GNULDBackend
GNULDBackend::GNULDBackend()
- : m_pArchiveReader(0),
- m_pObjectReader(0),
- m_pDynObjReader(0),
- m_pObjectWriter(0),
- m_pDynObjWriter(0),
- m_pDynObjFileFormat(0),
- m_pExecFileFormat(0),
- m_ELFSegmentTable(9)// magic number
-{
+ : m_pArchiveReader(NULL),
+ m_pObjectReader(NULL),
+ m_pDynObjReader(NULL),
+ m_pObjectWriter(NULL),
+ m_pDynObjWriter(NULL),
+ m_pExecWriter(NULL),
+ m_pDynObjFileFormat(NULL),
+ m_pExecFileFormat(NULL),
+ m_ELFSegmentTable(9), // magic number
+ m_pEhFrameHdr(NULL),
+ f_pPreInitArrayStart(NULL),
+ f_pPreInitArrayEnd(NULL),
+ f_pInitArrayStart(NULL),
+ f_pInitArrayEnd(NULL),
+ f_pFiniArrayStart(NULL),
+ f_pFiniArrayEnd(NULL),
+ f_pStack(NULL),
+ f_pExecutableStart(NULL),
+ f_pEText(NULL),
+ f_p_EText(NULL),
+ f_p__EText(NULL),
+ f_pEData(NULL),
+ f_p_EData(NULL),
+ f_pBSSStart(NULL),
+ f_pEnd(NULL),
+ f_p_End(NULL) {
m_pSymIndexMap = new HashTableType(1024);
}
GNULDBackend::~GNULDBackend()
{
- if (m_pArchiveReader)
+ if (NULL != m_pArchiveReader)
delete m_pArchiveReader;
- if (m_pObjectReader)
+ if (NULL != m_pObjectReader)
delete m_pObjectReader;
- if (m_pDynObjReader)
+ if (NULL != m_pDynObjReader)
delete m_pDynObjReader;
- if (m_pObjectWriter)
+ if (NULL != m_pObjectWriter)
delete m_pObjectWriter;
- if (m_pDynObjWriter)
+ if (NULL != m_pDynObjWriter)
delete m_pDynObjWriter;
- if (m_pDynObjFileFormat)
+ if (NULL != m_pExecWriter)
+ delete m_pExecWriter;
+ if (NULL != m_pDynObjFileFormat)
delete m_pDynObjFileFormat;
- if (m_pExecFileFormat)
+ if (NULL != m_pExecFileFormat)
delete m_pExecFileFormat;
- if(m_pSymIndexMap)
+ if (NULL != m_pSymIndexMap)
delete m_pSymIndexMap;
+ if (NULL != m_pEhFrameHdr)
+ delete m_pEhFrameHdr;
}
size_t GNULDBackend::sectionStartOffset() const
@@ -64,13 +87,20 @@
return sizeof(llvm::ELF::Elf64_Ehdr)+10*sizeof(llvm::ELF::Elf64_Phdr);
}
+uint64_t GNULDBackend::segmentStartAddr(const Output& pOutput,
+ const MCLDInfo& pInfo) const
+{
+ // TODO: handle the user option: -TText=
+ if (isOutputPIC(pOutput, pInfo))
+ return 0x0;
+ else
+ return defaultTextSegmentAddr();
+}
+
bool GNULDBackend::initArchiveReader(MCLinker&, MCLDInfo &pInfo)
{
if (0 == m_pArchiveReader)
- {
- LDReader::Endian isLittleEndian = LDReader::LittleEndian;
- m_pArchiveReader = new GNUArchiveReader(pInfo, isLittleEndian);
- }
+ m_pArchiveReader = new GNUArchiveReader(pInfo);
return true;
}
@@ -96,11 +126,18 @@
bool GNULDBackend::initDynObjWriter(MCLinker& pLinker)
{
- if (0 == m_pDynObjWriter)
+ if (NULL == m_pDynObjWriter)
m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker);
return true;
}
+bool GNULDBackend::initExecWriter(MCLinker& pLinker)
+{
+ if (NULL == m_pExecWriter)
+ m_pExecWriter = new ELFExecWriter(*this, pLinker);
+ return true;
+}
+
bool GNULDBackend::initExecSections(MCLinker& pMCLinker)
{
if (0 == m_pExecFileFormat)
@@ -121,8 +158,395 @@
return true;
}
-bool GNULDBackend::initStandardSymbols(MCLinker& pLinker)
+bool GNULDBackend::initStandardSymbols(MCLinker& pLinker, const Output& pOutput)
{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // ----- section symbols ----- //
+ // .preinit_array
+ MCFragmentRef* preinit_array = NULL;
+ if (file_format->hasPreInitArray()) {
+ preinit_array = pLinker.getLayout().getFragmentRef(
+ *(file_format->getPreInitArray().getSectionData()->begin()),
+ 0x0);
+ }
+ f_pPreInitArrayStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__preinit_array_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ preinit_array, // FragRef
+ ResolveInfo::Hidden);
+ f_pPreInitArrayEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__preinit_array_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Hidden);
+
+ // .init_array
+ MCFragmentRef* init_array = NULL;
+ if (file_format->hasInitArray()) {
+ init_array = pLinker.getLayout().getFragmentRef(
+ *(file_format->getInitArray().getSectionData()->begin()),
+ 0x0);
+ }
+
+ f_pInitArrayStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__init_array_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ init_array, // FragRef
+ ResolveInfo::Hidden);
+ f_pInitArrayEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__init_array_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ init_array, // FragRef
+ ResolveInfo::Hidden);
+
+ // .fini_array
+ MCFragmentRef* fini_array = NULL;
+ if (file_format->hasFiniArray()) {
+ fini_array = pLinker.getLayout().getFragmentRef(
+ *(file_format->getFiniArray().getSectionData()->begin()),
+ 0x0);
+ }
+
+ f_pFiniArrayStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__fini_array_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ fini_array, // FragRef
+ ResolveInfo::Hidden);
+ f_pFiniArrayEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__fini_array_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ fini_array, // FragRef
+ ResolveInfo::Hidden);
+
+ // .stack
+ MCFragmentRef* stack = NULL;
+ if (file_format->hasStack()) {
+ stack = pLinker.getLayout().getFragmentRef(
+ *(file_format->getStack().getSectionData()->begin()),
+ 0x0);
+ }
+ f_pStack =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__stack",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Global,
+ 0x0, // size
+ 0x0, // value
+ stack, // FragRef
+ ResolveInfo::Hidden);
+
+ // ----- segment symbols ----- //
+ f_pExecutableStart =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__executable_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_pEText =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("etext",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_p_EText =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("_etext",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_p__EText =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("__etext",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+ f_pEData =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("edata",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ f_pEnd =
+ pLinker.defineSymbol<MCLinker::AsRefered,
+ MCLinker::Resolve>("end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ // _edata is defined forcefully.
+ // @ref Google gold linker: defstd.cc: 186
+ f_p_EData =
+ pLinker.defineSymbol<MCLinker::Force,
+ MCLinker::Resolve>("_edata",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ // __bss_start is defined forcefully.
+ // @ref Google gold linker: defstd.cc: 214
+ f_pBSSStart =
+ pLinker.defineSymbol<MCLinker::Force,
+ MCLinker::Resolve>("__bss_start",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ // _end is defined forcefully.
+ // @ref Google gold linker: defstd.cc: 228
+ f_p_End =
+ pLinker.defineSymbol<MCLinker::Force,
+ MCLinker::Resolve>("_end",
+ false, // isDyn
+ ResolveInfo::NoType,
+ ResolveInfo::Define,
+ ResolveInfo::Absolute,
+ 0x0, // size
+ 0x0, // value
+ NULL, // FragRef
+ ResolveInfo::Default);
+
+ return true;
+}
+
+bool
+GNULDBackend::finalizeStandardSymbols(MCLinker& pLinker, const Output& pOutput)
+{
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ // ----- section symbols ----- //
+ if (NULL != f_pPreInitArrayStart) {
+ if (!f_pPreInitArrayStart->hasFragRef()) {
+ f_pPreInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pPreInitArrayStart->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pPreInitArrayEnd) {
+ if (f_pPreInitArrayEnd->hasFragRef()) {
+ f_pPreInitArrayEnd->setValue(f_pPreInitArrayEnd->value() +
+ file_format->getPreInitArray().size());
+ }
+ else {
+ f_pPreInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pPreInitArrayEnd->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pInitArrayStart) {
+ if (!f_pInitArrayStart->hasFragRef()) {
+ f_pInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pInitArrayStart->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pInitArrayEnd) {
+ if (f_pInitArrayEnd->hasFragRef()) {
+ f_pInitArrayEnd->setValue(f_pInitArrayEnd->value() +
+ file_format->getInitArray().size());
+ }
+ else {
+ f_pInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pInitArrayEnd->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pFiniArrayStart) {
+ if (!f_pFiniArrayStart->hasFragRef()) {
+ f_pFiniArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pFiniArrayStart->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pFiniArrayEnd) {
+ if (f_pFiniArrayEnd->hasFragRef()) {
+ f_pFiniArrayEnd->setValue(f_pFiniArrayEnd->value() +
+ file_format->getFiniArray().size());
+ }
+ else {
+ f_pFiniArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pFiniArrayEnd->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pStack) {
+ if (!f_pStack->hasFragRef()) {
+ f_pStack->resolveInfo()->setBinding(ResolveInfo::Absolute);
+ f_pStack->setValue(0x0);
+ }
+ }
+
+ // ----- segment symbols ----- //
+ if (NULL != f_pExecutableStart) {
+ ELFSegment* exec_start = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, 0x0, 0x0);
+ if (NULL != exec_start) {
+ if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) {
+ f_pExecutableStart->setValue(f_pExecutableStart->value() +
+ exec_start->vaddr());
+ }
+ }
+ else
+ f_pExecutableStart->setValue(0x0);
+ }
+
+ if (NULL != f_pEText || NULL != f_p_EText || NULL !=f_p__EText) {
+ ELFSegment* etext = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
+ llvm::ELF::PF_X,
+ llvm::ELF::PF_W);
+ if (NULL != etext) {
+ if (NULL != f_pEText && ResolveInfo::ThreadLocal != f_pEText->type()) {
+ f_pEText->setValue(f_pEText->value() +
+ etext->vaddr() +
+ etext->memsz());
+ }
+ if (NULL != f_p_EText && ResolveInfo::ThreadLocal != f_p_EText->type()) {
+ f_p_EText->setValue(f_p_EText->value() +
+ etext->vaddr() +
+ etext->memsz());
+ }
+ if (NULL != f_p__EText && ResolveInfo::ThreadLocal != f_p__EText->type()) {
+ f_p__EText->setValue(f_p__EText->value() +
+ etext->vaddr() +
+ etext->memsz());
+ }
+ }
+ else {
+ if (NULL != f_pEText)
+ f_pEText->setValue(0x0);
+ if (NULL != f_p_EText)
+ f_p_EText->setValue(0x0);
+ if (NULL != f_p__EText)
+ f_p__EText->setValue(0x0);
+ }
+ }
+
+ if (NULL != f_pEData || NULL != f_p_EData || NULL != f_pBSSStart ||
+ NULL != f_pEnd || NULL != f_p_End) {
+ ELFSegment* edata = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
+ llvm::ELF::PF_W,
+ 0x0);
+ if (NULL != edata) {
+ if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) {
+ f_pEData->setValue(f_pEData->value() +
+ edata->vaddr() +
+ edata->filesz());
+ }
+ if (NULL != f_p_EData && ResolveInfo::ThreadLocal != f_p_EData->type()) {
+ f_p_EData->setValue(f_p_EData->value() +
+ edata->vaddr() +
+ edata->filesz());
+ }
+ if (NULL != f_pBSSStart && ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
+ f_pBSSStart->setValue(f_pBSSStart->value() +
+ edata->vaddr() +
+ edata->filesz());
+ }
+
+ if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) {
+ f_pEnd->setValue(f_pEnd->value() +
+ edata->vaddr() +
+ edata->memsz());
+ }
+ if (NULL != f_p_End && ResolveInfo::ThreadLocal != f_p_End->type()) {
+ f_p_End->setValue(f_p_End->value() +
+ edata->vaddr() +
+ edata->memsz());
+ }
+ }
+ else {
+ if (NULL != f_pEData)
+ f_pEData->setValue(0x0);
+ if (NULL != f_p_EData)
+ f_p_EData->setValue(0x0);
+ if (NULL != f_pBSSStart)
+ f_pBSSStart->setValue(0x0);
+
+ if (NULL != f_pEnd)
+ f_pEnd->setValue(0x0);
+ if (NULL != f_p_End)
+ f_p_End->setValue(0x0);
+ }
+ }
+
return true;
}
@@ -132,7 +556,7 @@
return m_pArchiveReader;
}
-GNUArchiveReader *GNULDBackend::getArchiveReader() const
+const GNUArchiveReader *GNULDBackend::getArchiveReader() const
{
assert(0 != m_pArchiveReader);
return m_pArchiveReader;
@@ -144,7 +568,7 @@
return m_pObjectReader;
}
-ELFObjectReader *GNULDBackend::getObjectReader() const
+const ELFObjectReader *GNULDBackend::getObjectReader() const
{
assert(0 != m_pObjectReader);
return m_pObjectReader;
@@ -156,7 +580,7 @@
return m_pDynObjReader;
}
-ELFDynObjReader *GNULDBackend::getDynObjReader() const
+const ELFDynObjReader *GNULDBackend::getDynObjReader() const
{
assert(0 != m_pDynObjReader);
return m_pDynObjReader;
@@ -168,7 +592,7 @@
return NULL;
}
-ELFObjectWriter *GNULDBackend::getObjectWriter() const
+const ELFObjectWriter *GNULDBackend::getObjectWriter() const
{
// TODO
return NULL;
@@ -180,19 +604,61 @@
return m_pDynObjWriter;
}
-ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
+const ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
{
assert(0 != m_pDynObjWriter);
return m_pDynObjWriter;
}
+ELFExecWriter *GNULDBackend::getExecWriter()
+{
+ assert(NULL != m_pExecWriter);
+ return m_pExecWriter;
+}
+
+const ELFExecWriter *GNULDBackend::getExecWriter() const
+{
+ assert(NULL != m_pExecWriter);
+ return m_pExecWriter;
+}
+
+ELFFileFormat* GNULDBackend::getOutputFormat(const Output& pOutput)
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ fatal(diag::unrecognized_output_file) << pOutput.type();
+ return NULL;
+ }
+}
+
+const ELFFileFormat* GNULDBackend::getOutputFormat(const Output& pOutput) const
+{
+ switch (pOutput.type()) {
+ case Output::DynObj:
+ return getDynObjFileFormat();
+ case Output::Exec:
+ return getExecFileFormat();
+ // FIXME: We do not support building .o now
+ case Output::Object:
+ default:
+ fatal(diag::unrecognized_output_file) << pOutput.type();
+ return NULL;
+ }
+}
+
ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat()
{
assert(0 != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
}
-ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
+const ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
{
assert(0 != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
@@ -204,7 +670,7 @@
return m_pExecFileFormat;
}
-ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
+const ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
{
assert(0 != m_pExecFileFormat);
return m_pExecFileFormat;
@@ -241,20 +707,7 @@
strtab += str_size;
}
- ELFFileFormat* file_format = NULL;
- switch(pOutput.type()) {
- // compute size of .dynstr and .hash
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- // TODO: not support yet
- return;
- }
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
switch(pOutput.type()) {
// compute size of .dynstr and .hash
@@ -335,23 +788,14 @@
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
- ELFFileFormat* file_format = NULL;
- switch(pOutput.type()) {
- // compute size of .dynstr and .hash
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- // add first symbol into m_pSymIndexMap
- entry = m_pSymIndexMap->insert(NULL, sym_exist);
- entry->setValue(0);
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+ if (pOutput.type() == Output::Object) {
+ // add first symbol into m_pSymIndexMap
+ entry = m_pSymIndexMap->insert(NULL, sym_exist);
+ entry->setValue(0);
- // TODO: not support yet
- return;
+ // TODO: not support yet
+ return;
}
LDSection& symtab_sect = file_format->getSymTab();
@@ -446,25 +890,11 @@
const MCLDInfo& pLDInfo)
{
assert(pOutput.hasMemArea());
- ELFFileFormat* file_format = NULL;
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
- switch(pOutput.type()) {
- // compute size of .dynstr and .hash
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- // TODO: not support yet
- return;
- }
-
LDSection& symtab_sect = file_format->getDynSymTab();
LDSection& strtab_sect = file_format->getDynStrTab();
LDSection& hash_sect = file_format->getHashTab();
@@ -587,7 +1017,8 @@
// emit soname
// initialize value of ELF .dynamic section
- dynamic().applySoname(strtabsize);
+ if (Output::DynObj == pOutput.type())
+ dynamic().applySoname(strtabsize);
dynamic().applyEntries(pLDInfo, *file_format);
dynamic().emit(dyn_sect, *dyn_region);
@@ -633,9 +1064,44 @@
}
}
+/// sizeInterp - compute the size of the .interp section
+void GNULDBackend::sizeInterp(const Output& pOutput, const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.type() == Output::Exec);
+
+ const char* dyld_name;
+ if (pLDInfo.options().hasDyld())
+ dyld_name = pLDInfo.options().dyld().c_str();
+ else
+ dyld_name = dyld();
+
+ LDSection& interp = getExecFileFormat()->getInterp();
+ interp.setSize(std::strlen(dyld_name) + 1);
+}
+
+/// emitInterp - emit the .interp
+void GNULDBackend::emitInterp(Output& pOutput, const MCLDInfo& pLDInfo)
+{
+ assert(pOutput.type() == Output::Exec &&
+ getExecFileFormat()->hasInterp() &&
+ pOutput.hasMemArea());
+
+ const LDSection& interp = getExecFileFormat()->getInterp();
+ MemoryRegion *region = pOutput.memArea()->request(
+ interp.offset(), interp.size());
+ const char* dyld_name;
+ if (pLDInfo.options().hasDyld())
+ dyld_name = pLDInfo.options().dyld().c_str();
+ else
+ dyld_name = dyld();
+
+ std::memcpy(region->start(), dyld_name, interp.size());
+}
+
/// getSectionOrder
unsigned int GNULDBackend::getSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
// NULL section should be the "1st" section
if (LDFileFormat::Null == pSectHdr.kind())
@@ -647,19 +1113,7 @@
bool is_write = (pSectHdr.flag() & llvm::ELF::SHF_WRITE) != 0;
bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
- ELFFileFormat* file_format = NULL;
- switch (pOutput.type()) {
- case Output::DynObj:
- file_format = getDynObjFileFormat();
- break;
- case Output::Exec:
- file_format = getExecFileFormat();
- break;
- case Output::Object:
- default:
- assert(0 && "Not support yet.\n");
- break;
- }
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
// TODO: need to take care other possible output sections
switch (pSectHdr.kind()) {
@@ -673,13 +1127,18 @@
} else if (!is_write) {
return SHO_RO;
} else {
- if (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
- pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
- pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
- &pSectHdr == &file_format->getCtors() ||
- &pSectHdr == &file_format->getDtors())
- return SHO_RELRO;
-
+ if (pInfo.options().hasRelro()) {
+ if (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
+ pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
+ &pSectHdr == &file_format->getCtors() ||
+ &pSectHdr == &file_format->getDtors() ||
+ &pSectHdr == &file_format->getJCR() ||
+ 0 == pSectHdr.name().compare(".data.rel.ro"))
+ return SHO_RELRO;
+ if (0 == pSectHdr.name().compare(".data.rel.ro.local"))
+ return SHO_RELRO_LOCAL;
+ }
return SHO_DATA;
}
@@ -699,14 +1158,16 @@
// get the order from target for target specific sections
case LDFileFormat::Target:
- return getTargetSectionOrder(pOutput, pSectHdr);
+ return getTargetSectionOrder(pOutput, pSectHdr, pInfo);
// handle .interp
case LDFileFormat::Note:
return SHO_INTERP;
- case LDFileFormat::Exception:
- return SHO_EHFRAME;
+ case LDFileFormat::EhFrame:
+ case LDFileFormat::EhFrameHdr:
+ case LDFileFormat::GCCExceptTable:
+ return SHO_EXCEPTION;
case LDFileFormat::MetaData:
case LDFileFormat::Debug:
@@ -745,7 +1206,12 @@
pSymbol.visibility() == llvm::ELF::STV_HIDDEN)
bind = llvm::ELF::STB_LOCAL;
- return (pSymbol.resolveInfo()->type() | (bind << 4));
+ uint32_t type = pSymbol.resolveInfo()->type();
+ // if the IndirectFunc symbol (i.e., STT_GNU_IFUNC) is from dynobj, change
+ // its type to Function
+ if (type == ResolveInfo::IndirectFunc && pSymbol.isDyn())
+ type = ResolveInfo::Function;
+ return (type | (bind << 4));
}
/// getSymbolValue - this function is called after layout()
@@ -776,7 +1242,7 @@
}
}
- assert(pSymbol.hasFragRef());
+ assert(pSymbol.hasFragRef() && "symbols must have fragment reference to get its index");
return pLayout.getOutputLDSection(*pSymbol.fragRef()->frag())->index();
}
@@ -787,38 +1253,154 @@
return entry.getEntry()->value();
}
-/// emitProgramHdrs - emit ELF program headers
-void GNULDBackend::emitProgramHdrs(Output& pOutput)
+/// allocateCommonSymbols - allocate common symbols in the corresponding
+/// sections.
+/// @refer Google gold linker: common.cc: 214
+bool
+GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
{
- assert(NULL != pOutput.context());
- createProgramHdrs(*pOutput.context());
+ SymbolCategory& symbol_list = pLinker.getOutputSymbols();
- if (32 == bitclass())
- writeELF32ProgramHdrs(pOutput);
- else
- writeELF64ProgramHdrs(pOutput);
+ if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
+ return true;
+
+ SymbolCategory::iterator com_sym, com_end;
+
+ // FIXME: If the order of common symbols is defined, then sort common symbols
+ // std::sort(com_sym, com_end, some kind of order);
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+
+ LDSection* tbss_sect = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+
+ assert(NULL != bss_sect && NULL !=tbss_sect);
+
+ // get or create corresponding BSS MCSectionData
+ llvm::MCSectionData& bss_sect_data = pLinker.getOrCreateSectData(*bss_sect);
+ llvm::MCSectionData& tbss_sect_data = pLinker.getOrCreateSectData(*tbss_sect);
+
+ // remember original BSS size
+ uint64_t bss_offset = bss_sect->size();
+ uint64_t tbss_offset = tbss_sect->size();
+
+ // allocate all local common symbols
+ com_end = symbol_list.localEnd();
+
+ for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
+ if (ResolveInfo::Common == (*com_sym)->desc()) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
+ }
+ }
+
+ // allocate all global common symbols
+ com_end = symbol_list.commonEnd();
+ for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
+ // We have to reset the description of the symbol here. When doing
+ // incremental linking, the output relocatable object may have common
+ // symbols. Therefore, we can not treat common symbols as normal symbols
+ // when emitting the regular name pools. We must change the symbols'
+ // description here.
+ (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
+ (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
+ }
+
+ bss_sect->setSize(bss_offset);
+ tbss_sect->setSize(tbss_offset);
+ symbol_list.changeCommonsToGlobal();
+ return true;
}
+
/// createProgramHdrs - base on output sections to create the program headers
-void GNULDBackend::createProgramHdrs(LDContext& pContext)
+void GNULDBackend::createProgramHdrs(Output& pOutput, const MCLDInfo& pInfo)
{
+ assert(pOutput.hasContext());
+ ELFFileFormat *file_format = getOutputFormat(pOutput);
+
// make PT_PHDR
m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
// make PT_INTERP
- LDSection* interp = pContext.getSection(".interp");
- if (NULL != interp) {
+ if (file_format->hasInterp()) {
ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
- interp_seg->addSection(interp);
- interp_seg->setAlign(bitclass() / 8);
+ interp_seg->addSection(&file_format->getInterp());
+ }
+
+ if (pInfo.options().hasRelro()) {
+ // if -z relro is given, we need to adjust sections' offset again, and let
+ // PT_GNU_RELRO end on a common page boundary
+ LDContext::SectionTable& sect_table = pOutput.context()->getSectionTable();
+ size_t idx = 0;
+ while (idx < pOutput.context()->numOfSections()) {
+ // find the first non-relro section, and align its offset to a page
+ // boundary
+ if (getSectionOrder(pOutput, *sect_table[idx], pInfo) > SHO_RELRO_LAST) {
+ uint64_t offset = sect_table[idx]->offset();
+ alignAddress(offset, commonPageSize(pInfo));
+ sect_table[idx]->setOffset(offset);
+ ++idx;
+ break;
+ }
+ ++idx;
+ }
+ while (idx < pOutput.context()->numOfSections()) {
+ // adjust the remaining sections' offset
+ uint64_t offset = sect_table[idx - 1]->offset();
+ if (LDFileFormat::BSS != sect_table[idx - 1]->kind())
+ offset += sect_table[idx - 1]->size();
+ alignAddress(offset, sect_table[idx]->align());
+ sect_table[idx]->setOffset(offset);
+ ++idx;
+ }
}
uint32_t cur_seg_flag, prev_seg_flag = getSegmentFlag(0);
uint64_t padding = 0;
ELFSegment* load_seg = NULL;
// make possible PT_LOAD segments
- LDContext::sect_iterator sect, sect_end = pContext.sectEnd();
- for (sect = pContext.sectBegin(); sect != sect_end; ++sect) {
+ LDContext::sect_iterator sect, sect_end = pOutput.context()->sectEnd();
+ for (sect = pOutput.context()->sectBegin(); sect != sect_end; ++sect) {
+
if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
LDFileFormat::Null != (*sect)->kind())
continue;
@@ -829,36 +1411,60 @@
LDFileFormat::Null == (*sect)->kind()) {
// create new PT_LOAD segment
load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD);
- load_seg->setAlign(pagesize());
+ load_seg->setAlign(commonPageSize(pInfo));
// check if this segment needs padding
padding = 0;
- if (((*sect)->offset() & (load_seg->align() - 1)) != 0)
- padding = load_seg->align();
+ if (((*sect)->offset() & (abiPageSize(pInfo) - 1)) != 0)
+ padding = abiPageSize(pInfo);
}
assert(NULL != load_seg);
- load_seg->addSection(*sect);
- load_seg->updateFlag(cur_seg_flag);
+ load_seg->addSection((*sect));
+ if (cur_seg_flag != prev_seg_flag)
+ load_seg->updateFlag(cur_seg_flag);
- // FIXME: set section's vma
- // need to handle start vma for user-defined one or for executable.
- (*sect)->setAddr((*sect)->offset() + padding);
+ if (LDFileFormat::Null != (*sect)->kind())
+ (*sect)->setAddr(segmentStartAddr(pOutput, pInfo) +
+ (*sect)->offset() +
+ padding);
prev_seg_flag = cur_seg_flag;
}
// make PT_DYNAMIC
- LDSection* dynamic = pContext.getSection(".dynamic");
- if (NULL != dynamic) {
- ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC);
- dyn_seg->setFlag(llvm::ELF::PF_R | llvm::ELF::PF_W);
- dyn_seg->addSection(dynamic);
- dyn_seg->setAlign(bitclass() / 8);
+ if (file_format->hasDynamic()) {
+ ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC,
+ llvm::ELF::PF_R |
+ llvm::ELF::PF_W);
+ dyn_seg->addSection(&file_format->getDynamic());
}
+ if (pInfo.options().hasRelro()) {
+ // make PT_GNU_RELRO
+ ELFSegment* relro_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_RELRO);
+ for (LDContext::sect_iterator sect = pOutput.context()->sectBegin();
+ sect != pOutput.context()->sectEnd(); ++sect) {
+ unsigned int order = getSectionOrder(pOutput, **sect, pInfo);
+ if (SHO_RELRO_LOCAL == order ||
+ SHO_RELRO == order ||
+ SHO_RELRO_LAST == order) {
+ relro_seg->addSection(*sect);
+ }
+ }
+ }
+
+ // make PT_GNU_EH_FRAME
+ if (file_format->hasEhFrameHdr()) {
+ ELFSegment* eh_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_EH_FRAME);
+ eh_seg->addSection(&file_format->getEhFrameHdr());
+ }
+}
+
+/// setupProgramHdrs - set up the attributes of segments
+void GNULDBackend:: setupProgramHdrs(const Output& pOutput, const MCLDInfo& pInfo)
+{
// update segment info
- uint64_t file_size = 0;
ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) {
ELFSegment& segment = *seg;
@@ -875,7 +1481,7 @@
phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
}
segment.setOffset(offset);
- segment.setVaddr(offset);
+ segment.setVaddr(segmentStartAddr(pOutput, pInfo) + offset);
segment.setPaddr(segment.vaddr());
segment.setFilesz(numOfSegments() * phdr_size);
segment.setMemsz(numOfSegments() * phdr_size);
@@ -883,14 +1489,21 @@
continue;
}
- assert(NULL != segment.getFirstSection());
+ // bypass if there is no section in this segment (e.g., PT_GNU_STACK)
+ if (segment.numOfSections() == 0)
+ continue;
+
segment.setOffset(segment.getFirstSection()->offset());
- segment.setVaddr(segment.getFirstSection()->addr());
+ if (llvm::ELF::PT_LOAD == segment.type() &&
+ LDFileFormat::Null == segment.getFirstSection()->kind())
+ segment.setVaddr(segmentStartAddr(pOutput, pInfo));
+ else
+ segment.setVaddr(segment.getFirstSection()->addr());
segment.setPaddr(segment.vaddr());
const LDSection* last_sect = segment.getLastSection();
assert(NULL != last_sect);
- file_size = last_sect->offset() - segment.offset();
+ uint64_t file_size = last_sect->offset() - segment.offset();
if (LDFileFormat::BSS != last_sect->kind())
file_size += last_sect->size();
segment.setFilesz(file_size);
@@ -899,61 +1512,58 @@
}
}
-/// writeELF32ProgramHdrs - write out the ELF32 program headers
-void GNULDBackend::writeELF32ProgramHdrs(Output& pOutput)
+/// createGNUStackInfo - create an output GNU stack section or segment if needed
+/// @ref gold linker: layout.cc:2608
+void GNULDBackend::createGNUStackInfo(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
{
- assert(pOutput.hasMemArea());
+ uint32_t flag = 0x0;
+ if (pInfo.options().hasStackSet()) {
+ // 1. check the command line option (-z execstack or -z noexecstack)
+ if (pInfo.options().hasExecStack())
+ flag = llvm::ELF::SHF_EXECINSTR;
+ } else {
+ // 2. check the stack info from the input objects
+ size_t object_count = 0, stack_note_count = 0;
+ mcld::InputTree::const_bfs_iterator input, inEnd = pInfo.inputs().bfs_end();
+ for (input=pInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
+ if ((*input)->type() == Input::Object) {
+ ++object_count;
+ const LDSection* sect = (*input)->context()->getSection(
+ ".note.GNU-stack");
+ if (NULL != sect) {
+ ++stack_note_count;
+ // 2.1 found a stack note that is set as executable
+ if (0 != (llvm::ELF::SHF_EXECINSTR & sect->flag())) {
+ flag = llvm::ELF::SHF_EXECINSTR;
+ break;
+ }
+ }
+ }
+ }
- uint64_t start_offset, phdr_size;
+ // 2.2 there are no stack note sections in all input objects
+ if (0 == stack_note_count)
+ return;
- start_offset = sizeof(llvm::ELF::Elf32_Ehdr);
- phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
- // Program header must start directly after ELF header
- MemoryRegion *region = pOutput.memArea()->request(start_offset,
- numOfSegments()*phdr_size);
-
- llvm::ELF::Elf32_Phdr* phdr = (llvm::ELF::Elf32_Phdr*)region->start();
-
- size_t index = 0;
- ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
- for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
- phdr[index].p_type = (*seg).type();
- phdr[index].p_flags = (*seg).flag();
- phdr[index].p_offset = (*seg).offset();
- phdr[index].p_vaddr = (*seg).vaddr();
- phdr[index].p_paddr = (*seg).paddr();
- phdr[index].p_filesz = (*seg).filesz();
- phdr[index].p_memsz = (*seg).memsz();
- phdr[index].p_align = (*seg).align();
+ // 2.3 a special case. Use the target default to decide if the stack should
+ // be executable
+ if (llvm::ELF::SHF_EXECINSTR != flag && object_count != stack_note_count)
+ if (isDefaultExecStack())
+ flag = llvm::ELF::SHF_EXECINSTR;
}
-}
-/// writeELF64ProgramHdrs - write out the ELF64 program headers
-void GNULDBackend::writeELF64ProgramHdrs(Output& pOutput)
-{
- assert(pOutput.hasMemArea());
-
- uint64_t start_offset, phdr_size;
-
- start_offset = sizeof(llvm::ELF::Elf64_Ehdr);
- phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
- // Program header must start directly after ELF header
- MemoryRegion *region = pOutput.memArea()->request(start_offset,
- numOfSegments() *phdr_size);
- llvm::ELF::Elf64_Phdr* phdr = (llvm::ELF::Elf64_Phdr*)region->start();
-
- size_t index = 0;
- ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
- for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
- phdr[index].p_type = (*seg).type();
- phdr[index].p_flags = (*seg).flag();
- phdr[index].p_offset = (*seg).offset();
- phdr[index].p_vaddr = (*seg).vaddr();
- phdr[index].p_paddr = (*seg).paddr();
- phdr[index].p_filesz = (*seg).filesz();
- phdr[index].p_memsz = (*seg).memsz();
- phdr[index].p_align = (*seg).align();
- }
+ if (pOutput.type() != Output::Object)
+ m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_STACK,
+ llvm::ELF::PF_R |
+ llvm::ELF::PF_W |
+ getSegmentFlag(flag));
+ else
+ pLinker.getOrCreateOutputSectHdr(".note.GNU-stack",
+ LDFileFormat::Note,
+ llvm::ELF::SHT_PROGBITS,
+ flag);
}
/// preLayout - Backend can do any needed modification before layout
@@ -963,6 +1573,16 @@
{
// prelayout target first
doPreLayout(pOutput, pLDInfo, pLinker);
+
+ if (pLDInfo.options().hasEhFrameHdr()) {
+ // init EhFrameHdr and size the output section
+ ELFFileFormat* format = getOutputFormat(pOutput);
+ assert(NULL != getEhFrame());
+ m_pEhFrameHdr = new EhFrameHdr(*getEhFrame(),
+ format->getEhFrame(),
+ format->getEhFrameHdr());
+ m_pEhFrameHdr->sizeOutput();
+ }
}
/// postLayout -Backend can do any needed modification after layout
@@ -970,10 +1590,36 @@
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // post layout target first
+ // 1. emit program headers
+ if (pOutput.type() != Output::Object) {
+ // 1.1 create program headers
+ createProgramHdrs(pLinker.getLDInfo().output(), pInfo);
+ }
+
+ // 1.2 create special GNU Stack note section or segment
+ createGNUStackInfo(pOutput, pInfo, pLinker);
+
+ if (pOutput.type() != Output::Object) {
+ // 1.3 set up the attributes of program headers
+ setupProgramHdrs(pOutput, pInfo);
+ }
+
+ // 2. target specific post layout
doPostLayout(pOutput, pInfo, pLinker);
}
+void GNULDBackend::postProcessing(const Output& pOutput,
+ const MCLDInfo& pInfo,
+ MCLinker& pLinker)
+{
+ if (pInfo.options().hasEhFrameHdr()) {
+ // emit eh_frame_hdr
+ if (bitclass() == 32)
+ m_pEhFrameHdr->emitOutput<32>(pLinker.getLDInfo().output(),
+ pLinker);
+ }
+}
+
/// getHashBucketCount - calculate hash bucket count.
/// @ref Google gold linker, dynobj.cc:791
unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
@@ -1012,10 +1658,147 @@
// If we are building shared object, and the visibility is external, we
// need to add it.
- if (Output::DynObj == pOutput.type())
+ if (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type())
if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
return true;
+ return false;
+}
+
+/// commonPageSize - the common page size of the target machine.
+/// @ref gold linker: target.h:135
+uint64_t GNULDBackend::commonPageSize(const MCLDInfo& pInfo) const
+{
+ if (pInfo.options().commPageSize() > 0)
+ return std::min(pInfo.options().commPageSize(), abiPageSize(pInfo));
+ else
+ return std::min(static_cast<uint64_t>(0x1000), abiPageSize(pInfo));
+}
+
+/// abiPageSize - the abi page size of the target machine.
+/// @ref gold linker: target.h:125
+uint64_t GNULDBackend::abiPageSize(const MCLDInfo& pInfo) const
+{
+ if (pInfo.options().maxPageSize() > 0)
+ return pInfo.options().maxPageSize();
+ else
+ return static_cast<uint64_t>(0x1000);
+}
+
+/// isOutputPIC - return whether the output is position-independent
+bool GNULDBackend::isOutputPIC(const Output& pOutput,
+ const MCLDInfo& pInfo) const
+{
+ if (Output::DynObj == pOutput.type() || pInfo.options().isPIE())
+ return true;
+ return false;
+}
+
+/// isStaticLink - return whether we're doing static link
+bool GNULDBackend::isStaticLink(const Output& pOutput,
+ const MCLDInfo& pInfo) const
+{
+ InputTree::const_iterator it = pInfo.inputs().begin();
+ if (!isOutputPIC(pOutput, pInfo) && (*it)->attribute()->isStatic())
+ return true;
+ return false;
+}
+
+/// isSymbolPreemtible - whether the symbol can be preemted by other
+/// link unit
+/// @ref Google gold linker, symtab.h:551
+bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if (pSym.other() != ResolveInfo::Default)
+ return false;
+
+ if (Output::DynObj != pOutput.type())
+ return false;
+
+ if (pLDInfo.options().Bsymbolic())
+ return false;
+
+ return true;
+}
+
+/// symbolNeedsPLT - return whether the symbol needs a PLT entry
+/// @ref Google gold linker, symtab.h:596
+bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ if (pSym.isUndef() && !pSym.isDyn() && pOutput.type() != Output::DynObj)
+ return false;
+
+ // An IndirectFunc symbol (i.e., STT_GNU_IFUNC) always needs a plt entry
+ if (pSym.type() == ResolveInfo::IndirectFunc)
+ return true;
+
+ if (pSym.type() != ResolveInfo::Function)
+ return false;
+
+ if (isStaticLink(pOutput, pLDInfo) || pLDInfo.options().isPIE())
+ return false;
+
+ return (pSym.isDyn() ||
+ pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput));
+}
+
+/// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation
+/// @ref Google gold linker, symtab.h:645
+bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym,
+ bool pSymHasPLT,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput,
+ bool isAbsReloc) const
+{
+ // an undefined reference in the executables should be statically
+ // resolved to 0 and no need a dynamic relocation
+ if (pSym.isUndef() && !pSym.isDyn() && (Output::Exec == pOutput.type()))
+ return false;
+ if (pSym.isAbsolute())
+ return false;
+ if (isOutputPIC(pOutput, pLDInfo) && isAbsReloc)
+ return true;
+ if (pSymHasPLT && ResolveInfo::Function == pSym.type())
+ return false;
+ if (!isOutputPIC(pOutput, pLDInfo) && pSymHasPLT)
+ return false;
+ if (pSym.isDyn() || pSym.isUndef() ||
+ isSymbolPreemptible(pSym, pLDInfo, pOutput))
+ return true;
return false;
}
+
+/// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
+bool GNULDBackend::symbolNeedsCopyReloc(const Layout& pLayout,
+ const Relocation& pReloc,
+ const ResolveInfo& pSym,
+ const MCLDInfo& pLDInfo,
+ const Output& pOutput) const
+{
+ // only the reference from dynamic executable to non-function symbol in
+ // the dynamic objects may need copy relocation
+ if (isOutputPIC(pOutput, pLDInfo) ||
+ !pSym.isDyn() ||
+ pSym.type() == ResolveInfo::Function ||
+ pSym.size() == 0)
+ return false;
+
+ // check if the option -z nocopyreloc is given
+ if (pLDInfo.options().hasNoCopyReloc())
+ return false;
+
+ // TODO: Is this check necessary?
+ // if relocation target place is readonly, a copy relocation is needed
+ if ((pLayout.getOutputLDSection(*pReloc.targetRef().frag())->flag() &
+ llvm::ELF::SHF_WRITE) == 0)
+ return true;
+
+ return false;
+}
+
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.cpp b/lib/Target/Mips/MipsAndroidSectLinker.cpp
deleted file mode 100644
index e697fbc..0000000
--- a/lib/Target/Mips/MipsAndroidSectLinker.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-//===- MipsAndroidSectLinker.cpp ------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsAndroidSectLinker.h"
-
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-MipsAndroidSectLinker::MipsAndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : AndroidSectLinker(pOption,
- pLDBackend) {
- MCLDInfo &info = pOption.info();
- // set up target-dependent constraints of attibutes
- info.attrFactory().constraint().disableWholeArchive();
- info.attrFactory().constraint().disableAsNeeded();
- info.attrFactory().constraint().setSharedSystem();
-
- // set up the predefined attributes
- info.attrFactory().predefined().unsetWholeArchive();
- info.attrFactory().predefined().setDynamic();
-}
-
-MipsAndroidSectLinker::~MipsAndroidSectLinker()
-{
-}
diff --git a/lib/Target/Mips/MipsAndroidSectLinker.h b/lib/Target/Mips/MipsAndroidSectLinker.h
deleted file mode 100644
index ba216e4..0000000
--- a/lib/Target/Mips/MipsAndroidSectLinker.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- MipsAndroidSectLinker.h --------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MIPS_ANDROIDSECTLINKER_H
-#define MIPS_ANDROIDSECTLINKER_H
-
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-
-#include "mcld/Target/AndroidSectLinker.h"
-
-namespace mcld
-{
-
-/** \class MipsAndroidSectLinker
- * \brief MipsAndroidSectLinker sets up the environment for linking.
- *
- */
-class MipsAndroidSectLinker : public AndroidSectLinker
-{
-public:
- MipsAndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- ~MipsAndroidSectLinker();
-};
-
-} // namespace of mcld
-
-#endif
diff --git a/lib/Target/Mips/MipsDiagnostic.cpp b/lib/Target/Mips/MipsDiagnostic.cpp
new file mode 100644
index 0000000..c90c6ef
--- /dev/null
+++ b/lib/Target/Mips/MipsDiagnostic.cpp
@@ -0,0 +1,35 @@
+//===- MipsDiagnostic.cpp -------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/DWARFLineInfo.h>
+#include "Mips.h"
+
+using namespace mcld;
+
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createMipsDiagnostic - the help function to create corresponding
+// MipsDiagnostic
+DiagnosticLineInfo* createMipsDiagLineInfo(const llvm::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//==========================
+// InitializeMipsDiagnostic
+extern "C" void LLVMInitializeMipsDiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheMipselTarget, createMipsDiagLineInfo);
+}
+
diff --git a/lib/Target/Mips/MipsELFSectLinker.cpp b/lib/Target/Mips/MipsELFSectLinker.cpp
index aa41f36..dedf505 100644
--- a/lib/Target/Mips/MipsELFSectLinker.cpp
+++ b/lib/Target/Mips/MipsELFSectLinker.cpp
@@ -6,7 +6,6 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-
#include "MipsELFSectLinker.h"
#include <mcld/CodeGen/SectLinkerOption.h>
@@ -31,3 +30,4 @@
MipsELFSectLinker::~MipsELFSectLinker()
{
}
+
diff --git a/lib/Target/Mips/MipsELFSectLinker.h b/lib/Target/Mips/MipsELFSectLinker.h
index 949508d..1aacfef 100644
--- a/lib/Target/Mips/MipsELFSectLinker.h
+++ b/lib/Target/Mips/MipsELFSectLinker.h
@@ -6,8 +6,8 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#ifndef MIPS_ELFSECTLINKER_H
-#define MIPS_ELFSECTLINKER_H
+#ifndef MIPS_ELF_SECTION_LINKER_H
+#define MIPS_ELF_SECTION_LINKER_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
@@ -31,3 +31,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/Mips/MipsGOT.cpp b/lib/Target/Mips/MipsGOT.cpp
index e1185ca..9baa033 100644
--- a/lib/Target/Mips/MipsGOT.cpp
+++ b/lib/Target/Mips/MipsGOT.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include "MipsGOT.h"
namespace {
@@ -31,7 +31,7 @@
new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
if (NULL == entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
+ fatal(diag::fail_allocate_memory) << "GOT0";
m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
}
@@ -41,8 +41,7 @@
iterator ie = m_SectionData.end();
for (size_t i = 1; i < MipsGOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+ assert((it != ie) && "Generation of GOT0 entries is incomplete!");
++it;
}
@@ -95,7 +94,7 @@
new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
if (NULL == entry)
- llvm::report_fatal_error("Allocating new GOTEntry failed");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
}
@@ -118,12 +117,22 @@
GOTEntry* MipsGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
+ if (isLocal(&pInfo) && pInfo.type() == ResolveInfo::Section) {
+ pExist = false;
+ iterator& it = m_LocalGOTIterator;
+ ++it;
+ assert(it != m_SectionData.getFragmentList().end() &&
+ "The number of GOT Entries and ResolveInfo doesn't match");
+ GOTEntry* entry = llvm::cast<GOTEntry>(&(*it));
+ return entry;
+ }
+
GOTEntry*& entry = m_GeneralGOTMap[&pInfo];
pExist = NULL != entry;
if (!pExist) {
- iterator& it = pInfo.isLocal() ? m_LocalGOTIterator : m_GlobalGOTIterator;
+ iterator& it = isLocal(&pInfo) ? m_LocalGOTIterator : m_GlobalGOTIterator;
++it;
@@ -145,3 +154,4 @@
{
return m_pLocalNum;
}
+
diff --git a/lib/Target/Mips/MipsGOT.h b/lib/Target/Mips/MipsGOT.h
index dc8a23e..2f04ef4 100644
--- a/lib/Target/Mips/MipsGOT.h
+++ b/lib/Target/Mips/MipsGOT.h
@@ -26,6 +26,7 @@
{
private:
typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
+ typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolTypeMapType;
public:
typedef llvm::MCSectionData::iterator iterator;
@@ -50,8 +51,26 @@
size_t getTotalNum() const;
size_t getLocalNum() const;
+ void setLocal(const ResolveInfo* pInfo) {
+ m_GOTTypeMap[pInfo] = false;
+ }
+
+ void setGlobal(const ResolveInfo* pInfo) {
+ m_GOTTypeMap[pInfo] = true;
+ }
+
+ bool isLocal(const ResolveInfo* pInfo) {
+ return m_GOTTypeMap[pInfo] == false;
+ }
+
+ bool isGlobal(const ResolveInfo* pInfo) {
+ return m_GOTTypeMap[pInfo] == true;
+ }
+
private:
- SymbolIndexMapType m_GeneralGOTMap;
+ SymbolIndexMapType m_GeneralGOTMap; // Map ResolveInfo* to GOTEntry *.
+ SymbolTypeMapType m_GOTTypeMap;
+
iterator m_LocalGOTIterator; // last local GOT entries
iterator m_GlobalGOTIterator; // last global GOT entries
size_t m_pLocalNum;
@@ -64,3 +83,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp
index c7a6b23..87e43b8 100644
--- a/lib/Target/Mips/MipsLDBackend.cpp
+++ b/lib/Target/Mips/MipsLDBackend.cpp
@@ -14,6 +14,7 @@
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Target/OutputRelocSection.h>
@@ -66,11 +67,24 @@
void MipsGNULDBackend::initTargetSections(MCLinker& pLinker)
{
- // Nothing to do because we do not support
- // any MIPS specific sections now.
+ // Set up .dynamic
+ ELFFileFormat* file_format = NULL;
+ switch(pLinker.getLDInfo().output().type()) {
+ case Output::DynObj:
+ file_format = getDynObjFileFormat();
+ break;
+ case Output::Exec:
+ file_format = getExecFileFormat();
+ break;
+ case Output::Object:
+ default:
+ // TODO: not support yet
+ return;
+ }
+ file_format->getDynamic().setFlag(llvm::ELF::SHF_ALLOC);
}
-void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker)
+void MipsGNULDBackend::initTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
@@ -120,12 +134,21 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput)
+ const Output& pOutput,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) {
+ if (rsym->isLocal()) {
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+ }
+ return;
+ }
+
// A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies
// that a .got section is needed.
if (NULL == m_pGOT && NULL != m_pGOTSymbol) {
@@ -134,7 +157,15 @@
}
}
- if (rsym->isLocal())
+ // Skip relocation against _gp_disp
+ if (strcmp("_gp_disp", pInputSym.name()) == 0)
+ return;
+
+ // We test isLocal or if pInputSym is not a dynamic symbol
+ // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn()
+ // Don't put undef symbols into local entries.
+ if ((rsym->isLocal() || !isDynamicSymbol(pInputSym, pOutput) ||
+ !rsym->isDyn()) && !rsym->isUndef())
scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
else
scanGlobalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
@@ -177,6 +208,11 @@
return 32;
}
+uint64_t MipsGNULDBackend::defaultTextSegmentAddr() const
+{
+ return 0x80000;
+}
+
void MipsGNULDBackend::doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
MCLinker& pLinker)
@@ -191,9 +227,6 @@
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // emit program headers
- if (pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
- emitProgramHdrs(pLinker.getLDInfo().output());
}
/// dynamic - the dynamic section of the target machine.
@@ -217,11 +250,12 @@
uint64_t MipsGNULDBackend::emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const
{
assert(pRegion.size() && "Size of MemoryRegion is zero!");
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
if (&pSection == &(file_format->getGOT())) {
assert(NULL != m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
@@ -229,17 +263,15 @@
return result;
}
- llvm::report_fatal_error(llvm::Twine("Unable to emit section `") +
- pSection.name() +
- llvm::Twine("'.\n"));
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "[email protected]";
return 0;
}
-/// isGOTSymbol - return true if the symbol is the GOT entry.
-bool MipsGNULDBackend::isGOTSymbol(const LDSymbol& pSymbol) const
+/// isGlobalGOTSymbol - return true if the symbol is the global GOT entry.
+bool MipsGNULDBackend::isGlobalGOTSymbol(const LDSymbol& pSymbol) const
{
- return std::find(m_LocalGOTSyms.begin(),
- m_LocalGOTSyms.end(), &pSymbol) != m_LocalGOTSyms.end() ||
- std::find(m_GlobalGOTSyms.begin(),
+ return std::find(m_GlobalGOTSyms.begin(),
m_GlobalGOTSyms.end(), &pSymbol) != m_GlobalGOTSyms.end();
}
@@ -326,7 +358,7 @@
if (!isDynamicSymbol(**symbol, pOutput))
continue;
- if (isGOTSymbol(**symbol))
+ if (isGlobalGOTSymbol(**symbol))
continue;
emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
@@ -342,6 +374,12 @@
symbol_end = m_GlobalGOTSyms.end();
symbol != symbol_end; ++symbol) {
+ // Make sure this golbal GOT entry is a dynamic symbol.
+ // If not, something is wrong earlier when putting this symbol into
+ // global GOT.
+ if (!isDynamicSymbol(**symbol, pOutput))
+ fatal(diag::mips_got_symbol) << (*symbol)->name();
+
emitDynamicSymbol(symtab32[symtabIdx], pOutput, **symbol, pLayout, strtab,
strtabsize, symtabIdx);
@@ -382,7 +420,8 @@
// emit soname
// initialize value of ELF .dynamic section
- dynamic().applySoname(strtabsize);
+ if (Output::DynObj == pOutput.type())
+ dynamic().applySoname(strtabsize);
dynamic().applyEntries(pLDInfo, *file_format);
dynamic().emit(dyn_sect, *dyn_region);
@@ -445,9 +484,10 @@
unsigned int
MipsGNULDBackend::getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
if (&pSectHdr == &file_format->getGOT())
return SHO_DATA;
@@ -456,15 +496,10 @@
}
/// finalizeSymbol - finalize the symbol value
-/// If the symbol's reserved field is not zero, MCLinker will call back this
-/// function to ask the final value of the symbol
-bool MipsGNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+bool MipsGNULDBackend::finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
- if (&pSymbol == m_pGpDispSymbol) {
- m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
- return true;
- }
- return false;
+ m_pGpDispSymbol->setValue(m_pGOT->getSection().addr() + 0x7FF0);
+ return true;
}
/// allocateCommonSymbols - allocate common symbols in the corresponding
@@ -474,96 +509,112 @@
bool
MipsGNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
{
- // SymbolCategory contains all symbols that must emit to the output files.
- // We are not like Google gold linker, we don't remember symbols before symbol
- // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
- // don't need to care about some symbols may be changed its category due to symbol
- // resolution.
SymbolCategory& symbol_list = pLinker.getOutputSymbols();
if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
return true;
- // addralign := max value of all common symbols
- uint64_t addralign = 0x0;
-
- // Due to the visibility, some common symbols may be forcefully local.
- SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
- }
-
- // global common symbols.
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
+ SymbolCategory::iterator com_sym, com_end;
// FIXME: If the order of common symbols is defined, then sort common symbols
- // com_sym = symbol_list.commonBegin();
// std::sort(com_sym, com_end, some kind of order);
// get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ LDSection* bss_sect = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+
+ LDSection* tbss_sect = &pLinker.getOrCreateOutputSectHdr(
".tbss",
LDFileFormat::BSS,
llvm::ELF::SHT_NOBITS,
llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
- else {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+
+ // FIXME: .sbss amd .lbss currently unused.
+ /*
+ LDSection* sbss_sect = &pLinker.getOrCreateOutputSectHdr(
+ ".sbss",
LDFileFormat::BSS,
llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_MIPS_GPREL);
+
+ LDSection* lbss_sect = &pLinker.getOrCreateOutputSectHdr(
+ ".lbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_MIPS_LOCAL);
+ */
+
+ assert(NULL != bss_sect && NULL != tbss_sect);
// get or create corresponding BSS MCSectionData
- assert(NULL != bss_sect_hdr);
- llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
+ llvm::MCSectionData& bss_sect_data = pLinker.getOrCreateSectData(*bss_sect);
+ llvm::MCSectionData& tbss_sect_data = pLinker.getOrCreateSectData(*tbss_sect);
- // allocate all common symbols
- uint64_t offset = bss_sect_hdr->size();
+ // remember original BSS size
+ uint64_t bss_offset = bss_sect->size();
+ uint64_t tbss_offset = tbss_sect->size();
// allocate all local common symbols
com_end = symbol_list.localEnd();
+
for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
if (ResolveInfo::Common == (*com_sym)->desc()) {
- alignAddress(offset, (*com_sym)->value());
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
(*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- offset += (*com_sym)->size();
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ // FIXME: how to identify small and large common symbols?
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
}
}
// allocate all global common symbols
com_end = symbol_list.commonEnd();
for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- alignAddress(offset, (*com_sym)->value());
-
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size(), &bss_section);
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
(*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- offset += (*com_sym)->size();
+
+ if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
+ // allocate TLS common symbol in tbss section
+ tbss_offset += pLinker.getLayout().appendFragment(*frag,
+ tbss_sect_data,
+ (*com_sym)->value());
+ }
+ // FIXME: how to identify small and large common symbols?
+ else {
+ bss_offset += pLinker.getLayout().appendFragment(*frag,
+ bss_sect_data,
+ (*com_sym)->value());
+ }
}
- bss_sect_hdr->setSize(offset);
+ bss_sect->setSize(bss_offset);
+ tbss_sect->setSize(tbss_offset);
symbol_list.changeCommonsToGlobal();
return true;
}
@@ -573,7 +624,7 @@
const Layout& pLayout) const
{
// Update value keep in addend if we meet a section symbol
- if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ if (pReloc.symInfo()->type() == ResolveInfo::Section) {
pReloc.setAddend(pLayout.getOutputOffset(
*pInputSym.fragRef()) + pReloc.addend());
}
@@ -604,6 +655,12 @@
m_pRelDyn->reserveEntry(*m_pRelocFactory);
rsym->setReserved(rsym->reserved() | ReserveRel);
+
+ // Remeber this rsym is a local GOT entry (as if it needs an entry).
+ // Actually we don't allocate an GOT entry.
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+ m_pGOT->setLocal(rsym);
}
break;
case llvm::ELF::R_MIPS_REL32:
@@ -637,10 +694,19 @@
if (NULL == m_pGOT)
createGOT(pLinker, pOutput);
+ // For got16 section based relocations, we need to reserve got entries.
+ if (rsym->type() == ResolveInfo::Section) {
+ m_pGOT->reserveLocalEntry();
+ // Remeber this rsym is a local GOT entry
+ m_pGOT->setLocal(rsym);
+ return;
+ }
+
if (!(rsym->reserved() & MipsGNULDBackend::ReserveGot)) {
m_pGOT->reserveLocalEntry();
rsym->setReserved(rsym->reserved() | ReserveGot);
- m_LocalGOTSyms.push_back(rsym->outSymbol());
+ // Remeber this rsym is a local GOT entry
+ m_pGOT->setLocal(rsym);
}
break;
case llvm::ELF::R_MIPS_GPREL32:
@@ -668,11 +734,8 @@
case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
break;
default:
- llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine("for the local symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
}
}
@@ -701,12 +764,18 @@
case llvm::ELF::R_MIPS_64:
case llvm::ELF::R_MIPS_HI16:
case llvm::ELF::R_MIPS_LO16:
- if (isSymbolNeedsDynRel(*rsym, pOutput)) {
+ if (symbolNeedsDynRel(*rsym, false, pLDInfo, pOutput, true)) {
if (NULL == m_pRelDyn)
createRelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
rsym->setReserved(rsym->reserved() | ReserveRel);
+
+ // Remeber this rsym is a global GOT entry (as if it needs an entry).
+ // Actually we don't allocate an GOT entry.
+ if (NULL == m_pGOT)
+ createGOT(pLinker, pOutput);
+ m_pGOT->setGlobal(rsym);
}
break;
case llvm::ELF::R_MIPS_GOT16:
@@ -725,16 +794,14 @@
m_pGOT->reserveGlobalEntry();
rsym->setReserved(rsym->reserved() | ReserveGot);
m_GlobalGOTSyms.push_back(rsym->outSymbol());
+ // Remeber this rsym is a global GOT entry
+ m_pGOT->setGlobal(rsym);
}
break;
case llvm::ELF::R_MIPS_LITERAL:
case llvm::ELF::R_MIPS_GPREL32:
- llvm::report_fatal_error(llvm::Twine("Relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine(" is not defined for the "
- "global symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::invalid_global_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
break;
case llvm::ELF::R_MIPS_GPREL16:
break;
@@ -766,45 +833,14 @@
case llvm::ELF::R_MIPS_COPY:
case llvm::ELF::R_MIPS_GLOB_DAT:
case llvm::ELF::R_MIPS_JUMP_SLOT:
- llvm::report_fatal_error(llvm::Twine("Relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine("for the global symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("' should only be seen "
- "by the dynamic linker"));
+ fatal(diag::dynamic_relocation) << (int)pReloc.type();
break;
default:
- llvm::report_fatal_error(llvm::Twine("Unknown relocation ") +
- llvm::Twine(pReloc.type()) +
- llvm::Twine("for the global symbol `") +
- pReloc.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)pReloc.type()
+ << pReloc.symInfo()->name();
}
}
-bool MipsGNULDBackend::isSymbolNeedsPLT(ResolveInfo& pSym,
- const Output& pOutput) const
-{
- return (Output::DynObj == pOutput.type() &&
- ResolveInfo::Function == pSym.type() &&
- (pSym.isDyn() || pSym.isUndef()));
-}
-
-bool MipsGNULDBackend::isSymbolNeedsDynRel(ResolveInfo& pSym,
- const Output& pOutput) const
-{
- if(pSym.isUndef() && Output::Exec == pOutput.type())
- return false;
- if(pSym.isAbsolute())
- return false;
- if(Output::DynObj == pOutput.type())
- return true;
- if(pSym.isDyn() || pSym.isUndef())
- return true;
-
- return false;
-}
-
void MipsGNULDBackend::createGOT(MCLinker& pLinker, const Output& pOutput)
{
ELFFileFormat* file_format = getOutputFormat(pOutput);
@@ -813,7 +849,7 @@
m_pGOT = new MipsGOT(got, pLinker.getOrCreateSectData(got));
// define symbol _GLOBAL_OFFSET_TABLE_ when .got create
- if( m_pGOTSymbol != NULL ) {
+ if ( m_pGOTSymbol != NULL ) {
pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
false,
@@ -851,22 +887,6 @@
8);
}
-ELFFileFormat* MipsGNULDBackend::getOutputFormat(const Output& pOutput) const
-{
- switch (pOutput.type()) {
- case Output::DynObj:
- return getDynObjFileFormat();
- case Output::Exec:
- return getExecFileFormat();
- case Output::Object:
- return NULL;
- default:
- llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
- llvm::Twine(pOutput.type()));
- return NULL;
- }
-}
-
//===----------------------------------------------------------------------===//
/// createMipsLDBackend - the help funtion to create corresponding MipsLDBackend
///
diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h
index c4f1d46..f9742ed 100644
--- a/lib/Target/Mips/MipsLDBackend.h
+++ b/lib/Target/Mips/MipsLDBackend.h
@@ -43,7 +43,7 @@
void initTargetSections(MCLinker& pLinker);
/// initTargetSymbols - initialize target dependent symbols in output.
- void initTargetSymbols(MCLinker& pLinker);
+ void initTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// initRelocFactory - create and initialize RelocationFactory.
bool initRelocFactory(const MCLinker& pLinker);
@@ -58,7 +58,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput);
+ const Output& pOutput,
+ const LDSection& pSection);
uint32_t machine() const;
@@ -75,6 +76,8 @@
unsigned int bitclass() const;
+ uint64_t defaultTextSegmentAddr() const;
+
/// preLayout - Backend can do any needed modification before layout
void doPreLayout(const Output& pOutput,
const MCLDInfo& pInfo,
@@ -107,11 +110,13 @@
/// @param pOutput - the output file
/// @param pSection - the given LDSection
/// @param pInfo - all options in the command line.
+ /// @param pLayout - for comouting the size of fragment
/// @param pRegion - the region to write out data
/// @return the size of the table in the file.
uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const;
/// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
@@ -128,12 +133,11 @@
/// getTargetSectionOrder - compute the layout order of ARM target sections
unsigned int getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
/// finalizeSymbol - finalize the symbol value
- /// If the symbol's reserved field is not zero, MCLinker will call back this
- /// function to ask the final value of the symbol
- bool finalizeSymbol(LDSymbol& pSymbol) const;
+ bool finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections.
@@ -152,14 +156,9 @@
const MCLDInfo& pLDInfo,
const Output& pOutput);
- bool isSymbolNeedsPLT(ResolveInfo& pSym, const Output& pOutput) const;
- bool isSymbolNeedsDynRel(ResolveInfo& pSym, const Output& pOutput) const;
-
void createGOT(MCLinker& pLinker, const Output& pOutput);
void createRelDyn(MCLinker& pLinker, const Output& pOutput);
- ELFFileFormat* getOutputFormat(const Output& pOutput) const;
-
/// updateAddend - update addend value of the relocation if the
/// the target symbol is a section symbol. Addend is the offset
/// in the section. This value should be updated after section
@@ -178,12 +177,11 @@
LDSymbol* m_pGOTSymbol;
LDSymbol* m_pGpDispSymbol;
- std::vector<LDSymbol*> m_LocalGOTSyms;
std::vector<LDSymbol*> m_GlobalGOTSyms;
private:
- /// isGOTSymbol - return true if the symbol is the GOT entry.
- bool isGOTSymbol(const LDSymbol& pSymbol) const;
+ /// isGlobalGOTSymbol - return true if the symbol is the global GOT entry.
+ bool isGlobalGOTSymbol(const LDSymbol& pSymbol) const;
/// emitDynamicSymbol - emit dynamic symbol.
void emitDynamicSymbol(llvm::ELF::Elf32_Sym& sym32,
Output& pOutput,
@@ -197,3 +195,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/Mips/MipsRelocationFactory.cpp b/lib/Target/Mips/MipsRelocationFactory.cpp
index e3a7793..948e026 100644
--- a/lib/Target/Mips/MipsRelocationFactory.cpp
+++ b/lib/Target/Mips/MipsRelocationFactory.cpp
@@ -9,9 +9,9 @@
#include <llvm/ADT/Twine.h>
#include <llvm/Support/ELF.h>
-#include <llvm/Support/ErrorHandling.h>
#include <mcld/LD/Layout.h>
#include <mcld/Target/OutputRelocSection.h>
+#include <mcld/Support/MsgHandling.h>
#include "MipsRelocationFactory.h"
#include "MipsRelocationFunctions.h"
@@ -54,32 +54,26 @@
Relocation::Type type = pRelocation.type();
if (type >= sizeof(apply_functions) / sizeof(apply_functions[0])) {
- llvm::report_fatal_error(llvm::Twine("Unknown relocation type. "
- "To symbol `") +
- pRelocation.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)type
+ << pRelocation.symInfo()->name();
}
// apply the relocation
Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
// check result
+ if (OK == result) {
+ return;
+ }
if (Overflow == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' causes overflow. on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_overflow) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
if (BadReloc == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' encounters unexpected opcode. "
- "on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_badreloc) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
}
@@ -90,26 +84,6 @@
static const char * const GP_DISP_NAME = "_gp_disp";
-// Get an relocation entry in .rel.dyn and set its type to R_MIPS_REL32,
-// its FragmentRef to pReloc->targetFrag() and its ResolveInfo
-// to pReloc->symInfo()
-static
-void helper_SetRelDynEntry(Relocation& pReloc,
- MipsRelocationFactory& pParent)
-{
- // rsym - The relocation target symbol
- ResolveInfo* rsym = pReloc.symInfo();
- MipsGNULDBackend& ld_backend = pParent.getTarget();
-
- bool exist;
- Relocation& rel_entry =
- *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
-
- rel_entry.setType(llvm::ELF::R_MIPS_REL32);
- rel_entry.targetRef() = pReloc.targetRef();
- rel_entry.setSymInfo(0);
-}
-
// Find next R_MIPS_LO16 relocation paired to pReloc.
static
Relocation* helper_FindLo16Reloc(Relocation& pReloc)
@@ -142,24 +116,27 @@
static
GOTEntry& helper_GetGOTEntry(Relocation& pReloc,
- MipsRelocationFactory& pParent)
+ MipsRelocationFactory& pParent,
+ bool& pExist, int32_t value)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
MipsGNULDBackend& ld_backend = pParent.getTarget();
+ MipsGOT& got = ld_backend.getGOT();
- bool exist;
- GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
+ GOTEntry& got_entry = *got.getEntry(*rsym, pExist);
- if (exist)
+ if (pExist)
return got_entry;
// If we first get this GOT entry, we should initialize it.
- if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
- got_entry.setContent(pReloc.symValue());
- }
- else {
- llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ if (!(got.isLocal(rsym) && rsym->type() == ResolveInfo::Section)) {
+ if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
+ got_entry.setContent(pReloc.symValue());
+ }
+ else {
+ fatal(diag::reserve_entry_number_mismatch) << "GOT";
+ }
}
return got_entry;
@@ -169,7 +146,8 @@
RelocationFactory::Address helper_GetGOTOffset(Relocation& pReloc,
MipsRelocationFactory& pParent)
{
- GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
+ bool exist;
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, 0);
return pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
}
@@ -196,6 +174,7 @@
{
ResolveInfo* rsym = pReloc.symInfo();
MipsGNULDBackend& ld_backend = pParent.getTarget();
+ MipsGOT& got = ld_backend.getGOT();
bool exist;
Relocation& rel_entry =
@@ -203,7 +182,19 @@
rel_entry.setType(llvm::ELF::R_MIPS_REL32);
rel_entry.targetRef() = pReloc.targetRef();
- rel_entry.setSymInfo(rsym->isLocal() ? NULL : rsym);
+
+ RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
+ RelocationFactory::DWord S = pReloc.symValue();
+
+ if (got.isLocal(rsym)) {
+ rel_entry.setSymInfo(NULL);
+ pReloc.target() = A + S;
+ }
+ else {
+ rel_entry.setSymInfo(rsym);
+ // Don't add symbol value that will be resolved by the dynamic linker
+ pReloc.target() = A;
+ }
}
//=========================================//
@@ -227,14 +218,26 @@
{
ResolveInfo* rsym = pReloc.symInfo();
- if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
- helper_DynRel(pReloc, pParent);
- }
-
RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
RelocationFactory::DWord S = pReloc.symValue();
- pReloc.target() |= (S + A);
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ pReloc.target() = S + A;
+ return MipsRelocationFactory::OK;
+ }
+
+ if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
+ helper_DynRel(pReloc, pParent);
+
+ return MipsRelocationFactory::OK;
+ }
+
+ pReloc.target() = (S + A);
return MipsRelocationFactory::OK;
}
@@ -279,17 +282,21 @@
const MCLDInfo& pLDInfo,
MipsRelocationFactory& pParent)
{
- int32_t AHL = pParent.getAHL();
int32_t res = 0;
if (helper_isGpDisp(pReloc)) {
int32_t P = pReloc.place(pParent.getLayout());
int32_t GP = helper_GetGP(pParent);
+ int32_t AHL = pParent.getAHL();
res = AHL + GP - P + 4;
}
else {
int32_t S = pReloc.symValue();
- res = AHL + S;
+ // The previous AHL may be for other hi/lo pairs.
+ // We need to calcuate the lo part now. It is easy.
+ // Remember to add the section offset to ALO.
+ int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend();
+ res = ALO + S;
}
pReloc.target() &= 0xFFFF0000;
@@ -307,6 +314,7 @@
MipsRelocationFactory& pParent)
{
ResolveInfo* rsym = pReloc.symInfo();
+ RelocationFactory::Address G = 0;
if (rsym->isLocal()) {
Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
@@ -317,13 +325,16 @@
pParent.setAHL(AHL);
- GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent);
-
int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
- got_entry.setContent(res);
- }
+ bool exist;
+ GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, res);
- RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
+ got_entry.setContent(res);
+ G = pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
+ }
+ else {
+ G = helper_GetGOTOffset(pReloc, pParent);
+ }
pReloc.target() &= 0xFFFF0000;
pReloc.target() |= (G & 0xFFFF);
@@ -351,7 +362,8 @@
const MCLDInfo& pLDInfo,
MipsRelocationFactory& pParent)
{
- int32_t A = pReloc.target();
+ // Remember to add the section offset to A.
+ int32_t A = pReloc.target() + pReloc.addend();
int32_t S = pReloc.symValue();
int32_t GP = helper_GetGP(pParent);
diff --git a/lib/Target/Mips/MipsSectLinker.cpp b/lib/Target/Mips/MipsSectLinker.cpp
index af543c9..7a3082c 100644
--- a/lib/Target/Mips/MipsSectLinker.cpp
+++ b/lib/Target/Mips/MipsSectLinker.cpp
@@ -10,7 +10,7 @@
#include <llvm/ADT/Triple.h>
#include <mcld/Support/TargetRegistry.h>
#include "Mips.h"
-#include "MipsAndroidSectLinker.h"
+#include "MipsELFSectLinker.h"
using namespace mcld;
@@ -31,9 +31,7 @@
assert(0 && "COFF linker has not supported yet");
}
- // For now, use Android SectLinker directly
- return new MipsAndroidSectLinker(pOption,
- pLDBackend);
+ return new MipsELFSectLinker(pOption, pLDBackend);
}
} // namespace of mcld
diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp
index 89b4f52..dbb8194 100644
--- a/lib/Target/OutputRelocSection.cpp
+++ b/lib/Target/OutputRelocSection.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include <mcld/LD/LDSection.h>
#include <mcld/Target/OutputRelocSection.h>
+#include <mcld/Support/MsgHandling.h>
using namespace mcld;
@@ -64,18 +65,18 @@
if(isForGOT) {
// get or create entry in m_SymRelMap
- Relocation *&Entry = m_SymRelMap[&pSymbol];
- pExist = 1;
+ Relocation *&entry = m_SymRelMap[&pSymbol];
+ pExist = true;
- if(!Entry) {
- pExist = 0;
- Entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
+ if(NULL == entry) {
+ pExist = false;
+ entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
++m_ValidEntryIterator;
}
- result = Entry;
+ result = entry;
}
else {
- pExist = 0;
+ pExist = false;
result = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
++m_ValidEntryIterator;
}
diff --git a/lib/Target/Target.cpp b/lib/Target/Target.cpp
index 58178ec..ec8dc87 100644
--- a/lib/Target/Target.cpp
+++ b/lib/Target/Target.cpp
@@ -6,20 +6,19 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "mcld/Support/TargetRegistry.h"
-#include "mcld/Target/TargetMachine.h"
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/Target/TargetMachine.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Target/TargetMachine.h>
using namespace llvm;
-using namespace mcld;
-/* ** */
mcld::Target::Target()
- : TargetMachineCtorFn(0),
- SectLinkerCtorFn(0),
- TargetLDBackendCtorFn(0),
- m_pT(0)
+ : TargetMachineCtorFn(NULL),
+ SectLinkerCtorFn(NULL),
+ TargetLDBackendCtorFn(NULL),
+ DiagnosticLineInfoCtorFn(NULL),
+ m_pT(NULL)
{
}
diff --git a/lib/Target/TargetLDBackend.cpp b/lib/Target/TargetLDBackend.cpp
index 1a8ab6b..4eda0a6 100644
--- a/lib/Target/TargetLDBackend.cpp
+++ b/lib/Target/TargetLDBackend.cpp
@@ -14,10 +14,24 @@
/* ** */
TargetLDBackend::TargetLDBackend()
-{
+ : m_pEhFrame(NULL) {
}
TargetLDBackend::~TargetLDBackend()
{
+ if (NULL != m_pEhFrame)
+ delete m_pEhFrame;
}
+EhFrame* TargetLDBackend::getEhFrame()
+{
+ if (NULL == m_pEhFrame)
+ m_pEhFrame = new EhFrame();
+ return m_pEhFrame;
+}
+
+const EhFrame* TargetLDBackend::getEhFrame() const
+{
+ assert(NULL == m_pEhFrame);
+ return m_pEhFrame;
+}
diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h
index c575d80..2d07314 100644
--- a/lib/Target/X86/X86.h
+++ b/lib/Target/X86/X86.h
@@ -21,3 +21,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86AndroidSectLinker.cpp b/lib/Target/X86/X86AndroidSectLinker.cpp
deleted file mode 100644
index fe7a2cc..0000000
--- a/lib/Target/X86/X86AndroidSectLinker.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-//===- X86AndroidSectLinker.cpp -------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86AndroidSectLinker.h"
-
-#include <mcld/CodeGen/SectLinkerOption.h>
-
-using namespace mcld;
-
-X86AndroidSectLinker::X86AndroidSectLinker(SectLinkerOption &pOption,
- TargetLDBackend &pLDBackend)
- : AndroidSectLinker(pOption,
- pLDBackend) {
- MCLDInfo &info = pOption.info();
- // set up target-dependent constraints of attibutes
- info.attrFactory().constraint().disableWholeArchive();
- info.attrFactory().constraint().disableAsNeeded();
- info.attrFactory().constraint().setSharedSystem();
-
- // set up the predefined attributes
- info.attrFactory().predefined().unsetWholeArchive();
- info.attrFactory().predefined().setDynamic();
-
-}
-
-X86AndroidSectLinker::~X86AndroidSectLinker() {
-}
diff --git a/lib/Target/X86/X86AndroidSectLinker.h b/lib/Target/X86/X86AndroidSectLinker.h
deleted file mode 100644
index b275aca..0000000
--- a/lib/Target/X86/X86AndroidSectLinker.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===- X86AndroidSectLinker.h ---------------------------------------------===//
-//
-// The MCLinker Project
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef X86_ANDROIDSECTLINKER_H
-#define X86_ANDROIDSECTLINKER_H
-#ifdef ENABLE_UNITTEST
-#include <gtest.h>
-#endif
-#include <mcld/Target/AndroidSectLinker.h>
-
-namespace mcld
-{
-
-/** \class X86AndroidSectLinker
- * \brief X86AndroidSectLinker sets up the environment for linking.
- *
- * \see
- * \author Anders Cheng <[email protected]>
- */
-class X86AndroidSectLinker : public AndroidSectLinker
-{
-public:
- X86AndroidSectLinker(SectLinkerOption &pOption,
- mcld::TargetLDBackend &pLDBackend);
-
- ~X86AndroidSectLinker();
-};
-
-} // namespace of mcld
-
-#endif
-
diff --git a/lib/Target/X86/X86Diagnostic.cpp b/lib/Target/X86/X86Diagnostic.cpp
new file mode 100644
index 0000000..db12dde
--- /dev/null
+++ b/lib/Target/X86/X86Diagnostic.cpp
@@ -0,0 +1,38 @@
+//===- X86Diagnostic.cpp --------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <llvm/ADT/Triple.h>
+#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/DWARFLineInfo.h>
+#include "X86.h"
+
+using namespace mcld;
+
+//===----------------------------------------------------------------------===//
+// X86Diagnostic
+
+
+namespace mcld {
+//===----------------------------------------------------------------------===//
+// createX86Diagnostic - the help function to create corresponding X86Diagnostic
+//
+DiagnosticLineInfo* createX86DiagLineInfo(const llvm::Target& pTarget,
+ const std::string &pTriple)
+{
+ return new DWARFLineInfo();
+}
+
+} // namespace of mcld
+
+//==========================
+// InitializeX86Diagnostic
+extern "C" void LLVMInitializeX86DiagnosticLineInfo() {
+ // Register the linker frontend
+ mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86Target, createX86DiagLineInfo);
+}
+
diff --git a/lib/Target/X86/X86ELFDynamic.cpp b/lib/Target/X86/X86ELFDynamic.cpp
index ee6b1f6..af86b2c 100644
--- a/lib/Target/X86/X86ELFDynamic.cpp
+++ b/lib/Target/X86/X86ELFDynamic.cpp
@@ -13,24 +13,25 @@
using namespace mcld;
X86ELFDynamic::X86ELFDynamic(const GNULDBackend& pParent)
- : ELFDynamic(pParent), m_HasGOTPLT(false) {
+ : ELFDynamic(pParent)
+{
}
-X86ELFDynamic::~X86ELFDynamic() {
+X86ELFDynamic::~X86ELFDynamic()
+{
}
-void X86ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat) {
+void X86ELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat)
+{
// reservePLTGOT
- if (m_HasGOTPLT ? pFormat.hasGOTPLT() : pFormat.hasGOT())
+ if (pFormat.hasGOTPLT())
reserveOne(llvm::ELF::DT_PLTGOT);
}
-void X86ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat) {
+void X86ELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat)
+{
// applyPLTGOT
- if (m_HasGOTPLT) {
- if (pFormat.hasGOTPLT())
- applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
- }
- else if (pFormat.hasGOT())
- applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOT().addr());
+ if (pFormat.hasGOTPLT())
+ applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr());
}
+
diff --git a/lib/Target/X86/X86ELFDynamic.h b/lib/Target/X86/X86ELFDynamic.h
index b9e70ce..7053a0b 100644
--- a/lib/Target/X86/X86ELFDynamic.h
+++ b/lib/Target/X86/X86ELFDynamic.h
@@ -25,12 +25,6 @@
private:
void reserveTargetEntries(const ELFFileFormat& pFormat);
void applyTargetEntries(const ELFFileFormat& pFormat);
-
-private:
- // True if we have .got.plt section, which will avoid GOT0 entries
- // when PLT isn't used. To support .got.plt section, we must combine
- // .got section and .got.plt section into a single GOT.
- bool m_HasGOTPLT;
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp
index 544b5e9..91c7d65 100644
--- a/lib/Target/X86/X86GOT.cpp
+++ b/lib/Target/X86/X86GOT.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "X86GOT.h"
#include <mcld/LD/LDFileFormat.h>
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -21,36 +21,8 @@
// X86GOT
X86GOT::X86GOT(LDSection& pSection, llvm::MCSectionData& pSectionData)
: GOT(pSection, pSectionData, X86GOTEntrySize),
- m_GeneralGOTNum(0), m_GOTPLTNum(0), m_GeneralGOTIterator(),
- m_GOTPLTIterator(), m_LastGOT0()
+ m_GOTIterator(), m_fIsVisit(false)
{
- GOTEntry* Entry = 0;
-
- // Create GOT0 entries.
- for (unsigned int i = 0; i < X86GOT0Num; i++) {
- Entry = new (std::nothrow) GOTEntry(0, X86GOTEntrySize,
- &m_SectionData);
-
- if (!Entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
-
- m_Section.setSize(m_Section.size() + X86GOTEntrySize);
- }
-
- // Skip GOT0 entries.
- iterator it = m_SectionData.begin();
- iterator ie = m_SectionData.end();
-
- for (unsigned int i = 1; i < X86GOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
-
- ++it;
- }
-
- m_LastGOT0 = it;
- m_GeneralGOTIterator = it;
- m_GOTPLTIterator = it;
}
X86GOT::~X86GOT()
@@ -66,38 +38,37 @@
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating new memory for GOTEntry failed");
+ fatal(diag::fail_allocate_memory) << "GOTEntry";
m_Section.setSize(m_Section.size() + X86GOTEntrySize);
- ++m_GeneralGOTNum;
}
}
GOTEntry* X86GOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
- GOTEntry *&Entry = m_GeneralGOTMap[&pInfo];
+ // first time visit this function, set m_GOTIterator
+ if(!m_fIsVisit) {
+ assert( !m_SectionData.getFragmentList().empty() &&
+ "DynRelSection contains no entries.");
+ m_GOTIterator = m_SectionData.getFragmentList().begin();
+ m_fIsVisit = true;
+ }
+
+
+ GOTEntry *&Entry = m_GOTMap[&pInfo];
pExist = 1;
if (!Entry) {
pExist = 0;
-
- ++m_GeneralGOTIterator;
- assert(m_GeneralGOTIterator != m_SectionData.getFragmentList().end()
- && "The number of GOT Entries and ResolveInfo doesn't match!");
-
- Entry = llvm::cast<GOTEntry>(&(*m_GeneralGOTIterator));
+ assert(m_GOTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+ Entry = llvm::cast<GOTEntry>(&(*m_GOTIterator));
+ ++m_GOTIterator;
}
-
return Entry;
}
-void X86GOT::applyGOT0(uint64_t pAddress)
-{
- llvm::cast<GOTEntry>
- (*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
-}
-
X86GOT::iterator X86GOT::begin()
{
return m_SectionData.getFragmentList().begin();
@@ -118,11 +89,3 @@
return m_SectionData.getFragmentList().end();
}
-unsigned int X86GOT::getGOTPLTNum() const
-{ return m_GOTPLTNum; }
-
-X86GOT::iterator X86GOT::getLastGOT0()
-{ return m_LastGOT0; }
-
-const X86GOT::iterator X86GOT::getLastGOT0() const
-{ return m_LastGOT0; }
diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h
index 37b48a3..d758de0 100644
--- a/lib/Target/X86/X86GOT.h
+++ b/lib/Target/X86/X86GOT.h
@@ -23,18 +23,8 @@
* \brief X86 Global Offset Table.
*/
-const unsigned int X86GOT0Num = 3;
-
class X86GOT : public GOT
{
- friend void mcld::X86PLT::reserveEntry(size_t pNum);
-
- friend mcld::PLTEntry* mcld::X86PLT::getPLTEntry(
- const mcld::ResolveInfo& pSymbol,bool& pExist);
-
- friend mcld::GOTEntry* mcld::X86PLT::getGOTPLTEntry(
- const mcld::ResolveInfo& pSymbol,bool& pExist);
-
typedef llvm::DenseMap<const ResolveInfo*, GOTEntry*> SymbolIndexMapType;
public:
@@ -51,8 +41,6 @@
GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
- void applyGOT0(uint64_t pAddress);
-
iterator begin();
const_iterator begin() const;
@@ -61,30 +49,17 @@
const_iterator end() const;
- unsigned int getGOTPLTNum() const;
-
- iterator getLastGOT0();
-
- const iterator getLastGOT0() const;
-
private:
+ /// m_GOTIterator - point to the first valid entry in GOT list
+ iterator m_GOTIterator;
- unsigned int m_GeneralGOTNum;
- unsigned int m_GOTPLTNum;
+ /// m_fIsVisit - first time visit the function getEntry() or not
+ bool m_fIsVisit;
- // Used by getGeneralGOTEntry()
- iterator m_GeneralGOTIterator;
-
- // Used by getGOTPLTEntry()
- iterator m_GOTPLTIterator;
-
- // The last GOT0 entry
- iterator m_LastGOT0;
-
- SymbolIndexMapType m_GOTPLTMap;
- SymbolIndexMapType m_GeneralGOTMap;
+ SymbolIndexMapType m_GOTMap;
};
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp
index 55596e3..960c86b 100644
--- a/lib/Target/X86/X86GOTPLT.cpp
+++ b/lib/Target/X86/X86GOTPLT.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include "X86GOTPLT.h"
-#include "mcld/LD/LDFileFormat.h"
-#include <llvm/Support/ErrorHandling.h>
+#include <mcld/LD/LDFileFormat.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
@@ -25,12 +25,12 @@
GOTEntry* Entry = 0;
// Create GOT0 entries.
- for (int i = 0; i < 3; i++) {
+ for (size_t i = 0; i < X86GOTPLT0Num; i++) {
Entry = new (std::nothrow) GOTEntry(0, X86GOTPLTEntrySize,
&m_SectionData);
if (!Entry)
- llvm::report_fatal_error("Allocating GOT0 entries failed!");
+ fatal(diag::fail_allocate_memory) << "GOT0";
m_Section.setSize(m_Section.size() + X86GOTPLTEntrySize);
}
@@ -39,9 +39,8 @@
iterator it = m_SectionData.begin();
iterator ie = m_SectionData.end();
- for (size_t i = 1; i < X86GOT0Num; ++i) {
- if (it == ie)
- llvm::report_fatal_error("Generation of GOT0 entries is incomplete!");
+ for (size_t i = 1; i < X86GOTPLT0Num; ++i) {
+ assert((it != ie) && "Generation of GOT0 entries is incomplete!");
++it;
}
@@ -73,31 +72,38 @@
return m_SectionData.end();
}
-void X86GOTPLT::applyGOT0(const uint64_t pAddress)
+void X86GOTPLT::applyGOT0(uint64_t pAddress)
{
llvm::cast<GOTEntry>
(*(m_SectionData.getFragmentList().begin())).setContent(pAddress);
}
-void X86GOTPLT::reserveGOTPLTEntry()
+void X86GOTPLT::reserveEntry(size_t pNum)
{
- GOTEntry* got_entry = 0;
-
- got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData()));
-
+ GOTEntry* got_entry = NULL;
+ for (size_t i = 0; i < pNum; ++i) {
+ got_entry = new GOTEntry(0, getEntrySize(),&(getSectionData()));
if (!got_entry)
- llvm::report_fatal_error("Allocating new memory for GOT failed!");
+ fatal(diag::fail_allocate_memory) << "GOT";
m_Section.setSize(m_Section.size() + getEntrySize());
+ }
}
-void X86GOTPLT::applyAllGOTPLT(const uint64_t pPLTBase)
+void X86GOTPLT::applyAllGOTPLT(uint64_t pPLTBase,
+ unsigned int pPLT0Size,
+ unsigned int pPLT1Size)
{
- iterator gotplt_it = begin();
- iterator gotplt_ie = end();
-
- for (; gotplt_it != gotplt_ie; ++gotplt_it)
- llvm::cast<GOTEntry>(*gotplt_it).setContent(pPLTBase);
+ iterator it = begin();
+ // skip GOT0
+ for (size_t i = 0; i < X86GOTPLT0Num; ++i)
+ ++it;
+ // address of corresponding plt entry
+ uint64_t plt_addr = pPLTBase + pPLT0Size;
+ for (; it != end() ; ++it) {
+ llvm::cast<GOTEntry>(*it).setContent(plt_addr + 6);
+ plt_addr += pPLT1Size;
+ }
}
GOTEntry*& X86GOTPLT::lookupGOTPLTMap(const ResolveInfo& pSymbol)
@@ -105,9 +111,22 @@
return m_GOTPLTMap[&pSymbol];
}
-X86GOTPLT::iterator X86GOTPLT::getNextGOTPLTEntry()
+GOTEntry* X86GOTPLT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
- return ++m_GOTPLTIterator;
+ GOTEntry *&Entry = m_GOTPLTMap[&pInfo];
+ pExist = 1;
+
+ if (!Entry) {
+ pExist = 0;
+
+ ++m_GOTPLTIterator;
+ assert(m_GOTPLTIterator != m_SectionData.getFragmentList().end()
+ && "The number of GOT Entries and ResolveInfo doesn't match!");
+
+ Entry = llvm::cast<GOTEntry>(&(*m_GOTPLTIterator));
+ }
+
+ return Entry;
}
} //end mcld namespace
diff --git a/lib/Target/X86/X86GOTPLT.h b/lib/Target/X86/X86GOTPLT.h
index 04bfad0..ae9f0f7 100644
--- a/lib/Target/X86/X86GOTPLT.h
+++ b/lib/Target/X86/X86GOTPLT.h
@@ -12,7 +12,7 @@
#include <gtest.h>
#endif
-#include "mcld/Target/GOT.h"
+#include <mcld/Target/GOT.h>
namespace mcld
{
@@ -22,7 +22,7 @@
* \brief X86 .got.plt section.
*/
-const unsigned int X86GOT0Num = 3;
+const unsigned int X86GOTPLT0Num = 3;
class X86GOTPLT : public GOT
{
@@ -47,18 +47,20 @@
// For GOT0
public:
- void applyGOT0(const uint64_t pAddress);
+ void applyGOT0(uint64_t pAddress);
// For GOTPLT
public:
- void reserveGOTPLTEntry();
+ void reserveEntry(size_t pNum = 1);
- void applyAllGOTPLT(const uint64_t pPLTBase);
+ GOTEntry* getEntry(const ResolveInfo& pSymbol, bool& pExist);
+
+ void applyAllGOTPLT(uint64_t pPLTBase,
+ unsigned int pPLT0Size,
+ unsigned int pPLT1Size);
GOTEntry*& lookupGOTPLTMap(const ResolveInfo& pSymbol);
- iterator getNextGOTPLTEntry();
-
private:
iterator m_GOTPLTIterator;
SymbolIndexMapType m_GOTPLTMap;
@@ -67,3 +69,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp
index 354cd51..79d160e 100644
--- a/lib/Target/X86/X86LDBackend.cpp
+++ b/lib/Target/X86/X86LDBackend.cpp
@@ -13,13 +13,14 @@
#include "X86RelocationFactory.h"
#include <llvm/ADT/Triple.h>
-#include <mcld/Support/MemoryRegion.h>
-#include <mcld/Support/TargetRegistry.h>
+#include <mcld/LD/SectionMap.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLDOutput.h>
#include <mcld/MC/MCLinker.h>
-#include <mcld/LD/SectionMap.h>
#include <mcld/MC/MCRegionFragment.h>
+#include <mcld/Support/MemoryRegion.h>
+#include <mcld/Support/MsgHandling.h>
+#include <mcld/Support/TargetRegistry.h>
#include <cstring>
@@ -29,6 +30,7 @@
: m_pRelocFactory(NULL),
m_pGOT(NULL),
m_pPLT(NULL),
+ m_pGOTPLT(NULL),
m_pRelDyn(NULL),
m_pRelPLT(NULL),
m_pDynamic(NULL) {
@@ -42,6 +44,8 @@
delete m_pGOT;
if (NULL != m_pPLT)
delete m_pPLT;
+ if (NULL != m_pGOTPLT)
+ delete m_pGOTPLT;
if (NULL !=m_pRelDyn)
delete m_pRelDyn;
if (NULL != m_pRelPLT)
@@ -70,17 +74,15 @@
MCLinker& pLinker)
{
// when building shared object, the .got section is needed
- if(pOutput.type() == Output::DynObj && (NULL == m_pGOT))
- createX86GOT(pLinker, pOutput);
+ if (Output::DynObj == pOutput.type() && (NULL == m_pGOTPLT)) {
+ createX86GOTPLT(pLinker, pOutput);
+ }
}
void X86GNULDBackend::doPostLayout(const Output& pOutput,
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
- // emit program headers
- if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec)
- emitProgramHdrs(pLinker.getLDInfo().output());
}
/// dynamic - the dynamic section of the target machine.
@@ -108,9 +110,18 @@
LDSection& got = file_format->getGOT();
m_pGOT = new X86GOT(got, pLinker.getOrCreateSectData(got));
+}
- // define symbol _GLOBAL_OFFSET_TABLE_ when .got create
- if( m_pGOTSymbol != NULL ) {
+void X86GNULDBackend::createX86GOTPLT(MCLinker& pLinker, const Output& pOutput)
+{
+ // get .got.plt LDSection and create MCSectionData
+ ELFFileFormat* file_format = getOutputFormat(pOutput);
+
+ LDSection& gotplt = file_format->getGOTPLT();
+ m_pGOTPLT = new X86GOTPLT(gotplt, pLinker.getOrCreateSectData(gotplt));
+
+ // define symbol _GLOBAL_OFFSET_TABLE_ when .got.plt create
+ if (m_pGOTSymbol != NULL) {
pLinker.defineSymbol<MCLinker::Force, MCLinker::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
false,
@@ -119,7 +130,8 @@
ResolveInfo::Local,
0x0, // size
0x0, // value
- pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ pLinker.getLayout().getFragmentRef(*(m_pGOTPLT->begin()),
+ 0x0),
ResolveInfo::Hidden);
}
else {
@@ -131,7 +143,8 @@
ResolveInfo::Local,
0x0, // size
0x0, // value
- pLinker.getLayout().getFragmentRef(*(m_pGOT->begin()), 0x0),
+ pLinker.getLayout().getFragmentRef(*(m_pGOTPLT->begin()),
+ 0x0),
ResolveInfo::Hidden);
}
}
@@ -143,8 +156,9 @@
LDSection& plt = file_format->getPLT();
LDSection& relplt = file_format->getRelPlt();
+ assert(m_pGOTPLT != NULL);
// create MCSectionData and X86PLT
- m_pPLT = new X86PLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOT, pOutput);
+ m_pPLT = new X86PLT(plt, pLinker.getOrCreateSectData(plt), *m_pGOTPLT, pOutput);
// set info of .rel.plt to .plt
relplt.setLink(&plt);
@@ -167,63 +181,73 @@
8);
}
-ELFFileFormat* X86GNULDBackend::getOutputFormat(const Output& pOutput) const
+void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym)
{
- switch (pOutput.type()) {
- case Output::DynObj:
- return getDynObjFileFormat();
- case Output::Exec:
- return getExecFileFormat();
- // FIXME: We do not support building .o now
- case Output::Object:
- default:
- llvm::report_fatal_error(llvm::Twine("Unsupported output file format: ") +
- llvm::Twine(pOutput.type()));
- return NULL;
+ bool exist;
+ Relocation& rel_entry = *m_pRelDyn->getEntry(pSym, false, exist);
+ rel_entry.setType(llvm::ELF::R_386_COPY);
+ assert(pSym.outSymbol()->hasFragRef());
+ rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
+ rel_entry.setSymInfo(&pSym);
+}
+
+LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(MCLinker& pLinker,
+ const ResolveInfo& pSym)
+{
+ // For a symbol needing copy relocation, define a copy symbol in the BSS
+ // section and all other reference to this symbol should refer to this
+ // copy.
+
+ // get or create corresponding BSS LDSection
+ LDSection* bss_sect_hdr = NULL;
+ if (ResolveInfo::ThreadLocal == pSym.type()) {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
+ ".tbss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
}
-}
+ else {
+ bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
+ LDFileFormat::BSS,
+ llvm::ELF::SHT_NOBITS,
+ llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
+ }
-bool X86GNULDBackend::isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- return((Output::DynObj == pOutput.type())
- &&(ResolveInfo::Function == pSym.type())
- &&(pSym.isDyn() || pSym.isUndef() ||
- isSymbolPreemptible(pSym, pLDInfo, pOutput))
- );
-}
+ // get or create corresponding BSS MCSectionData
+ assert(NULL != bss_sect_hdr);
+ llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(
+ *bss_sect_hdr);
-bool X86GNULDBackend::isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const
-{
- if(pSym.isUndef() && (pOutput.type()==Output::Exec))
- return false;
- if(pSym.isAbsolute())
- return false;
- if(pOutput.type()==Output::DynObj && isAbsReloc)
- return true;
- if(pSym.isDyn() || pSym.isUndef())
- return true;
+ // Determine the alignment by the symbol value
+ // FIXME: here we use the largest alignment
+ uint32_t addralign = bitclass() / 8;
- return false;
-}
+ // allocate space in BSS for the copy symbol
+ llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, pSym.size());
+ uint64_t size = pLinker.getLayout().appendFragment(*frag,
+ bss_section,
+ addralign);
+ bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
-bool X86GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const
-{
- if(pSym.other() != ResolveInfo::Default)
- return false;
+ // change symbol binding to Global if it's a weak symbol
+ ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
+ if (binding == ResolveInfo::Weak)
+ binding = ResolveInfo::Global;
- if(pOutput.type() != Output::DynObj)
- return false;
+ // Define the copy symbol in the bss section and resolve it
+ LDSymbol* cpy_sym = pLinker.defineSymbol<MCLinker::Force, MCLinker::Resolve>(
+ pSym.name(),
+ false,
+ (ResolveInfo::Type)pSym.type(),
+ ResolveInfo::Define,
+ binding,
+ pSym.size(), // size
+ 0x0, // value
+ pLinker.getLayout().getFragmentRef(*frag, 0x0),
+ (ResolveInfo::Visibility)pSym.other());
- if(pLDInfo.options().Bsymbolic())
- return false;
-
- return true;
+ return *cpy_sym;
}
void X86GNULDBackend::updateAddend(Relocation& pReloc,
@@ -231,7 +255,7 @@
const Layout& pLayout) const
{
// Update value keep in addend if we meet a section symbol
- if(pReloc.symInfo()->type() == ResolveInfo::Section) {
+ if (pReloc.symInfo()->type() == ResolveInfo::Section) {
pReloc.setAddend(pLayout.getOutputOffset(
*pInputSym.fragRef()) + pReloc.addend());
}
@@ -254,9 +278,9 @@
// If buiding PIC object (shared library or PIC executable),
// a dynamic relocations with RELATIVE type to this location is needed.
// Reserve an entry in .rel.dyn
- if(Output::DynObj == pOutput.type()) {
+ if (isOutputPIC(pOutput, pLDInfo)) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createX86RelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set Rel bit
@@ -267,7 +291,7 @@
case llvm::ELF::R_386_GOTOFF:
case llvm::ELF::R_386_GOTPC:
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createX86GOT(pLinker, pOutput);
return;
@@ -275,9 +299,8 @@
return;
default:
- llvm::report_fatal_error(llvm::Twine("unexpected reloc ") +
- llvm::Twine((int) pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::unsupported_relocation) << (int)pReloc.type()
+ << "[email protected]";
break;
} // end switch
}
@@ -295,14 +318,14 @@
case llvm::ELF::R_386_32:
// Absolute relocation type, symbol may needs PLT entry or
// dynamic relocation entry
- if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
+ if (symbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
// create plt for this symbol if it does not have one
- if(!(rsym->reserved() & ReservePLT)){
+ if (!(rsym->reserved() & ReservePLT)){
// Create .got section if it dosen't exist
- if(NULL == m_pGOT)
- createX86GOT(pLinker, pOutput);
+ if (NULL == m_pGOTPLT)
+ createX86GOTPLT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createX86PLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -315,21 +338,29 @@
}
}
- if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, true)) {
// symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createX86RelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
- // set Rel bit
- rsym->setReserved(rsym->reserved() | ReserveRel);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
}
return;
case llvm::ELF::R_386_GOTOFF:
case llvm::ELF::R_386_GOTPC: {
// A GOT section is needed
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createX86GOT(pLinker, pOutput);
return;
}
@@ -338,21 +369,21 @@
// A PLT entry is needed when building shared library
// return if we already create plt for this symbol
- if(rsym->reserved() & ReservePLT)
+ if (rsym->reserved() & ReservePLT)
return;
// if symbol is defined in the ouput file and it's not
// preemptible, no need plt
- if(rsym->isDefine() && !rsym->isDyn() &&
+ if (rsym->isDefine() && !rsym->isDyn() &&
!isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
return;
}
// Create .got section if it dosen't exist
- if(NULL == m_pGOT)
- createX86GOT(pLinker, pOutput);
+ if (NULL == m_pGOTPLT)
+ createX86GOTPLT(pLinker, pOutput);
// create .plt and .rel.plt if not exist
- if(NULL == m_pPLT)
+ if (NULL == m_pPLT)
createX86PLTandRelPLT(pLinker, pOutput);
// Symbol needs PLT entry, we need to reserve a PLT entry
// and the corresponding GOT and dynamic relocation entry
@@ -367,17 +398,17 @@
case llvm::ELF::R_386_GOT32:
// Symbol needs GOT entry, reserve entry in .got
// return if we already create GOT for this symbol
- if(rsym->reserved() & (ReserveGOT | GOTRel))
+ if (rsym->reserved() & (ReserveGOT | GOTRel))
return;
- if(NULL == m_pGOT)
+ if (NULL == m_pGOT)
createX86GOT(pLinker, pOutput);
m_pGOT->reserveEntry();
// If building shared object or the symbol is undefined, a dynamic
// relocation is needed to relocate this GOT entry. Reserve an
// entry in .rel.dyn
- if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
+ if (Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
// create .rel.dyn section if not exist
- if(NULL == m_pRelDyn)
+ if (NULL == m_pRelDyn)
createX86RelDyn(pLinker, pOutput);
m_pRelDyn->reserveEntry(*m_pRelocFactory);
// set GOTRel bit
@@ -389,15 +420,49 @@
return;
case llvm::ELF::R_386_PC32:
- // We allow R_386_PC32 only if it isn't preemptible. Otherwise
- // we will generate writable text section in output.
- if (!isSymbolPreemptible(*rsym, pLDInfo, pOutput))
- return;
+ if (symbolNeedsPLT(*rsym, pLDInfo, pOutput) &&
+ pOutput.type() != Output::DynObj) {
+ // create plt for this symbol if it does not have one
+ if (!(rsym->reserved() & ReservePLT)){
+ // Create .got section if it dosen't exist
+ if (NULL == m_pGOTPLT)
+ createX86GOTPLT(pLinker, pOutput);
+ // create .plt and .rel.plt if not exist
+ if (NULL == m_pPLT)
+ createX86PLTandRelPLT(pLinker, pOutput);
+ // Symbol needs PLT entry, we need to reserve a PLT entry
+ // and the corresponding GOT and dynamic relocation entry
+ // in .got and .rel.plt. (GOT entry will be reserved simultaneously
+ // when calling X86PLT->reserveEntry())
+ m_pPLT->reserveEntry();
+ m_pRelPLT->reserveEntry(*m_pRelocFactory);
+ // set PLT bit
+ rsym->setReserved(rsym->reserved() | ReservePLT);
+ }
+ }
+
+ if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT),
+ pLDInfo, pOutput, false)) {
+ // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
+ // create .rel.dyn section if not exist
+ if (NULL == m_pRelDyn)
+ createX86RelDyn(pLinker, pOutput);
+ m_pRelDyn->reserveEntry(*m_pRelocFactory);
+ if (symbolNeedsCopyReloc(pLinker.getLayout(), pReloc, *rsym, pLDInfo,
+ pOutput)) {
+ LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym);
+ addCopyReloc(*cpy_sym.resolveInfo());
+ }
+ else {
+ // set Rel bit
+ rsym->setReserved(rsym->reserved() | ReserveRel);
+ }
+ }
+ return;
default: {
- llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
- llvm::Twine((int) pReloc.type()) +
- llvm::Twine(" in object file"));
+ fatal(diag::unsupported_relocation) << (int)pReloc.type()
+ << "[email protected]";
break;
}
} // end switch
@@ -407,27 +472,36 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput)
+ const Output& pOutput,
+ const LDSection& pSection)
{
// rsym - The relocation target symbol
ResolveInfo* rsym = pReloc.symInfo();
assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation");
+ assert(NULL != pSection.getLink());
+ if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) {
+ if (rsym->isLocal()) {
+ updateAddend(pReloc, pInputSym, pLinker.getLayout());
+ }
+ return;
+ }
+
// Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
// entries should be created.
// FIXME: Below judgements concern only .so is generated as output
// FIXME: Below judgements concren nothing about TLS related relocation
- // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got section
- // is needed
- if(NULL == m_pGOT && NULL != m_pGOTSymbol) {
- if(rsym == m_pGOTSymbol->resolveInfo()) {
- createX86GOT(pLinker, pOutput);
+ // A refernece to symbol _GLOBAL_OFFSET_TABLE_ implies that a .got.plt
+ // section is needed
+ if (NULL == m_pGOTPLT && NULL != m_pGOTSymbol) {
+ if (rsym == m_pGOTSymbol->resolveInfo()) {
+ createX86GOTPLT(pLinker, pOutput);
}
}
// rsym is local
- if(rsym->isLocal())
+ if (rsym->isLocal())
scanLocalReloc(pReloc, pInputSym, pLinker, pLDInfo, pOutput);
// rsym is external
@@ -439,11 +513,12 @@
uint64_t X86GNULDBackend::emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const
{
assert(pRegion.size() && "Size of MemoryRegion is zero!");
- ELFFileFormat* FileFormat = getOutputFormat(pOutput);
+ const ELFFileFormat* FileFormat = getOutputFormat(pOutput);
assert(FileFormat &&
"ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!");
@@ -479,8 +554,6 @@
else if (&pSection == &(FileFormat->getGOT())) {
assert(m_pGOT && "emitSectionData failed, m_pGOT is NULL!");
- m_pGOT->applyGOT0(FileFormat->getDynamic().addr());
-
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
GOTEntry* got = 0;
@@ -494,10 +567,28 @@
}
}
- else
- llvm::report_fatal_error("unsupported section name "
- + pSection.name() + " !");
+ else if (&pSection == &(FileFormat->getGOTPLT())) {
+ assert(m_pGOTPLT && "emitSectionData failed, m_pGOTPLT is NULL!");
+ m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
+ uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
+
+ GOTEntry* got = 0;
+ EntrySize = m_pGOTPLT->getEntrySize();
+
+ for (X86GOTPLT::iterator it = m_pGOTPLT->begin(),
+ ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) {
+ got = &(llvm::cast<GOTEntry>((*it)));
+ *buffer = static_cast<uint32_t>(got->getContent());
+ RegionSize += EntrySize;
+ }
+ }
+
+ else {
+ fatal(diag::unrecognized_output_sectoin)
+ << pSection.name()
+ << "[email protected]";
+ }
return RegionSize;
}
uint32_t X86GNULDBackend::machine() const
@@ -517,6 +608,18 @@
return *m_pGOT;
}
+X86GOTPLT& X86GNULDBackend::getGOTPLT()
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
+
+const X86GOTPLT& X86GNULDBackend::getGOTPLT() const
+{
+ assert(NULL != m_pGOTPLT);
+ return *m_pGOTPLT;
+}
+
X86PLT& X86GNULDBackend::getPLT()
{
assert(NULL != m_pPLT && "PLT section not exist");
@@ -555,17 +658,22 @@
unsigned int
X86GNULDBackend::getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const
{
- ELFFileFormat* file_format = getOutputFormat(pOutput);
+ const ELFFileFormat* file_format = getOutputFormat(pOutput);
- // FIXME: if command line option, "-z now", is given, we can let the order of
- // .got and .got.plt be the same as RELRO sections
- if (&pSectHdr == &file_format->getGOT())
+ if (&pSectHdr == &file_format->getGOT()) {
+ if (pInfo.options().hasNow())
+ return SHO_RELRO;
return SHO_RELRO_LAST;
+ }
- if (&pSectHdr == &file_format->getGOTPLT())
+ if (&pSectHdr == &file_format->getGOTPLT()) {
+ if (pInfo.options().hasNow())
+ return SHO_RELRO;
return SHO_NON_RELRO_FIRST;
+ }
if (&pSectHdr == &file_format->getPLT())
return SHO_PLT;
@@ -587,7 +695,7 @@
{
}
-void X86GNULDBackend::initTargetSymbols(MCLinker& pLinker)
+void X86GNULDBackend::initTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
@@ -604,113 +712,8 @@
}
/// finalizeSymbol - finalize the symbol value
-/// If the symbol's reserved field is not zero, MCLinker will call back this
-/// function to ask the final value of the symbol
-bool X86GNULDBackend::finalizeSymbol(LDSymbol& pSymbol) const
+bool X86GNULDBackend::finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput)
{
- return false;
-}
-
-/// allocateCommonSymbols - allocate common symbols in the corresponding
-/// sections.
-/// @refer Google gold linker: common.cc: 214
-bool
-X86GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const
-{
- // SymbolCategory contains all symbols that must emit to the output files.
- // We are not like Google gold linker, we don't remember symbols before symbol
- // resolution. All symbols in SymbolCategory are already resolved. Therefore, we
- // don't need to care about some symbols may be changed its category due to symbol
- // resolution.
- SymbolCategory& symbol_list = pLinker.getOutputSymbols();
-
- if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
- return true;
-
- // addralign := max value of all common symbols
- uint64_t addralign = 0x0;
-
- // Due to the visibility, some common symbols may be forcefully local.
- SymbolCategory::iterator com_sym, com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
- }
-
- // global common symbols.
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- if ((*com_sym)->value() > addralign)
- addralign = (*com_sym)->value();
- }
-
- // FIXME: If the order of common symbols is defined, then sort common symbols
- // com_sym = symbol_list.commonBegin();
- // std::sort(com_sym, com_end, some kind of order);
-
- // get or create corresponding BSS LDSection
- LDSection* bss_sect_hdr = NULL;
- if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(
- ".tbss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
- else {
- bss_sect_hdr = &pLinker.getOrCreateOutputSectHdr(".bss",
- LDFileFormat::BSS,
- llvm::ELF::SHT_NOBITS,
- llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC);
- }
-
- // get or create corresponding BSS MCSectionData
- assert(NULL != bss_sect_hdr);
- llvm::MCSectionData& bss_section = pLinker.getOrCreateSectData(*bss_sect_hdr);
-
- // allocate all common symbols
- uint64_t offset = bss_sect_hdr->size();
-
- // allocate all local common symbols
- com_end = symbol_list.localEnd();
- for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
- if (ResolveInfo::Common == (*com_sym)->desc()) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
- }
-
- // allocate all global common symbols
- com_end = symbol_list.commonEnd();
- for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
- // We have to reset the description of the symbol here. When doing
- // incremental linking, the output relocatable object may have common
- // symbols. Therefore, we can not treat common symbols as normal symbols
- // when emitting the regular name pools. We must change the symbols'
- // description here.
- (*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
- llvm::MCFragment* frag = new llvm::MCFillFragment(0x0, 1, (*com_sym)->size());
- (*com_sym)->setFragmentRef(new MCFragmentRef(*frag, 0));
- uint64_t size = pLinker.getLayout().appendFragment(*frag,
- bss_section,
- (*com_sym)->value());
- offset += size;
- }
-
- bss_sect_hdr->setSize(offset);
- symbol_list.changeCommonsToGlobal();
return true;
}
diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h
index a745999..7264c40 100644
--- a/lib/Target/X86/X86LDBackend.h
+++ b/lib/Target/X86/X86LDBackend.h
@@ -11,6 +11,7 @@
#include "X86ELFDynamic.h"
#include "X86GOT.h"
+#include "X86GOTPLT.h"
#include "X86PLT.h"
#include <mcld/LD/LDSection.h>
#include <mcld/Target/GNULDBackend.h>
@@ -82,6 +83,10 @@
const X86GOT& getGOT() const;
+ X86GOTPLT& getGOTPLT();
+
+ const X86GOTPLT& getGOTPLT() const;
+
X86PLT& getPLT();
const X86PLT& getPLT() const;
@@ -120,11 +125,13 @@
/// @param pOutput - the output file
/// @param pSection - the given LDSection
/// @param pInfo - all options in the command line.
+ /// @param pLayout - for comouting the size of fragment
/// @param pRegion - the region to write out data
/// @return the size of the table in the file.
uint64_t emitSectionData(const Output& pOutput,
const LDSection& pSection,
const MCLDInfo& pInfo,
+ const Layout& pLayout,
MemoryRegion& pRegion) const;
/// OSABI - the value of e_ident[EI_OSABI]
@@ -142,6 +149,9 @@
uint64_t flags() const
{ return 0x0; }
+ uint64_t defaultTextSegmentAddr() const
+ { return 0x08048000; }
+
/// initTargetSectionMap - initialize target dependent section mapping
bool initTargetSectionMap(SectionMap& pSectionMap);
@@ -150,7 +160,7 @@
void initTargetSections(MCLinker& pLinker);
- void initTargetSymbols(MCLinker& pLinker);
+ void initTargetSymbols(MCLinker& pLinker, const Output& pOutput);
/// scanRelocation - determine the empty entries are needed or not and create
/// the empty entries if needed.
@@ -162,7 +172,8 @@
const LDSymbol& pInputSym,
MCLinker& pLinker,
const MCLDInfo& pLDInfo,
- const Output& pOutput);
+ const Output& pOutput,
+ const LDSection& pSection);
OutputRelocSection& getRelDyn();
@@ -174,21 +185,11 @@
/// getTargetSectionOrder - compute the layout order of X86 target sections
unsigned int getTargetSectionOrder(const Output& pOutput,
- const LDSection& pSectHdr) const;
+ const LDSection& pSectHdr,
+ const MCLDInfo& pInfo) const;
- /// finalizeSymbol - finalize the symbol value
- /// If the symbol's reserved field is not zero, MCLinker will call back this
- /// function to ask the final value of the symbol
- bool finalizeSymbol(LDSymbol& pSymbol) const;
-
- /// allocateCommonSymbols - allocate common symbols in the corresponding
- /// sections.
- bool allocateCommonSymbols(const MCLDInfo& pLDInfo, MCLinker& pLinker) const;
-
-public:
- bool isSymbolPreemptible(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
+ /// finalizeTargetSymbols - finalize the symbol value
+ bool finalizeTargetSymbols(MCLinker& pLinker, const Output& pOutput);
private:
void scanLocalReloc(Relocation& pReloc,
@@ -203,28 +204,30 @@
const MCLDInfo& pLDInfo,
const Output& pOutput);
- bool isSymbolNeedsPLT(const ResolveInfo& pSym,
- const MCLDInfo& pLDInfo,
- const Output& pOutput) const;
+ /// addCopyReloc - add a copy relocation into .rel.dyn for pSym
+ /// @param pSym - A resolved copy symbol that defined in BSS section
+ void addCopyReloc(ResolveInfo& pSym);
- bool isSymbolNeedsDynRel(const ResolveInfo& pSym,
- const Output& pOutput,
- bool isAbsReloc) const;
+ /// defineSymbolforCopyReloc - allocate a space in BSS section and
+ /// and force define the copy of pSym to BSS section
+ /// @return the output LDSymbol of the copy symbol
+ LDSymbol& defineSymbolforCopyReloc(MCLinker& pLinker,
+ const ResolveInfo& pSym);
void updateAddend(Relocation& pReloc,
const LDSymbol& pInputSym,
const Layout& pLayout) const;
void createX86GOT(MCLinker& pLinker, const Output& pOutput);
+ void createX86GOTPLT(MCLinker& pLinker, const Output& pOutput);
void createX86PLTandRelPLT(MCLinker& pLinker, const Output& pOutput);
void createX86RelDyn(MCLinker& pLinker, const Output& pOutput);
- ELFFileFormat* getOutputFormat(const Output& pOutput) const;
-
private:
RelocationFactory* m_pRelocFactory;
X86GOT* m_pGOT;
X86PLT* m_pPLT;
+ X86GOTPLT* m_pGOTPLT;
/// m_RelDyn - dynamic relocation table of .rel.dyn
OutputRelocSection* m_pRelDyn;
/// m_RelPLT - dynamic relocation table of .rel.plt
@@ -254,3 +257,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp
index e9f9db1..caf6f32 100644
--- a/lib/Target/X86/X86PLT.cpp
+++ b/lib/Target/X86/X86PLT.cpp
@@ -6,38 +6,38 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "X86GOT.h"
+#include "X86GOTPLT.h"
#include "X86PLT.h"
#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/ELF.h>
#include <mcld/MC/MCLDOutput.h>
+#include <mcld/Support/MsgHandling.h>
#include <new>
namespace {
const uint8_t x86_dyn_plt0[] = {
- 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx)
- 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx)
- 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+ 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx)
+ 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx)
+ 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax)
};
const uint8_t x86_dyn_plt1[] = {
- 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx)
- 0x68, 0, 0, 0, 0, // pushl $offset
- 0xe9, 0, 0, 0, 0 // jmp plt0
+ 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
};
const uint8_t x86_exec_plt0[] = {
- 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4
- 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8)
- 0xf, 0x1f, 0x4, 0 // nopl 0(%eax)
+ 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8)
+ 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax)
};
const uint8_t x86_exec_plt1[] = {
- 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got)
- 0x68, 0, 0, 0, 0, // pushl $offset
- 0xe9, 0, 0, 0, 0 // jmp plt0
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got)
+ 0x68, 0, 0, 0, 0, // pushl $offset
+ 0xe9, 0, 0, 0, 0 // jmp plt0
};
}
@@ -55,9 +55,12 @@
X86PLT::X86PLT(LDSection& pSection,
llvm::MCSectionData& pSectionData,
- X86GOT &pGOTPLT,
- const Output& pOutput)
- : PLT(pSection, pSectionData), m_GOT(pGOTPLT), m_PLTEntryIterator()
+ X86GOTPLT &pGOTPLT,
+ const Output& pOutput)
+ : PLT(pSection, pSectionData),
+ m_GOTPLT(pGOTPLT),
+ m_PLTEntryIterator(),
+ m_Output(pOutput)
{
assert (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type());
if (Output::DynObj == pOutput.type()) {
@@ -86,26 +89,17 @@
void X86PLT::reserveEntry(size_t pNum)
{
X86PLT1* plt1_entry = 0;
- GOTEntry* got_entry = 0;
for (size_t i = 0; i < pNum; ++i) {
plt1_entry = new (std::nothrow) X86PLT1(&m_SectionData, m_PLT1Size);
if (!plt1_entry)
- llvm::report_fatal_error("Allocating new memory for X86PLT1 failed!");
+ fatal(diag::fail_allocate_memory) << "X86PLT1";
m_Section.setSize(m_Section.size() + plt1_entry->getEntrySize());
- got_entry= new (std::nothrow) GOTEntry(0, m_GOT.getEntrySize(),
- &(m_GOT.m_SectionData));
-
- if (!got_entry)
- llvm::report_fatal_error("Allocating new memory for GOT failed!");
-
- m_GOT.m_Section.setSize(m_GOT.m_Section.size() + m_GOT.f_EntrySize);
-
- ++(m_GOT.m_GOTPLTNum);
- ++(m_GOT.m_GeneralGOTIterator);
+ // reserve corresponding entry in .got.plt
+ m_GOTPLT.reserveEntry(pNum);
}
}
@@ -116,47 +110,20 @@
pExist = 1;
if (!PLTEntry) {
- GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
- assert(!GOTPLTEntry && "PLT entry and got.plt entry doesn't match!");
-
pExist = 0;
// This will skip PLT0.
++m_PLTEntryIterator;
assert(m_PLTEntryIterator != m_SectionData.end() &&
"The number of PLT Entries and ResolveInfo doesn't match");
- ++(m_GOT.m_GOTPLTIterator);
-
PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
- GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
}
-
return PLTEntry;
}
GOTEntry* X86PLT::getGOTPLTEntry(const ResolveInfo& pSymbol, bool& pExist)
{
- GOTEntry *&GOTPLTEntry = m_GOT.m_GOTPLTMap[&pSymbol];
-
- pExist = 1;
-
- if (!GOTPLTEntry) {
- X86PLT1 *&PLTEntry = m_PLTEntryMap[&pSymbol];
- assert(!PLTEntry && "PLT entry and got.plt entry doesn't match!");
-
- pExist = 0;
-
- // This will skip PLT0.
- ++m_PLTEntryIterator;
- assert(m_PLTEntryIterator != m_SectionData.end() &&
- "The number of PLT Entries and ResolveInfo doesn't match");
- ++(m_GOT.m_GOTPLTIterator);
-
- PLTEntry = llvm::cast<X86PLT1>(&(*m_PLTEntryIterator));
- GOTPLTEntry = llvm::cast<GOTEntry>(&(*(m_GOT.m_GOTPLTIterator)));
- }
-
- return GOTPLTEntry;
+ return m_GOTPLT.getEntry(pSymbol, pExist);
}
X86PLT0* X86PLT::getPLT0() const {
@@ -185,12 +152,12 @@
data = static_cast<unsigned char*>(malloc(plt0->getEntrySize()));
if (!data)
- llvm::report_fatal_error("Allocating new memory for plt0 failed!");
+ fatal(diag::fail_allocate_memory) << "plt0";
memcpy(data, m_PLT0, plt0->getEntrySize());
if (m_PLT0 == x86_exec_plt0) {
- uint64_t got_base = m_GOT.getSection().addr();
+ uint64_t got_base = m_GOTPLT.getSection().addr();
assert(got_base && ".got base address is NULL!");
uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2);
*offset = got_base + 4;
@@ -207,17 +174,17 @@
uint64_t plt_base = m_Section.addr();
assert(plt_base && ".plt base address is NULL!");
- uint64_t got_base = m_GOT.getSection().addr();
+ uint64_t got_base = m_GOTPLT.getSection().addr();
assert(got_base && ".got base address is NULL!");
X86PLT::iterator it = m_SectionData.begin();
X86PLT::iterator ie = m_SectionData.end();
assert(it!=ie && "FragmentList is empty, applyPLT1 failed!");
- uint64_t GOTEntrySize = m_GOT.getEntrySize();
+ uint64_t GOTEntrySize = m_GOTPLT.getEntrySize();
// Skip GOT0
- uint64_t GOTEntryOffset = GOTEntrySize * X86GOT0Num;
+ uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num;
//skip PLT0
uint64_t PLTEntryOffset = m_PLT0Size;
@@ -233,14 +200,19 @@
data = static_cast<unsigned char*>(malloc(plt1->getEntrySize()));
if (!data)
- llvm::report_fatal_error("Allocating new memory for plt1 failed!");
+ fatal(diag::fail_allocate_memory) << "plt1";
memcpy(data, m_PLT1, plt1->getEntrySize());
uint32_t* offset;
offset = reinterpret_cast<uint32_t*>(data + 2);
- *offset = GOTEntryOffset;
+ if (m_Output.type() == Output::DynObj) {
+ *offset = GOTEntryOffset;
+ } else {
+ // Exec
+ *offset = got_base + GOTEntryOffset;
+ }
GOTEntryOffset += GOTEntrySize;
offset = reinterpret_cast<uint32_t*>(data + 7);
@@ -255,24 +227,9 @@
++it;
}
- unsigned int GOTPLTNum = m_GOT.getGOTPLTNum();
-
- if (GOTPLTNum != 0) {
- X86GOT::iterator gotplt_it = m_GOT.getLastGOT0();
- X86GOT::iterator list_ie = m_GOT.getSectionData().getFragmentList().end();
-
- ++gotplt_it;
- uint64_t PLTEntryAddress = plt_base + m_PLT0Size;
- for (unsigned int i = 0; i < GOTPLTNum; ++i) {
- if (gotplt_it == list_ie)
- llvm::report_fatal_error(
- "The number of got.plt entries is inconsistent!");
-
- llvm::cast<GOTEntry>(*gotplt_it).setContent(PLTEntryAddress + 6);
- PLTEntryAddress += m_PLT1Size;
- ++gotplt_it;
- }
- }
+ // apply .got.plt
+ m_GOTPLT.applyAllGOTPLT(plt_base, m_PLT0Size, m_PLT1Size);
}
} // end namespace mcld
+
diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h
index dd72f52..6c7002a 100644
--- a/lib/Target/X86/X86PLT.h
+++ b/lib/Target/X86/X86PLT.h
@@ -13,7 +13,7 @@
namespace mcld {
-class X86GOT;
+class X86GOTPLT;
class GOTEntry;
class Output;
@@ -41,8 +41,8 @@
public:
X86PLT(LDSection& pSection,
llvm::MCSectionData& pSectionData,
- X86GOT& pGOTPLT,
- const Output& pOutput);
+ X86GOTPLT& pGOTPLT,
+ const Output& pOutput);
~X86PLT();
// Override virtual function.
@@ -72,7 +72,7 @@
void applyPLT1();
private:
- X86GOT& m_GOT;
+ X86GOTPLT& m_GOTPLT;
// Used by getEntry() for mapping a ResolveInfo
// instance to a PLT1 Entry.
@@ -84,6 +84,8 @@
const uint8_t *m_PLT1;
unsigned int m_PLT0Size;
unsigned int m_PLT1Size;
+
+ const Output& m_Output;
};
} // namespace of mcld
diff --git a/lib/Target/X86/X86RelocationFactory.cpp b/lib/Target/X86/X86RelocationFactory.cpp
index 15b9a6b..9090d1a 100644
--- a/lib/Target/X86/X86RelocationFactory.cpp
+++ b/lib/Target/X86/X86RelocationFactory.cpp
@@ -8,11 +8,11 @@
//===----------------------------------------------------------------------===//
#include <llvm/ADT/Twine.h>
-#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/DataTypes.h>
#include <llvm/Support/ELF.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/Layout.h>
+#include <mcld/Support/MsgHandling.h>
#include "X86RelocationFactory.h"
#include "X86RelocationFunctions.h"
@@ -56,11 +56,8 @@
};
if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
- llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
- llvm::Twine((int) type) +
- llvm::Twine(" to symbol `") +
- pRelocation.symInfo()->name() +
- llvm::Twine("'."));
+ fatal(diag::unknown_relocation) << (int)type <<
+ pRelocation.symInfo()->name();
return;
}
@@ -68,22 +65,18 @@
Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
// check result
+ if (OK == result) {
+ return;
+ }
if (Overflow == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' causes overflow. on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_overflow) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
if (BadReloc == result) {
- llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
- llvm::Twine(apply_functions[type].name) +
- llvm::Twine("' encounters unexpected opcode. "
- "on symbol: `") +
- llvm::Twine(pRelocation.symInfo()->name()) +
- llvm::Twine("'."));
+ error(diag::result_badreloc) << apply_functions[type].name
+ << pRelocation.symInfo()->name();
return;
}
}
@@ -104,7 +97,7 @@
{
// if symbol is dynamic or undefine or preemptible
- if(pSym.isDyn() ||
+ if (pSym.isDyn() ||
pSym.isUndef() ||
pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
return false;
@@ -133,7 +126,7 @@
Relocation& rel_entry =
*ld_backend.getRelDyn().getEntry(*rsym, true, exist);
assert(!exist && "GOT entry not exist, but DynRel entry exist!");
- if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
// Initialize got entry to target symbol address
got_entry.setContent(pReloc.symValue());
rel_entry.setType(llvm::ELF::R_386_RELATIVE);
@@ -147,7 +140,7 @@
rel_entry.targetRef().assign(got_entry);
}
else {
- llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "GOT";
}
}
return got_entry;
@@ -157,7 +150,7 @@
static
X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
{
- return pParent.getTarget().getGOT().getSection().addr();
+ return pParent.getTarget().getGOTPLT().getSection().addr();
}
@@ -167,7 +160,9 @@
X86RelocationFactory& pParent)
{
GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent);
- return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
+ X86RelocationFactory::Address got_addr =
+ pParent.getTarget().getGOT().getSection().addr();
+ return got_addr + pParent.getLayout().getOutputOffset(got_entry);
}
@@ -195,7 +190,7 @@
rel_entry.setSymInfo(rsym);
}
else {
- llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
+ fatal(diag::reserve_entry_number_mismatch) << "PLT";
}
}
return plt_entry;
@@ -235,7 +230,7 @@
rel_entry.setType(pType);
rel_entry.targetRef() = pReloc.targetRef();
- if(pType == llvm::ELF::R_386_RELATIVE)
+ if (pType == llvm::ELF::R_386_RELATIVE)
rel_entry.setSymInfo(0);
else
rel_entry.setSymInfo(rsym);
@@ -263,18 +258,34 @@
RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
RelocationFactory::DWord S = pReloc.symValue();
- if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ pReloc.target() = S + A;
+ return X86RelocationFactory::OK;
+ }
+
+ // A local symbol may need REL Type dynamic relocation
+ if (rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
pReloc.target() = S + A;
return X86RelocationFactory::OK;
}
- else if(!rsym->isLocal()) {
- if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
S = helper_PLT(pReloc, pParent);
pReloc.target() = S + A;
}
- if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
- if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
+ // If we generate a dynamic relocation (except R_386_RELATIVE)
+ // for a place, we should not perform static relocation on it
+ // in order to keep the addend store in the place correct.
+ if (rsym->reserved() & X86GNULDBackend::ReserveRel) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
}
else {
@@ -294,10 +305,42 @@
const MCLDInfo& pLDInfo,
X86RelocationFactory& pParent)
{
- // perform static relocation
+ ResolveInfo* rsym = pReloc.symInfo();
RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
- pReloc.target() = pReloc.symValue() + A
- - pReloc.place(pParent.getLayout());
+ RelocationFactory::DWord S = pReloc.symValue();
+ RelocationFactory::DWord P = pReloc.place(pParent.getLayout());
+
+ const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
+ *(pReloc.targetRef().frag()));
+ assert(NULL != target_sect);
+ // If the flag of target section is not ALLOC, we will not scan this relocation
+ // but perform static relocation. (e.g., applying .debug section)
+ if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
+ pReloc.target() = S + A - P;
+ return X86RelocationFactory::OK;
+ }
+
+ // An external symbol may need PLT and dynamic relocation
+ if (!rsym->isLocal()) {
+ if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
+ S = helper_PLT(pReloc, pParent);
+ pReloc.target() = S + A - P;
+ }
+ if (pParent.getTarget().symbolNeedsDynRel(
+ *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), pLDInfo,
+ pLDInfo.output(), false)) {
+ if (helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
+ helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
+ }
+ else {
+ helper_DynRel(pReloc, pReloc.type(), pParent);
+ return X86RelocationFactory::OK;
+ }
+ }
+ }
+
+ // perform static relocation
+ pReloc.target() = S + A - P;
return X86RelocationFactory::OK;
}
@@ -331,7 +374,7 @@
const MCLDInfo& pLDInfo,
X86RelocationFactory& pParent)
{
- if(!(pReloc.symInfo()->reserved()
+ if (!(pReloc.symInfo()->reserved()
& (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
return X86RelocationFactory::BadReloc;
}
@@ -350,7 +393,7 @@
{
// PLT_S depends on if there is a PLT entry.
X86RelocationFactory::Address PLT_S;
- if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
+ if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
PLT_S = helper_PLT(pReloc, pParent);
else
PLT_S = pReloc.symValue();
diff --git a/lib/Target/X86/X86RelocationFactory.h b/lib/Target/X86/X86RelocationFactory.h
index 779a21d..6a6c372 100644
--- a/lib/Target/X86/X86RelocationFactory.h
+++ b/lib/Target/X86/X86RelocationFactory.h
@@ -55,3 +55,4 @@
} // namespace of mcld
#endif
+
diff --git a/lib/Target/X86/X86SectLinker.cpp b/lib/Target/X86/X86SectLinker.cpp
index 14621f3..a25a4c3 100644
--- a/lib/Target/X86/X86SectLinker.cpp
+++ b/lib/Target/X86/X86SectLinker.cpp
@@ -10,7 +10,6 @@
#include <mcld/Support/TargetRegistry.h>
#include "X86.h"
-#include "X86AndroidSectLinker.h"
#include "X86ELFSectLinker.h"
using namespace mcld;
@@ -31,9 +30,10 @@
assert(0 && "COFF linker has not supported yet");
}
- // For now, use Android SectLinker directly
- return new X86AndroidSectLinker(pOption,
- pLDBackend);
+ if (theTriple.isArch32Bit())
+ return new X86ELFSectLinker(pOption, pLDBackend);
+
+ assert(0 && "X86_64 has not supported yet");
}
} // namespace of mcld
@@ -44,3 +44,4 @@
// Register the linker frontend
mcld::TargetRegistry::RegisterSectLinker(TheX86Target, createX86SectLinker);
}
+
diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp
index b3d7779..b036137 100644
--- a/lib/Target/X86/X86TargetMachine.cpp
+++ b/lib/Target/X86/X86TargetMachine.cpp
@@ -31,3 +31,4 @@
{
delete m_pLDInfo;
}
+