[WebAssembly] Don't assume that strongly defined symbols are DSO-local

The current PIC model for WebAssembly is more like ELF in that it
allows symbol interposition.

This means that more functions end up being addressed via the GOT
and fewer directly added to the wasm table.

One effect is a reduction in the number of wasm table entries similar
to the previous attempt in https://reviews.llvm.org/D61539 which was
reverted.

Differential Revision: https://reviews.llvm.org/D61772

llvm-svn: 360402
This commit is contained in:
Sam Clegg 2019-05-10 01:52:08 +00:00
parent 2147365484
commit ea38ac5ba3
6 changed files with 27 additions and 16 deletions

View File

@ -11,7 +11,7 @@ target triple = "wasm32-unknown-unknown"
@data_addr = local_unnamed_addr global i32* @data, align 4
@data_addr_external = local_unnamed_addr global i32* @data_external, align 4
define i32 @foo() {
define hidden i32 @foo() {
entry:
; To ensure we use __stack_pointer
%ptr = alloca i32

View File

@ -28,12 +28,12 @@ entry:
ret i32 %0
}
define default i32* @get_data_address() {
define hidden i32* @get_data_address() {
entry:
ret i32* @data_external
}
define default i8* @get_func_address() {
define hidden i8* @get_func_address() {
entry:
ret i8* bitcast (void ()* @func_external to i8*)
}
@ -54,7 +54,7 @@ declare void @func_external()
; CHECK-NEXT: Name: dylink
; CHECK-NEXT: MemorySize: 24
; CHECK-NEXT: MemoryAlignment: 2
; CHECK-NEXT: TableSize: 3
; CHECK-NEXT: TableSize: 2
; CHECK-NEXT: TableAlignment: 0
; CHECK-NEXT: Needed: []
; CHECK-NEXT: - Type: TYPE
@ -74,7 +74,7 @@ declare void @func_external()
; CHECK-NEXT: Table:
; CHECK-NEXT: ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Initial: 0x00000003
; CHECK-NEXT: Initial: 0x00000002
; CHECK-NEXT: - Module: env
; CHECK-NEXT: Field: __stack_pointer
; CHECK-NEXT: Kind: GLOBAL
@ -95,7 +95,7 @@ declare void @func_external()
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: SigIndex: 1
; CHECK-NEXT: - Module: GOT.mem
; CHECK-NEXT: Field: data_external
; CHECK-NEXT: Field: indirect_func
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: true
@ -105,6 +105,11 @@ declare void @func_external()
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: true
; CHECK-NEXT: - Module: GOT.mem
; CHECK-NEXT: Field: data_external
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: true
; CHECK-NEXT: - Module: GOT.mem
; CHECK-NEXT: Field: extern_struct
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: GlobalType: I32
@ -124,7 +129,7 @@ declare void @func_external()
; CHECK-NEXT: - Offset:
; CHECK-NEXT: Opcode: GLOBAL_GET
; CHECK-NEXT: Index: 2
; CHECK-NEXT: Functions: [ 5, 3, 0 ]
; CHECK-NEXT: Functions: [ 4, 3 ]
; check the generated code in __wasm_call_ctors and __wasm_apply_relocs functions
; TODO(sbc): Disassemble and verify instructions.
@ -136,7 +141,7 @@ declare void @func_external()
; CHECK-NEXT: Body: 10020B
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals: []
; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2303360200230141146A230541046A3602000B
; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2305360200230141146A230641046A3602000B
; check the data segment initialized with __memory_base global as offset
@ -147,4 +152,4 @@ declare void @func_external()
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: GLOBAL_GET
; CHECK-NEXT: Index: 1
; CHECK-NEXT: Content: '020000000100000002000000000000000000000000000000'
; CHECK-NEXT: Content: '020000000100000000000000000000000000000000000000'

View File

@ -171,6 +171,8 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
if (Config->Pic && !getFunctionSymbol(Reloc.Index)->hasTableIndex())
return 0;
return getFunctionSymbol(Reloc.Index)->getTableIndex();
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_I32:

View File

@ -1142,6 +1142,10 @@ void Writer::calculateTypes() {
registerType(E->Signature);
}
static bool requiresGOTAccess(const Symbol* Sym) {
return Config->Pic && !Sym->isHidden() && !Sym->isLocal();
}
void Writer::processRelocations(InputChunk *Chunk) {
if (!Chunk->Live)
return;
@ -1153,8 +1157,8 @@ void Writer::processRelocations(InputChunk *Chunk) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB: {
FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index);
if (Sym->hasTableIndex() || !Sym->hasFunctionIndex())
continue;
if (Sym->hasTableIndex() || !Sym->hasFunctionIndex() || requiresGOTAccess(Sym))
break;
Sym->setTableIndex(TableBase + IndirectFunctions.size());
IndirectFunctions.emplace_back(Sym);
break;
@ -1206,7 +1210,7 @@ void Writer::processRelocations(InputChunk *Chunk) {
// will be converted into code by `generateRelocationCode`. This code
// requires the symbols to have GOT entires.
auto* Sym = File->getSymbols()[Reloc.Index];
if (!Sym->isHidden() && !Sym->isLocal() && !Sym->isInGOT()) {
if (requiresGOTAccess(Sym) && !Sym->isInGOT()) {
Sym->setGOTIndex(NumImportedGlobals++);
GOTSymbols.push_back(Sym);
}

View File

@ -167,13 +167,13 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
if (GV && !GV->hasDefaultVisibility())
return true;
if (TT.isOSBinFormatMachO() || TT.isOSBinFormatWasm()) {
if (TT.isOSBinFormatMachO()) {
if (RM == Reloc::Static)
return true;
return GV && GV->isStrongDefinitionForLinker();
}
assert(TT.isOSBinFormatELF());
assert(TT.isOSBinFormatELF() || TT.isOSBinFormatWasm());
assert(RM != Reloc::DynamicNoPIC);
bool IsExecutable =
@ -201,7 +201,7 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
return true;
}
// ELF supports preemption of other symbols.
// ELF & wasm support preemption of other symbols.
return false;
}

View File

@ -7,7 +7,7 @@ declare i32 @foo()
declare i32 @bar()
declare hidden i32 @hidden_function()
@indirect_func = global i32 ()* @foo
@indirect_func = hidden global i32 ()* @foo
@alias_func = hidden alias i32 (), i32 ()* @local_function
define i32 @local_function() {