Index: lld/trunk/test/wasm/Inputs/call-indirect.ll =================================================================== --- lld/trunk/test/wasm/Inputs/call-indirect.ll +++ lld/trunk/test/wasm/Inputs/call-indirect.ll @@ -4,13 +4,13 @@ @indirect_bar = hidden local_unnamed_addr global i32 ()* @bar, align 4 ; Function Attrs: norecurse nounwind readnone -define hidden i32 @bar() #0 { +define i32 @bar() #0 { entry: ret i32 1 } ; Function Attrs: nounwind -define hidden void @call_bar_indirect() local_unnamed_addr #1 { +define void @call_bar_indirect() local_unnamed_addr #1 { entry: %0 = load i32 ()*, i32 ()** @indirect_bar, align 4 %call = tail call i32 %0() #2 Index: lld/trunk/test/wasm/Inputs/hidden.ll =================================================================== --- lld/trunk/test/wasm/Inputs/hidden.ll +++ lld/trunk/test/wasm/Inputs/hidden.ll @@ -0,0 +1,14 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +; Function Attrs: norecurse nounwind readnone +define hidden i32 @archiveHidden() #0 { +entry: + ret i32 0 +} + +; Function Attrs: norecurse nounwind readnone +define i32 @archiveDefault() #1 { +entry: + ret i32 0 +} Index: lld/trunk/test/wasm/Inputs/ret32.ll =================================================================== --- lld/trunk/test/wasm/Inputs/ret32.ll +++ lld/trunk/test/wasm/Inputs/ret32.ll @@ -2,7 +2,7 @@ target triple = "wasm32-unknown-unknown-wasm" ; Function Attrs: norecurse nounwind readnone -define hidden i32 @ret32(float %arg) #0 { +define i32 @ret32(float %arg) #0 { entry: ret i32 0 ; ptrtoint (i32 (float)* @ret32 to i32) Index: lld/trunk/test/wasm/Inputs/ret64.ll =================================================================== --- lld/trunk/test/wasm/Inputs/ret64.ll +++ lld/trunk/test/wasm/Inputs/ret64.ll @@ -1,7 +1,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown-wasm" -define hidden i64 @ret64(double %arg) local_unnamed_addr #0 { +define i64 @ret64(double %arg) local_unnamed_addr #0 { entry: ret i64 1 } Index: lld/trunk/test/wasm/Inputs/weak-alias.ll =================================================================== --- lld/trunk/test/wasm/Inputs/weak-alias.ll +++ lld/trunk/test/wasm/Inputs/weak-alias.ll @@ -5,7 +5,7 @@ @bar = weak alias i32 (), i32 ()* @foo -define hidden i32 @call_bar() #0 { +define i32 @call_bar() #0 { entry: %call = call i32 @bar() ret i32 %call Index: lld/trunk/test/wasm/call-indirect.ll =================================================================== --- lld/trunk/test/wasm/call-indirect.ll +++ lld/trunk/test/wasm/call-indirect.ll @@ -11,16 +11,16 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown-wasm" -@indirect_func = hidden local_unnamed_addr global i32 ()* @foo, align 4 +@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 ; Function Attrs: norecurse nounwind readnone -define hidden i32 @foo() #0 { +define i32 @foo() #0 { entry: ret i32 1 } ; Function Attrs: nounwind -define hidden void @_start() local_unnamed_addr #1 { +define void @_start() local_unnamed_addr #1 { entry: %0 = load i32 ()*, i32 ()** @indirect_func, align 4 %call = tail call i32 %0() #2 @@ -63,6 +63,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: bar ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 @@ -72,9 +75,6 @@ ; CHECK-NEXT: - Name: foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 ; CHECK: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: Index: lld/trunk/test/wasm/entry.ll =================================================================== --- lld/trunk/test/wasm/entry.ll +++ lld/trunk/test/wasm/entry.ll @@ -7,7 +7,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown-wasm" -define hidden void @entry() local_unnamed_addr #0 { +define void @entry() local_unnamed_addr #0 { entry: ret void } Index: lld/trunk/test/wasm/visibility-hidden.ll =================================================================== --- lld/trunk/test/wasm/visibility-hidden.ll +++ lld/trunk/test/wasm/visibility-hidden.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/hidden.ll -o %t2.o +; RUN: llvm-ar rcs %t2.a %t2.o +; RUN: lld -flavor wasm %t.o %t2.a -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; Test that hidden symbols are not exported, whether pulled in from an archive +; or directly. + +define hidden i32 @objectHidden() { +entry: + ret i32 0 +} + +define i32 @objectDefault() { +entry: + ret i32 0 +} + +declare i32 @archiveHidden() +declare i32 @archiveDefault() + +define i32 @_start() { +entry: + %call1 = call i32 @objectHidden() + %call2 = call i32 @objectDefault() + %call3 = call i32 @archiveHidden() + %call4 = call i32 @archiveDefault() + ret i32 0 +} + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: archiveDefault +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: objectDefault +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: Index: lld/trunk/test/wasm/weak-alias-overide.ll =================================================================== --- lld/trunk/test/wasm/weak-alias-overide.ll +++ lld/trunk/test/wasm/weak-alias-overide.ll @@ -53,12 +53,12 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: bar -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: bar +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 Index: lld/trunk/test/wasm/weak-alias.ll =================================================================== --- lld/trunk/test/wasm/weak-alias.ll +++ lld/trunk/test/wasm/weak-alias.ll @@ -47,12 +47,12 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: bar -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: bar +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 Index: lld/trunk/test/wasm/weak-external.ll =================================================================== --- lld/trunk/test/wasm/weak-external.ll +++ lld/trunk/test/wasm/weak-external.ll @@ -9,16 +9,16 @@ declare extern_weak i32 @foo() -define hidden i8* @get_address_of_foo() #0 { +define i8* @get_address_of_foo() #0 { entry: ret i8* bitcast (i32 ()* @foo to i8*) } -define hidden i32* @get_address_of_global_var() #0 { +define i32* @get_address_of_global_var() #0 { ret i32* @global_var } -define hidden i32 @_start() #0 { +define i32 @_start() #0 { entry: %0 = load i32, i32* @global_var, align 4 ret i32 %0 @@ -57,15 +57,15 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: get_address_of_foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: get_address_of_global_var ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: Index: lld/trunk/wasm/Symbols.h =================================================================== --- lld/trunk/wasm/Symbols.h +++ lld/trunk/wasm/Symbols.h @@ -58,6 +58,7 @@ bool isGlobal() const { return !isFunction(); } bool isLocal() const { return IsLocal; } bool isWeak() const; + bool isHidden() const; // Returns the symbol name. StringRef getName() const { return Name; } Index: lld/trunk/wasm/Symbols.cpp =================================================================== --- lld/trunk/wasm/Symbols.cpp +++ lld/trunk/wasm/Symbols.cpp @@ -74,6 +74,8 @@ bool Symbol::isWeak() const { return Sym && Sym->isWeak(); } +bool Symbol::isHidden() const { return Sym && Sym->isHidden(); } + std::string lld::toString(wasm::Symbol &Sym) { return wasm::displayName(Sym.getName()); } Index: lld/trunk/wasm/Writer.cpp =================================================================== --- lld/trunk/wasm/Writer.cpp +++ lld/trunk/wasm/Writer.cpp @@ -259,22 +259,26 @@ void Writer::createExportSection() { // Memory is and main function are exported for executables. bool ExportMemory = !Config->Relocatable && !Config->ImportMemory; - bool ExportMain = !Config->Relocatable; - bool ExportOther = true; // Config->Relocatable; + bool ExportOther = true; // ??? TODO Config->Relocatable; + bool ExportHidden = Config->Relocatable; + Symbol *EntrySym = Symtab->find(Config->Entry); + bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined(); uint32_t NumExports = 0; if (ExportMemory) ++NumExports; - if (ExportMain && !ExportOther) + if (ExportEntry) ++NumExports; if (ExportOther) { for (ObjFile *File : Symtab->ObjectFiles) { for (Symbol *Sym : File->getSymbols()) { if (!Sym->isFunction() || Sym->isLocal() || Sym->isUndefined() || - Sym->WrittenToSymtab) + (Sym->isHidden() && !ExportHidden) || Sym->WrittenToSymtab) + continue; + if (Sym == EntrySym) continue; Sym->WrittenToSymtab = true; ++NumExports; @@ -298,27 +302,21 @@ writeExport(OS, MemoryExport); } - if (ExportMain) { - Symbol *Sym = Symtab->find(Config->Entry); - if (Sym->isDefined()) { - if (!Sym->isFunction()) - fatal("entry point is not a function: " + Sym->getName()); - - if (!ExportOther) { - WasmExport MainExport; - MainExport.Name = Config->Entry; - MainExport.Kind = WASM_EXTERNAL_FUNCTION; - MainExport.Index = Sym->getOutputIndex(); - writeExport(OS, MainExport); - } - } + if (ExportEntry) { + WasmExport EntryExport; + EntryExport.Name = Config->Entry; + EntryExport.Kind = WASM_EXTERNAL_FUNCTION; + EntryExport.Index = EntrySym->getOutputIndex(); + writeExport(OS, EntryExport); } if (ExportOther) { for (ObjFile *File : Symtab->ObjectFiles) { for (Symbol *Sym : File->getSymbols()) { - if (!Sym->isFunction() || Sym->isLocal() | Sym->isUndefined() || - !Sym->WrittenToSymtab) + if (!Sym->isFunction() || Sym->isLocal() || Sym->isUndefined() || + (Sym->isHidden() && !ExportHidden) || !Sym->WrittenToSymtab) + continue; + if (Sym == EntrySym) continue; Sym->WrittenToSymtab = false; log("Export: " + Sym->getName()); @@ -332,9 +330,6 @@ writeExport(OS, Export); } } - - // TODO(sbc): Export local symbols too, Even though they are not part - // of the symbol table? } }