[WebAssembly] Fix symbol exports under -r/--relocatable

This change cleans up the way wasm exports and globals
are generated, particualrly for -r/--relocatable where
globals need to be created and exported in order for
output relocations which reference them.

Remove the need for a per file GlobalIndexOffset and
instead set the output index for each symbol directly.
This simplifies the code in several places.

Differential Revision: https://reviews.llvm.org/D40859

llvm-svn: 320001
This commit is contained in:
Sam Clegg 2017-12-07 01:51:24 +00:00
parent c325d30d2c
commit 74fe0ba105
9 changed files with 94 additions and 117 deletions

View File

@ -23,6 +23,11 @@ target triple = "wasm32-unknown-unknown-wasm"
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1052
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1024
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
@ -34,16 +39,11 @@ target triple = "wasm32-unknown-unknown-wasm"
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1048
; CHECK-NEXT: - Type: I32
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1052
; CHECK: - Type: DATA
; CHECK-NEXT: Relocations:
; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32
; CHECK-NEXT: Index: 4
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Offset: 0x0000001F
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 7

View File

@ -93,6 +93,18 @@ declare i32 @foo_import() local_unnamed_addr
; CHECK-NEXT: - Name: my_func
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: hello_str
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 1
; CHECK-NEXT: - Name: func_addr1
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: func_addr2
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: data_addr1
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:

View File

@ -142,7 +142,6 @@ static Symbol* addSyntheticGlobal(StringRef Name, int32_t Value) {
log("injecting global: " + Name);
Symbol *S = Symtab->addDefinedGlobal(Name);
S->setVirtualAddress(Value);
S->setOutputIndex(Config->SyntheticGlobals.size());
Config->SyntheticGlobals.emplace_back(S);
return S;
}

View File

@ -47,7 +47,6 @@ void ObjFile::dumpInfo() const {
" FunctionIndexOffset : " + Twine(FunctionIndexOffset) + "\n" +
" NumFunctionImports : " + Twine(NumFunctionImports()) + "\n" +
" TableIndexOffset : " + Twine(TableIndexOffset) + "\n" +
" GlobalIndexOffset : " + Twine(GlobalIndexOffset) + "\n" +
" NumGlobalImports : " + Twine(NumGlobalImports()) + "\n");
}
@ -68,15 +67,10 @@ uint32_t ObjFile::getRelocatedAddress(uint32_t Index) const {
}
uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const {
DEBUG(dbgs() << "relocateFunctionIndex: " << Original);
const Symbol *Sym = getFunctionSymbol(Original);
uint32_t Index;
if (Sym)
Index = Sym->getOutputIndex();
else
Index = Original + FunctionIndexOffset;
DEBUG(dbgs() << " -> " << Index << "\n");
uint32_t Index = Sym->getOutputIndex();
DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": "
<< Original << " -> " << Index << "\n");
return Index;
}
@ -89,15 +83,10 @@ uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
}
uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const {
DEBUG(dbgs() << "relocateGlobalIndex: " << Original);
uint32_t Index;
const Symbol *Sym = getGlobalSymbol(Original);
if (Sym)
Index = Sym->getOutputIndex();
else
Index = Original + GlobalIndexOffset;
DEBUG(dbgs() << " -> " << Index << "\n");
uint32_t Index = Sym->getOutputIndex();
DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n");
return Index;
}

View File

@ -103,7 +103,6 @@ public:
size_t NumGlobalImports() const { return GlobalImports; }
int32_t FunctionIndexOffset = 0;
int32_t GlobalIndexOffset = 0;
int32_t TableIndexOffset = 0;
const WasmSection *CodeSection = nullptr;
std::vector<OutputRelocation> CodeRelocations;

View File

@ -72,9 +72,8 @@ std::string lld::toString(OutputSection *Section) {
static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) {
DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type
<< " index=" << Reloc.Reloc.Index << " new=" << Reloc.NewIndex
<< " value=" << Reloc.Value << " offset=" << Reloc.Reloc.Offset
<< "\n");
<< " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value
<< " offset=" << Reloc.Reloc.Offset << "\n");
Buf += Reloc.Reloc.Offset;
int64_t ExistingValue;
switch (Reloc.Reloc.Type) {
@ -149,15 +148,18 @@ static void calcRelocations(const ObjFile &File,
int32_t OutputOffset) {
log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset));
for (const WasmRelocation &Reloc : Relocs) {
int64_t NewIndex = calcNewIndex(File, Reloc);
OutputRelocation NewReloc;
NewReloc.Reloc = Reloc;
NewReloc.Reloc.Offset += OutputOffset;
NewReloc.NewIndex = NewIndex;
DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index
<< " offset=" << Reloc.Offset << " new=" << NewIndex
<< " offset=" << Reloc.Offset
<< " newOffset=" << NewReloc.Reloc.Offset << "\n");
if (Config->EmitRelocs)
NewReloc.NewIndex = calcNewIndex(File, Reloc);
else
NewReloc.NewIndex = UINT32_MAX;
switch (Reloc.Type) {
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
@ -167,7 +169,8 @@ static void calcRelocations(const ObjFile &File,
NewReloc.Value += Reloc.Addend;
break;
default:
NewReloc.Value = NewIndex;
NewReloc.Value = calcNewIndex(File, Reloc);
break;
}
OutputRelocs.emplace_back(NewReloc);

View File

@ -34,8 +34,7 @@ void SymbolTable::addFile(InputFile *File) {
void SymbolTable::reportRemainingUndefines() {
std::unordered_set<Symbol *> Undefs;
for (auto &I : SymMap) {
Symbol *Sym = I.second;
for (Symbol *Sym : SymVector) {
if (Sym->isUndefined() && !Sym->isWeak() &&
Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
Undefs.insert(Sym);
@ -67,6 +66,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
if (Sym)
return {Sym, false};
Sym = make<Symbol>(Name, false);
SymVector.emplace_back(Sym);
return {Sym, true};
}

View File

@ -47,6 +47,7 @@ public:
void reportDuplicate(Symbol *Existing, InputFile *NewFile);
void reportRemainingUndefines();
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
Symbol *find(StringRef Name);
Symbol *addDefined(InputFile *F, const WasmSymbol *Sym,
@ -60,6 +61,7 @@ private:
std::pair<Symbol *, bool> insert(StringRef Name);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
std::vector<Symbol *> SymVector;
};
extern SymbolTable *Symtab;

View File

@ -111,8 +111,9 @@ private:
std::vector<const WasmSignature *> Types;
DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;
std::vector<Symbol *> FunctionImports;
std::vector<Symbol *> GlobalImports;
std::vector<const Symbol *> FunctionImports;
std::vector<const Symbol *> GlobalImports;
std::vector<const Symbol *> DefinedGlobals;
// Elements that are used to construct the final output
std::string Header;
@ -217,11 +218,14 @@ void Writer::createMemorySection() {
}
void Writer::createGlobalSection() {
if (DefinedGlobals.empty())
return;
SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
raw_ostream &OS = Section->getStream();
writeUleb128(OS, NumGlobals, "global count");
for (const Symbol *Sym : Config->SyntheticGlobals) {
writeUleb128(OS, DefinedGlobals.size(), "global count");
for (const Symbol *Sym : DefinedGlobals) {
WasmGlobal Global;
Global.Type = WASM_TYPE_I32;
Global.Mutable = Sym == Config->StackPointerSymbol;
@ -229,24 +233,6 @@ void Writer::createGlobalSection() {
Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
writeGlobal(OS, Global);
}
if (Config->EmitRelocs) {
for (ObjFile *File : Symtab->ObjectFiles) {
uint32_t GlobalIndex = File->NumGlobalImports();
for (const WasmGlobal &Global : File->getWasmObj()->globals()) {
WasmGlobal RelocatedGlobal(Global);
if (Global.Type != WASM_TYPE_I32)
fatal("unsupported global type: " + Twine(Global.Type));
if (Global.InitExpr.Opcode != WASM_OPCODE_I32_CONST)
fatal("unsupported global init opcode: " +
Twine(Global.InitExpr.Opcode));
RelocatedGlobal.InitExpr.Value.Int32 =
File->getRelocatedAddress(GlobalIndex);
writeGlobal(OS, RelocatedGlobal);
++GlobalIndex;
}
}
}
}
void Writer::createTableSection() {
@ -261,35 +247,36 @@ void Writer::createTableSection() {
}
void Writer::createExportSection() {
// Memory is and main function are exported for executables.
bool ExportMemory = !Config->Relocatable && !Config->ImportMemory;
bool ExportOther = true; // ??? TODO Config->Relocatable;
bool ExportHidden = Config->Relocatable;
Symbol *EntrySym = Symtab->find(Config->Entry);
bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined();
bool ExportHidden = Config->EmitRelocs;
uint32_t NumExports = 0;
if (ExportMemory)
++NumExports;
uint32_t NumExports = ExportMemory ? 1 : 0;
std::vector<const Symbol *> SymbolExports;
if (ExportEntry)
++NumExports;
SymbolExports.emplace_back(EntrySym);
if (ExportOther) {
for (ObjFile *File : Symtab->ObjectFiles) {
for (Symbol *Sym : File->getSymbols()) {
if (!Sym->isFunction() || Sym->isLocal() || Sym->isUndefined() ||
(Sym->isHidden() && !ExportHidden) || Sym->WrittenToSymtab)
continue;
if (Sym == EntrySym)
continue;
Sym->WrittenToSymtab = true;
++NumExports;
}
}
for (const Symbol *Sym : Symtab->getSymbols()) {
if (Sym->isUndefined() || Sym->isGlobal())
continue;
if (Sym->isHidden() && !ExportHidden)
continue;
if (ExportEntry && Sym == EntrySym)
continue;
SymbolExports.emplace_back(Sym);
}
for (const Symbol *Sym : DefinedGlobals) {
// Can't export the SP right now because it mutable and mutable globals
// connot be exported.
if (Sym == Config->StackPointerSymbol)
continue;
SymbolExports.emplace_back(Sym);
}
NumExports += SymbolExports.size();
if (!NumExports)
return;
@ -306,34 +293,16 @@ void Writer::createExportSection() {
writeExport(OS, MemoryExport);
}
if (ExportEntry) {
WasmExport EntryExport;
EntryExport.Name = Config->Entry;
EntryExport.Kind = WASM_EXTERNAL_FUNCTION;
EntryExport.Index = EntrySym->getOutputIndex();
writeExport(OS, EntryExport);
}
if (ExportOther) {
for (ObjFile *File : Symtab->ObjectFiles) {
for (Symbol *Sym : File->getSymbols()) {
if (!Sym->isFunction() || Sym->isLocal() || Sym->isUndefined() ||
(Sym->isHidden() && !ExportHidden) || !Sym->WrittenToSymtab)
continue;
if (Sym == EntrySym)
continue;
Sym->WrittenToSymtab = false;
log("Export: " + Sym->getName());
WasmExport Export;
Export.Name = Sym->getName();
Export.Index = Sym->getOutputIndex();
if (Sym->isFunction())
Export.Kind = WASM_EXTERNAL_FUNCTION;
else
Export.Kind = WASM_EXTERNAL_GLOBAL;
writeExport(OS, Export);
}
}
for (const Symbol *Sym : SymbolExports) {
log("Export: " + Sym->getName());
WasmExport Export;
Export.Name = Sym->getName();
Export.Index = Sym->getOutputIndex();
if (Sym->isFunction())
Export.Kind = WASM_EXTERNAL_FUNCTION;
else
Export.Kind = WASM_EXTERNAL_GLOBAL;
writeExport(OS, Export);
}
}
@ -557,7 +526,6 @@ void Writer::createSections() {
}
void Writer::calculateOffsets() {
NumGlobals = Config->SyntheticGlobals.size();
NumTableElems = InitialTableOffset;
for (ObjFile *File : Symtab->ObjectFiles) {
@ -568,13 +536,6 @@ void Writer::calculateOffsets() {
FunctionImports.size() - File->NumFunctionImports() + NumFunctions;
NumFunctions += WasmFile->functions().size();
// Global Index
if (Config->EmitRelocs) {
File->GlobalIndexOffset =
GlobalImports.size() - File->NumGlobalImports() + NumGlobals;
NumGlobals += WasmFile->globals().size();
}
// Memory
if (WasmFile->memories().size()) {
if (WasmFile->memories().size() > 1) {
@ -640,19 +601,31 @@ void Writer::calculateTypes() {
}
void Writer::assignSymbolIndexes() {
uint32_t GlobalIndex = GlobalImports.size();
if (Config->StackPointerSymbol) {
DefinedGlobals.emplace_back(Config->StackPointerSymbol);
Config->StackPointerSymbol->setOutputIndex(GlobalIndex++);
}
if (Config->EmitRelocs)
DefinedGlobals.reserve(Symtab->getSymbols().size());
for (ObjFile *File : Symtab->ObjectFiles) {
DEBUG(dbgs() << "assignSymbolIndexes: " << File->getName() << "\n");
for (Symbol *Sym : File->getSymbols()) {
if (Sym->hasOutputIndex() || !Sym->isDefined())
continue;
if (Sym->getFile() && isa<ObjFile>(Sym->getFile())) {
auto *Obj = cast<ObjFile>(Sym->getFile());
if (Sym->isFunction())
if (Sym->isFunction()) {
if (Sym->getFile() && isa<ObjFile>(Sym->getFile())) {
auto *Obj = cast<ObjFile>(Sym->getFile());
Sym->setOutputIndex(Obj->FunctionIndexOffset +
Sym->getFunctionIndex());
else
Sym->setOutputIndex(Obj->GlobalIndexOffset + Sym->getGlobalIndex());
}
} else if (Config->EmitRelocs) {
DefinedGlobals.emplace_back(Sym);
Sym->setOutputIndex(GlobalIndex++);
}
}
}