[MC][WebAssembly] Only emit indirect function table import if needed

The indirect function table, synthesized by the linker, is needed if and
only if there are TABLE_INDEX relocs.

Differential Revision: https://reviews.llvm.org/D91637
This commit is contained in:
Andy Wingo 2020-11-25 08:31:05 -08:00 committed by Sam Clegg
parent a8d74517dc
commit feac819e50
15 changed files with 127 additions and 85 deletions

View File

@ -96,6 +96,15 @@ public:
StringRef getExportName() const { return ExportName.getValue(); }
void setExportName(StringRef Name) { ExportName = Name; }
bool isFunctionTable() const {
return isTable() && hasTableType() &&
getTableType() == wasm::ValType::FUNCREF;
}
void setFunctionTable() {
setType(wasm::WASM_SYMBOL_TYPE_TABLE);
setTableType(wasm::ValType::FUNCREF);
}
void setUsedInGOT() const { IsUsedInGOT = true; }
bool isUsedInGOT() const { return IsUsedInGOT; }
@ -111,8 +120,9 @@ public:
}
void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; }
const wasm::ValType &getTableType() const {
assert(TableType.hasValue());
bool hasTableType() const { return TableType.hasValue(); }
wasm::ValType getTableType() const {
assert(hasTableType());
return TableType.getValue();
}
void setTableType(wasm::ValType TT) { TableType = TT; }

View File

@ -299,6 +299,7 @@ private:
uint32_t DataSection = 0;
uint32_t EventSection = 0;
uint32_t GlobalSection = 0;
uint32_t TableSection = 0;
};
class WasmSectionOrderChecker {

View File

@ -40,8 +40,8 @@ using namespace llvm;
namespace {
// Went we ceate the indirect function table we start at 1, so that there is
// and emtpy slot at 0 and therefore calling a null function pointer will trap.
// When we create the indirect function table we start at 1, so that there is
// and empty slot at 0 and therefore calling a null function pointer will trap.
static const uint32_t InitialTableOffset = 1;
// For patching purposes, we need to remember where each section starts, both
@ -218,9 +218,7 @@ class WasmObjectWriter : public MCObjectWriter {
SmallVector<WasmDataSegment, 4> DataSegments;
unsigned NumFunctionImports = 0;
unsigned NumGlobalImports = 0;
// NumTableImports is initialized to 1 to account for the hardcoded import of
// __indirect_function_table
unsigned NumTableImports = 1;
unsigned NumTableImports = 0;
unsigned NumEventImports = 0;
uint32_t SectionCount = 0;
@ -270,7 +268,7 @@ private:
SectionFunctions.clear();
NumFunctionImports = 0;
NumGlobalImports = 0;
NumTableImports = 1;
NumTableImports = 0;
MCObjectWriter::reset();
}
@ -497,6 +495,29 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
SymA = cast<MCSymbolWasm>(SectionSymbol);
}
if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
Type == wasm::R_WASM_TABLE_INDEX_SLEB ||
Type == wasm::R_WASM_TABLE_INDEX_SLEB64 ||
Type == wasm::R_WASM_TABLE_INDEX_I32 ||
Type == wasm::R_WASM_TABLE_INDEX_I64) {
// TABLE_INDEX relocs implicitly use the default indirect function table.
auto TableName = "__indirect_function_table";
MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(TableName));
if (Sym) {
if (!Sym->isFunctionTable())
Ctx.reportError(
Fixup.getLoc(),
"symbol '__indirect_function_table' is not a function table");
} else {
Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(TableName));
Sym->setFunctionTable();
// The default function table is synthesized by the linker.
Sym->setUndefined();
}
Sym->setUsedInReloc();
Asm.registerSymbol(*Sym);
}
// Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
// against a named symbol.
if (Type != wasm::R_WASM_TYPE_INDEX_LEB) {
@ -1201,16 +1222,6 @@ void WasmObjectWriter::prepareImports(
: wasm::WASM_LIMITS_FLAG_NONE;
Imports.push_back(MemImport);
// For now, always emit the table section, since indirect calls are not
// valid without it. In the future, we could perhaps be more clever and omit
// it if there are no indirect calls.
wasm::WasmImport TableImport;
TableImport.Module = "env";
TableImport.Field = "__indirect_function_table";
TableImport.Kind = wasm::WASM_EXTERNAL_TABLE;
TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF;
Imports.push_back(TableImport);
// Populate SignatureIndices, and Imports and WasmIndices for undefined
// symbols. This must be done before populating WasmIndices for defined
// symbols.
@ -1269,6 +1280,23 @@ void WasmObjectWriter::prepareImports(
Imports.push_back(Import);
assert(WasmIndices.count(&WS) == 0);
WasmIndices[&WS] = NumEventImports++;
} else if (WS.isTable()) {
if (WS.isWeak())
report_fatal_error("undefined table symbol cannot be weak");
wasm::WasmImport Import;
Import.Module = WS.getImportModule();
Import.Field = WS.getImportName();
Import.Kind = wasm::WASM_EXTERNAL_TABLE;
wasm::ValType ElemType = WS.getTableType();
Import.Table.ElemType = uint8_t(ElemType);
// FIXME: Extend table type to include limits? For now we don't specify
// a min or max which does not place any restrictions on the size of the
// imported table.
Import.Table.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0};
Imports.push_back(Import);
assert(WasmIndices.count(&WS) == 0);
WasmIndices[&WS] = NumTableImports++;
}
}
}
@ -1618,6 +1646,10 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
WS.setIndex(InvalidIndex);
continue;
}
if (WS.isTable() && WS.getName() == "__indirect_function_table") {
// For the moment, don't emit table symbols -- wasm-ld can't handle them.
continue;
}
LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
uint32_t Flags = 0;

View File

@ -498,9 +498,11 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
std::vector<wasm::WasmImport *> ImportedGlobals;
std::vector<wasm::WasmImport *> ImportedFunctions;
std::vector<wasm::WasmImport *> ImportedEvents;
std::vector<wasm::WasmImport *> ImportedTables;
ImportedGlobals.reserve(Imports.size());
ImportedFunctions.reserve(Imports.size());
ImportedEvents.reserve(Imports.size());
ImportedTables.reserve(Imports.size());
for (auto &I : Imports) {
if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
ImportedFunctions.emplace_back(&I);
@ -508,6 +510,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
ImportedGlobals.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
ImportedEvents.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
ImportedTables.emplace_back(&I);
}
while (Count--) {
@ -600,8 +604,18 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
if (Table.SymbolName.empty())
Table.SymbolName = Info.Name;
} else {
return make_error<GenericBinaryError>("undefined table symbol",
object_error::parse_failed);
wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
Info.Name = readString(Ctx);
Info.ImportName = Import.Field;
} else {
Info.Name = Import.Field;
}
TableType = Import.Table.ElemType;
// FIXME: Parse limits here too.
if (!Import.Module.empty()) {
Info.ImportModule = Import.Module;
}
}
break;
@ -1060,6 +1074,7 @@ Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
}
Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
TableSection = Sections.size();
uint32_t Count = readVaruint32(Ctx);
Tables.reserve(Count);
while (Count--) {
@ -1432,6 +1447,7 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
case wasm::WASM_SYMBOL_TYPE_TABLE:
return Sym.Info.ElementIndex;
case wasm::WASM_SYMBOL_TYPE_DATA: {
// The value of a data symbol is the segment offset, plus the symbol
@ -1481,6 +1497,8 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
return SymbolRef::ST_Debug;
case wasm::WASM_SYMBOL_TYPE_EVENT:
return SymbolRef::ST_Other;
case wasm::WASM_SYMBOL_TYPE_TABLE:
return SymbolRef::ST_Other;
}
llvm_unreachable("Unknown WasmSymbol::SymbolType");
@ -1515,6 +1533,8 @@ uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
return Sym.Info.ElementIndex;
case wasm::WASM_SYMBOL_TYPE_EVENT:
return EventSection;
case wasm::WASM_SYMBOL_TYPE_TABLE:
return TableSection;
default:
llvm_unreachable("Unknown WasmSymbol::SymbolType");
}

View File

@ -52,14 +52,6 @@ entry:
; CHECK-NEXT: Memory:
; CHECK-NEXT: Initial: 0x0
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK-NEXT: Kind: TABLE
; CHECK-NEXT: Table:
; CHECK-NEXT: Index: 0
; CHECK-NEXT: ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Initial: 0x0
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: bar
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1

View File

@ -39,14 +39,6 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) {
; CHECK-NEXT: Memory:
; CHECK-NEXT: Initial: 0x1
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK-NEXT: Kind: TABLE
; CHECK-NEXT: Table:
; CHECK-NEXT: Index: 0
; CHECK-NEXT: ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Initial: 0x0
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: funcImport
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 0

View File

@ -15,18 +15,18 @@ target triple = "wasm32-unknown-unknown"
; CHECK: Section {
; CHECK: Type: CUSTOM (0x0)
; CHECK: Size: 3
; CHECK: Offset: 72
; CHECK: Offset: 38
; CHECK: Name: red
; CHECK: }
; CHECK: Section {
; CHECK: Type: CUSTOM (0x0)
; CHECK: Size: 6
; CHECK: Offset: 85
; CHECK: Offset: 51
; CHECK: Name: green
; CHECK: }
; CHECK: Section {
; CHECK: Type: CUSTOM (0x0)
; CHECK: Size: 25
; CHECK: Offset: 118
; CHECK: Offset: 84
; CHECK: Name: producers
; CHECK: }

View File

@ -45,14 +45,6 @@ test0:
# BIN-NEXT: Kind: MEMORY
# BIN-NEXT: Memory:
# BIN-NEXT: Initial: 0x1
# BIN-NEXT: - Module: env
# BIN-NEXT: Field: __indirect_function_table
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Table:
# BIN-NEXT: Index: 0
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Type: FUNCTION
# BIN-NEXT: FunctionTypes: [ 0 ]
# BIN-NEXT: - Type: DATACOUNT

View File

@ -56,4 +56,4 @@ define i32 @test_throw1(i8* %p) {
; SEC: Type: EVENT (0xD)
; SEC-NEXT: Size: 3
; SEC-NEXT: Offset: 97
; SEC-NEXT: Offset: 63

View File

@ -42,8 +42,6 @@ define void @call(i32) {
; CHECK: - Module: env
; CHECK-NEXT: Field: __linear_memory
; CHECK: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK: - Module: env
; CHECK-NEXT: Field: varargs
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1
@ -53,6 +51,8 @@ define void @call(i32) {
; CHECK-NEXT: Field: f1
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 0
; CHECK: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:

View File

@ -27,14 +27,6 @@ declare void @func3()
; CHECK-NEXT: Memory:
; CHECK-NEXT: Initial: 0x1
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK-NEXT: Kind: TABLE
; CHECK-NEXT: Table:
; CHECK-NEXT: Index: 0
; CHECK-NEXT: ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Initial: 0x2
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: func3
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1
@ -54,6 +46,14 @@ declare void @func3()
; CHECK-NEXT: Field: func0
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __indirect_function_table
; CHECK-NEXT: Kind: TABLE
; CHECK-NEXT: Table:
; CHECK-NEXT: Index: 0
; CHECK-NEXT: ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Initial: 0x2
; CHECK-NEXT: - Type: FUNCTION
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1 ]
; CHECK-NEXT: - Type: ELEM

View File

@ -63,6 +63,10 @@ hidden_func:
# CHECK-NEXT: Memory:
# CHECK-NEXT: Initial: 0x1
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: default_func
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: SigIndex: 0
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __indirect_function_table
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Table:
@ -70,10 +74,6 @@ hidden_func:
# CHECK-NEXT: ElemType: FUNCREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Initial: 0x1
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: default_func
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: SigIndex: 0
# CHECK-NEXT: - Module: GOT.mem
# CHECK-NEXT: Field: default_data
# CHECK-NEXT: Kind: GLOBAL

View File

@ -121,14 +121,22 @@ table_fill:
# BIN: - Type: TABLE
# BIN-NEXT: Tables:
# BIN-NEXT: - Index: 1
# BIN-NEXT: - Index: 0
# BIN-NEXT: ElemType: EXTERNREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Index: 1
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Index: 2
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Index: 3
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN: - Type: CODE
# BIN-NEXT: Relocations:
@ -162,19 +170,19 @@ table_fill:
# BIN-NEXT: Functions:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 20002001FC108380808000FC0E838080800084808080000B
# BIN-NEXT: Body: 20002001FC108280808000FC0E828080800083808080000B
# BIN-NEXT: - Index: 1
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 20002581808080000B
# BIN-NEXT: Body: 20002580808080000B
# BIN-NEXT: - Index: 2
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 200020012681808080000B
# BIN-NEXT: Body: 200020012680808080000B
# BIN-NEXT: - Index: 3
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 41002581808080002000FC0F818080800020006A0B
# BIN-NEXT: Body: 41002580808080002000FC0F808080800020006A0B
# BIN-NEXT: - Index: 4
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 200041002583808080002001FC1183808080000B
# BIN-NEXT: Body: 200041002582808080002001FC1182808080000B
# BIN: - Type: CUSTOM
# BIN-NEXT: Name: linking
@ -184,9 +192,20 @@ table_fill:
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Name: foo
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Table: 1
# BIN-NEXT: Table: 0
# BIN-NEXT: - Index: 1
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Name: bar
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Table: 1
# BIN-NEXT: - Index: 2
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Name: table1
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Table: 2
# BIN-NEXT: - Index: 3
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Name: table2
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Table: 3
# BIN-NEXT: - Index: 4

View File

@ -38,14 +38,6 @@ test0:
# BIN-NEXT: Kind: MEMORY
# BIN-NEXT: Memory:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Module: env
# BIN-NEXT: Field: __indirect_function_table
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Table:
# BIN-NEXT: Index: 0
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Type: FUNCTION
# BIN-NEXT: FunctionTypes: [ 0 ]
# BIN-NEXT: - Type: CODE

View File

@ -150,14 +150,6 @@ test:
# BIN-NEXT: Flags: [ IS_64 ]
# BIN-NEXT: Initial: 0x1
# BIN-NEXT: - Module: env
# BIN-NEXT: Field: __indirect_function_table
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Table:
# BIN-NEXT: Index: 0
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Module: env
# BIN-NEXT: Field: myglob64
# BIN-NEXT: Kind: GLOBAL
# BIN-NEXT: GlobalType: I64