forked from OSchip/llvm-project
[lld][WebAssembly] Fix static linking of -fPIC code with external undefined functions
Differential Revision: https://reviews.llvm.org/D66784 llvm-svn: 372779
This commit is contained in:
parent
e9e1c88ed9
commit
937b955837
|
@ -3,12 +3,13 @@
|
|||
; fixed values.
|
||||
; RUN: llc -relocation-model=pic -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
|
||||
; RUN: llc -relocation-model=pic -filetype=obj %s -o %t.o
|
||||
; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o
|
||||
; RUN: wasm-ld --allow-undefined --export-all -o %t.wasm %t.o %t.ret32.o
|
||||
; RUN: obj2yaml %t.wasm | FileCheck %s
|
||||
|
||||
target triple = "wasm32-unknown-emscripten"
|
||||
|
||||
declare i32 @ret32(float)
|
||||
declare i32 @missing_function(float)
|
||||
@global_float = global float 1.0
|
||||
@hidden_float = hidden global float 2.0
|
||||
|
||||
|
@ -18,6 +19,10 @@ define i32 (float)* @getaddr_external() {
|
|||
ret i32 (float)* @ret32;
|
||||
}
|
||||
|
||||
define i32 (float)* @getaddr_missing_function() {
|
||||
ret i32 (float)* @missing_function;
|
||||
}
|
||||
|
||||
define i32 ()* @getaddr_hidden() {
|
||||
ret i32 ()* @hidden_func;
|
||||
}
|
||||
|
@ -60,10 +65,18 @@ entry:
|
|||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
; CHECK-NEXT: Opcode: I32_CONST
|
||||
; CHECK-NEXT: Value: 1
|
||||
|
||||
; GOT.func.missing_function
|
||||
; CHECK-NEXT: - Index: 2
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
; CHECK-NEXT: Opcode: I32_CONST
|
||||
; CHECK-NEXT: Value: 2
|
||||
|
||||
; __table_base
|
||||
; CHECK-NEXT: - Index: 2
|
||||
; CHECK-NEXT: - Index: 3
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
|
@ -71,7 +84,7 @@ entry:
|
|||
; CHECK-NEXT: Value: 1
|
||||
|
||||
; GOT.mem.global_float
|
||||
; CHECK-NEXT: - Index: 3
|
||||
; CHECK-NEXT: - Index: 4
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
|
@ -79,7 +92,7 @@ entry:
|
|||
; CHECK-NEXT: Value: 1024
|
||||
|
||||
; GOT.mem.ret32_ptr
|
||||
; CHECK-NEXT: - Index: 4
|
||||
; CHECK-NEXT: - Index: 5
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
|
@ -87,7 +100,7 @@ entry:
|
|||
; CHECK-NEXT: Value: 1032
|
||||
|
||||
; __memory_base
|
||||
; CHECK-NEXT: - Index: 5
|
||||
; CHECK-NEXT: - Index: 6
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
|
|
|
@ -165,10 +165,15 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &reloc) const {
|
|||
switch (reloc.Type) {
|
||||
case R_WASM_TABLE_INDEX_I32:
|
||||
case R_WASM_TABLE_INDEX_SLEB:
|
||||
case R_WASM_TABLE_INDEX_REL_SLEB:
|
||||
case R_WASM_TABLE_INDEX_REL_SLEB: {
|
||||
if (!getFunctionSymbol(reloc.Index)->hasTableIndex())
|
||||
return 0;
|
||||
return getFunctionSymbol(reloc.Index)->getTableIndex();
|
||||
uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex();
|
||||
if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB)
|
||||
index -= config->tableBase;
|
||||
return index;
|
||||
|
||||
}
|
||||
case R_WASM_MEMORY_ADDR_SLEB:
|
||||
case R_WASM_MEMORY_ADDR_I32:
|
||||
case R_WASM_MEMORY_ADDR_LEB:
|
||||
|
|
|
@ -51,7 +51,7 @@ static void addGOTEntry(Symbol *sym) {
|
|||
if (config->isPic)
|
||||
out.importSec->addGOTEntry(sym);
|
||||
else
|
||||
out.globalSec->addDummyGOTEntry(sym);
|
||||
out.globalSec->addStaticGOTEntry(sym);
|
||||
}
|
||||
|
||||
void lld::wasm::scanRelocations(InputChunk *chunk) {
|
||||
|
|
|
@ -113,8 +113,6 @@ public:
|
|||
|
||||
const WasmSignature* getSignature() const;
|
||||
|
||||
bool isInGOT() const { return gotIndex != INVALID_INDEX; }
|
||||
|
||||
uint32_t getGOTIndex() const {
|
||||
assert(gotIndex != INVALID_INDEX);
|
||||
return gotIndex;
|
||||
|
@ -126,8 +124,9 @@ public:
|
|||
protected:
|
||||
Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
|
||||
: name(name), file(f), flags(flags), symbolKind(k),
|
||||
referenced(!config->gcSections), isUsedInRegularObj(false),
|
||||
forceExport(false), canInline(false), traced(false) {}
|
||||
referenced(!config->gcSections), requiresGOT(false),
|
||||
isUsedInRegularObj(false), forceExport(false), canInline(false),
|
||||
traced(false) {}
|
||||
|
||||
StringRef name;
|
||||
InputFile *file;
|
||||
|
@ -139,6 +138,10 @@ protected:
|
|||
public:
|
||||
bool referenced : 1;
|
||||
|
||||
// True for data symbols that needs a dummy GOT entry. Used for static
|
||||
// linking of GOT accesses.
|
||||
bool requiresGOT : 1;
|
||||
|
||||
// True if the symbol was used for linking and thus need to be added to the
|
||||
// output file's symbol table. This is true for all symbols except for
|
||||
// unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that
|
||||
|
|
|
@ -103,9 +103,9 @@ uint32_t ImportSection::getNumImports() const {
|
|||
|
||||
void ImportSection::addGOTEntry(Symbol *sym) {
|
||||
assert(!isSealed);
|
||||
LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n");
|
||||
if (sym->hasGOTIndex())
|
||||
return;
|
||||
LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n");
|
||||
sym->setGOTIndex(numImportedGlobals++);
|
||||
gotSymbols.push_back(sym);
|
||||
}
|
||||
|
@ -244,15 +244,21 @@ void GlobalSection::assignIndexes() {
|
|||
uint32_t globalIndex = out.importSec->getNumImportedGlobals();
|
||||
for (InputGlobal *g : inputGlobals)
|
||||
g->setGlobalIndex(globalIndex++);
|
||||
for (Symbol *sym : gotSymbols)
|
||||
for (Symbol *sym : staticGotSymbols)
|
||||
sym->setGOTIndex(globalIndex++);
|
||||
isSealed = true;
|
||||
}
|
||||
|
||||
void GlobalSection::addDummyGOTEntry(Symbol *sym) {
|
||||
LLVM_DEBUG(dbgs() << "addDummyGOTEntry: " << toString(*sym) << "\n");
|
||||
if (sym->hasGOTIndex())
|
||||
void GlobalSection::addStaticGOTEntry(Symbol *sym) {
|
||||
assert(!isSealed);
|
||||
if (sym->requiresGOT)
|
||||
return;
|
||||
gotSymbols.push_back(sym);
|
||||
LLVM_DEBUG(dbgs() << "addStaticGOTEntry: " << sym->getName() << " "
|
||||
<< toString(sym->kind()) << "\n");
|
||||
sym->requiresGOT = true;
|
||||
if (auto *F = dyn_cast<FunctionSymbol>(sym))
|
||||
out.elemSec->addEntry(F);
|
||||
staticGotSymbols.push_back(sym);
|
||||
}
|
||||
|
||||
void GlobalSection::writeBody() {
|
||||
|
@ -261,26 +267,27 @@ void GlobalSection::writeBody() {
|
|||
writeUleb128(os, numGlobals(), "global count");
|
||||
for (InputGlobal *g : inputGlobals)
|
||||
writeGlobal(os, g->global);
|
||||
for (const DefinedData *sym : definedFakeGlobals) {
|
||||
for (const Symbol *sym : staticGotSymbols) {
|
||||
WasmGlobal global;
|
||||
global.Type = {WASM_TYPE_I32, false};
|
||||
global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
if (auto *d = dyn_cast<DefinedData>(sym))
|
||||
global.InitExpr.Value.Int32 = d->getVirtualAddress();
|
||||
else if (auto *f = cast<FunctionSymbol>(sym))
|
||||
global.InitExpr.Value.Int32 = f->getTableIndex();
|
||||
writeGlobal(os, global);
|
||||
}
|
||||
for (const DefinedData *sym : dataAddressGlobals) {
|
||||
WasmGlobal global;
|
||||
global.Type = {WASM_TYPE_I32, false};
|
||||
global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
global.InitExpr.Value.Int32 = sym->getVirtualAddress();
|
||||
writeGlobal(os, global);
|
||||
}
|
||||
for (const Symbol *sym : gotSymbols) {
|
||||
WasmGlobal global;
|
||||
global.Type = {WASM_TYPE_I32, false};
|
||||
global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
||||
if (auto *d = dyn_cast<DefinedData>(sym))
|
||||
global.InitExpr.Value.Int32 = d->getVirtualAddress();
|
||||
else if (auto *f = cast<DefinedFunction>(sym))
|
||||
global.InitExpr.Value.Int32 = f->getTableIndex();
|
||||
writeGlobal(os, global);
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalSection::addGlobal(InputGlobal *global) {
|
||||
assert(!isSealed);
|
||||
if (!global->live)
|
||||
return;
|
||||
inputGlobals.push_back(global);
|
||||
|
|
|
@ -175,17 +175,23 @@ class GlobalSection : public SyntheticSection {
|
|||
public:
|
||||
GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}
|
||||
uint32_t numGlobals() const {
|
||||
return inputGlobals.size() + definedFakeGlobals.size() + gotSymbols.size();
|
||||
assert(isSealed);
|
||||
return inputGlobals.size() + dataAddressGlobals.size() +
|
||||
staticGotSymbols.size();
|
||||
}
|
||||
bool isNeeded() const override { return numGlobals() > 0; }
|
||||
void assignIndexes() override;
|
||||
void writeBody() override;
|
||||
void addGlobal(InputGlobal *global);
|
||||
void addDummyGOTEntry(Symbol *sym);
|
||||
void addDataAddressGlobal(DefinedData *global);
|
||||
void addStaticGOTEntry(Symbol *sym);
|
||||
|
||||
std::vector<const DefinedData *> definedFakeGlobals;
|
||||
std::vector<const DefinedData *> dataAddressGlobals;
|
||||
|
||||
protected:
|
||||
bool isSealed = false;
|
||||
std::vector<InputGlobal *> inputGlobals;
|
||||
std::vector<Symbol *> gotSymbols;
|
||||
std::vector<Symbol *> staticGotSymbols;
|
||||
};
|
||||
|
||||
// The event section contains a list of declared wasm events associated with the
|
||||
|
|
|
@ -509,8 +509,8 @@ void Writer::calculateExports() {
|
|||
out.exportSec->exports.push_back(
|
||||
WasmExport{functionTableName, WASM_EXTERNAL_TABLE, 0});
|
||||
|
||||
unsigned fakeGlobalIndex = out.importSec->getNumImportedGlobals() +
|
||||
out.globalSec->inputGlobals.size();
|
||||
unsigned globalIndex =
|
||||
out.importSec->getNumImportedGlobals() + out.globalSec->numGlobals();
|
||||
|
||||
for (Symbol *sym : symtab->getSymbols()) {
|
||||
if (!sym->isExported())
|
||||
|
@ -536,8 +536,8 @@ void Writer::calculateExports() {
|
|||
export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()};
|
||||
} else {
|
||||
auto *d = cast<DefinedData>(sym);
|
||||
out.globalSec->definedFakeGlobals.emplace_back(d);
|
||||
export_ = {name, WASM_EXTERNAL_GLOBAL, fakeGlobalIndex++};
|
||||
out.globalSec->dataAddressGlobals.push_back(d);
|
||||
export_ = {name, WASM_EXTERNAL_GLOBAL, globalIndex++};
|
||||
}
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Export: " << name << "\n");
|
||||
|
@ -1035,7 +1035,7 @@ void Writer::run() {
|
|||
|
||||
if (errorHandler().verbose) {
|
||||
log("Defined Functions: " + Twine(out.functionSec->inputFunctions.size()));
|
||||
log("Defined Globals : " + Twine(out.globalSec->inputGlobals.size()));
|
||||
log("Defined Globals : " + Twine(out.globalSec->numGlobals()));
|
||||
log("Defined Events : " + Twine(out.eventSec->inputEvents.size()));
|
||||
log("Function Imports : " +
|
||||
Twine(out.importSec->getNumImportedFunctions()));
|
||||
|
|
Loading…
Reference in New Issue