mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
492f752969
This change implements lowering of references global symbols in PIC mode. This change implements lowering of global references in PIC mode using a new @GOT reference type. @GOT references can be used with function or data symbol names combined with the get_global instruction. In this case the linker will insert the wasm global that stores the address of the symbol (either in memory for data symbols or in the wasm table for function symbols). For now I'm continuing to use the R_WASM_GLOBAL_INDEX_LEB relocation type for this type of reference which means that this relocation type can refer to either a global or a function or data symbol. We could choose to introduce specific relocation types for GOT entries in the future. See the current dynamic linking proposal: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md Differential Revision: https://reviews.llvm.org/D54647 llvm-svn: 357022
323 lines
9.6 KiB
C++
323 lines
9.6 KiB
C++
//===- Symbols.cpp --------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Symbols.h"
|
|
#include "Config.h"
|
|
#include "InputChunks.h"
|
|
#include "InputEvent.h"
|
|
#include "InputFiles.h"
|
|
#include "InputGlobal.h"
|
|
#include "OutputSegment.h"
|
|
#include "lld/Common/ErrorHandler.h"
|
|
#include "lld/Common/Strings.h"
|
|
|
|
#define DEBUG_TYPE "lld"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::wasm;
|
|
using namespace lld;
|
|
using namespace lld::wasm;
|
|
|
|
DefinedFunction *WasmSym::CallCtors;
|
|
DefinedData *WasmSym::DsoHandle;
|
|
DefinedData *WasmSym::DataEnd;
|
|
DefinedData *WasmSym::HeapBase;
|
|
GlobalSymbol *WasmSym::StackPointer;
|
|
UndefinedGlobal *WasmSym::TableBase;
|
|
UndefinedGlobal *WasmSym::MemoryBase;
|
|
|
|
WasmSymbolType Symbol::getWasmType() const {
|
|
if (isa<FunctionSymbol>(this))
|
|
return WASM_SYMBOL_TYPE_FUNCTION;
|
|
if (isa<DataSymbol>(this))
|
|
return WASM_SYMBOL_TYPE_DATA;
|
|
if (isa<GlobalSymbol>(this))
|
|
return WASM_SYMBOL_TYPE_GLOBAL;
|
|
if (isa<EventSymbol>(this))
|
|
return WASM_SYMBOL_TYPE_EVENT;
|
|
if (isa<SectionSymbol>(this))
|
|
return WASM_SYMBOL_TYPE_SECTION;
|
|
llvm_unreachable("invalid symbol kind");
|
|
}
|
|
|
|
const WasmSignature *Symbol::getSignature() const {
|
|
if (auto* F = dyn_cast<FunctionSymbol>(this))
|
|
return F->Signature;
|
|
if (auto *L = dyn_cast<LazySymbol>(this))
|
|
return L->Signature;
|
|
return nullptr;
|
|
}
|
|
|
|
InputChunk *Symbol::getChunk() const {
|
|
if (auto *F = dyn_cast<DefinedFunction>(this))
|
|
return F->Function;
|
|
if (auto *D = dyn_cast<DefinedData>(this))
|
|
return D->Segment;
|
|
return nullptr;
|
|
}
|
|
|
|
bool Symbol::isLive() const {
|
|
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
|
return G->Global->Live;
|
|
if (auto *E = dyn_cast<DefinedEvent>(this))
|
|
return E->Event->Live;
|
|
if (InputChunk *C = getChunk())
|
|
return C->Live;
|
|
return Referenced;
|
|
}
|
|
|
|
void Symbol::markLive() {
|
|
if (auto *G = dyn_cast<DefinedGlobal>(this))
|
|
G->Global->Live = true;
|
|
if (auto *E = dyn_cast<DefinedEvent>(this))
|
|
E->Event->Live = true;
|
|
if (InputChunk *C = getChunk())
|
|
C->Live = true;
|
|
Referenced = true;
|
|
}
|
|
|
|
uint32_t Symbol::getOutputSymbolIndex() const {
|
|
assert(OutputSymbolIndex != INVALID_INDEX);
|
|
return OutputSymbolIndex;
|
|
}
|
|
|
|
void Symbol::setOutputSymbolIndex(uint32_t Index) {
|
|
LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index
|
|
<< "\n");
|
|
assert(OutputSymbolIndex == INVALID_INDEX);
|
|
OutputSymbolIndex = Index;
|
|
}
|
|
|
|
void Symbol::setGOTIndex(uint32_t Index) {
|
|
LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
|
|
assert(GOTIndex == INVALID_INDEX);
|
|
GOTIndex = Index;
|
|
}
|
|
|
|
bool Symbol::isWeak() const {
|
|
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
|
|
}
|
|
|
|
bool Symbol::isLocal() const {
|
|
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
|
|
}
|
|
|
|
bool Symbol::isHidden() const {
|
|
return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
|
|
}
|
|
|
|
void Symbol::setHidden(bool IsHidden) {
|
|
LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
|
|
Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
|
|
if (IsHidden)
|
|
Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
|
|
else
|
|
Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
|
|
}
|
|
|
|
bool Symbol::isExported() const {
|
|
if (!isDefined() || isLocal())
|
|
return false;
|
|
|
|
if (ForceExport || Config->ExportAll)
|
|
return true;
|
|
|
|
if (Config->ExportDynamic && !isHidden())
|
|
return true;
|
|
|
|
return Flags & WASM_SYMBOL_EXPORTED;
|
|
}
|
|
|
|
uint32_t FunctionSymbol::getFunctionIndex() const {
|
|
if (auto *F = dyn_cast<DefinedFunction>(this))
|
|
return F->Function->getFunctionIndex();
|
|
assert(FunctionIndex != INVALID_INDEX);
|
|
return FunctionIndex;
|
|
}
|
|
|
|
void FunctionSymbol::setFunctionIndex(uint32_t Index) {
|
|
LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
|
|
assert(FunctionIndex == INVALID_INDEX);
|
|
FunctionIndex = Index;
|
|
}
|
|
|
|
bool FunctionSymbol::hasFunctionIndex() const {
|
|
if (auto *F = dyn_cast<DefinedFunction>(this))
|
|
return F->Function->hasFunctionIndex();
|
|
return FunctionIndex != INVALID_INDEX;
|
|
}
|
|
|
|
uint32_t FunctionSymbol::getTableIndex() const {
|
|
if (auto *F = dyn_cast<DefinedFunction>(this))
|
|
return F->Function->getTableIndex();
|
|
assert(TableIndex != INVALID_INDEX);
|
|
return TableIndex;
|
|
}
|
|
|
|
bool FunctionSymbol::hasTableIndex() const {
|
|
if (auto *F = dyn_cast<DefinedFunction>(this))
|
|
return F->Function->hasTableIndex();
|
|
return TableIndex != INVALID_INDEX;
|
|
}
|
|
|
|
void FunctionSymbol::setTableIndex(uint32_t Index) {
|
|
// For imports, we set the table index here on the Symbol; for defined
|
|
// functions we set the index on the InputFunction so that we don't export
|
|
// the same thing twice (keeps the table size down).
|
|
if (auto *F = dyn_cast<DefinedFunction>(this)) {
|
|
F->Function->setTableIndex(Index);
|
|
return;
|
|
}
|
|
LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
|
|
assert(TableIndex == INVALID_INDEX);
|
|
TableIndex = Index;
|
|
}
|
|
|
|
DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
|
|
InputFunction *Function)
|
|
: FunctionSymbol(Name, DefinedFunctionKind, Flags, F,
|
|
Function ? &Function->Signature : nullptr),
|
|
Function(Function) {}
|
|
|
|
uint32_t DefinedData::getVirtualAddress() const {
|
|
LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
|
|
if (Segment)
|
|
return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset;
|
|
return Offset;
|
|
}
|
|
|
|
void DefinedData::setVirtualAddress(uint32_t Value) {
|
|
LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
|
|
assert(!Segment);
|
|
Offset = Value;
|
|
}
|
|
|
|
uint32_t DefinedData::getOutputSegmentOffset() const {
|
|
LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
|
|
return Segment->OutputSegmentOffset + Offset;
|
|
}
|
|
|
|
uint32_t DefinedData::getOutputSegmentIndex() const {
|
|
LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
|
|
return Segment->OutputSeg->Index;
|
|
}
|
|
|
|
uint32_t GlobalSymbol::getGlobalIndex() const {
|
|
if (auto *F = dyn_cast<DefinedGlobal>(this))
|
|
return F->Global->getGlobalIndex();
|
|
assert(GlobalIndex != INVALID_INDEX);
|
|
return GlobalIndex;
|
|
}
|
|
|
|
void GlobalSymbol::setGlobalIndex(uint32_t Index) {
|
|
LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
|
|
assert(GlobalIndex == INVALID_INDEX);
|
|
GlobalIndex = Index;
|
|
}
|
|
|
|
bool GlobalSymbol::hasGlobalIndex() const {
|
|
if (auto *F = dyn_cast<DefinedGlobal>(this))
|
|
return F->Global->hasGlobalIndex();
|
|
return GlobalIndex != INVALID_INDEX;
|
|
}
|
|
|
|
DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
|
|
InputGlobal *Global)
|
|
: GlobalSymbol(Name, DefinedGlobalKind, Flags, File,
|
|
Global ? &Global->getType() : nullptr),
|
|
Global(Global) {}
|
|
|
|
uint32_t EventSymbol::getEventIndex() const {
|
|
if (auto *F = dyn_cast<DefinedEvent>(this))
|
|
return F->Event->getEventIndex();
|
|
assert(EventIndex != INVALID_INDEX);
|
|
return EventIndex;
|
|
}
|
|
|
|
void EventSymbol::setEventIndex(uint32_t Index) {
|
|
LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n");
|
|
assert(EventIndex == INVALID_INDEX);
|
|
EventIndex = Index;
|
|
}
|
|
|
|
bool EventSymbol::hasEventIndex() const {
|
|
if (auto *F = dyn_cast<DefinedEvent>(this))
|
|
return F->Event->hasEventIndex();
|
|
return EventIndex != INVALID_INDEX;
|
|
}
|
|
|
|
DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
|
|
InputEvent *Event)
|
|
: EventSymbol(Name, DefinedEventKind, Flags, File,
|
|
Event ? &Event->getType() : nullptr,
|
|
Event ? &Event->Signature : nullptr),
|
|
Event(Event) {}
|
|
|
|
uint32_t SectionSymbol::getOutputSectionIndex() const {
|
|
LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
|
|
assert(OutputSectionIndex != INVALID_INDEX);
|
|
return OutputSectionIndex;
|
|
}
|
|
|
|
void SectionSymbol::setOutputSectionIndex(uint32_t Index) {
|
|
LLVM_DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index
|
|
<< "\n");
|
|
assert(Index != INVALID_INDEX);
|
|
OutputSectionIndex = Index;
|
|
}
|
|
|
|
void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
|
|
|
|
std::string lld::toString(const wasm::Symbol &Sym) {
|
|
return lld::maybeDemangleSymbol(Sym.getName());
|
|
}
|
|
|
|
std::string lld::maybeDemangleSymbol(StringRef Name) {
|
|
if (Config->Demangle)
|
|
if (Optional<std::string> S = demangleItanium(Name))
|
|
return *S;
|
|
return Name;
|
|
}
|
|
|
|
std::string lld::toString(wasm::Symbol::Kind Kind) {
|
|
switch (Kind) {
|
|
case wasm::Symbol::DefinedFunctionKind:
|
|
return "DefinedFunction";
|
|
case wasm::Symbol::DefinedDataKind:
|
|
return "DefinedData";
|
|
case wasm::Symbol::DefinedGlobalKind:
|
|
return "DefinedGlobal";
|
|
case wasm::Symbol::DefinedEventKind:
|
|
return "DefinedEvent";
|
|
case wasm::Symbol::UndefinedFunctionKind:
|
|
return "UndefinedFunction";
|
|
case wasm::Symbol::UndefinedDataKind:
|
|
return "UndefinedData";
|
|
case wasm::Symbol::UndefinedGlobalKind:
|
|
return "UndefinedGlobal";
|
|
case wasm::Symbol::LazyKind:
|
|
return "LazyKind";
|
|
case wasm::Symbol::SectionKind:
|
|
return "SectionKind";
|
|
}
|
|
llvm_unreachable("invalid symbol kind");
|
|
}
|
|
|
|
// Print out a log message for --trace-symbol.
|
|
void lld::wasm::printTraceSymbol(Symbol *Sym) {
|
|
std::string S;
|
|
if (Sym->isUndefined())
|
|
S = ": reference to ";
|
|
else if (Sym->isLazy())
|
|
S = ": lazy definition of ";
|
|
else
|
|
S = ": definition of ";
|
|
|
|
message(toString(Sym->getFile()) + S + Sym->getName());
|
|
}
|