Index: test/wasm/Inputs/call-indirect.ll =================================================================== --- test/wasm/Inputs/call-indirect.ll +++ 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: test/wasm/Inputs/hidden.ll =================================================================== --- test/wasm/Inputs/hidden.ll +++ test/wasm/Inputs/hidden.ll @@ -2,8 +2,13 @@ target triple = "wasm32-unknown-unknown-wasm" ; Function Attrs: norecurse nounwind readnone -define hidden i32 @ret32(float %arg) #0 { +define hidden i32 @archiveHidden() #0 { +entry: + ret i32 0 +} + +; Function Attrs: norecurse nounwind readnone +define i32 @archiveDefault() #1 { entry: ret i32 0 - ; ptrtoint (i32 (float)* @ret32 to i32) } Index: test/wasm/Inputs/ret32.ll =================================================================== --- test/wasm/Inputs/ret32.ll +++ 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: test/wasm/Inputs/ret64.ll =================================================================== --- test/wasm/Inputs/ret64.ll +++ 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: test/wasm/Inputs/weak-alias.ll =================================================================== --- test/wasm/Inputs/weak-alias.ll +++ 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: test/wasm/call-indirect.ll =================================================================== --- test/wasm/call-indirect.ll +++ 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 Index: test/wasm/entry.ll =================================================================== --- test/wasm/entry.ll +++ 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: test/wasm/visibility-hidden.ll =================================================================== --- /dev/null +++ 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: archiveDefault +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: objectDefault +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Type: \ No newline at end of file Index: test/wasm/weak-external.ll =================================================================== --- test/wasm/weak-external.ll +++ 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 Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -184,7 +184,7 @@ // Inject a new wasm global into the output binary with the given value. // Wasm global are used in relocatable object files to model symbol imports -// and exports. In the final exectuable the only use of wasm globals is the +// and exports. In the final executable the only use of wasm globals is // for the exlicit stack pointer (__stack_pointer). static void addSyntheticGlobal(StringRef Name, int32_t Value) { log("injecting global: " + Name); Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -128,14 +128,14 @@ S->update(Kind, F, Sym, Segment); } else if (Sym->isWeak()) { // the new symbol is weak we can ignore it - DEBUG(dbgs() << "existing symbol takes precensence\n"); + DEBUG(dbgs() << "existing symbol takes precedence\n"); } else if (S->isWeak()) { // the new symbol is not weak and the existing symbol is, so we replace // it DEBUG(dbgs() << "replacing existing weak symbol\n"); S->update(Kind, F, Sym, Segment); } else { - // niether symbol is week. They conflict. + // neither symbol is week. They conflict. reportDuplicate(S, F); } return S; Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -57,6 +57,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: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -83,6 +83,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: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -267,7 +267,8 @@ // 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; uint32_t NumExports = 0; @@ -281,7 +282,7 @@ 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; Sym->WrittenToSymtab = true; ++NumExports; @@ -324,8 +325,8 @@ 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; Sym->WrittenToSymtab = false; log("Export: " + Sym->getName()); @@ -339,9 +340,6 @@ writeExport(OS, Export); } } - - // TODO(sbc): Export local symbols too, Even though they are not part - // of the symbol table? } } @@ -416,7 +414,7 @@ } } -// Create the custome "linking" section containing linker metadata. +// Create the custom "linking" section containing linker metadata. // This is only created when relocatable output is requested. void Writer::createLinkingSection() { SyntheticSection *Section = @@ -487,7 +485,7 @@ } // Fix the memory layout of the output binary. This assigns memory offsets -// to each of the intput data sections as well as the explicit stack region. +// to each of the input data sections as well as the explicit stack region. void Writer::layoutMemory() { uint32_t MemoryPtr = 0; if (!Config->Relocatable) {