mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-18 00:38:31 +00:00
Start adding support for symbols in shared libraries.
llvm-svn: 247019
This commit is contained in:
parent
3ecd8c0aab
commit
18173d420e
@ -54,6 +54,24 @@ template <class ELFT> void ELFData<ELFT>::openELF(MemoryBufferRef MB) {
|
||||
error(EC);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename ELFData<ELFT>::Elf_Sym_Range ELFData<ELFT>::getNonLocalSymbols() {
|
||||
if (!Symtab)
|
||||
return Elf_Sym_Range(nullptr, nullptr);
|
||||
|
||||
ErrorOr<StringRef> StringTableOrErr =
|
||||
ELFObj->getStringTableForSymtab(*Symtab);
|
||||
error(StringTableOrErr.getError());
|
||||
StringTable = *StringTableOrErr;
|
||||
|
||||
Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
|
||||
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
uint32_t FirstNonLocal = Symtab->sh_info;
|
||||
if (FirstNonLocal > NumSymbols)
|
||||
error("Invalid sh_info in symbol table");
|
||||
return llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
|
||||
this->openELF(MB);
|
||||
|
||||
@ -69,7 +87,7 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
|
||||
for (const Elf_Shdr &Sec : this->ELFObj->sections()) {
|
||||
switch (Sec.sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
Symtab = &Sec;
|
||||
this->Symtab = &Sec;
|
||||
break;
|
||||
case SHT_SYMTAB_SHNDX: {
|
||||
ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable =
|
||||
@ -101,20 +119,11 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
|
||||
ErrorOr<StringRef> StringTableOrErr =
|
||||
this->ELFObj->getStringTableForSymtab(*Symtab);
|
||||
error(StringTableOrErr.getError());
|
||||
StringRef StringTable = *StringTableOrErr;
|
||||
|
||||
Elf_Sym_Range Syms = this->ELFObj->symbols(Symtab);
|
||||
Elf_Sym_Range Syms = this->getNonLocalSymbols();
|
||||
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
uint32_t FirstNonLocal = Symtab->sh_info;
|
||||
if (FirstNonLocal > NumSymbols)
|
||||
error("Invalid sh_info in symbol table");
|
||||
Syms = llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
|
||||
SymbolBodies.reserve(NumSymbols - FirstNonLocal);
|
||||
SymbolBodies.reserve(NumSymbols);
|
||||
for (const Elf_Sym &Sym : Syms)
|
||||
SymbolBodies.push_back(createSymbolBody(StringTable, &Sym));
|
||||
SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -133,8 +142,8 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
case SHN_COMMON:
|
||||
return new (Alloc) DefinedCommon<ELFT>(Name, *Sym);
|
||||
case SHN_XINDEX:
|
||||
SecIndex =
|
||||
this->ELFObj->getExtendedSymbolTableIndex(Sym, Symtab, SymtabSHNDX);
|
||||
SecIndex = this->ELFObj->getExtendedSymbolTableIndex(Sym, this->Symtab,
|
||||
SymtabSHNDX);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -181,7 +190,30 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
|
||||
return *Ret;
|
||||
}
|
||||
|
||||
template <class ELFT> void SharedFile<ELFT>::parse() { this->openELF(MB); }
|
||||
template <class ELFT> void SharedFile<ELFT>::parse() {
|
||||
this->openELF(MB);
|
||||
|
||||
for (const Elf_Shdr &Sec : this->ELFObj->sections()) {
|
||||
if (Sec.sh_type == SHT_DYNSYM) {
|
||||
this->Symtab = &Sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Elf_Sym_Range Syms = this->getNonLocalSymbols();
|
||||
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
SymbolBodies.reserve(NumSymbols);
|
||||
for (const Elf_Sym &Sym : Syms) {
|
||||
if (Sym.isUndefined())
|
||||
continue;
|
||||
|
||||
ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable);
|
||||
error(NameOrErr.getError());
|
||||
StringRef Name = *NameOrErr;
|
||||
|
||||
SymbolBodies.emplace_back(Name, Sym);
|
||||
}
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
@ -95,12 +95,18 @@ template <class ELFT> static ELFKind getStaticELFKind() {
|
||||
|
||||
template <class ELFT> class ELFData {
|
||||
public:
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
|
||||
|
||||
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;
|
||||
const Elf_Shdr *Symtab = nullptr;
|
||||
StringRef StringTable;
|
||||
Elf_Sym_Range getNonLocalSymbols();
|
||||
|
||||
void openELF(MemoryBufferRef MB);
|
||||
};
|
||||
@ -126,7 +132,7 @@ public:
|
||||
ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
|
||||
|
||||
SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
|
||||
uint32_t FirstNonLocal = Symtab->sh_info;
|
||||
uint32_t FirstNonLocal = this->Symtab->sh_info;
|
||||
if (SymbolIndex < FirstNonLocal)
|
||||
return nullptr;
|
||||
return SymbolBodies[SymbolIndex - FirstNonLocal]->getReplacement();
|
||||
@ -141,7 +147,6 @@ private:
|
||||
// List of all chunks defined by this file.
|
||||
std::vector<SectionChunk<ELFT> *> Chunks;
|
||||
|
||||
const Elf_Shdr *Symtab = nullptr;
|
||||
ArrayRef<Elf_Word> SymtabSHNDX;
|
||||
};
|
||||
|
||||
@ -174,7 +179,17 @@ public:
|
||||
|
||||
template <class ELFT>
|
||||
class SharedFile : public SharedFileBase, public ELFData<ELFT> {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
|
||||
|
||||
std::vector<SharedSymbol<ELFT>> SymbolBodies;
|
||||
|
||||
public:
|
||||
llvm::MutableArrayRef<SharedSymbol<ELFT>> getSharedSymbols() {
|
||||
return SymbolBodies;
|
||||
}
|
||||
|
||||
static bool classof(const InputFile *F) {
|
||||
return F->kind() == SharedKind &&
|
||||
cast<ELFFileBase>(F)->getELFKind() == getStaticELFKind<ELFT>();
|
||||
|
@ -51,8 +51,11 @@ template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
|
||||
resolve<ELFT>(Body);
|
||||
}
|
||||
|
||||
if (auto *S = dyn_cast<SharedFileBase>(File))
|
||||
if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
|
||||
SharedFiles.emplace_back(S);
|
||||
for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
|
||||
resolve<ELFT>(&Body);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTable::addELFFile(ELFFileBase *File) {
|
||||
|
@ -45,6 +45,9 @@ template <class ELFT> int SymbolBody::compare(SymbolBody *Other) {
|
||||
MostConstrainingVisibility = getMinVisibility(LV, RV);
|
||||
Other->MostConstrainingVisibility = MostConstrainingVisibility;
|
||||
|
||||
IsUsedInRegularObj |= Other->IsUsedInRegularObj;
|
||||
Other->IsUsedInRegularObj |= IsUsedInRegularObj;
|
||||
|
||||
if (L != R)
|
||||
return -1;
|
||||
|
||||
|
@ -41,9 +41,10 @@ public:
|
||||
DefinedRegularKind = 0,
|
||||
DefinedAbsoluteKind = 1,
|
||||
DefinedCommonKind = 2,
|
||||
DefinedLast = 2,
|
||||
UndefinedKind = 3,
|
||||
LazyKind = 4,
|
||||
SharedKind = 3,
|
||||
DefinedLast = 3,
|
||||
UndefinedKind = 4,
|
||||
LazyKind = 5,
|
||||
};
|
||||
|
||||
Kind kind() const { return static_cast<Kind>(SymbolKind); }
|
||||
@ -54,6 +55,8 @@ public:
|
||||
bool isStrongUndefined() const { return !IsWeak && isUndefined(); }
|
||||
bool isCommon() const { return SymbolKind == DefinedCommonKind; }
|
||||
bool isLazy() const { return SymbolKind == LazyKind; }
|
||||
bool isShared() const { return SymbolKind == SharedKind; }
|
||||
bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
|
||||
|
||||
// Returns the symbol name.
|
||||
StringRef getName() const { return Name; }
|
||||
@ -79,12 +82,15 @@ public:
|
||||
protected:
|
||||
SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility)
|
||||
: SymbolKind(K), IsWeak(IsWeak), MostConstrainingVisibility(Visibility),
|
||||
Name(Name) {}
|
||||
Name(Name) {
|
||||
IsUsedInRegularObj = K != SharedKind && K != LazyKind;
|
||||
}
|
||||
|
||||
protected:
|
||||
const unsigned SymbolKind : 8;
|
||||
const unsigned IsWeak : 1;
|
||||
unsigned MostConstrainingVisibility : 2;
|
||||
unsigned IsUsedInRegularObj : 1;
|
||||
StringRef Name;
|
||||
Symbol *Backref = nullptr;
|
||||
};
|
||||
@ -202,6 +208,19 @@ public:
|
||||
template <class ELFT>
|
||||
typename Undefined<ELFT>::Elf_Sym Undefined<ELFT>::Synthetic;
|
||||
|
||||
template <class ELFT> class SharedSymbol : public ELFSymbolBody<ELFT> {
|
||||
typedef ELFSymbolBody<ELFT> Base;
|
||||
typedef typename Base::Elf_Sym Elf_Sym;
|
||||
|
||||
public:
|
||||
static bool classof(const SymbolBody *S) {
|
||||
return S->kind() == Base::SharedKind;
|
||||
}
|
||||
|
||||
SharedSymbol(StringRef Name, const Elf_Sym &Sym)
|
||||
: ELFSymbolBody<ELFT>(Base::SharedKind, Name, Sym) {}
|
||||
};
|
||||
|
||||
// This class represents a symbol defined in an archive file. It is
|
||||
// created from an archive file header, and it knows how to load an
|
||||
// object file from an archive to replace itself with a defined
|
||||
|
@ -297,6 +297,17 @@ static int compareSym(const typename ELFFile<ELFT>::Elf_Sym *A,
|
||||
return AN - BN;
|
||||
}
|
||||
|
||||
static bool includeInSymtab(const SymbolBody &B) {
|
||||
if (B.isLazy())
|
||||
return false;
|
||||
if (!B.isUsedInRegularObj())
|
||||
return false;
|
||||
uint8_t V = B.getMostConstrainingVisibility();
|
||||
if (V != STV_DEFAULT && V != STV_PROTECTED)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
uint8_t *BufStart = Buf;
|
||||
|
||||
@ -305,14 +316,10 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
StringRef Name = P.first;
|
||||
Symbol *Sym = P.second;
|
||||
SymbolBody *Body = Sym->Body;
|
||||
if (Body->isLazy())
|
||||
if (!includeInSymtab(*Body))
|
||||
continue;
|
||||
const Elf_Sym &InputSym = cast<ELFSymbolBody<ELFT>>(Body)->Sym;
|
||||
|
||||
uint8_t V = Body->getMostConstrainingVisibility();
|
||||
if (V != STV_DEFAULT && V != STV_PROTECTED)
|
||||
continue;
|
||||
|
||||
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
||||
ESym->st_name = Builder.getOffset(Name);
|
||||
|
||||
@ -330,6 +337,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
if (!Body->isWeak())
|
||||
error(Twine("undefined symbol: ") + Name);
|
||||
case SymbolBody::DefinedAbsoluteKind:
|
||||
case SymbolBody::SharedKind:
|
||||
break;
|
||||
case SymbolBody::LazyKind:
|
||||
llvm_unreachable("Lazy symbol got to output symbol table!");
|
||||
@ -458,12 +466,9 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
||||
for (auto &P : Symtab.getSymbols()) {
|
||||
StringRef Name = P.first;
|
||||
SymbolBody *Body = P.second->Body;
|
||||
if (Body->isLazy())
|
||||
continue;
|
||||
if (auto *C = dyn_cast<DefinedCommon<ELFT>>(Body))
|
||||
CommonSymbols.push_back(C);
|
||||
uint8_t V = Body->getMostConstrainingVisibility();
|
||||
if (V != STV_DEFAULT && V != STV_PROTECTED)
|
||||
if (!includeInSymtab(*Body))
|
||||
continue;
|
||||
NumVisible++;
|
||||
Builder.add(Name);
|
||||
|
Binary file not shown.
38
lld/test/elf2/shared.s
Normal file
38
lld/test/elf2/shared.s
Normal file
@ -0,0 +1,38 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
|
||||
// RUN: lld -flavor gnu2 %t.o %p/Inputs/i686-simple-library.so -o %t
|
||||
// RUN: llvm-readobj -t %t | FileCheck %s
|
||||
// REQUIRES: x86
|
||||
|
||||
// CHECK: Symbols [
|
||||
// CHECK-NEXT: Symbol {
|
||||
// CHECK-NEXT: Name:
|
||||
// CHECK-NEXT: Value: 0x0
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Local
|
||||
// CHECK-NEXT: Type: None
|
||||
// CHECK-NEXT: Other: 0
|
||||
// CHECK-NEXT: Section: Undefined
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Symbol {
|
||||
// CHECK-NEXT: Name: _start
|
||||
// CHECK-NEXT: Value: 0x1000
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Global
|
||||
// CHECK-NEXT: Type: None
|
||||
// CHECK-NEXT: Other: 0
|
||||
// CHECK-NEXT: Section: .text
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Symbol {
|
||||
// CHECK-NEXT: Name: bar
|
||||
// CHECK-NEXT: Value: 0x0
|
||||
// CHECK-NEXT: Size: 0
|
||||
// CHECK-NEXT: Binding: Global
|
||||
// CHECK-NEXT: Type: Function
|
||||
// CHECK-NEXT: Other: 0
|
||||
// CHECK-NEXT: Section: Undefined
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
.long bar
|
Loading…
x
Reference in New Issue
Block a user