Commit feac819e authored by Andy Wingo's avatar Andy Wingo Committed by Sam Clegg
Browse files

[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
parent a8d74517
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -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; }
+1 −0
Original line number Diff line number Diff line
@@ -299,6 +299,7 @@ private:
  uint32_t DataSection = 0;
  uint32_t EventSection = 0;
  uint32_t GlobalSection = 0;
  uint32_t TableSection = 0;
};

class WasmSectionOrderChecker {
+48 −16
Original line number Diff line number Diff line
@@ -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;
+22 −2
Original line number Diff line number Diff line
@@ -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");
  }
+0 −8
Original line number Diff line number Diff line
@@ -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
Loading