1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:37:35 +00:00

LibWasm: Implement a very basic linker

This will simply "link" any given module instances and produce a list of
external values that can be used to instantiate a module.
Note that this is extremely basic and cannot resolve circular
dependencies, and depends on the instance order.
This commit is contained in:
Ali Mohammad Pur 2021-05-10 17:26:17 +04:30 committed by Linus Groh
parent 3283c8a495
commit 35b3ae26ed
3 changed files with 206 additions and 15 deletions

View file

@ -11,6 +11,30 @@
#include <LibWasm/Printer/Printer.h>
#include <LibWasm/Types.h>
static Optional<Wasm::Module> parse(const StringView& filename)
{
auto result = Core::File::open(filename, Core::OpenMode::ReadOnly);
if (result.is_error()) {
warnln("Failed to open {}: {}", filename, result.error());
return {};
}
auto stream = Core::InputFileStream(result.release_value());
auto parse_result = Wasm::Module::parse(stream);
if (parse_result.is_error()) {
warnln("Something went wrong, either the file is invalid, or there's a bug with LibWasm!");
warnln("The parse error was {}", Wasm::parse_error_to_string(parse_result.error()));
return {};
}
return parse_result.release_value();
}
static void print_link_error(const Wasm::LinkError& error)
{
for (const auto& missing : error.missing_imports)
warnln("Missing import '{}'", missing);
}
int main(int argc, char* argv[])
{
const char* filename = nullptr;
@ -18,12 +42,27 @@ int main(int argc, char* argv[])
bool attempt_instantiate = false;
String exported_function_to_execute;
Vector<u64> values_to_push;
Vector<String> modules_to_link_in;
Core::ArgsParser parser;
parser.add_positional_argument(filename, "File name to parse", "file");
parser.add_option(print, "Print the parsed module", "print", 'p');
parser.add_option(attempt_instantiate, "Attempt to instantiate the module", "instantiate", 'i');
parser.add_option(exported_function_to_execute, "Attempt to execute the named exported function from the module (implies -i)", "execute", 'e', "name");
parser.add_option(Core::ArgsParser::Option {
.requires_argument = true,
.help_string = "Extra modules to link with, use to resolve imports",
.long_name = "link",
.short_name = 'l',
.value_name = "file",
.accept_value = [&](const char* str) {
if (auto v = StringView { str }; !v.is_empty()) {
modules_to_link_in.append(v);
return true;
}
return false;
},
});
parser.add_option(Core::ArgsParser::Option {
.requires_argument = true,
.help_string = "Supply arguments to the function (default=0) (expects u64, casts to required type)",
@ -43,20 +82,7 @@ int main(int argc, char* argv[])
if (!exported_function_to_execute.is_empty())
attempt_instantiate = true;
auto result = Core::File::open(filename, Core::OpenMode::ReadOnly);
if (result.is_error()) {
warnln("Failed to open {}: {}", filename, result.error());
return 1;
}
auto stream = Core::InputFileStream(result.release_value());
auto parse_result = Wasm::Module::parse(stream);
if (parse_result.is_error()) {
warnln("Something went wrong, either the file is invalid, or there's a bug with LibWasm!");
warnln("The parse error was {}", Wasm::parse_error_to_string(parse_result.error()));
return 2;
}
auto parse_result = parse(filename);
if (print && !attempt_instantiate) {
auto out_stream = Core::OutputFileStream::standard_output();
Wasm::Printer printer(out_stream);
@ -65,7 +91,43 @@ int main(int argc, char* argv[])
if (attempt_instantiate) {
Wasm::AbstractMachine machine;
auto result = machine.instantiate(parse_result.value(), {});
// First, resolve the linked modules
NonnullOwnPtrVector<Wasm::ModuleInstance> linked_instances;
Vector<Wasm::Module> linked_modules;
for (auto& name : modules_to_link_in) {
auto parse_result = parse(name);
if (!parse_result.has_value()) {
warnln("Failed to parse linked module '{}'", name);
return 1;
}
linked_modules.append(parse_result.release_value());
Wasm::Linker linker { linked_modules.last() };
for (auto& instance : linked_instances)
linker.link(instance);
auto link_result = linker.finish();
if (link_result.is_error()) {
warnln("Linking imported module '{}' failed", name);
print_link_error(link_result.error());
return 1;
}
auto instantiation_result = machine.instantiate(linked_modules.last(), link_result.release_value());
if (instantiation_result.is_error()) {
warnln("Instantiation of imported module '{}' failed: {}", name, instantiation_result.error().error);
return 1;
}
linked_instances.append(instantiation_result.release_value());
}
Wasm::Linker linker { parse_result.value() };
for (auto& instance : linked_instances)
linker.link(instance);
auto link_result = linker.finish();
if (link_result.is_error()) {
warnln("Linking main module failed");
print_link_error(link_result.error());
return 1;
}
auto result = machine.instantiate(parse_result.value(), link_result.release_value());
if (result.is_error()) {
warnln("Module instantiation failed: {}", result.error().error);
return 1;