2017-02-09 02:09:54 +01:00
|
|
|
//===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
|
2016-11-30 17:49:11 +01:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2016-11-30 17:49:11 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-02-09 02:09:54 +01:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2018-01-12 03:11:31 +01:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2017-02-09 02:09:54 +01:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2019-01-17 03:29:55 +01:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2017-02-09 02:09:54 +01:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2018-01-10 00:43:14 +01:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2020-05-28 16:26:15 +02:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2017-02-09 02:09:54 +01:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2017-06-07 05:48:56 +02:00
|
|
|
#include "llvm/BinaryFormat/Wasm.h"
|
2017-04-22 00:03:05 +02:00
|
|
|
#include "llvm/MC/SubtargetFeature.h"
|
2017-02-09 02:09:54 +01:00
|
|
|
#include "llvm/Object/Binary.h"
|
|
|
|
#include "llvm/Object/Error.h"
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
|
|
|
#include "llvm/Object/SymbolicFile.h"
|
2016-11-30 17:49:11 +01:00
|
|
|
#include "llvm/Object/Wasm.h"
|
|
|
|
#include "llvm/Support/Endian.h"
|
2017-02-09 02:09:54 +01:00
|
|
|
#include "llvm/Support/Error.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2016-11-30 17:49:11 +01:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2018-12-15 01:58:12 +01:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2017-02-09 02:09:54 +01:00
|
|
|
#include <algorithm>
|
2017-04-22 00:03:05 +02:00
|
|
|
#include <cassert>
|
2017-02-09 02:09:54 +01:00
|
|
|
#include <cstdint>
|
2017-04-22 00:03:05 +02:00
|
|
|
#include <cstring>
|
2017-02-09 02:09:54 +01:00
|
|
|
#include <system_error>
|
2016-11-30 17:49:11 +01:00
|
|
|
|
2017-06-20 06:04:59 +02:00
|
|
|
#define DEBUG_TYPE "wasm-object"
|
|
|
|
|
2017-02-09 02:09:54 +01:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
2016-11-30 17:49:11 +01:00
|
|
|
|
2018-05-16 23:24:03 +02:00
|
|
|
void WasmSymbol::print(raw_ostream &Out) const {
|
|
|
|
Out << "Name=" << Info.Name
|
2021-05-02 00:37:40 +02:00
|
|
|
<< ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
|
|
|
|
<< Twine::utohexstr(Info.Flags);
|
2018-05-16 23:24:03 +02:00
|
|
|
if (!isTypeData()) {
|
|
|
|
Out << ", ElemIndex=" << Info.ElementIndex;
|
|
|
|
} else if (isDefined()) {
|
|
|
|
Out << ", Segment=" << Info.DataRef.Segment;
|
|
|
|
Out << ", Offset=" << Info.DataRef.Offset;
|
|
|
|
Out << ", Size=" << Info.DataRef.Size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[NFC] WebAssembly build break #2
Summary:
Same as r332530, move WasmSymbol::dump to an implementation file to avoid linker
issues when the dump function is seen in the header, doesn't get eliminated, and
then linking fails because of the missing dependency.
<rdar://problem/40258137>
Reviewers: sbc100, ncw, paquette, vsk, dschuff
Subscribers: jgravelle-google, aheejin, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D46985
llvm-svn: 332542
2018-05-17 00:31:42 +02:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
|
|
|
|
#endif
|
|
|
|
|
2016-11-30 17:49:11 +01:00
|
|
|
Expected<std::unique_ptr<WasmObjectFile>>
|
|
|
|
ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
|
|
|
|
Error Err = Error::success();
|
2019-08-15 17:54:37 +02:00
|
|
|
auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
|
2016-11-30 17:49:11 +01:00
|
|
|
if (Err)
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(Err);
|
2016-11-30 17:49:11 +01:00
|
|
|
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(ObjectFile);
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2018-09-05 03:27:38 +02:00
|
|
|
#define VARINT7_MAX ((1 << 7) - 1)
|
|
|
|
#define VARINT7_MIN (-(1 << 7))
|
|
|
|
#define VARUINT7_MAX (1 << 7)
|
2017-03-30 21:44:09 +02:00
|
|
|
#define VARUINT1_MAX (1)
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
if (Ctx.Ptr == Ctx.End)
|
|
|
|
report_fatal_error("EOF while reading uint8");
|
|
|
|
return *Ctx.Ptr++;
|
|
|
|
}
|
2017-03-30 21:44:09 +02:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
if (Ctx.Ptr + 4 > Ctx.End)
|
|
|
|
report_fatal_error("EOF while reading uint32");
|
|
|
|
uint32_t Result = support::endian::read32le(Ctx.Ptr);
|
|
|
|
Ctx.Ptr += 4;
|
2016-11-30 17:49:11 +01:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
|
2018-08-31 16:54:01 +02:00
|
|
|
if (Ctx.Ptr + 4 > Ctx.End)
|
|
|
|
report_fatal_error("EOF while reading float64");
|
2017-03-30 21:44:09 +02:00
|
|
|
int32_t Result = 0;
|
2018-05-29 21:58:59 +02:00
|
|
|
memcpy(&Result, Ctx.Ptr, sizeof(Result));
|
|
|
|
Ctx.Ptr += sizeof(Result);
|
2017-03-30 21:44:09 +02:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
|
2018-08-31 16:54:01 +02:00
|
|
|
if (Ctx.Ptr + 8 > Ctx.End)
|
|
|
|
report_fatal_error("EOF while reading float64");
|
2017-03-30 21:44:09 +02:00
|
|
|
int64_t Result = 0;
|
2018-05-29 21:58:59 +02:00
|
|
|
memcpy(&Result, Ctx.Ptr, sizeof(Result));
|
|
|
|
Ctx.Ptr += sizeof(Result);
|
2017-03-30 21:44:09 +02:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
|
2016-11-30 17:49:11 +01:00
|
|
|
unsigned Count;
|
2018-09-05 03:27:38 +02:00
|
|
|
const char *Error = nullptr;
|
2018-05-29 21:58:59 +02:00
|
|
|
uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
|
|
|
|
if (Error)
|
|
|
|
report_fatal_error(Error);
|
|
|
|
Ctx.Ptr += Count;
|
2016-11-30 17:49:11 +01:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
uint32_t StringLen = readULEB128(Ctx);
|
|
|
|
if (Ctx.Ptr + StringLen > Ctx.End)
|
|
|
|
report_fatal_error("EOF while reading string");
|
|
|
|
StringRef Return =
|
|
|
|
StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
|
|
|
|
Ctx.Ptr += StringLen;
|
2016-11-30 17:49:11 +01:00
|
|
|
return Return;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
|
2017-03-30 21:44:09 +02:00
|
|
|
unsigned Count;
|
2018-09-05 03:27:38 +02:00
|
|
|
const char *Error = nullptr;
|
2018-05-29 21:58:59 +02:00
|
|
|
uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
|
|
|
|
if (Error)
|
|
|
|
report_fatal_error(Error);
|
|
|
|
Ctx.Ptr += Count;
|
2017-03-30 21:44:09 +02:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
int64_t Result = readLEB128(Ctx);
|
|
|
|
if (Result > VARUINT1_MAX || Result < 0)
|
2018-05-18 23:08:26 +02:00
|
|
|
report_fatal_error("LEB is outside Varuint1 range");
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
return Result;
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
int64_t Result = readLEB128(Ctx);
|
|
|
|
if (Result > INT32_MAX || Result < INT32_MIN)
|
2018-05-18 23:08:26 +02:00
|
|
|
report_fatal_error("LEB is outside Varint32 range");
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
return Result;
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
uint64_t Result = readULEB128(Ctx);
|
|
|
|
if (Result > UINT32_MAX)
|
2018-05-18 23:08:26 +02:00
|
|
|
report_fatal_error("LEB is outside Varuint32 range");
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
return Result;
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
return readLEB128(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
2020-06-05 18:03:12 +02:00
|
|
|
static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
return readULEB128(Ctx);
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
return readUint8(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static Error readInitExpr(wasm::WasmInitExpr &Expr,
|
|
|
|
WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
Expr.Opcode = readOpcode(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
|
|
|
|
switch (Expr.Opcode) {
|
|
|
|
case wasm::WASM_OPCODE_I32_CONST:
|
2018-05-29 21:58:59 +02:00
|
|
|
Expr.Value.Int32 = readVarint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
|
|
|
case wasm::WASM_OPCODE_I64_CONST:
|
2018-05-29 21:58:59 +02:00
|
|
|
Expr.Value.Int64 = readVarint64(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
|
|
|
case wasm::WASM_OPCODE_F32_CONST:
|
2018-05-29 21:58:59 +02:00
|
|
|
Expr.Value.Float32 = readFloat32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
|
|
|
case wasm::WASM_OPCODE_F64_CONST:
|
2018-05-29 21:58:59 +02:00
|
|
|
Expr.Value.Float64 = readFloat64(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2019-01-08 07:25:55 +01:00
|
|
|
case wasm::WASM_OPCODE_GLOBAL_GET:
|
2018-05-29 21:58:59 +02:00
|
|
|
Expr.Value.Global = readULEB128(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2020-06-17 00:41:20 +02:00
|
|
|
case wasm::WASM_OPCODE_REF_NULL: {
|
|
|
|
wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
|
|
|
|
if (Ty != wasm::ValType::EXTERNREF) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid type for ref.null",
|
2020-06-17 00:41:20 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2017-03-30 21:44:09 +02:00
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid opcode in init_expr",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
uint8_t EndOpcode = readOpcode(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
if (EndOpcode != wasm::WASM_OPCODE_END) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid init_expr",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
|
2017-03-30 21:44:09 +02:00
|
|
|
wasm::WasmLimits Result;
|
2018-11-06 18:27:25 +01:00
|
|
|
Result.Flags = readVaruint32(Ctx);
|
2021-03-23 14:46:32 +01:00
|
|
|
Result.Minimum = readVaruint64(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
|
2020-06-30 02:53:09 +02:00
|
|
|
Result.Maximum = readVaruint64(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2020-11-25 16:54:31 +01:00
|
|
|
static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
|
|
|
|
wasm::WasmTableType TableType;
|
|
|
|
TableType.ElemType = readUint8(Ctx);
|
|
|
|
TableType.Limits = readLimits(Ctx);
|
|
|
|
return TableType;
|
2017-05-10 01:48:41 +02:00
|
|
|
}
|
|
|
|
|
2018-12-15 01:58:12 +01:00
|
|
|
static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
|
|
|
|
WasmSectionOrderChecker &Checker) {
|
2018-05-29 21:58:59 +02:00
|
|
|
Section.Offset = Ctx.Ptr - Ctx.Start;
|
|
|
|
Section.Type = readUint8(Ctx);
|
2018-05-29 22:16:47 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Size = readVaruint32(Ctx);
|
2016-11-30 17:49:11 +01:00
|
|
|
if (Size == 0)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<StringError>("zero length section",
|
2016-11-30 17:49:11 +01:00
|
|
|
object_error::parse_failed);
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr + Size > Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<StringError>("section too large",
|
2017-10-23 20:04:34 +02:00
|
|
|
object_error::parse_failed);
|
2018-04-12 22:31:12 +02:00
|
|
|
if (Section.Type == wasm::WASM_SEC_CUSTOM) {
|
2018-08-08 18:34:03 +02:00
|
|
|
WasmObjectFile::ReadContext SectionCtx;
|
|
|
|
SectionCtx.Start = Ctx.Ptr;
|
|
|
|
SectionCtx.Ptr = Ctx.Ptr;
|
|
|
|
SectionCtx.End = Ctx.Ptr + Size;
|
|
|
|
|
|
|
|
Section.Name = readString(SectionCtx);
|
|
|
|
|
|
|
|
uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
|
|
|
|
Ctx.Ptr += SectionNameSize;
|
|
|
|
Size -= SectionNameSize;
|
2018-04-12 22:31:12 +02:00
|
|
|
}
|
2018-12-15 01:58:12 +01:00
|
|
|
|
|
|
|
if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<StringError>("out of order section type: " +
|
2018-12-15 01:58:12 +01:00
|
|
|
llvm::to_string(Section.Type),
|
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
|
|
|
|
Ctx.Ptr += Size;
|
2016-11-30 17:49:11 +01:00
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
|
2017-04-22 00:03:05 +02:00
|
|
|
: ObjectFile(Binary::ID_Wasm, Buffer) {
|
2016-11-30 17:49:11 +01:00
|
|
|
ErrorAsOutParameter ErrAsOutParam(&Err);
|
|
|
|
Header.Magic = getData().substr(0, 4);
|
|
|
|
if (Header.Magic != StringRef("\0asm", 4)) {
|
2021-01-22 16:46:28 +01:00
|
|
|
Err = make_error<StringError>("invalid magic number",
|
|
|
|
object_error::parse_failed);
|
2016-11-30 17:49:11 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-08-23 23:36:04 +02:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
ReadContext Ctx;
|
2019-04-07 05:58:42 +02:00
|
|
|
Ctx.Start = getData().bytes_begin();
|
2018-05-29 21:58:59 +02:00
|
|
|
Ctx.Ptr = Ctx.Start + 4;
|
|
|
|
Ctx.End = Ctx.Start + getData().size();
|
2017-08-23 23:36:04 +02:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr + 4 > Ctx.End) {
|
2021-01-22 16:46:28 +01:00
|
|
|
Err = make_error<StringError>("missing version number",
|
2017-08-23 23:36:04 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Header.Version = readUint32(Ctx);
|
2016-11-30 17:49:11 +01:00
|
|
|
if (Header.Version != wasm::WasmVersion) {
|
2021-01-22 16:46:28 +01:00
|
|
|
Err = make_error<StringError>("invalid version number: " +
|
|
|
|
Twine(Header.Version),
|
2016-11-30 17:49:11 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
WasmSection Sec;
|
2018-12-15 01:58:12 +01:00
|
|
|
WasmSectionOrderChecker Checker;
|
2018-05-29 21:58:59 +02:00
|
|
|
while (Ctx.Ptr < Ctx.End) {
|
2018-12-15 01:58:12 +01:00
|
|
|
if ((Err = readSection(Sec, Ctx, Checker)))
|
2016-11-30 17:49:11 +01:00
|
|
|
return;
|
2017-03-30 21:44:09 +02:00
|
|
|
if ((Err = parseSection(Sec)))
|
|
|
|
return;
|
|
|
|
|
2016-11-30 17:49:11 +01:00
|
|
|
Sections.push_back(Sec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
Error WasmObjectFile::parseSection(WasmSection &Sec) {
|
2018-05-29 21:58:59 +02:00
|
|
|
ReadContext Ctx;
|
|
|
|
Ctx.Start = Sec.Content.data();
|
|
|
|
Ctx.End = Ctx.Start + Sec.Content.size();
|
|
|
|
Ctx.Ptr = Ctx.Start;
|
2017-03-30 21:44:09 +02:00
|
|
|
switch (Sec.Type) {
|
|
|
|
case wasm::WASM_SEC_CUSTOM:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseCustomSection(Sec, Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_TYPE:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseTypeSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_IMPORT:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseImportSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_FUNCTION:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseFunctionSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_TABLE:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseTableSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_MEMORY:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseMemorySection(Ctx);
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_SEC_TAG:
|
|
|
|
return parseTagSection(Ctx);
|
2020-03-25 03:36:13 +01:00
|
|
|
case wasm::WASM_SEC_GLOBAL:
|
|
|
|
return parseGlobalSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_EXPORT:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseExportSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_START:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseStartSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_ELEM:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseElemSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_CODE:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseCodeSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
case wasm::WASM_SEC_DATA:
|
2018-05-29 21:58:59 +02:00
|
|
|
return parseDataSection(Ctx);
|
2019-04-13 00:27:48 +02:00
|
|
|
case wasm::WASM_SEC_DATACOUNT:
|
|
|
|
return parseDataCountSection(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
default:
|
2019-04-20 02:11:46 +02:00
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 19:36:24 +01:00
|
|
|
Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
|
|
|
|
// See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
|
2019-03-13 22:29:20 +01:00
|
|
|
HasDylinkSection = true;
|
2018-11-14 19:36:24 +01:00
|
|
|
DylinkInfo.MemorySize = readVaruint32(Ctx);
|
|
|
|
DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
|
|
|
|
DylinkInfo.TableSize = readVaruint32(Ctx);
|
|
|
|
DylinkInfo.TableAlignment = readVaruint32(Ctx);
|
2018-12-13 00:40:58 +01:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
|
|
|
while (Count--) {
|
|
|
|
DylinkInfo.Needed.push_back(readString(Ctx));
|
|
|
|
}
|
2018-11-14 19:36:24 +01:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
|
|
|
return make_error<GenericBinaryError>("dylink section ended prematurely",
|
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
|
2020-11-19 06:38:23 +01:00
|
|
|
llvm::DenseSet<uint64_t> SeenFunctions;
|
|
|
|
llvm::DenseSet<uint64_t> SeenGlobals;
|
2020-12-09 06:47:19 +01:00
|
|
|
llvm::DenseSet<uint64_t> SeenSegments;
|
2019-11-05 19:15:56 +01:00
|
|
|
if (FunctionTypes.size() && !SeenCodeSection) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("names must come after code section",
|
2018-01-17 20:28:43 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
2018-01-12 03:11:31 +01:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
while (Ctx.Ptr < Ctx.End) {
|
|
|
|
uint8_t Type = readUint8(Ctx);
|
|
|
|
uint32_t Size = readVaruint32(Ctx);
|
|
|
|
const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
|
2017-03-30 21:44:09 +02:00
|
|
|
switch (Type) {
|
2020-11-19 06:38:23 +01:00
|
|
|
case wasm::WASM_NAMES_FUNCTION:
|
2020-12-09 06:47:19 +01:00
|
|
|
case wasm::WASM_NAMES_GLOBAL:
|
|
|
|
case wasm::WASM_NAMES_DATA_SEGMENT: {
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
while (Count--) {
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Index = readVaruint32(Ctx);
|
|
|
|
StringRef Name = readString(Ctx);
|
2020-12-09 06:47:19 +01:00
|
|
|
wasm::NameType nameType = wasm::NameType::FUNCTION;
|
2020-11-19 06:38:23 +01:00
|
|
|
if (Type == wasm::WASM_NAMES_FUNCTION) {
|
|
|
|
if (!SeenFunctions.insert(Index).second)
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"function named more than once", object_error::parse_failed);
|
2020-11-19 06:38:23 +01:00
|
|
|
if (!isValidFunctionIndex(Index) || Name.empty())
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid name entry",
|
2020-11-19 06:38:23 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
|
|
|
|
if (isDefinedFunctionIndex(Index))
|
|
|
|
getDefinedFunction(Index).DebugName = Name;
|
2020-12-09 06:47:19 +01:00
|
|
|
} else if (Type == wasm::WASM_NAMES_GLOBAL) {
|
|
|
|
nameType = wasm::NameType::GLOBAL;
|
2020-11-19 06:38:23 +01:00
|
|
|
if (!SeenGlobals.insert(Index).second)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("global named more than once",
|
2020-11-19 06:38:23 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
if (!isValidGlobalIndex(Index) || Name.empty())
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid name entry",
|
2020-11-19 06:38:23 +01:00
|
|
|
object_error::parse_failed);
|
2020-12-09 06:47:19 +01:00
|
|
|
} else {
|
|
|
|
nameType = wasm::NameType::DATA_SEGMENT;
|
|
|
|
if (!SeenSegments.insert(Index).second)
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"segment named more than once", object_error::parse_failed);
|
2020-12-09 06:47:19 +01:00
|
|
|
if (Index > DataSegments.size())
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid named data segment",
|
2020-12-09 06:47:19 +01:00
|
|
|
object_error::parse_failed);
|
2020-11-19 06:38:23 +01:00
|
|
|
}
|
2020-12-09 06:47:19 +01:00
|
|
|
DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Ignore local names for now
|
|
|
|
case wasm::WASM_NAMES_LOCAL:
|
|
|
|
default:
|
2018-05-29 21:58:59 +02:00
|
|
|
Ctx.Ptr += Size;
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != SubSectionEnd)
|
2018-09-05 03:27:38 +02:00
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"name sub-section ended prematurely", object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("name section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
|
2017-06-27 22:40:53 +02:00
|
|
|
HasLinkingSection = true;
|
2019-11-05 19:15:56 +01:00
|
|
|
if (FunctionTypes.size() && !SeenCodeSection) {
|
2018-01-17 20:28:43 +01:00
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"linking data must come after code section",
|
2018-09-05 03:27:38 +02:00
|
|
|
object_error::parse_failed);
|
2018-01-17 20:28:43 +01:00
|
|
|
}
|
2017-09-07 00:05:41 +02:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
LinkingData.Version = readVaruint32(Ctx);
|
2018-04-26 20:15:32 +02:00
|
|
|
if (LinkingData.Version != wasm::WasmMetadataVersion) {
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"unexpected metadata version: " + Twine(LinkingData.Version) +
|
2018-04-26 20:15:32 +02:00
|
|
|
" (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
|
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
const uint8_t *OrigEnd = Ctx.End;
|
|
|
|
while (Ctx.Ptr < OrigEnd) {
|
|
|
|
Ctx.End = OrigEnd;
|
|
|
|
uint8_t Type = readUint8(Ctx);
|
|
|
|
uint32_t Size = readVaruint32(Ctx);
|
2018-05-29 22:16:47 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
|
|
|
|
<< "\n");
|
2018-05-29 21:58:59 +02:00
|
|
|
Ctx.End = Ctx.Ptr + Size;
|
2017-06-20 06:04:59 +02:00
|
|
|
switch (Type) {
|
2018-02-23 06:08:34 +01:00
|
|
|
case wasm::WASM_SYMBOL_TABLE:
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Error Err = parseLinkingSectionSymtab(Ctx))
|
2018-02-23 06:08:34 +01:00
|
|
|
return Err;
|
2017-06-20 06:04:59 +02:00
|
|
|
break;
|
2017-09-29 18:50:08 +02:00
|
|
|
case wasm::WASM_SEGMENT_INFO: {
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-09-20 21:03:35 +02:00
|
|
|
if (Count > DataSegments.size())
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("too many segment names",
|
2017-09-20 21:03:35 +02:00
|
|
|
object_error::parse_failed);
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
for (uint32_t I = 0; I < Count; I++) {
|
|
|
|
DataSegments[I].Data.Name = readString(Ctx);
|
|
|
|
DataSegments[I].Data.Alignment = readVaruint32(Ctx);
|
2021-02-27 01:09:32 +01:00
|
|
|
DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
|
2017-09-29 18:50:08 +02:00
|
|
|
}
|
2017-09-20 21:03:35 +02:00
|
|
|
break;
|
|
|
|
}
|
2017-12-14 22:10:03 +01:00
|
|
|
case wasm::WASM_INIT_FUNCS: {
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-12-14 22:10:03 +01:00
|
|
|
LinkingData.InitFunctions.reserve(Count);
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
for (uint32_t I = 0; I < Count; I++) {
|
2017-12-14 22:10:03 +01:00
|
|
|
wasm::WasmInitFunc Init;
|
2018-05-29 21:58:59 +02:00
|
|
|
Init.Priority = readVaruint32(Ctx);
|
|
|
|
Init.Symbol = readVaruint32(Ctx);
|
2018-03-05 14:32:38 +01:00
|
|
|
if (!isValidFunctionSymbol(Init.Symbol))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid function symbol: " +
|
2018-02-23 06:08:34 +01:00
|
|
|
Twine(Init.Symbol),
|
2017-12-14 22:10:03 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
LinkingData.InitFunctions.emplace_back(Init);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2018-01-10 00:43:14 +01:00
|
|
|
case wasm::WASM_COMDAT_INFO:
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Error Err = parseLinkingSectionComdat(Ctx))
|
2018-01-10 00:43:14 +01:00
|
|
|
return Err;
|
|
|
|
break;
|
2017-06-20 06:04:59 +02:00
|
|
|
default:
|
2018-05-29 21:58:59 +02:00
|
|
|
Ctx.Ptr += Size;
|
2017-06-20 06:04:59 +02:00
|
|
|
break;
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2017-06-20 06:04:59 +02:00
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"linking sub-section ended prematurely", object_error::parse_failed);
|
2017-06-20 06:04:59 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != OrigEnd)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("linking section ended prematurely",
|
2017-06-20 06:04:59 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
LinkingData.SymbolTable.reserve(Count);
|
|
|
|
Symbols.reserve(Count);
|
|
|
|
StringSet<> SymbolNames;
|
|
|
|
|
|
|
|
std::vector<wasm::WasmImport *> ImportedGlobals;
|
|
|
|
std::vector<wasm::WasmImport *> ImportedFunctions;
|
2021-06-15 10:49:43 +02:00
|
|
|
std::vector<wasm::WasmImport *> ImportedTags;
|
2020-11-25 17:31:05 +01:00
|
|
|
std::vector<wasm::WasmImport *> ImportedTables;
|
2018-02-23 06:08:34 +01:00
|
|
|
ImportedGlobals.reserve(Imports.size());
|
|
|
|
ImportedFunctions.reserve(Imports.size());
|
2021-06-15 10:49:43 +02:00
|
|
|
ImportedTags.reserve(Imports.size());
|
2020-11-25 17:31:05 +01:00
|
|
|
ImportedTables.reserve(Imports.size());
|
2018-02-23 06:08:34 +01:00
|
|
|
for (auto &I : Imports) {
|
|
|
|
if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
|
|
|
|
ImportedFunctions.emplace_back(&I);
|
|
|
|
else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
|
|
|
|
ImportedGlobals.emplace_back(&I);
|
2021-06-15 10:49:43 +02:00
|
|
|
else if (I.Kind == wasm::WASM_EXTERNAL_TAG)
|
|
|
|
ImportedTags.emplace_back(&I);
|
2020-11-25 17:31:05 +01:00
|
|
|
else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
|
|
|
|
ImportedTables.emplace_back(&I);
|
2018-02-23 06:08:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
while (Count--) {
|
|
|
|
wasm::WasmSymbolInfo Info;
|
2018-12-08 07:16:13 +01:00
|
|
|
const wasm::WasmSignature *Signature = nullptr;
|
2018-02-23 06:08:34 +01:00
|
|
|
const wasm::WasmGlobalType *GlobalType = nullptr;
|
2021-01-05 12:08:58 +01:00
|
|
|
const wasm::WasmTableType *TableType = nullptr;
|
2021-06-15 10:49:43 +02:00
|
|
|
const wasm::WasmTagType *TagType = nullptr;
|
2018-02-23 06:08:34 +01:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.Kind = readUint8(Ctx);
|
|
|
|
Info.Flags = readVaruint32(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
|
|
|
|
|
|
|
|
switch (Info.Kind) {
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.ElementIndex = readVaruint32(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
if (!isValidFunctionIndex(Info.ElementIndex) ||
|
|
|
|
IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
|
|
|
|
return make_error<GenericBinaryError>("invalid function symbol index",
|
|
|
|
object_error::parse_failed);
|
|
|
|
if (IsDefined) {
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.Name = readString(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
|
2018-12-08 07:16:13 +01:00
|
|
|
Signature = &Signatures[FunctionTypes[FuncIndex]];
|
2018-03-05 13:16:32 +01:00
|
|
|
wasm::WasmFunction &Function = Functions[FuncIndex];
|
2018-04-20 19:07:24 +02:00
|
|
|
if (Function.SymbolName.empty())
|
|
|
|
Function.SymbolName = Info.Name;
|
2018-02-23 06:08:34 +01:00
|
|
|
} else {
|
|
|
|
wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
|
2020-02-06 06:18:55 +01:00
|
|
|
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
|
2019-02-07 23:03:32 +01:00
|
|
|
Info.Name = readString(Ctx);
|
2020-02-06 06:18:55 +01:00
|
|
|
Info.ImportName = Import.Field;
|
|
|
|
} else {
|
2019-02-07 23:03:32 +01:00
|
|
|
Info.Name = Import.Field;
|
2020-02-06 06:18:55 +01:00
|
|
|
}
|
2018-12-08 07:16:13 +01:00
|
|
|
Signature = &Signatures[Import.SigIndex];
|
2020-02-06 06:18:55 +01:00
|
|
|
if (!Import.Module.empty()) {
|
|
|
|
Info.ImportModule = Import.Module;
|
|
|
|
}
|
2018-02-23 06:08:34 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.ElementIndex = readVaruint32(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
if (!isValidGlobalIndex(Info.ElementIndex) ||
|
|
|
|
IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
|
|
|
|
return make_error<GenericBinaryError>("invalid global symbol index",
|
|
|
|
object_error::parse_failed);
|
2018-09-05 03:27:38 +02:00
|
|
|
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
|
|
|
|
wasm::WASM_SYMBOL_BINDING_WEAK)
|
2018-03-09 17:30:44 +01:00
|
|
|
return make_error<GenericBinaryError>("undefined weak global symbol",
|
|
|
|
object_error::parse_failed);
|
2018-02-23 06:08:34 +01:00
|
|
|
if (IsDefined) {
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.Name = readString(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
|
2018-03-05 13:16:32 +01:00
|
|
|
wasm::WasmGlobal &Global = Globals[GlobalIndex];
|
|
|
|
GlobalType = &Global.Type;
|
2018-04-20 19:07:24 +02:00
|
|
|
if (Global.SymbolName.empty())
|
|
|
|
Global.SymbolName = Info.Name;
|
2018-02-23 06:08:34 +01:00
|
|
|
} else {
|
|
|
|
wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
|
2020-02-06 06:18:55 +01:00
|
|
|
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
|
2019-02-07 23:03:32 +01:00
|
|
|
Info.Name = readString(Ctx);
|
2020-02-06 06:18:55 +01:00
|
|
|
Info.ImportName = Import.Field;
|
|
|
|
} else {
|
2019-02-07 23:03:32 +01:00
|
|
|
Info.Name = Import.Field;
|
2020-02-06 06:18:55 +01:00
|
|
|
}
|
2018-02-23 06:08:34 +01:00
|
|
|
GlobalType = &Import.Global;
|
2020-02-06 06:18:55 +01:00
|
|
|
if (!Import.Module.empty()) {
|
|
|
|
Info.ImportModule = Import.Module;
|
|
|
|
}
|
2018-02-23 06:08:34 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-10-13 16:13:10 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TABLE:
|
|
|
|
Info.ElementIndex = readVaruint32(Ctx);
|
2021-03-04 10:30:00 +01:00
|
|
|
if (!isValidTableNumber(Info.ElementIndex) ||
|
|
|
|
IsDefined != isDefinedTableNumber(Info.ElementIndex))
|
2020-10-13 16:13:10 +02:00
|
|
|
return make_error<GenericBinaryError>("invalid table symbol index",
|
|
|
|
object_error::parse_failed);
|
|
|
|
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
|
|
|
|
wasm::WASM_SYMBOL_BINDING_WEAK)
|
|
|
|
return make_error<GenericBinaryError>("undefined weak table symbol",
|
|
|
|
object_error::parse_failed);
|
|
|
|
if (IsDefined) {
|
|
|
|
Info.Name = readString(Ctx);
|
2021-03-04 10:30:00 +01:00
|
|
|
unsigned TableNumber = Info.ElementIndex - NumImportedTables;
|
|
|
|
wasm::WasmTable &Table = Tables[TableNumber];
|
2021-01-05 12:08:58 +01:00
|
|
|
TableType = &Table.Type;
|
2020-11-25 16:54:31 +01:00
|
|
|
if (Table.SymbolName.empty())
|
|
|
|
Table.SymbolName = Info.Name;
|
2020-10-13 16:13:10 +02:00
|
|
|
} else {
|
2020-11-25 17:31:05 +01:00
|
|
|
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;
|
|
|
|
}
|
2021-01-05 12:08:58 +01:00
|
|
|
TableType = &Import.Table;
|
2020-11-25 17:31:05 +01:00
|
|
|
if (!Import.Module.empty()) {
|
|
|
|
Info.ImportModule = Import.Module;
|
|
|
|
}
|
2020-10-13 16:13:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_DATA:
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.Name = readString(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
if (IsDefined) {
|
2020-06-05 18:03:12 +02:00
|
|
|
auto Index = readVaruint32(Ctx);
|
2018-02-23 06:08:34 +01:00
|
|
|
if (Index >= DataSegments.size())
|
|
|
|
return make_error<GenericBinaryError>("invalid data symbol index",
|
|
|
|
object_error::parse_failed);
|
2020-06-05 18:03:12 +02:00
|
|
|
auto Offset = readVaruint64(Ctx);
|
|
|
|
auto Size = readVaruint64(Ctx);
|
2021-05-12 00:16:00 +02:00
|
|
|
size_t SegmentSize = DataSegments[Index].Data.Content.size();
|
|
|
|
if (Offset > SegmentSize)
|
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"invalid data symbol offset: `" + Info.Name + "` (offset: " +
|
|
|
|
Twine(Offset) + " segment size: " + Twine(SegmentSize) + ")",
|
|
|
|
object_error::parse_failed);
|
2018-02-23 06:08:34 +01:00
|
|
|
Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-04-26 21:27:28 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_SECTION: {
|
2018-04-27 02:17:21 +02:00
|
|
|
if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
|
|
|
|
wasm::WASM_SYMBOL_BINDING_LOCAL)
|
2018-04-27 02:17:24 +02:00
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"section symbols must have local binding",
|
2018-04-27 02:17:24 +02:00
|
|
|
object_error::parse_failed);
|
2018-05-29 21:58:59 +02:00
|
|
|
Info.ElementIndex = readVaruint32(Ctx);
|
2018-04-26 21:27:28 +02:00
|
|
|
// Use somewhat unique section name as symbol name.
|
|
|
|
StringRef SectionName = Sections[Info.ElementIndex].Name;
|
|
|
|
Info.Name = SectionName;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TAG: {
|
2018-11-14 03:46:21 +01:00
|
|
|
Info.ElementIndex = readVaruint32(Ctx);
|
2021-06-15 10:49:43 +02:00
|
|
|
if (!isValidTagIndex(Info.ElementIndex) ||
|
|
|
|
IsDefined != isDefinedTagIndex(Info.ElementIndex))
|
|
|
|
return make_error<GenericBinaryError>("invalid tag symbol index",
|
2018-11-14 03:46:21 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
|
|
|
|
wasm::WASM_SYMBOL_BINDING_WEAK)
|
|
|
|
return make_error<GenericBinaryError>("undefined weak global symbol",
|
|
|
|
object_error::parse_failed);
|
|
|
|
if (IsDefined) {
|
|
|
|
Info.Name = readString(Ctx);
|
2021-06-15 10:49:43 +02:00
|
|
|
unsigned TagIndex = Info.ElementIndex - NumImportedTags;
|
|
|
|
wasm::WasmTag &Tag = Tags[TagIndex];
|
|
|
|
Signature = &Signatures[Tag.Type.SigIndex];
|
|
|
|
TagType = &Tag.Type;
|
|
|
|
if (Tag.SymbolName.empty())
|
|
|
|
Tag.SymbolName = Info.Name;
|
2018-11-14 03:46:21 +01:00
|
|
|
|
|
|
|
} else {
|
2021-06-15 10:49:43 +02:00
|
|
|
wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
|
2020-02-06 06:18:55 +01:00
|
|
|
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
|
2019-02-07 23:03:32 +01:00
|
|
|
Info.Name = readString(Ctx);
|
2020-02-06 06:18:55 +01:00
|
|
|
Info.ImportName = Import.Field;
|
|
|
|
} else {
|
2019-02-07 23:03:32 +01:00
|
|
|
Info.Name = Import.Field;
|
2020-02-06 06:18:55 +01:00
|
|
|
}
|
2021-06-15 10:49:43 +02:00
|
|
|
TagType = &Import.Tag;
|
|
|
|
Signature = &Signatures[TagType->SigIndex];
|
2020-02-06 06:18:55 +01:00
|
|
|
if (!Import.Module.empty()) {
|
|
|
|
Info.ImportModule = Import.Module;
|
|
|
|
}
|
2018-11-14 03:46:21 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid symbol type: " +
|
2021-01-21 21:07:43 +01:00
|
|
|
Twine(unsigned(Info.Kind)),
|
2018-02-23 06:08:34 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
|
|
|
|
wasm::WASM_SYMBOL_BINDING_LOCAL &&
|
|
|
|
!SymbolNames.insert(Info.Name).second)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("duplicate symbol name " +
|
2018-02-23 06:08:34 +01:00
|
|
|
Twine(Info.Name),
|
|
|
|
object_error::parse_failed);
|
|
|
|
LinkingData.SymbolTable.emplace_back(Info);
|
2020-10-13 16:13:10 +02:00
|
|
|
Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType,
|
2021-06-15 10:49:43 +02:00
|
|
|
TagType, Signature);
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
|
2018-02-23 06:08:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
|
|
|
|
uint32_t ComdatCount = readVaruint32(Ctx);
|
2018-01-10 00:43:14 +01:00
|
|
|
StringSet<> ComdatSet;
|
2018-03-14 16:44:45 +01:00
|
|
|
for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
|
2018-05-29 21:58:59 +02:00
|
|
|
StringRef Name = readString(Ctx);
|
2018-01-10 00:43:14 +01:00
|
|
|
if (Name.empty() || !ComdatSet.insert(Name).second)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
|
2018-09-05 03:27:38 +02:00
|
|
|
Twine(Name),
|
2018-01-10 00:43:14 +01:00
|
|
|
object_error::parse_failed);
|
2018-03-14 16:44:45 +01:00
|
|
|
LinkingData.Comdats.emplace_back(Name);
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Flags = readVaruint32(Ctx);
|
2018-01-10 00:43:14 +01:00
|
|
|
if (Flags != 0)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("unsupported COMDAT flags",
|
2018-01-10 00:43:14 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t EntryCount = readVaruint32(Ctx);
|
2018-01-10 00:43:14 +01:00
|
|
|
while (EntryCount--) {
|
2018-05-29 21:58:59 +02:00
|
|
|
unsigned Kind = readVaruint32(Ctx);
|
|
|
|
unsigned Index = readVaruint32(Ctx);
|
2018-01-10 00:43:14 +01:00
|
|
|
switch (Kind) {
|
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid COMDAT entry type",
|
2018-01-10 00:43:14 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
case wasm::WASM_COMDAT_DATA:
|
|
|
|
if (Index >= DataSegments.size())
|
2018-09-05 03:27:38 +02:00
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"COMDAT data index out of range", object_error::parse_failed);
|
2018-03-14 16:44:45 +01:00
|
|
|
if (DataSegments[Index].Data.Comdat != UINT32_MAX)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("data segment in two COMDATs",
|
2018-01-10 00:43:14 +01:00
|
|
|
object_error::parse_failed);
|
2018-03-14 16:44:45 +01:00
|
|
|
DataSegments[Index].Data.Comdat = ComdatIndex;
|
2018-01-10 00:43:14 +01:00
|
|
|
break;
|
|
|
|
case wasm::WASM_COMDAT_FUNCTION:
|
2018-01-24 02:27:17 +01:00
|
|
|
if (!isDefinedFunctionIndex(Index))
|
2018-09-05 03:27:38 +02:00
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"COMDAT function index out of range", object_error::parse_failed);
|
2018-03-14 16:44:45 +01:00
|
|
|
if (getDefinedFunction(Index).Comdat != UINT32_MAX)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("function in two COMDATs",
|
2018-01-10 00:43:14 +01:00
|
|
|
object_error::parse_failed);
|
2018-03-14 16:44:45 +01:00
|
|
|
getDefinedFunction(Index).Comdat = ComdatIndex;
|
2018-01-10 00:43:14 +01:00
|
|
|
break;
|
2020-12-04 22:45:42 +01:00
|
|
|
case wasm::WASM_COMDAT_SECTION:
|
|
|
|
if (Index >= Sections.size())
|
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"COMDAT section index out of range", object_error::parse_failed);
|
|
|
|
if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"non-custom section in a COMDAT", object_error::parse_failed);
|
2020-12-04 22:45:42 +01:00
|
|
|
Sections[Index].Comdat = ComdatIndex;
|
|
|
|
break;
|
2018-01-10 00:43:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-01-17 03:29:55 +01:00
|
|
|
Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
|
|
|
|
llvm::SmallSet<StringRef, 3> FieldsSeen;
|
|
|
|
uint32_t Fields = readVaruint32(Ctx);
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
for (size_t I = 0; I < Fields; ++I) {
|
2019-01-17 03:29:55 +01:00
|
|
|
StringRef FieldName = readString(Ctx);
|
|
|
|
if (!FieldsSeen.insert(FieldName).second)
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"producers section does not have unique fields",
|
2019-01-17 03:29:55 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
|
|
|
|
if (FieldName == "language") {
|
|
|
|
ProducerVec = &ProducerInfo.Languages;
|
|
|
|
} else if (FieldName == "processed-by") {
|
|
|
|
ProducerVec = &ProducerInfo.Tools;
|
|
|
|
} else if (FieldName == "sdk") {
|
|
|
|
ProducerVec = &ProducerInfo.SDKs;
|
|
|
|
} else {
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"producers section field is not named one of language, processed-by, "
|
2019-01-17 03:29:55 +01:00
|
|
|
"or sdk",
|
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
uint32_t ValueCount = readVaruint32(Ctx);
|
|
|
|
llvm::SmallSet<StringRef, 8> ProducersSeen;
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
for (size_t J = 0; J < ValueCount; ++J) {
|
2019-01-17 03:29:55 +01:00
|
|
|
StringRef Name = readString(Ctx);
|
|
|
|
StringRef Version = readString(Ctx);
|
|
|
|
if (!ProducersSeen.insert(Name).second) {
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"producers section contains repeated producer",
|
2019-01-17 03:29:55 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
2020-01-29 02:09:24 +01:00
|
|
|
ProducerVec->emplace_back(std::string(Name), std::string(Version));
|
2019-01-17 03:29:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("producers section ended prematurely",
|
2019-01-17 03:29:55 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
|
|
|
|
llvm::SmallSet<std::string, 8> FeaturesSeen;
|
|
|
|
uint32_t FeatureCount = readVaruint32(Ctx);
|
|
|
|
for (size_t I = 0; I < FeatureCount; ++I) {
|
|
|
|
wasm::WasmFeatureEntry Feature;
|
|
|
|
Feature.Prefix = readUint8(Ctx);
|
|
|
|
switch (Feature.Prefix) {
|
|
|
|
case wasm::WASM_FEATURE_PREFIX_USED:
|
|
|
|
case wasm::WASM_FEATURE_PREFIX_REQUIRED:
|
|
|
|
case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
|
|
|
|
break;
|
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("unknown feature policy prefix",
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
2020-01-28 20:23:46 +01:00
|
|
|
Feature.Name = std::string(readString(Ctx));
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
if (!FeaturesSeen.insert(Feature.Name).second)
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"target features section contains repeated feature \"" +
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
Feature.Name + "\"",
|
|
|
|
object_error::parse_failed);
|
|
|
|
TargetFeatures.push_back(Feature);
|
|
|
|
}
|
|
|
|
if (Ctx.Ptr != Ctx.End)
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"target features section ended prematurely",
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
|
|
|
|
uint32_t SectionIndex = readVaruint32(Ctx);
|
2018-04-24 20:11:36 +02:00
|
|
|
if (SectionIndex >= Sections.size())
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid section index",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
2018-09-05 03:27:38 +02:00
|
|
|
WasmSection &Section = Sections[SectionIndex];
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t RelocCount = readVaruint32(Ctx);
|
2018-04-24 20:11:36 +02:00
|
|
|
uint32_t EndOffset = Section.Content.size();
|
2018-08-22 19:27:31 +02:00
|
|
|
uint32_t PreviousOffset = 0;
|
2017-03-30 21:44:09 +02:00
|
|
|
while (RelocCount--) {
|
2018-03-05 14:32:38 +01:00
|
|
|
wasm::WasmRelocation Reloc = {};
|
2021-01-21 21:07:43 +01:00
|
|
|
uint32_t type = readVaruint32(Ctx);
|
|
|
|
Reloc.Type = type;
|
2018-05-29 21:58:59 +02:00
|
|
|
Reloc.Offset = readVaruint32(Ctx);
|
2018-08-22 19:27:31 +02:00
|
|
|
if (Reloc.Offset < PreviousOffset)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("relocations not in offset order",
|
2018-08-22 19:27:31 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
PreviousOffset = Reloc.Offset;
|
2018-05-29 21:58:59 +02:00
|
|
|
Reloc.Index = readVaruint32(Ctx);
|
2021-01-21 21:07:43 +01:00
|
|
|
switch (type) {
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_FUNCTION_INDEX_LEB:
|
|
|
|
case wasm::R_WASM_TABLE_INDEX_SLEB:
|
2020-07-11 01:51:01 +02:00
|
|
|
case wasm::R_WASM_TABLE_INDEX_SLEB64:
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_TABLE_INDEX_I32:
|
2020-07-11 01:51:01 +02:00
|
|
|
case wasm::R_WASM_TABLE_INDEX_I64:
|
2019-04-04 19:43:50 +02:00
|
|
|
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
|
2021-04-23 01:54:58 +02:00
|
|
|
case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
|
2018-03-05 14:32:38 +01:00
|
|
|
if (!isValidFunctionSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"invalid relocation function index", object_error::parse_failed);
|
2018-03-05 14:32:38 +01:00
|
|
|
break;
|
2020-10-23 17:36:06 +02:00
|
|
|
case wasm::R_WASM_TABLE_NUMBER_LEB:
|
|
|
|
if (!isValidTableSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation table index",
|
2020-10-23 17:36:06 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
break;
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_TYPE_INDEX_LEB:
|
2018-03-05 14:32:38 +01:00
|
|
|
if (Reloc.Index >= Signatures.size())
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation type index",
|
2018-03-05 14:32:38 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
break;
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_GLOBAL_INDEX_LEB:
|
2019-03-26 20:46:15 +01:00
|
|
|
// R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
|
2019-08-02 16:44:17 +02:00
|
|
|
// symbols to refer to their GOT entries.
|
2019-03-26 20:46:15 +01:00
|
|
|
if (!isValidGlobalSymbol(Reloc.Index) &&
|
|
|
|
!isValidDataSymbol(Reloc.Index) &&
|
|
|
|
!isValidFunctionSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation global index",
|
2018-03-05 14:32:38 +01:00
|
|
|
object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2020-03-20 03:53:51 +01:00
|
|
|
case wasm::R_WASM_GLOBAL_INDEX_I32:
|
|
|
|
if (!isValidGlobalSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation global index",
|
2020-03-20 03:53:51 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
break;
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::R_WASM_TAG_INDEX_LEB:
|
|
|
|
if (!isValidTagSymbol(Reloc.Index))
|
|
|
|
return make_error<GenericBinaryError>("invalid relocation tag index",
|
2018-11-14 03:46:21 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
break;
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_MEMORY_ADDR_LEB:
|
|
|
|
case wasm::R_WASM_MEMORY_ADDR_SLEB:
|
|
|
|
case wasm::R_WASM_MEMORY_ADDR_I32:
|
2019-04-04 19:43:50 +02:00
|
|
|
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
|
2020-11-11 02:46:52 +01:00
|
|
|
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
|
2021-03-08 20:23:33 +01:00
|
|
|
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
|
2018-03-05 14:32:38 +01:00
|
|
|
if (!isValidDataSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation data index",
|
2018-03-05 14:32:38 +01:00
|
|
|
object_error::parse_failed);
|
2018-05-29 21:58:59 +02:00
|
|
|
Reloc.Addend = readVarint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2020-06-05 18:03:12 +02:00
|
|
|
case wasm::R_WASM_MEMORY_ADDR_LEB64:
|
|
|
|
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
|
|
|
|
case wasm::R_WASM_MEMORY_ADDR_I64:
|
|
|
|
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
|
2021-07-15 22:24:28 +02:00
|
|
|
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
|
2020-06-05 18:03:12 +02:00
|
|
|
if (!isValidDataSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation data index",
|
2020-06-05 18:03:12 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
Reloc.Addend = readVarint64(Ctx);
|
|
|
|
break;
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_FUNCTION_OFFSET_I32:
|
2018-04-26 21:27:28 +02:00
|
|
|
if (!isValidFunctionSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"invalid relocation function index", object_error::parse_failed);
|
2018-05-29 21:58:59 +02:00
|
|
|
Reloc.Addend = readVarint32(Ctx);
|
2018-04-26 21:27:28 +02:00
|
|
|
break;
|
2020-11-13 00:05:05 +01:00
|
|
|
case wasm::R_WASM_FUNCTION_OFFSET_I64:
|
|
|
|
if (!isValidFunctionSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"invalid relocation function index", object_error::parse_failed);
|
2020-11-13 00:05:05 +01:00
|
|
|
Reloc.Addend = readVarint64(Ctx);
|
|
|
|
break;
|
2019-02-04 18:28:46 +01:00
|
|
|
case wasm::R_WASM_SECTION_OFFSET_I32:
|
2018-04-26 21:27:28 +02:00
|
|
|
if (!isValidSectionSymbol(Reloc.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"invalid relocation section index", object_error::parse_failed);
|
2018-05-29 21:58:59 +02:00
|
|
|
Reloc.Addend = readVarint32(Ctx);
|
2018-04-26 21:27:28 +02:00
|
|
|
break;
|
2017-03-30 21:44:09 +02:00
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation type: " +
|
|
|
|
Twine(type),
|
|
|
|
object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-03-05 14:32:38 +01:00
|
|
|
|
|
|
|
// Relocations must fit inside the section, and must appear in order. They
|
|
|
|
// also shouldn't overlap a function/element boundary, but we don't bother
|
|
|
|
// to check that.
|
|
|
|
uint64_t Size = 5;
|
2020-06-05 18:03:12 +02:00
|
|
|
if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
|
|
|
|
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
|
|
|
|
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
|
|
|
|
Size = 10;
|
2019-02-04 18:28:46 +01:00
|
|
|
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
|
|
|
|
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
|
2021-03-08 20:23:33 +01:00
|
|
|
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
|
2019-02-04 18:28:46 +01:00
|
|
|
Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
|
2020-03-20 03:53:51 +01:00
|
|
|
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
|
|
|
|
Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
|
2018-03-05 14:32:38 +01:00
|
|
|
Size = 4;
|
2020-07-11 01:51:01 +02:00
|
|
|
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
|
2020-11-13 00:05:05 +01:00
|
|
|
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
|
|
|
|
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
|
2020-06-05 18:03:12 +02:00
|
|
|
Size = 8;
|
2018-03-06 08:13:10 +01:00
|
|
|
if (Reloc.Offset + Size > EndOffset)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid relocation offset",
|
2018-03-05 14:32:38 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
|
2018-04-24 20:11:36 +02:00
|
|
|
Section.Relocations.push_back(Reloc);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("reloc section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
|
2018-11-14 19:36:24 +01:00
|
|
|
if (Sec.Name == "dylink") {
|
|
|
|
if (Error Err = parseDylinkSection(Ctx))
|
|
|
|
return Err;
|
|
|
|
} else if (Sec.Name == "name") {
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Error Err = parseNameSection(Ctx))
|
2017-03-30 21:44:09 +02:00
|
|
|
return Err;
|
2017-06-20 06:04:59 +02:00
|
|
|
} else if (Sec.Name == "linking") {
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Error Err = parseLinkingSection(Ctx))
|
2017-06-20 06:04:59 +02:00
|
|
|
return Err;
|
2019-01-17 03:29:55 +01:00
|
|
|
} else if (Sec.Name == "producers") {
|
|
|
|
if (Error Err = parseProducersSection(Ctx))
|
|
|
|
return Err;
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
} else if (Sec.Name == "target_features") {
|
|
|
|
if (Error Err = parseTargetFeaturesSection(Ctx))
|
|
|
|
return Err;
|
2017-03-30 21:44:09 +02:00
|
|
|
} else if (Sec.Name.startswith("reloc.")) {
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Error Err = parseRelocSection(Sec.Name, Ctx))
|
2017-03-30 21:44:09 +02:00
|
|
|
return Err;
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Signatures.reserve(Count);
|
|
|
|
while (Count--) {
|
|
|
|
wasm::WasmSignature Sig;
|
2018-05-29 21:58:59 +02:00
|
|
|
uint8_t Form = readUint8(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
if (Form != wasm::WASM_TYPE_FUNC) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid signature type",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t ParamCount = readVaruint32(Ctx);
|
2018-10-04 00:22:48 +02:00
|
|
|
Sig.Params.reserve(ParamCount);
|
2017-03-30 21:44:09 +02:00
|
|
|
while (ParamCount--) {
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t ParamType = readUint8(Ctx);
|
2018-10-04 00:22:48 +02:00
|
|
|
Sig.Params.push_back(wasm::ValType(ParamType));
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t ReturnCount = readVaruint32(Ctx);
|
2019-10-18 22:27:30 +02:00
|
|
|
while (ReturnCount--) {
|
|
|
|
uint32_t ReturnType = readUint8(Ctx);
|
|
|
|
Sig.Returns.push_back(wasm::ValType(ReturnType));
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-10-04 00:22:48 +02:00
|
|
|
Signatures.push_back(std::move(Sig));
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("type section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Imports.reserve(Count);
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
for (uint32_t I = 0; I < Count; I++) {
|
2017-03-30 21:44:09 +02:00
|
|
|
wasm::WasmImport Im;
|
2018-05-29 21:58:59 +02:00
|
|
|
Im.Module = readString(Ctx);
|
|
|
|
Im.Field = readString(Ctx);
|
|
|
|
Im.Kind = readUint8(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
switch (Im.Kind) {
|
|
|
|
case wasm::WASM_EXTERNAL_FUNCTION:
|
2017-08-31 23:43:45 +02:00
|
|
|
NumImportedFunctions++;
|
2018-05-29 21:58:59 +02:00
|
|
|
Im.SigIndex = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
|
|
|
case wasm::WASM_EXTERNAL_GLOBAL:
|
2017-08-31 23:43:45 +02:00
|
|
|
NumImportedGlobals++;
|
2018-05-29 21:58:59 +02:00
|
|
|
Im.Global.Type = readUint8(Ctx);
|
|
|
|
Im.Global.Mutable = readVaruint1(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2017-05-10 01:48:41 +02:00
|
|
|
case wasm::WASM_EXTERNAL_MEMORY:
|
2018-05-29 21:58:59 +02:00
|
|
|
Im.Memory = readLimits(Ctx);
|
2020-07-06 22:34:16 +02:00
|
|
|
if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
|
|
|
|
HasMemory64 = true;
|
2017-05-10 01:48:41 +02:00
|
|
|
break;
|
2020-10-13 16:13:10 +02:00
|
|
|
case wasm::WASM_EXTERNAL_TABLE: {
|
2020-11-25 16:54:31 +01:00
|
|
|
Im.Table = readTableType(Ctx);
|
2020-10-13 16:13:10 +02:00
|
|
|
NumImportedTables++;
|
|
|
|
auto ElemType = Im.Table.ElemType;
|
|
|
|
if (ElemType != wasm::WASM_TYPE_FUNCREF &&
|
|
|
|
ElemType != wasm::WASM_TYPE_EXTERNREF)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid table element type",
|
2017-05-10 01:48:41 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
break;
|
2020-10-13 16:13:10 +02:00
|
|
|
}
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_EXTERNAL_TAG:
|
|
|
|
NumImportedTags++;
|
2021-06-18 23:41:01 +02:00
|
|
|
Im.Tag.Attribute = readUint8(Ctx);
|
2021-06-15 10:49:43 +02:00
|
|
|
Im.Tag.SigIndex = readVarint32(Ctx);
|
2018-11-14 03:46:21 +01:00
|
|
|
break;
|
2017-03-30 21:44:09 +02:00
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("unexpected import kind",
|
2018-09-05 03:27:38 +02:00
|
|
|
object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
Imports.push_back(Im);
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("import section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
FunctionTypes.reserve(Count);
|
2019-11-05 19:15:56 +01:00
|
|
|
Functions.resize(Count);
|
2018-03-02 15:35:29 +01:00
|
|
|
uint32_t NumTypes = Signatures.size();
|
2017-03-30 21:44:09 +02:00
|
|
|
while (Count--) {
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Type = readVaruint32(Ctx);
|
2018-03-02 15:35:29 +01:00
|
|
|
if (Type >= NumTypes)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid function type",
|
2018-03-02 15:35:29 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
FunctionTypes.push_back(Type);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("function section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
|
2020-11-25 17:31:05 +01:00
|
|
|
TableSection = Sections.size();
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Tables.reserve(Count);
|
|
|
|
while (Count--) {
|
2020-11-25 16:54:31 +01:00
|
|
|
wasm::WasmTable T;
|
|
|
|
T.Type = readTableType(Ctx);
|
2020-10-13 16:13:10 +02:00
|
|
|
T.Index = NumImportedTables + Tables.size();
|
|
|
|
Tables.push_back(T);
|
2020-11-25 16:54:31 +01:00
|
|
|
auto ElemType = Tables.back().Type.ElemType;
|
2020-10-13 16:13:10 +02:00
|
|
|
if (ElemType != wasm::WASM_TYPE_FUNCREF &&
|
|
|
|
ElemType != wasm::WASM_TYPE_EXTERNREF) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid table element type",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("table section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Memories.reserve(Count);
|
|
|
|
while (Count--) {
|
2020-07-06 22:34:16 +02:00
|
|
|
auto Limits = readLimits(Ctx);
|
|
|
|
if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
|
|
|
|
HasMemory64 = true;
|
|
|
|
Memories.push_back(Limits);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("memory section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2021-06-15 10:49:43 +02:00
|
|
|
Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
|
|
|
|
TagSection = Sections.size();
|
2021-03-30 21:57:20 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2021-06-15 10:49:43 +02:00
|
|
|
Tags.reserve(Count);
|
2020-03-25 03:36:13 +01:00
|
|
|
while (Count--) {
|
2021-06-15 10:49:43 +02:00
|
|
|
wasm::WasmTag Tag;
|
|
|
|
Tag.Index = NumImportedTags + Tags.size();
|
2021-06-18 23:41:01 +02:00
|
|
|
Tag.Type.Attribute = readUint8(Ctx);
|
2021-06-15 10:49:43 +02:00
|
|
|
Tag.Type.SigIndex = readVaruint32(Ctx);
|
|
|
|
Tags.push_back(Tag);
|
2020-03-25 03:36:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-06-15 10:49:43 +02:00
|
|
|
return make_error<GenericBinaryError>("tag section ended prematurely",
|
2020-03-25 03:36:13 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
|
2018-02-23 06:08:34 +01:00
|
|
|
GlobalSection = Sections.size();
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Globals.reserve(Count);
|
|
|
|
while (Count--) {
|
|
|
|
wasm::WasmGlobal Global;
|
2018-01-09 22:38:53 +01:00
|
|
|
Global.Index = NumImportedGlobals + Globals.size();
|
2018-05-29 21:58:59 +02:00
|
|
|
Global.Type.Type = readUint8(Ctx);
|
|
|
|
Global.Type.Mutable = readVaruint1(Ctx);
|
|
|
|
if (Error Err = readInitExpr(Global.InitExpr, Ctx))
|
2017-03-30 21:44:09 +02:00
|
|
|
return Err;
|
|
|
|
Globals.push_back(Global);
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("global section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Exports.reserve(Count);
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-04 20:13:39 +01:00
|
|
|
for (uint32_t I = 0; I < Count; I++) {
|
2017-03-30 21:44:09 +02:00
|
|
|
wasm::WasmExport Ex;
|
2018-05-29 21:58:59 +02:00
|
|
|
Ex.Name = readString(Ctx);
|
|
|
|
Ex.Kind = readUint8(Ctx);
|
|
|
|
Ex.Index = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
switch (Ex.Kind) {
|
|
|
|
case wasm::WASM_EXTERNAL_FUNCTION:
|
2019-11-05 19:15:56 +01:00
|
|
|
|
|
|
|
if (!isDefinedFunctionIndex(Ex.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid function export",
|
2017-08-31 23:43:45 +02:00
|
|
|
object_error::parse_failed);
|
2019-11-05 19:15:56 +01:00
|
|
|
getDefinedFunction(Ex.Index).ExportName = Ex.Name;
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2018-02-23 06:08:34 +01:00
|
|
|
case wasm::WASM_EXTERNAL_GLOBAL:
|
|
|
|
if (!isValidGlobalIndex(Ex.Index))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid global export",
|
2017-08-31 23:43:45 +02:00
|
|
|
object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_EXTERNAL_TAG:
|
|
|
|
if (!isValidTagIndex(Ex.Index))
|
|
|
|
return make_error<GenericBinaryError>("invalid tag export",
|
2018-11-14 03:46:21 +01:00
|
|
|
object_error::parse_failed);
|
|
|
|
break;
|
2017-05-10 01:48:41 +02:00
|
|
|
case wasm::WASM_EXTERNAL_MEMORY:
|
|
|
|
case wasm::WASM_EXTERNAL_TABLE:
|
|
|
|
break;
|
2017-03-30 21:44:09 +02:00
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("unexpected export kind",
|
2018-09-05 03:27:38 +02:00
|
|
|
object_error::parse_failed);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2017-06-20 06:04:59 +02:00
|
|
|
Exports.push_back(Ex);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("export section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2017-12-14 22:10:03 +01:00
|
|
|
bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
|
2018-02-23 06:08:34 +01:00
|
|
|
return Index < NumImportedFunctions + FunctionTypes.size();
|
2017-12-14 22:10:03 +01:00
|
|
|
}
|
|
|
|
|
2018-01-24 02:27:17 +01:00
|
|
|
bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
|
|
|
|
return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
|
|
|
|
}
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
|
|
|
|
return Index < NumImportedGlobals + Globals.size();
|
|
|
|
}
|
|
|
|
|
2021-03-04 10:30:00 +01:00
|
|
|
bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
|
2020-10-13 16:13:10 +02:00
|
|
|
return Index < NumImportedTables + Tables.size();
|
|
|
|
}
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
|
|
|
|
return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
|
|
|
|
}
|
|
|
|
|
2021-03-04 10:30:00 +01:00
|
|
|
bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
|
|
|
|
return Index >= NumImportedTables && isValidTableNumber(Index);
|
2020-10-13 16:13:10 +02:00
|
|
|
}
|
|
|
|
|
2021-06-15 10:49:43 +02:00
|
|
|
bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
|
|
|
|
return Index < NumImportedTags + Tags.size();
|
2018-11-14 03:46:21 +01:00
|
|
|
}
|
|
|
|
|
2021-06-15 10:49:43 +02:00
|
|
|
bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
|
|
|
|
return Index >= NumImportedTags && isValidTagIndex(Index);
|
2018-11-14 03:46:21 +01:00
|
|
|
}
|
|
|
|
|
2018-03-05 14:32:38 +01:00
|
|
|
bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
|
2018-02-23 06:08:34 +01:00
|
|
|
return Index < Symbols.size() && Symbols[Index].isTypeFunction();
|
|
|
|
}
|
|
|
|
|
2020-10-23 17:36:06 +02:00
|
|
|
bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
|
|
|
|
return Index < Symbols.size() && Symbols[Index].isTypeTable();
|
|
|
|
}
|
|
|
|
|
2018-03-05 14:32:38 +01:00
|
|
|
bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
|
|
|
|
return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
|
|
|
|
}
|
|
|
|
|
2021-06-15 10:49:43 +02:00
|
|
|
bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
|
|
|
|
return Index < Symbols.size() && Symbols[Index].isTypeTag();
|
2018-11-14 03:46:21 +01:00
|
|
|
}
|
|
|
|
|
2018-03-05 14:32:38 +01:00
|
|
|
bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
|
|
|
|
return Index < Symbols.size() && Symbols[Index].isTypeData();
|
|
|
|
}
|
|
|
|
|
2018-04-26 21:27:28 +02:00
|
|
|
bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
|
|
|
|
return Index < Symbols.size() && Symbols[Index].isTypeSection();
|
|
|
|
}
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
|
2018-01-24 02:27:17 +01:00
|
|
|
assert(isDefinedFunctionIndex(Index));
|
|
|
|
return Functions[Index - NumImportedFunctions];
|
|
|
|
}
|
|
|
|
|
2019-01-17 19:14:09 +01:00
|
|
|
const wasm::WasmFunction &
|
|
|
|
WasmObjectFile::getDefinedFunction(uint32_t Index) const {
|
|
|
|
assert(isDefinedFunctionIndex(Index));
|
|
|
|
return Functions[Index - NumImportedFunctions];
|
|
|
|
}
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
|
|
|
|
assert(isDefinedGlobalIndex(Index));
|
|
|
|
return Globals[Index - NumImportedGlobals];
|
|
|
|
}
|
|
|
|
|
2021-06-15 10:49:43 +02:00
|
|
|
wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
|
|
|
|
assert(isDefinedTagIndex(Index));
|
|
|
|
return Tags[Index - NumImportedTags];
|
2018-11-14 03:46:21 +01:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
|
|
|
|
StartFunction = readVaruint32(Ctx);
|
2017-12-14 22:10:03 +01:00
|
|
|
if (!isValidFunctionIndex(StartFunction))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid start function",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
|
2019-11-05 19:15:56 +01:00
|
|
|
SeenCodeSection = true;
|
2018-02-09 21:21:50 +01:00
|
|
|
CodeSection = Sections.size();
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t FunctionCount = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
if (FunctionCount != FunctionTypes.size()) {
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid function count",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
2019-11-05 19:15:56 +01:00
|
|
|
for (uint32_t i = 0; i < FunctionCount; i++) {
|
|
|
|
wasm::WasmFunction& Function = Functions[i];
|
2018-05-29 21:58:59 +02:00
|
|
|
const uint8_t *FunctionStart = Ctx.Ptr;
|
|
|
|
uint32_t Size = readVaruint32(Ctx);
|
|
|
|
const uint8_t *FunctionEnd = Ctx.Ptr + Size;
|
2017-12-17 18:50:07 +01:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Function.CodeOffset = Ctx.Ptr - FunctionStart;
|
2019-11-05 19:15:56 +01:00
|
|
|
Function.Index = NumImportedFunctions + i;
|
2018-05-29 21:58:59 +02:00
|
|
|
Function.CodeSectionOffset = FunctionStart - Ctx.Start;
|
2017-12-17 18:50:07 +01:00
|
|
|
Function.Size = FunctionEnd - FunctionStart;
|
2017-03-30 21:44:09 +02:00
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t NumLocalDecls = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Function.Locals.reserve(NumLocalDecls);
|
|
|
|
while (NumLocalDecls--) {
|
|
|
|
wasm::WasmLocalDecl Decl;
|
2018-05-29 21:58:59 +02:00
|
|
|
Decl.Count = readVaruint32(Ctx);
|
|
|
|
Decl.Type = readUint8(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
Function.Locals.push_back(Decl);
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t BodySize = FunctionEnd - Ctx.Ptr;
|
|
|
|
Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
|
2018-03-14 16:44:45 +01:00
|
|
|
// This will be set later when reading in the linking metadata section.
|
|
|
|
Function.Comdat = UINT32_MAX;
|
2018-05-29 21:58:59 +02:00
|
|
|
Ctx.Ptr += BodySize;
|
|
|
|
assert(Ctx.Ptr == FunctionEnd);
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("code section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
|
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
ElemSegments.reserve(Count);
|
|
|
|
while (Count--) {
|
|
|
|
wasm::WasmElemSegment Segment;
|
2021-03-04 10:30:00 +01:00
|
|
|
Segment.Flags = readVaruint32(Ctx);
|
|
|
|
|
|
|
|
uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
|
|
|
|
wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
|
|
|
|
wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
|
|
|
|
if (Segment.Flags & ~SupportedFlags)
|
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"Unsupported flags for element segment", object_error::parse_failed);
|
|
|
|
|
|
|
|
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
|
|
|
|
Segment.TableNumber = readVaruint32(Ctx);
|
|
|
|
else
|
|
|
|
Segment.TableNumber = 0;
|
|
|
|
if (!isValidTableNumber(Segment.TableNumber))
|
|
|
|
return make_error<GenericBinaryError>("invalid TableNumber",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
2021-03-04 10:30:00 +01:00
|
|
|
|
|
|
|
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
|
|
|
|
Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
|
|
|
|
Segment.Offset.Value.Int32 = 0;
|
|
|
|
} else {
|
|
|
|
if (Error Err = readInitExpr(Segment.Offset, Ctx))
|
|
|
|
return Err;
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
2021-03-04 10:30:00 +01:00
|
|
|
|
|
|
|
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
|
|
|
|
Segment.ElemKind = readUint8(Ctx);
|
|
|
|
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
|
|
|
|
if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
|
|
|
|
Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
|
|
|
|
return make_error<GenericBinaryError>("invalid reference type",
|
|
|
|
object_error::parse_failed);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (Segment.ElemKind != 0)
|
|
|
|
return make_error<GenericBinaryError>("invalid elemtype",
|
|
|
|
object_error::parse_failed);
|
|
|
|
Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
|
|
|
|
return make_error<GenericBinaryError>(
|
|
|
|
"elem segment init expressions not yet implemented",
|
|
|
|
object_error::parse_failed);
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t NumElems = readVaruint32(Ctx);
|
2017-03-30 21:44:09 +02:00
|
|
|
while (NumElems--) {
|
2018-05-29 21:58:59 +02:00
|
|
|
Segment.Functions.push_back(readVaruint32(Ctx));
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
ElemSegments.push_back(Segment);
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("elem section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2018-05-29 21:58:59 +02:00
|
|
|
Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
|
2018-02-09 21:21:50 +01:00
|
|
|
DataSection = Sections.size();
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Count = readVaruint32(Ctx);
|
2019-04-13 00:27:48 +02:00
|
|
|
if (DataCount && Count != DataCount.getValue())
|
|
|
|
return make_error<GenericBinaryError>(
|
2021-01-22 16:46:28 +01:00
|
|
|
"number of data segments does not match DataCount section");
|
2017-03-30 21:44:09 +02:00
|
|
|
DataSegments.reserve(Count);
|
|
|
|
while (Count--) {
|
2017-07-12 02:24:54 +02:00
|
|
|
WasmSegment Segment;
|
2019-02-19 23:56:19 +01:00
|
|
|
Segment.Data.InitFlags = readVaruint32(Ctx);
|
2020-11-30 14:55:29 +01:00
|
|
|
Segment.Data.MemoryIndex =
|
|
|
|
(Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
|
|
|
|
? readVaruint32(Ctx)
|
|
|
|
: 0;
|
|
|
|
if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
|
2019-02-19 23:56:19 +01:00
|
|
|
if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
|
|
|
|
return Err;
|
|
|
|
} else {
|
|
|
|
Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
|
|
|
|
Segment.Data.Offset.Value.Int32 = 0;
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
uint32_t Size = readVaruint32(Ctx);
|
2018-06-26 12:02:12 +02:00
|
|
|
if (Size > (size_t)(Ctx.End - Ctx.Ptr))
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("invalid segment size",
|
2018-05-18 23:08:26 +02:00
|
|
|
object_error::parse_failed);
|
2018-05-29 21:58:59 +02:00
|
|
|
Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
|
2018-03-14 16:44:45 +01:00
|
|
|
// The rest of these Data fields are set later, when reading in the linking
|
|
|
|
// metadata section.
|
2017-09-29 18:50:08 +02:00
|
|
|
Segment.Data.Alignment = 0;
|
2021-02-27 01:09:32 +01:00
|
|
|
Segment.Data.LinkingFlags = 0;
|
2018-03-14 16:44:45 +01:00
|
|
|
Segment.Data.Comdat = UINT32_MAX;
|
2018-05-29 21:58:59 +02:00
|
|
|
Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
|
|
|
|
Ctx.Ptr += Size;
|
2017-03-30 21:44:09 +02:00
|
|
|
DataSegments.push_back(Segment);
|
|
|
|
}
|
2018-05-29 21:58:59 +02:00
|
|
|
if (Ctx.Ptr != Ctx.End)
|
2021-01-22 16:46:28 +01:00
|
|
|
return make_error<GenericBinaryError>("data section ended prematurely",
|
2017-03-30 21:44:09 +02:00
|
|
|
object_error::parse_failed);
|
2016-11-30 17:49:11 +01:00
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2019-04-13 00:27:48 +02:00
|
|
|
Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
|
|
|
|
DataCount = readVaruint32(Ctx);
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2016-11-30 17:49:11 +01:00
|
|
|
const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
|
|
|
|
return Header;
|
|
|
|
}
|
|
|
|
|
2019-01-29 23:22:32 +01:00
|
|
|
void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
|
2016-11-30 17:49:11 +01:00
|
|
|
|
2020-04-10 14:24:21 +02:00
|
|
|
Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
|
2017-05-04 21:32:43 +02:00
|
|
|
uint32_t Result = SymbolRef::SF_None;
|
2017-03-30 21:44:09 +02:00
|
|
|
const WasmSymbol &Sym = getWasmSymbol(Symb);
|
2017-05-04 21:32:43 +02:00
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
|
2018-01-31 20:50:14 +01:00
|
|
|
if (Sym.isBindingWeak())
|
2017-06-20 06:04:59 +02:00
|
|
|
Result |= SymbolRef::SF_Weak;
|
2018-01-31 20:50:14 +01:00
|
|
|
if (!Sym.isBindingLocal())
|
2017-09-20 23:17:04 +02:00
|
|
|
Result |= SymbolRef::SF_Global;
|
2017-12-03 02:19:23 +01:00
|
|
|
if (Sym.isHidden())
|
|
|
|
Result |= SymbolRef::SF_Hidden;
|
2018-02-23 06:08:34 +01:00
|
|
|
if (!Sym.isDefined())
|
2017-05-04 21:32:43 +02:00
|
|
|
Result |= SymbolRef::SF_Undefined;
|
2018-02-23 06:08:34 +01:00
|
|
|
if (Sym.isTypeFunction())
|
|
|
|
Result |= SymbolRef::SF_Executable;
|
2017-05-04 21:32:43 +02:00
|
|
|
return Result;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
basic_symbol_iterator WasmObjectFile::symbol_begin() const {
|
2017-03-30 21:44:09 +02:00
|
|
|
DataRefImpl Ref;
|
2019-01-29 23:22:32 +01:00
|
|
|
Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
|
|
|
|
Ref.d.b = 0; // Symbol index
|
2017-03-30 21:44:09 +02:00
|
|
|
return BasicSymbolRef(Ref, this);
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
basic_symbol_iterator WasmObjectFile::symbol_end() const {
|
2017-03-30 21:44:09 +02:00
|
|
|
DataRefImpl Ref;
|
2019-01-29 23:22:32 +01:00
|
|
|
Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
|
|
|
|
Ref.d.b = Symbols.size(); // Symbol index
|
2017-03-30 21:44:09 +02:00
|
|
|
return BasicSymbolRef(Ref, this);
|
|
|
|
}
|
|
|
|
|
2017-05-10 01:48:41 +02:00
|
|
|
const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
|
2019-01-29 23:22:32 +01:00
|
|
|
return Symbols[Symb.d.b];
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2017-05-10 01:48:41 +02:00
|
|
|
const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
|
|
|
|
return getWasmSymbol(Symb.getRawDataRefImpl());
|
|
|
|
}
|
|
|
|
|
2016-11-30 17:49:11 +01:00
|
|
|
Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
|
2018-02-23 06:08:34 +01:00
|
|
|
return getWasmSymbol(Symb).Info.Name;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
|
2019-01-17 19:14:09 +01:00
|
|
|
auto &Sym = getWasmSymbol(Symb);
|
|
|
|
if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
|
|
|
|
isDefinedFunctionIndex(Sym.Info.ElementIndex))
|
|
|
|
return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
|
|
|
|
else
|
|
|
|
return getSymbolValue(Symb);
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2018-09-05 03:27:38 +02:00
|
|
|
uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
|
2018-02-23 06:08:34 +01:00
|
|
|
switch (Sym.Info.Kind) {
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TAG:
|
2020-11-25 17:31:05 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TABLE:
|
2018-02-23 06:08:34 +01:00
|
|
|
return Sym.Info.ElementIndex;
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_DATA: {
|
|
|
|
// The value of a data symbol is the segment offset, plus the symbol
|
|
|
|
// offset within the segment.
|
|
|
|
uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
|
|
|
|
const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
|
2020-06-05 18:03:12 +02:00
|
|
|
if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
|
|
|
|
return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
|
|
|
|
} else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
|
|
|
|
return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
|
|
|
|
} else {
|
|
|
|
llvm_unreachable("unknown init expr opcode");
|
|
|
|
}
|
2017-09-01 01:22:44 +02:00
|
|
|
}
|
2018-04-26 21:27:28 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_SECTION:
|
|
|
|
return 0;
|
2017-06-20 06:04:59 +02:00
|
|
|
}
|
2017-06-20 06:47:58 +02:00
|
|
|
llvm_unreachable("invalid symbol type");
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2017-09-20 23:17:04 +02:00
|
|
|
uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
|
|
|
|
return getWasmSymbolValue(getWasmSymbol(Symb));
|
|
|
|
}
|
|
|
|
|
2016-11-30 17:49:11 +01:00
|
|
|
uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
|
|
|
|
llvm_unreachable("not yet implemented");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
|
|
|
|
llvm_unreachable("not yet implemented");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<SymbolRef::Type>
|
|
|
|
WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
|
2017-05-04 21:32:43 +02:00
|
|
|
const WasmSymbol &Sym = getWasmSymbol(Symb);
|
|
|
|
|
2018-02-23 06:08:34 +01:00
|
|
|
switch (Sym.Info.Kind) {
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
|
2017-05-04 21:32:43 +02:00
|
|
|
return SymbolRef::ST_Function;
|
2018-02-23 06:08:34 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
|
|
|
|
return SymbolRef::ST_Other;
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_DATA:
|
2017-05-04 21:32:43 +02:00
|
|
|
return SymbolRef::ST_Data;
|
2018-04-26 21:27:28 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_SECTION:
|
|
|
|
return SymbolRef::ST_Debug;
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TAG:
|
2018-11-14 03:46:21 +01:00
|
|
|
return SymbolRef::ST_Other;
|
2020-11-25 17:31:05 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TABLE:
|
|
|
|
return SymbolRef::ST_Other;
|
2017-05-04 21:32:43 +02:00
|
|
|
}
|
|
|
|
|
2021-01-22 16:46:28 +01:00
|
|
|
llvm_unreachable("unknown WasmSymbol::SymbolType");
|
2017-05-04 21:32:43 +02:00
|
|
|
return SymbolRef::ST_Other;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Expected<section_iterator>
|
|
|
|
WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
|
2018-09-05 03:27:38 +02:00
|
|
|
const WasmSymbol &Sym = getWasmSymbol(Symb);
|
2018-02-23 06:08:34 +01:00
|
|
|
if (Sym.isUndefined())
|
2018-02-09 21:21:50 +01:00
|
|
|
return section_end();
|
2018-02-23 06:08:34 +01:00
|
|
|
|
|
|
|
DataRefImpl Ref;
|
2020-01-23 02:40:11 +01:00
|
|
|
Ref.d.a = getSymbolSectionIdImpl(Sym);
|
|
|
|
return section_iterator(SectionRef(Ref, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
|
|
|
|
const WasmSymbol &Sym = getWasmSymbol(Symb);
|
|
|
|
return getSymbolSectionIdImpl(Sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
|
2018-02-23 06:08:34 +01:00
|
|
|
switch (Sym.Info.Kind) {
|
|
|
|
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
|
2020-01-23 02:40:11 +01:00
|
|
|
return CodeSection;
|
2018-02-23 06:08:34 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
|
2020-01-23 02:40:11 +01:00
|
|
|
return GlobalSection;
|
2018-02-23 06:08:34 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_DATA:
|
2020-01-23 02:40:11 +01:00
|
|
|
return DataSection;
|
2018-11-14 03:46:21 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_SECTION:
|
2020-01-23 02:40:11 +01:00
|
|
|
return Sym.Info.ElementIndex;
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TAG:
|
|
|
|
return TagSection;
|
2020-11-25 17:31:05 +01:00
|
|
|
case wasm::WASM_SYMBOL_TYPE_TABLE:
|
|
|
|
return TableSection;
|
2018-02-23 06:08:34 +01:00
|
|
|
default:
|
2021-01-22 16:46:28 +01:00
|
|
|
llvm_unreachable("unknown WasmSymbol::SymbolType");
|
2018-02-23 06:08:34 +01:00
|
|
|
}
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
|
|
|
|
|
2019-05-02 12:32:03 +02:00
|
|
|
Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
|
2017-03-30 21:44:09 +02:00
|
|
|
const WasmSection &S = Sections[Sec.d.a];
|
2016-11-30 17:49:11 +01:00
|
|
|
#define ECase(X) \
|
|
|
|
case wasm::WASM_SEC_##X: \
|
2019-05-02 12:32:03 +02:00
|
|
|
return #X;
|
2016-11-30 17:49:11 +01:00
|
|
|
switch (S.Type) {
|
|
|
|
ECase(TYPE);
|
|
|
|
ECase(IMPORT);
|
|
|
|
ECase(FUNCTION);
|
|
|
|
ECase(TABLE);
|
|
|
|
ECase(MEMORY);
|
|
|
|
ECase(GLOBAL);
|
2021-06-15 10:49:43 +02:00
|
|
|
ECase(TAG);
|
2016-11-30 17:49:11 +01:00
|
|
|
ECase(EXPORT);
|
|
|
|
ECase(START);
|
|
|
|
ECase(ELEM);
|
|
|
|
ECase(CODE);
|
|
|
|
ECase(DATA);
|
2019-04-13 00:27:48 +02:00
|
|
|
ECase(DATACOUNT);
|
2017-01-31 00:30:52 +01:00
|
|
|
case wasm::WASM_SEC_CUSTOM:
|
2019-05-02 12:32:03 +02:00
|
|
|
return S.Name;
|
2016-11-30 17:49:11 +01:00
|
|
|
default:
|
2019-05-02 12:32:03 +02:00
|
|
|
return createStringError(object_error::invalid_section_index, "");
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
#undef ECase
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
|
|
|
|
|
2017-05-27 20:10:23 +02:00
|
|
|
uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
|
|
|
|
return Sec.d.a;
|
|
|
|
}
|
|
|
|
|
2016-11-30 17:49:11 +01:00
|
|
|
uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
|
2017-03-30 21:44:09 +02:00
|
|
|
const WasmSection &S = Sections[Sec.d.a];
|
2016-11-30 17:49:11 +01:00
|
|
|
return S.Content.size();
|
|
|
|
}
|
|
|
|
|
2019-05-14 06:22:51 +02:00
|
|
|
Expected<ArrayRef<uint8_t>>
|
|
|
|
WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
|
2017-03-30 21:44:09 +02:00
|
|
|
const WasmSection &S = Sections[Sec.d.a];
|
2016-11-30 17:49:11 +01:00
|
|
|
// This will never fail since wasm sections can never be empty (user-sections
|
|
|
|
// must have a name and non-user sections each have a defined structure).
|
2019-05-14 06:22:51 +02:00
|
|
|
return S.Content;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
|
2017-03-30 21:44:09 +02:00
|
|
|
return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
|
2017-03-30 21:44:09 +02:00
|
|
|
return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
|
|
|
|
|
|
|
|
bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
|
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
|
|
|
|
DataRefImpl RelocRef;
|
|
|
|
RelocRef.d.a = Ref.d.a;
|
|
|
|
RelocRef.d.b = 0;
|
|
|
|
return relocation_iterator(RelocationRef(RelocRef, this));
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
|
|
|
|
const WasmSection &Sec = getWasmSection(Ref);
|
|
|
|
DataRefImpl RelocRef;
|
|
|
|
RelocRef.d.a = Ref.d.a;
|
|
|
|
RelocRef.d.b = Sec.Relocations.size();
|
|
|
|
return relocation_iterator(RelocationRef(RelocRef, this));
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2018-09-05 03:27:38 +02:00
|
|
|
void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
|
2016-11-30 17:49:11 +01:00
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
|
|
|
|
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
|
|
|
|
return Rel.Offset;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2018-04-26 18:41:51 +02:00
|
|
|
symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
|
|
|
|
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
|
2019-02-04 18:28:46 +01:00
|
|
|
if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
|
2018-04-26 18:41:51 +02:00
|
|
|
return symbol_end();
|
|
|
|
DataRefImpl Sym;
|
2019-01-30 01:15:48 +01:00
|
|
|
Sym.d.a = 1;
|
|
|
|
Sym.d.b = Rel.Index;
|
2018-04-26 18:41:51 +02:00
|
|
|
return symbol_iterator(SymbolRef(Sym, this));
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
|
|
|
|
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
|
|
|
|
return Rel.Type;
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void WasmObjectFile::getRelocationTypeName(
|
2017-03-30 21:44:09 +02:00
|
|
|
DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
|
2018-09-05 03:27:38 +02:00
|
|
|
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
|
2017-03-30 21:44:09 +02:00
|
|
|
StringRef Res = "Unknown";
|
|
|
|
|
2018-09-05 03:27:38 +02:00
|
|
|
#define WASM_RELOC(name, value) \
|
|
|
|
case wasm::name: \
|
|
|
|
Res = #name; \
|
2017-03-30 21:44:09 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
switch (Rel.Type) {
|
2017-12-21 04:16:34 +01:00
|
|
|
#include "llvm/BinaryFormat/WasmRelocs.def"
|
2017-03-30 21:44:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef WASM_RELOC
|
|
|
|
|
|
|
|
Result.append(Res.begin(), Res.end());
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
section_iterator WasmObjectFile::section_begin() const {
|
|
|
|
DataRefImpl Ref;
|
|
|
|
Ref.d.a = 0;
|
|
|
|
return section_iterator(SectionRef(Ref, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
section_iterator WasmObjectFile::section_end() const {
|
|
|
|
DataRefImpl Ref;
|
|
|
|
Ref.d.a = Sections.size();
|
|
|
|
return section_iterator(SectionRef(Ref, this));
|
|
|
|
}
|
|
|
|
|
2020-07-06 22:34:16 +02:00
|
|
|
uint8_t WasmObjectFile::getBytesInAddress() const {
|
|
|
|
return HasMemory64 ? 8 : 4;
|
|
|
|
}
|
2016-11-30 17:49:11 +01:00
|
|
|
|
|
|
|
StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
|
|
|
|
|
2020-07-06 22:34:16 +02:00
|
|
|
Triple::ArchType WasmObjectFile::getArch() const {
|
|
|
|
return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
|
|
|
|
}
|
2016-11-30 17:49:11 +01:00
|
|
|
|
|
|
|
SubtargetFeatures WasmObjectFile::getFeatures() const {
|
|
|
|
return SubtargetFeatures();
|
|
|
|
}
|
|
|
|
|
2018-09-05 03:27:38 +02:00
|
|
|
bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
|
2016-11-30 17:49:11 +01:00
|
|
|
|
2018-12-13 00:40:58 +01:00
|
|
|
bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
|
|
|
|
|
2017-03-30 21:44:09 +02:00
|
|
|
const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
|
2017-04-01 21:47:52 +02:00
|
|
|
assert(Ref.d.a < Sections.size());
|
2017-03-30 21:44:09 +02:00
|
|
|
return Sections[Ref.d.a];
|
|
|
|
}
|
|
|
|
|
|
|
|
const WasmSection &
|
2016-11-30 17:49:11 +01:00
|
|
|
WasmObjectFile::getWasmSection(const SectionRef &Section) const {
|
2017-03-30 21:44:09 +02:00
|
|
|
return getWasmSection(Section.getRawDataRefImpl());
|
|
|
|
}
|
|
|
|
|
|
|
|
const wasm::WasmRelocation &
|
|
|
|
WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
|
|
|
|
return getWasmRelocation(Ref.getRawDataRefImpl());
|
|
|
|
}
|
|
|
|
|
|
|
|
const wasm::WasmRelocation &
|
|
|
|
WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
|
2017-04-01 21:47:52 +02:00
|
|
|
assert(Ref.d.a < Sections.size());
|
2018-09-05 03:27:38 +02:00
|
|
|
const WasmSection &Sec = Sections[Ref.d.a];
|
2017-04-01 21:47:52 +02:00
|
|
|
assert(Ref.d.b < Sec.Relocations.size());
|
2017-03-30 21:44:09 +02:00
|
|
|
return Sec.Relocations[Ref.d.b];
|
2016-11-30 17:49:11 +01:00
|
|
|
}
|
2018-12-15 01:58:12 +01:00
|
|
|
|
|
|
|
int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
|
|
|
|
StringRef CustomSectionName) {
|
|
|
|
switch (ID) {
|
|
|
|
case wasm::WASM_SEC_CUSTOM:
|
|
|
|
return StringSwitch<unsigned>(CustomSectionName)
|
|
|
|
.Case("dylink", WASM_SEC_ORDER_DYLINK)
|
|
|
|
.Case("linking", WASM_SEC_ORDER_LINKING)
|
|
|
|
.StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
|
|
|
|
.Case("name", WASM_SEC_ORDER_NAME)
|
|
|
|
.Case("producers", WASM_SEC_ORDER_PRODUCERS)
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 21:26:45 +01:00
|
|
|
.Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
|
2019-02-20 03:22:36 +01:00
|
|
|
.Default(WASM_SEC_ORDER_NONE);
|
2018-12-15 01:58:12 +01:00
|
|
|
case wasm::WASM_SEC_TYPE:
|
|
|
|
return WASM_SEC_ORDER_TYPE;
|
|
|
|
case wasm::WASM_SEC_IMPORT:
|
|
|
|
return WASM_SEC_ORDER_IMPORT;
|
|
|
|
case wasm::WASM_SEC_FUNCTION:
|
|
|
|
return WASM_SEC_ORDER_FUNCTION;
|
|
|
|
case wasm::WASM_SEC_TABLE:
|
|
|
|
return WASM_SEC_ORDER_TABLE;
|
|
|
|
case wasm::WASM_SEC_MEMORY:
|
|
|
|
return WASM_SEC_ORDER_MEMORY;
|
|
|
|
case wasm::WASM_SEC_GLOBAL:
|
|
|
|
return WASM_SEC_ORDER_GLOBAL;
|
|
|
|
case wasm::WASM_SEC_EXPORT:
|
|
|
|
return WASM_SEC_ORDER_EXPORT;
|
|
|
|
case wasm::WASM_SEC_START:
|
|
|
|
return WASM_SEC_ORDER_START;
|
|
|
|
case wasm::WASM_SEC_ELEM:
|
|
|
|
return WASM_SEC_ORDER_ELEM;
|
|
|
|
case wasm::WASM_SEC_CODE:
|
|
|
|
return WASM_SEC_ORDER_CODE;
|
|
|
|
case wasm::WASM_SEC_DATA:
|
|
|
|
return WASM_SEC_ORDER_DATA;
|
|
|
|
case wasm::WASM_SEC_DATACOUNT:
|
|
|
|
return WASM_SEC_ORDER_DATACOUNT;
|
2021-06-15 10:49:43 +02:00
|
|
|
case wasm::WASM_SEC_TAG:
|
|
|
|
return WASM_SEC_ORDER_TAG;
|
2018-12-15 01:58:12 +01:00
|
|
|
default:
|
2019-04-20 02:11:46 +02:00
|
|
|
return WASM_SEC_ORDER_NONE;
|
2018-12-15 01:58:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-20 03:22:36 +01:00
|
|
|
// Represents the edges in a directed graph where any node B reachable from node
|
|
|
|
// A is not allowed to appear before A in the section ordering, but may appear
|
|
|
|
// afterward.
|
2020-03-25 03:36:13 +01:00
|
|
|
int WasmSectionOrderChecker::DisallowedPredecessors
|
|
|
|
[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
|
|
|
|
// WASM_SEC_ORDER_NONE
|
|
|
|
{},
|
|
|
|
// WASM_SEC_ORDER_TYPE
|
|
|
|
{WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
|
|
|
|
// WASM_SEC_ORDER_IMPORT
|
|
|
|
{WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
|
|
|
|
// WASM_SEC_ORDER_FUNCTION
|
|
|
|
{WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
|
|
|
|
// WASM_SEC_ORDER_TABLE
|
|
|
|
{WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
|
|
|
|
// WASM_SEC_ORDER_MEMORY
|
2021-06-15 10:49:43 +02:00
|
|
|
{WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
|
|
|
|
// WASM_SEC_ORDER_TAG
|
|
|
|
{WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
|
2020-03-25 03:36:13 +01:00
|
|
|
// WASM_SEC_ORDER_GLOBAL
|
|
|
|
{WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
|
|
|
|
// WASM_SEC_ORDER_EXPORT
|
|
|
|
{WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
|
|
|
|
// WASM_SEC_ORDER_START
|
|
|
|
{WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
|
|
|
|
// WASM_SEC_ORDER_ELEM
|
|
|
|
{WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
|
|
|
|
// WASM_SEC_ORDER_DATACOUNT
|
|
|
|
{WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
|
|
|
|
// WASM_SEC_ORDER_CODE
|
|
|
|
{WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
|
|
|
|
// WASM_SEC_ORDER_DATA
|
|
|
|
{WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
|
|
|
|
|
|
|
|
// Custom Sections
|
|
|
|
// WASM_SEC_ORDER_DYLINK
|
|
|
|
{WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
|
|
|
|
// WASM_SEC_ORDER_LINKING
|
|
|
|
{WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
|
|
|
|
// WASM_SEC_ORDER_RELOC (can be repeated)
|
|
|
|
{},
|
|
|
|
// WASM_SEC_ORDER_NAME
|
|
|
|
{WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
|
|
|
|
// WASM_SEC_ORDER_PRODUCERS
|
|
|
|
{WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
|
|
|
|
// WASM_SEC_ORDER_TARGET_FEATURES
|
|
|
|
{WASM_SEC_ORDER_TARGET_FEATURES}};
|
2019-02-20 03:22:36 +01:00
|
|
|
|
2018-12-15 01:58:12 +01:00
|
|
|
bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
|
|
|
|
StringRef CustomSectionName) {
|
|
|
|
int Order = getSectionOrder(ID, CustomSectionName);
|
2019-02-20 03:22:36 +01:00
|
|
|
if (Order == WASM_SEC_ORDER_NONE)
|
2018-12-15 01:58:12 +01:00
|
|
|
return true;
|
2019-02-20 03:22:36 +01:00
|
|
|
|
|
|
|
// Disallowed predecessors we need to check for
|
|
|
|
SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
|
|
|
|
|
|
|
|
// Keep track of completed checks to avoid repeating work
|
|
|
|
bool Checked[WASM_NUM_SEC_ORDERS] = {};
|
|
|
|
|
|
|
|
int Curr = Order;
|
|
|
|
while (true) {
|
|
|
|
// Add new disallowed predecessors to work list
|
|
|
|
for (size_t I = 0;; ++I) {
|
|
|
|
int Next = DisallowedPredecessors[Curr][I];
|
|
|
|
if (Next == WASM_SEC_ORDER_NONE)
|
|
|
|
break;
|
|
|
|
if (Checked[Next])
|
|
|
|
continue;
|
|
|
|
WorkList.push_back(Next);
|
|
|
|
Checked[Next] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WorkList.empty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Consider next disallowed predecessor
|
|
|
|
Curr = WorkList.pop_back_val();
|
|
|
|
if (Seen[Curr])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Have not seen any disallowed predecessors
|
|
|
|
Seen[Order] = true;
|
|
|
|
return true;
|
2018-12-15 01:58:12 +01:00
|
|
|
}
|