Index: Common/Args.cpp =================================================================== --- Common/Args.cpp +++ Common/Args.cpp @@ -27,6 +27,17 @@ return V; } +unsigned lld::args::getInteger(opt::InputArgList &Args, unsigned Key, + unsigned Default) { + unsigned V = Default; + if (auto *Arg = Args.getLastArg(Key)) { + StringRef S = Arg->getValue(); + if (!to_integer(S, V, 10)) + error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); + } + return V; +} + std::vector lld::args::getStrings(opt::InputArgList &Args, int Id) { std::vector V; for (auto *Arg : Args.filtered(Id)) Index: include/lld/Common/Args.h =================================================================== --- include/lld/Common/Args.h +++ include/lld/Common/Args.h @@ -23,6 +23,8 @@ namespace lld { namespace args { int getInteger(llvm::opt::InputArgList &Args, unsigned Key, int Default); +unsigned getInteger(llvm::opt::InputArgList &Args, unsigned Key, + unsigned Default); std::vector getStrings(llvm::opt::InputArgList &Args, int Id); uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key, Index: test/wasm/data-layout.ll =================================================================== --- test/wasm/data-layout.ll +++ test/wasm/data-layout.ll @@ -12,7 +12,10 @@ ; RUN: wasm-ld -no-gc-sections --check-signatures --allow-undefined -o %t.wasm %t.o %t.hello.o ; RUN: obj2yaml %t.wasm | FileCheck %s -; CHECK: - Type: GLOBAL +; CHECK: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000002 +; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Type: I32 @@ -43,6 +46,18 @@ ; CHECK-NEXT: Content: 68656C6C6F0A00 +; RUN: wasm-ld -no-gc-sections --check-signatures --allow-undefined \ +; RUN: --initial-memory=200000 --max-memory=300000 -o %t_max.wasm %t.o \ +; RUN: %t.hello.o +; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX + +; CHECK-MAX: - Type: MEMORY +; CHECK-MAX-NEXT: Memories: +; CHECK-MAX-NEXT: - Flags: [ HAS_MAX ] +; CHECK-MAX-NEXT: Initial: 0x00000004 +; CHECK-MAX-NEXT: Maximum: 0x00000005 + + ; RUN: wasm-ld --check-signatures --relocatable -o %t_reloc.wasm %t.o %t.hello.o ; RUN: obj2yaml %t_reloc.wasm | FileCheck %s -check-prefix=RELOC Index: test/wasm/demange.ll =================================================================== --- /dev/null +++ test/wasm/demange.ll @@ -0,0 +1,17 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: not wasm-ld --check-signatures --undefined _Z3fooi \ +; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s + +; CHECK: error: undefined symbol: `foo(int)' + +; RUN: not wasm-ld --check-signatures --no-demangle --undefined _Z3fooi \ +; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s + +; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi + +target triple = "wasm32-unknown-unknown-wasm" + +define hidden void @_start() local_unnamed_addr { +entry: + ret void +} Index: test/wasm/import-memory.test =================================================================== --- test/wasm/import-memory.test +++ test/wasm/import-memory.test @@ -11,3 +11,23 @@ # CHECK-NEXT: Kind: MEMORY # CHECK-NEXT: Memory: # CHECK-NEXT: Initial: 0x00000002 +# CHECK-NEXT: - Type: + + + +# RUN: wasm-ld --check-signatures --import-memory --initial-memory=200000 \ +# RUN: --max-memory=300000 -o %t.max.wasm %t.start.o +# RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-MAX %s + +# Verify the --initial-memory and --max-memory arguments work with imports + +# CHECK-MAX: - Type: IMPORT +# CHECK-MAX-NEXT: Imports: +# CHECK-MAX-NEXT: - Module: env +# CHECK-MAX-NEXT: Field: memory +# CHECK-MAX-NEXT: Kind: MEMORY +# CHECK-MAX-NEXT: Memory: +# CHECK-MAX-NEXT: Flags: [ HAS_MAX ] +# CHECK-MAX-NEXT: Initial: 0x00000004 +# CHECK-MAX-NEXT: Maximum: 0x00000005 +# CHECK-MAX-NEXT: - Type: Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -242,6 +242,7 @@ Config->AllowUndefined = Args.hasArg(OPT_allow_undefined); Config->CheckSignatures = Args.hasFlag(OPT_check_signatures, OPT_no_check_signatures, false); + Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start"); Config->ImportMemory = Args.hasArg(OPT_import_memory); Config->OutputFile = Args.getLastArgValue(OPT_o); @@ -256,9 +257,9 @@ errorHandler().Verbose = Args.hasArg(OPT_verbose); ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); - Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0); - Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024); - Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0); + Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0u); + Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024u); + Config->MaxMemory = args::getInteger(Args, OPT_max_memory, UINT32_MAX); Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize); Index: wasm/Options.td =================================================================== --- wasm/Options.td +++ wasm/Options.td @@ -11,6 +11,11 @@ def _eq: Joined<["--", "-"], name # "=">, Alias(NAME)>; } +multiclass B { + def NAME: Flag<["--", "-"], name>, HelpText; + def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText; +} + // The follow flags are shared with the ELF linker def color_diagnostics: F<"color-diagnostics">, HelpText<"Use colors in diagnostics">; @@ -18,6 +23,10 @@ def color_diagnostics_eq: J<"color-diagnostics=">, HelpText<"Use colors in diagnostics">; +defm demangle: B<"demangle", + "Demangle symbol names", + "Do not demangle symbol names">; + def entry: S<"entry">, MetaVarName<"">, HelpText<"Name of entry point symbol">; @@ -27,8 +36,9 @@ def fatal_warnings: F<"fatal-warnings">, HelpText<"Treat warnings as errors">; -def gc_sections: F<"gc-sections">, - HelpText<"Enable garbage collection of unused sections">; +defm gc_sections: B<"gc-sections", + "Enable garbage collection of unused sections", + "Disable garbage collection of unused sections">; def help: F<"help">, HelpText<"Print option help">; @@ -48,17 +58,12 @@ def no_fatal_warnings: F<"no-fatal-warnings">; -def no_gc_sections: F<"no-gc-sections">, - HelpText<"Disable garbage collection of unused sections">; - -def no_print_gc_sections: F<"no-print-gc-sections">, - HelpText<"Do not list removed unused sections">; - def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"">, HelpText<"Path to file to write output">; -def print_gc_sections: F<"print-gc-sections">, - HelpText<"List removed unused sections">; +defm print_gc_sections: B<"print-gc-sections", + "List removed unused sections", + "Do not list removed unused sections">; def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -117,6 +117,7 @@ uint64_t FileSize = 0; uint32_t NumMemoryPages = 0; + uint32_t MaxMemoryPages = UINT32_MAX; std::vector Types; DenseMap TypeIndices; @@ -173,6 +174,10 @@ Import.Kind = WASM_EXTERNAL_MEMORY; Import.Memory.Flags = 0; Import.Memory.Initial = NumMemoryPages; + if (MaxMemoryPages != UINT32_MAX) { + Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; + Import.Memory.Maximum = MaxMemoryPages; + } writeImport(OS, Import); } @@ -219,9 +224,12 @@ SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY); raw_ostream &OS = Section->getStream(); + bool HasMax = MaxMemoryPages != UINT32_MAX; writeUleb128(OS, 1, "memory count"); - writeUleb128(OS, 0, "memory limits flags"); + writeUleb128(OS, HasMax ? WASM_LIMITS_FLAG_HAS_MAX : 0, "memory limits flags"); writeUleb128(OS, NumMemoryPages, "initial pages"); + if (HasMax) + writeUleb128(OS, MaxMemoryPages, "max pages"); } void Writer::createGlobalSection() { @@ -606,9 +614,19 @@ debugPrint("mem: heap base = %d\n", MemoryPtr); } + if (MemoryPtr < Config->InitialMemory) + MemoryPtr = Config->InitialMemory; uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize); NumMemoryPages = MemSize / WasmPageSize; debugPrint("mem: total pages = %d\n", NumMemoryPages); + + if (Config->MaxMemory != UINT32_MAX) { + if (MemoryPtr < Config->MaxMemory) + MemoryPtr = Config->MaxMemory; + uint32_t MaxSize = alignTo(MemoryPtr, WasmPageSize); + MaxMemoryPages = MaxSize / WasmPageSize; + debugPrint("mem: max pages = %d\n", MaxMemoryPages); + } } SyntheticSection *Writer::createSyntheticSection(uint32_t Type,