From 4b27c0554ccdb0c8a380c9b2a9d242674cf66601 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sun, 3 Dec 2017 02:38:04 +0000 Subject: [PATCH] Reland "[WebAssembly] Add support for visibility flag"" Subscribers: jfb, dschuff, jgravelle-google, aheejin, sunfish Differential Revision: https://reviews.llvm.org/D40773 llvm-svn: 319627 --- lld/test/wasm/Inputs/call-indirect.ll | 4 +-- lld/test/wasm/Inputs/hidden.ll | 14 ++++++++ lld/test/wasm/Inputs/ret32.ll | 2 +- lld/test/wasm/Inputs/ret64.ll | 2 +- lld/test/wasm/Inputs/weak-alias.ll | 2 +- lld/test/wasm/call-indirect.ll | 12 +++---- lld/test/wasm/entry.ll | 2 +- lld/test/wasm/visibility-hidden.ll | 46 +++++++++++++++++++++++++++ lld/test/wasm/weak-alias-overide.ll | 6 ++-- lld/test/wasm/weak-alias.ll | 6 ++-- lld/test/wasm/weak-external.ll | 12 +++---- lld/wasm/Symbols.cpp | 2 ++ lld/wasm/Symbols.h | 1 + lld/wasm/Writer.cpp | 41 +++++++++++------------- 14 files changed, 105 insertions(+), 47 deletions(-) create mode 100644 lld/test/wasm/Inputs/hidden.ll create mode 100644 lld/test/wasm/visibility-hidden.ll diff --git a/lld/test/wasm/Inputs/call-indirect.ll b/lld/test/wasm/Inputs/call-indirect.ll index 1ffd2427ce69..13e5987116ae 100644 --- a/lld/test/wasm/Inputs/call-indirect.ll +++ b/lld/test/wasm/Inputs/call-indirect.ll @@ -4,13 +4,13 @@ target triple = "wasm32-unknown-unknown-wasm" @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 diff --git a/lld/test/wasm/Inputs/hidden.ll b/lld/test/wasm/Inputs/hidden.ll new file mode 100644 index 000000000000..a2dd10fff989 --- /dev/null +++ b/lld/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 +} diff --git a/lld/test/wasm/Inputs/ret32.ll b/lld/test/wasm/Inputs/ret32.ll index fd840de97c06..dd891d7d0f57 100644 --- a/lld/test/wasm/Inputs/ret32.ll +++ b/lld/test/wasm/Inputs/ret32.ll @@ -2,7 +2,7 @@ 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 @ret32(float %arg) #0 { +define i32 @ret32(float %arg) #0 { entry: ret i32 0 ; ptrtoint (i32 (float)* @ret32 to i32) diff --git a/lld/test/wasm/Inputs/ret64.ll b/lld/test/wasm/Inputs/ret64.ll index 8ece8d7cf9c3..7cf1a9526dc0 100644 --- a/lld/test/wasm/Inputs/ret64.ll +++ b/lld/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 } diff --git a/lld/test/wasm/Inputs/weak-alias.ll b/lld/test/wasm/Inputs/weak-alias.ll index 86664b489d00..c2c454037149 100644 --- a/lld/test/wasm/Inputs/weak-alias.ll +++ b/lld/test/wasm/Inputs/weak-alias.ll @@ -5,7 +5,7 @@ entry: @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 diff --git a/lld/test/wasm/call-indirect.ll b/lld/test/wasm/call-indirect.ll index ecc91dc6933c..38b432b80dcd 100644 --- a/lld/test/wasm/call-indirect.ll +++ b/lld/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 @@ entry: ; 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 @@ entry: ; 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: diff --git a/lld/test/wasm/entry.ll b/lld/test/wasm/entry.ll index 65a1e39f5333..8b3d39e4f85e 100644 --- a/lld/test/wasm/entry.ll +++ b/lld/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 } diff --git a/lld/test/wasm/visibility-hidden.ll b/lld/test/wasm/visibility-hidden.ll new file mode 100644 index 000000000000..ac83d122f973 --- /dev/null +++ b/lld/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: diff --git a/lld/test/wasm/weak-alias-overide.ll b/lld/test/wasm/weak-alias-overide.ll index d929d918181b..7ed3ff1f3805 100644 --- a/lld/test/wasm/weak-alias-overide.ll +++ b/lld/test/wasm/weak-alias-overide.ll @@ -53,12 +53,12 @@ entry: ; 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 diff --git a/lld/test/wasm/weak-alias.ll b/lld/test/wasm/weak-alias.ll index 94907b5ac423..736159d24dd4 100644 --- a/lld/test/wasm/weak-alias.ll +++ b/lld/test/wasm/weak-alias.ll @@ -47,12 +47,12 @@ entry: ; 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 diff --git a/lld/test/wasm/weak-external.ll b/lld/test/wasm/weak-external.ll index a600eaee1a8e..b109a50037d0 100644 --- a/lld/test/wasm/weak-external.ll +++ b/lld/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 @@ entry: ; 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: diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index 78b0de77cf02..ba23e395dd19 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -74,6 +74,8 @@ void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym, 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()); } diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index 29fbdf4b34cb..8e0e6d503b00 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -58,6 +58,7 @@ public: 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; } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 8edcb6ebe3c4..309b10cabc46 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -259,22 +259,26 @@ void Writer::createTableSection() { 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 @@ void Writer::createExportSection() { 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 @@ void Writer::createExportSection() { writeExport(OS, Export); } } - - // TODO(sbc): Export local symbols too, Even though they are not part - // of the symbol table? } }