llvm-project/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp

181 lines
4.8 KiB
C++

//===- lib/ReaderWriter/ELF/ELFTargetInfo.cpp -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/ELFTargetInfo.h"
#include "TargetHandler.h"
#include "Targets.h"
#include "lld/Passes/LayoutPass.h"
#include "lld/ReaderWriter/ReaderLinkerScript.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace lld {
ELFTargetInfo::ELFTargetInfo(llvm::Triple triple)
: _outputFileType(elf::ET_EXEC)
, _triple(triple)
, _baseAddress(0)
, _isStaticExecutable(false)
, _outputYAML(false)
, _noInhibitExec(false)
, _mergeCommonStrings(false)
, _runLayoutPass(true) {
}
bool ELFTargetInfo::is64Bits() const {
return getTriple().isArch64Bit();
}
bool ELFTargetInfo::isLittleEndian() const {
// TODO: Do this properly. It is not defined purely by arch.
return true;
}
void ELFTargetInfo::addPasses(PassManager &pm) const {
if (_runLayoutPass)
pm.add(std::unique_ptr<Pass>(new LayoutPass()));
}
uint16_t ELFTargetInfo::getOutputMachine() const {
switch (getTriple().getArch()) {
case llvm::Triple::x86:
return llvm::ELF::EM_386;
case llvm::Triple::x86_64:
return llvm::ELF::EM_X86_64;
case llvm::Triple::hexagon:
return llvm::ELF::EM_HEXAGON;
case llvm::Triple::ppc:
return llvm::ELF::EM_PPC;
default:
llvm_unreachable("Unhandled arch");
}
}
bool ELFTargetInfo::validate(raw_ostream &diagnostics) {
if (_outputFileType == elf::ET_EXEC) {
if (_entrySymbolName.empty()) {
_entrySymbolName = "_start";
}
}
if (_inputFiles.empty()) {
diagnostics << "No input files\n";
return true;
}
return false;
}
bool ELFTargetInfo::isDynamic() const {
switch (_outputFileType) {
case llvm::ELF::ET_EXEC:
if (_isStaticExecutable)
return false;
else
return true;
case llvm::ELF::ET_DYN:
return true;
}
return false;
}
error_code ELFTargetInfo::parseFile(std::unique_ptr<MemoryBuffer> &mb,
std::vector<std::unique_ptr<File>> &result) const {
if (!_elfReader)
_elfReader = createReaderELF(*this);
error_code ec = _elfReader->parseFile(mb, result);
if (ec) {
// Not an ELF file, check file extension to see if it might be yaml
StringRef path = mb->getBufferIdentifier();
if ( path.endswith(".objtxt") ) {
if (!_yamlReader)
_yamlReader = createReaderYAML(*this);
ec = _yamlReader->parseFile(mb, result);
}
if (ec) {
// Not a yaml file, assume it is a linkerscript
if (!_linkerScriptReader)
_linkerScriptReader.reset(new ReaderLinkerScript(*this));
ec = _linkerScriptReader->parseFile(mb, result);
}
}
return ec;
}
Writer &ELFTargetInfo::writer() const {
if (!_writer) {
if (_outputYAML)
_writer = createWriterYAML(*this);
else
_writer = createWriterELF(*this);
}
return *_writer;
}
std::unique_ptr<ELFTargetInfo> ELFTargetInfo::create(llvm::Triple triple) {
switch (triple.getArch()) {
case llvm::Triple::x86:
return std::unique_ptr<ELFTargetInfo>(new lld::elf::X86TargetInfo(triple));
case llvm::Triple::x86_64:
return std::unique_ptr<
ELFTargetInfo>(new lld::elf::X86_64TargetInfo(triple));
case llvm::Triple::hexagon:
return std::unique_ptr<
ELFTargetInfo>(new lld::elf::HexagonTargetInfo(triple));
case llvm::Triple::ppc:
return std::unique_ptr<ELFTargetInfo>(new lld::elf::PPCTargetInfo(triple));
default:
return std::unique_ptr<ELFTargetInfo>();
}
}
bool ELFTargetInfo::appendLibrary(StringRef libName) {
bool foundFile = false;
StringRef pathref;
for (StringRef dir : _inputSearchPaths) {
// Search for dynamic library
if (!_isStaticExecutable) {
SmallString<128> dynlibPath;
dynlibPath.assign(dir);
llvm::sys::path::append(dynlibPath, Twine("lib") + libName + ".so");
pathref = dynlibPath.str();
if (llvm::sys::fs::exists(pathref)) {
foundFile = true;
}
}
// Search for static libraries too
if (!foundFile) {
SmallString<128> archivefullPath;
archivefullPath.assign(dir);
llvm::sys::path::append(archivefullPath, Twine("lib") + libName + ".a");
pathref = archivefullPath.str();
if (llvm::sys::fs::exists(pathref)) {
foundFile = true;
}
}
if (foundFile) {
unsigned pathlen = pathref.size();
char *x = _extraStrings.Allocate<char>(pathlen);
memcpy(x, pathref.data(), pathlen);
appendInputFile(StringRef(x,pathlen));
return false;
}
}
return true;
}
} // end namespace lld