mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-01 12:43:47 +00:00
Start adding support for shared libraries.
This just adds the types and enough support to detect incompatibilities among shared libraries and object files. llvm-svn: 246797
This commit is contained in:
parent
8aeb13fec1
commit
f98d6d84cd
@ -14,6 +14,7 @@
|
||||
#include "SymbolTable.h"
|
||||
#include "Writer.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -44,21 +45,33 @@ MemoryBufferRef LinkerDriver::openFile(StringRef Path) {
|
||||
return MBRef;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB,
|
||||
bool IsShared) {
|
||||
if (IsShared)
|
||||
return make_unique<SharedFile<ELFT>>(MB);
|
||||
return make_unique<ObjectFile<ELFT>>(MB);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
|
||||
using namespace llvm::sys::fs;
|
||||
file_magic Magic = identify_magic(MB.getBuffer());
|
||||
|
||||
std::pair<unsigned char, unsigned char> Type =
|
||||
object::getElfArchType(MB.getBuffer());
|
||||
if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB)
|
||||
error("Invalid data encoding");
|
||||
|
||||
bool IsShared = Magic == file_magic::elf_shared_object;
|
||||
if (Type.first == ELF::ELFCLASS32) {
|
||||
if (Type.second == ELF::ELFDATA2LSB)
|
||||
return make_unique<ObjectFile<object::ELF32LE>>(MB);
|
||||
return make_unique<ObjectFile<object::ELF32BE>>(MB);
|
||||
return createFile<object::ELF32LE>(MB, IsShared);
|
||||
return createFile<object::ELF32BE>(MB, IsShared);
|
||||
}
|
||||
if (Type.first == ELF::ELFCLASS64) {
|
||||
if (Type.second == ELF::ELFDATA2LSB)
|
||||
return make_unique<ObjectFile<object::ELF64LE>>(MB);
|
||||
return make_unique<ObjectFile<object::ELF64BE>>(MB);
|
||||
return createFile<object::ELF64LE>(MB, IsShared);
|
||||
return createFile<object::ELF64BE>(MB, IsShared);
|
||||
}
|
||||
error("Invalid file class");
|
||||
}
|
||||
@ -98,8 +111,8 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
Symtab.reportRemainingUndefines();
|
||||
|
||||
// Write the result.
|
||||
ObjectFileBase &FirstObj = *Symtab.getFirstObject();
|
||||
switch (FirstObj.getELFKind()) {
|
||||
const ELFFileBase *FirstObj = Symtab.getFirstELF();
|
||||
switch (FirstObj->getELFKind()) {
|
||||
case ELF32LEKind:
|
||||
writeResult<object::ELF32LE>(&Symtab);
|
||||
return;
|
||||
|
@ -14,23 +14,46 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace llvm::ELF;
|
||||
using namespace llvm::object;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
template <class ELFT>
|
||||
bool ObjectFile<ELFT>::isCompatibleWith(const ObjectFileBase &Other) const {
|
||||
if (getELFKind() != Other.getELFKind())
|
||||
return false;
|
||||
return getObj()->getHeader()->e_machine ==
|
||||
cast<ObjectFile<ELFT>>(Other).getObj()->getHeader()->e_machine;
|
||||
template <class ELFT> static uint16_t getEMachine(const ELFFileBase &B) {
|
||||
bool IsShared = isa<SharedFileBase>(B);
|
||||
if (IsShared)
|
||||
return cast<SharedFile<ELFT>>(B).getEMachine();
|
||||
return cast<ObjectFile<ELFT>>(B).getEMachine();
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
|
||||
static uint16_t getEMachine(const ELFFileBase &B) {
|
||||
ELFKind K = B.getELFKind();
|
||||
switch (K) {
|
||||
case ELF32BEKind:
|
||||
return getEMachine<ELF32BE>(B);
|
||||
case ELF32LEKind:
|
||||
return getEMachine<ELF32LE>(B);
|
||||
case ELF64BEKind:
|
||||
return getEMachine<ELF64BE>(B);
|
||||
case ELF64LEKind:
|
||||
return getEMachine<ELF64LE>(B);
|
||||
}
|
||||
}
|
||||
|
||||
bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const {
|
||||
return getELFKind() == Other.getELFKind() &&
|
||||
getEMachine(*this) == getEMachine(Other);
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFData<ELFT>::openELF(MemoryBufferRef MB) {
|
||||
// Parse a memory buffer as a ELF file.
|
||||
std::error_code EC;
|
||||
ELFObj = llvm::make_unique<ELFFile<ELFT>>(MB.getBuffer(), EC);
|
||||
error(EC);
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
|
||||
this->openELF(MB);
|
||||
|
||||
// Read section and symbol tables.
|
||||
initializeChunks();
|
||||
@ -38,16 +61,17 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
|
||||
uint64_t Size = ELFObj->getNumSections();
|
||||
uint64_t Size = this->ELFObj->getNumSections();
|
||||
Chunks.resize(Size);
|
||||
unsigned I = 0;
|
||||
for (const Elf_Shdr &Sec : ELFObj->sections()) {
|
||||
for (const Elf_Shdr &Sec : this->ELFObj->sections()) {
|
||||
switch (Sec.sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
Symtab = &Sec;
|
||||
break;
|
||||
case SHT_SYMTAB_SHNDX: {
|
||||
ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = ELFObj->getSHNDXTable(Sec);
|
||||
ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable =
|
||||
this->ELFObj->getSHNDXTable(Sec);
|
||||
error(ErrorOrTable);
|
||||
SymtabSHNDX = *ErrorOrTable;
|
||||
break;
|
||||
@ -76,11 +100,11 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
|
||||
ErrorOr<StringRef> StringTableOrErr =
|
||||
ELFObj->getStringTableForSymtab(*Symtab);
|
||||
this->ELFObj->getStringTableForSymtab(*Symtab);
|
||||
error(StringTableOrErr.getError());
|
||||
StringRef StringTable = *StringTableOrErr;
|
||||
|
||||
Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
|
||||
Elf_Sym_Range Syms = this->ELFObj->symbols(Symtab);
|
||||
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
uint32_t FirstNonLocal = Symtab->sh_info;
|
||||
if (FirstNonLocal > NumSymbols)
|
||||
@ -107,7 +131,8 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
case SHN_COMMON:
|
||||
return new (Alloc) DefinedCommon<ELFT>(Name, *Sym);
|
||||
case SHN_XINDEX:
|
||||
SecIndex = ELFObj->getExtendedSymbolTableIndex(Sym, Symtab, SymtabSHNDX);
|
||||
SecIndex =
|
||||
this->ELFObj->getExtendedSymbolTableIndex(Sym, Symtab, SymtabSHNDX);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -124,11 +149,18 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void SharedFile<ELFT>::parse() { this->openELF(MB); }
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
template class elf2::ObjectFile<llvm::object::ELF32LE>;
|
||||
template class elf2::ObjectFile<llvm::object::ELF32BE>;
|
||||
template class elf2::ObjectFile<llvm::object::ELF64LE>;
|
||||
template class elf2::ObjectFile<llvm::object::ELF64BE>;
|
||||
|
||||
template class elf2::SharedFile<llvm::object::ELF32LE>;
|
||||
template class elf2::SharedFile<llvm::object::ELF32BE>;
|
||||
template class elf2::SharedFile<llvm::object::ELF64LE>;
|
||||
template class elf2::SharedFile<llvm::object::ELF64BE>;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class SymbolBody;
|
||||
// The root class of input files.
|
||||
class InputFile {
|
||||
public:
|
||||
enum Kind { ObjectKind };
|
||||
enum Kind { ObjectKind, SharedKind };
|
||||
Kind kind() const { return FileKind; }
|
||||
virtual ~InputFile() {}
|
||||
|
||||
@ -42,59 +42,79 @@ private:
|
||||
|
||||
enum ELFKind { ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind };
|
||||
|
||||
class ELFFileBase : public InputFile {
|
||||
public:
|
||||
explicit ELFFileBase(Kind K, ELFKind EKind, MemoryBufferRef M)
|
||||
: InputFile(K, M), EKind(EKind) {}
|
||||
static bool classof(const InputFile *F) {
|
||||
Kind K = F->kind();
|
||||
return K == ObjectKind || K == SharedKind;
|
||||
}
|
||||
|
||||
bool isCompatibleWith(const ELFFileBase &Other) const;
|
||||
ELFKind getELFKind() const { return EKind; }
|
||||
|
||||
protected:
|
||||
const ELFKind EKind;
|
||||
};
|
||||
|
||||
// .o file.
|
||||
class ObjectFileBase : public InputFile {
|
||||
class ObjectFileBase : public ELFFileBase {
|
||||
public:
|
||||
explicit ObjectFileBase(ELFKind EKind, MemoryBufferRef M)
|
||||
: InputFile(ObjectKind, M), EKind(EKind) {}
|
||||
: ELFFileBase(ObjectKind, EKind, M) {}
|
||||
static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
|
||||
|
||||
ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; }
|
||||
|
||||
virtual bool isCompatibleWith(const ObjectFileBase &Other) const = 0;
|
||||
|
||||
ELFKind getELFKind() const { return EKind; }
|
||||
|
||||
protected:
|
||||
// List of all symbols referenced or defined by this file.
|
||||
std::vector<SymbolBody *> SymbolBodies;
|
||||
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
const ELFKind EKind;
|
||||
};
|
||||
|
||||
template <class ELFT> class ObjectFile : public ObjectFileBase {
|
||||
template <class ELFT> static ELFKind getStaticELFKind() {
|
||||
if (!ELFT::Is64Bits) {
|
||||
if (ELFT::TargetEndianness == llvm::support::little)
|
||||
return ELF32LEKind;
|
||||
return ELF32BEKind;
|
||||
}
|
||||
if (ELFT::TargetEndianness == llvm::support::little)
|
||||
return ELF64LEKind;
|
||||
return ELF64BEKind;
|
||||
}
|
||||
|
||||
template <class ELFT> class ELFData {
|
||||
public:
|
||||
llvm::object::ELFFile<ELFT> *getObj() const { return ELFObj.get(); }
|
||||
|
||||
uint16_t getEMachine() const { return getObj()->getHeader()->e_machine; }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<llvm::object::ELFFile<ELFT>> ELFObj;
|
||||
|
||||
void openELF(MemoryBufferRef MB);
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class ObjectFile : public ObjectFileBase, public ELFData<ELFT> {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
|
||||
|
||||
public:
|
||||
bool isCompatibleWith(const ObjectFileBase &Other) const override;
|
||||
|
||||
static ELFKind getStaticELFKind() {
|
||||
if (!ELFT::Is64Bits) {
|
||||
if (ELFT::TargetEndianness == llvm::support::little)
|
||||
return ELF32LEKind;
|
||||
return ELF32BEKind;
|
||||
}
|
||||
if (ELFT::TargetEndianness == llvm::support::little)
|
||||
return ELF64LEKind;
|
||||
return ELF64BEKind;
|
||||
}
|
||||
|
||||
static bool classof(const InputFile *F) {
|
||||
return F->kind() == ObjectKind &&
|
||||
cast<ObjectFileBase>(F)->getELFKind() == getStaticELFKind();
|
||||
cast<ELFFileBase>(F)->getELFKind() == getStaticELFKind<ELFT>();
|
||||
}
|
||||
|
||||
explicit ObjectFile(MemoryBufferRef M)
|
||||
: ObjectFileBase(getStaticELFKind(), M) {}
|
||||
: ObjectFileBase(getStaticELFKind<ELFT>(), M) {}
|
||||
void parse() override;
|
||||
|
||||
// Returns the underying ELF file.
|
||||
llvm::object::ELFFile<ELFT> *getObj() const { return ELFObj.get(); }
|
||||
|
||||
ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
|
||||
|
||||
SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
|
||||
@ -110,8 +130,6 @@ private:
|
||||
|
||||
SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
|
||||
|
||||
std::unique_ptr<llvm::object::ELFFile<ELFT>> ELFObj;
|
||||
|
||||
// List of all chunks defined by this file.
|
||||
std::vector<SectionChunk<ELFT> *> Chunks;
|
||||
|
||||
@ -119,6 +137,28 @@ private:
|
||||
ArrayRef<Elf_Word> SymtabSHNDX;
|
||||
};
|
||||
|
||||
// .so file.
|
||||
class SharedFileBase : public ELFFileBase {
|
||||
public:
|
||||
explicit SharedFileBase(ELFKind EKind, MemoryBufferRef M)
|
||||
: ELFFileBase(SharedKind, EKind, M) {}
|
||||
static bool classof(const InputFile *F) { return F->kind() == SharedKind; }
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class SharedFile : public SharedFileBase, public ELFData<ELFT> {
|
||||
public:
|
||||
static bool classof(const InputFile *F) {
|
||||
return F->kind() == SharedKind &&
|
||||
cast<ELFFileBase>(F)->getELFKind() == getStaticELFKind<ELFT>();
|
||||
}
|
||||
|
||||
explicit SharedFile(MemoryBufferRef M)
|
||||
: SharedFileBase(getStaticELFKind<ELFT>(), M) {}
|
||||
|
||||
void parse() override;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
|
@ -23,8 +23,8 @@ SymbolTable::SymbolTable() {
|
||||
void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
|
||||
File->parse();
|
||||
InputFile *FileP = File.release();
|
||||
auto *P = cast<ObjectFileBase>(FileP);
|
||||
addObject(P);
|
||||
auto *P = cast<ELFFileBase>(FileP);
|
||||
addELFFile(P);
|
||||
}
|
||||
|
||||
template <class ELFT> void SymbolTable::init() {
|
||||
@ -32,8 +32,8 @@ template <class ELFT> void SymbolTable::init() {
|
||||
Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic));
|
||||
}
|
||||
|
||||
void SymbolTable::addObject(ObjectFileBase *File) {
|
||||
if (const ObjectFileBase *Old = getFirstObject()) {
|
||||
void SymbolTable::addELFFile(ELFFileBase *File) {
|
||||
if (const ELFFileBase *Old = getFirstELF()) {
|
||||
if (!Old->isCompatibleWith(*File))
|
||||
error(Twine(Old->getName() + " is incompatible with " + File->getName()));
|
||||
} else {
|
||||
@ -53,23 +53,28 @@ void SymbolTable::addObject(ObjectFileBase *File) {
|
||||
}
|
||||
}
|
||||
|
||||
ObjectFiles.emplace_back(File);
|
||||
for (SymbolBody *Body : File->getSymbols()) {
|
||||
switch (File->getELFKind()) {
|
||||
case ELF32LEKind:
|
||||
resolve<ELF32LE>(Body);
|
||||
break;
|
||||
case ELF32BEKind:
|
||||
resolve<ELF32BE>(Body);
|
||||
break;
|
||||
case ELF64LEKind:
|
||||
resolve<ELF64LE>(Body);
|
||||
break;
|
||||
case ELF64BEKind:
|
||||
resolve<ELF64BE>(Body);
|
||||
break;
|
||||
if (auto *O = dyn_cast<ObjectFileBase>(File)) {
|
||||
ObjectFiles.emplace_back(O);
|
||||
for (SymbolBody *Body : O->getSymbols()) {
|
||||
switch (File->getELFKind()) {
|
||||
case ELF32LEKind:
|
||||
resolve<ELF32LE>(Body);
|
||||
break;
|
||||
case ELF32BEKind:
|
||||
resolve<ELF32BE>(Body);
|
||||
break;
|
||||
case ELF64LEKind:
|
||||
resolve<ELF64LE>(Body);
|
||||
break;
|
||||
case ELF64BEKind:
|
||||
resolve<ELF64BE>(Body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto *S = dyn_cast<SharedFileBase>(File))
|
||||
SharedFiles.emplace_back(S);
|
||||
}
|
||||
|
||||
void SymbolTable::reportRemainingUndefines() {
|
||||
|
@ -34,9 +34,11 @@ public:
|
||||
|
||||
void addFile(std::unique_ptr<InputFile> File);
|
||||
|
||||
ObjectFileBase *getFirstObject() const {
|
||||
const ELFFileBase *getFirstELF() const {
|
||||
if (!ObjectFiles.empty())
|
||||
return ObjectFiles[0].get();
|
||||
if (!SharedFiles.empty())
|
||||
return SharedFiles[0].get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -52,7 +54,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void addObject(ObjectFileBase *File);
|
||||
void addELFFile(ELFFileBase *File);
|
||||
|
||||
template <class ELFT> void init();
|
||||
template <class ELFT> void resolve(SymbolBody *Body);
|
||||
@ -62,6 +64,8 @@ private:
|
||||
|
||||
// The writer needs to infer the machine type from the object files.
|
||||
std::vector<std::unique_ptr<ObjectFileBase>> ObjectFiles;
|
||||
|
||||
std::vector<std::unique_ptr<SharedFileBase>> SharedFiles;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
|
@ -543,8 +543,8 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||
|
||||
EHdr->e_type = ET_EXEC;
|
||||
const SymbolTable &Symtab = SymTable.getSymTable();
|
||||
auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab.getFirstObject());
|
||||
EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
|
||||
auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab.getFirstELF());
|
||||
EHdr->e_machine = FirstObj.getEMachine();
|
||||
EHdr->e_version = EV_CURRENT;
|
||||
EHdr->e_entry = 0x401000;
|
||||
EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
|
||||
|
BIN
lld/test/elf2/Inputs/i686-simple-library.so
Executable file
BIN
lld/test/elf2/Inputs/i686-simple-library.so
Executable file
Binary file not shown.
@ -10,4 +10,17 @@
|
||||
// RUN: FileCheck --check-prefix=B-AND-C %s
|
||||
// B-AND-C: b.o is incompatible with {{.*}}c.o
|
||||
|
||||
// FIMME: create the .so ourselves once we are able to
|
||||
// RUN: not lld -flavor gnu2 %ta.o %p/Inputs/i686-simple-library.so -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=A-AND-SO %s
|
||||
// A-AND-SO: a.o is incompatible with {{.*}}/Inputs/i686-simple-library.so
|
||||
|
||||
// RUN: not lld -flavor gnu2 %tc.o %p/Inputs/i686-simple-library.so -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=C-AND-SO %s
|
||||
// C-AND-SO: c.o is incompatible with {{.*}}/Inputs/i686-simple-library.so
|
||||
|
||||
// RUN: not lld -flavor gnu2 %p/Inputs/i686-simple-library.so %tc.o -o %t 2>&1 | \
|
||||
// RUN: FileCheck --check-prefix=SO-AND-C %s
|
||||
// SO-AND-C: /Inputs/i686-simple-library.so is incompatible with {{.*}}c.o
|
||||
|
||||
// REQUIRES: x86,arm
|
||||
|
Loading…
x
Reference in New Issue
Block a user