[AsmPrinter][ELF] Define local aliases (.Lfoo$local) for GlobalObjects
For `MC_GlobalAddress` operands referencing **certain** GlobalObjects,
we can lower them to STB_LOCAL aliases to avoid costs brought by
assembler/linker's conservative decisions about symbol interposition:
* An assembler conservatively assumes a global default visibility symbol interposable (ELF
semantics). So relocations in object files are needed even if the code generator assumed
the definition exact and non-interposable.
* The relocations can cause the creation of PLT entries on some targets for -shared links.
A linker conservatively assumes a global default visibility symbol interposable (if not
otherwise constrained by -Bsymbolic/--dynamic-list/VER_NDX_LOCAL/etc).
"certain" refers to GlobalObjects in the intersection of
`hasExactDefinition() and !isInterposable()`: `external`, `appending`, `internal`, `private`.
Local linkages (`internal` and `private`) cannot be interposed. `appending` is for very
few objects LLVM interpret specially. So the set just includes `external`.
This patch emits STB_LOCAL aliases (.Lfoo$local) for such GlobalObjects, so that targets can lower
MC_GlobalAddress operands to STB_LOCAL aliases if applicable.
We may extend the scope and include GlobalAlias in the future.
LLVM's existing -fno-semantic-interposition behaviors give us license to do such optimizations:
* Various optimizations (ipconstprop, inliner, sccp, sroa, etc) treat normal ExternalLinkage
GlobalObjects as non-interposable.
* Before D72197, MC resolved a PC-relative VK_None fixup to a non-local symbol at assembly time (no
outstanding relocation), if the target is defined in the same section. Put it simply, even if IR
optimizations failed to optimize and allowed interposition for the function call in
`void foo() {} void bar() { foo(); }`, the assembler would disallow it.
This patch sets up AsmPrinter infrastructure to make -fno-semantic-interposition more so.
With and without the patch, the object file output should be identical:
`.Lfoo$local` does not take a symbol table entry.
Reviewed By: sfertile
Differential Revision: https://reviews.llvm.org/D73228
2020-01-23 04:26:04 +08:00
|
|
|
; RUN: llc -mtriple x86_64-pc-linux -relocation-model=static < %s | \
|
|
|
|
; RUN: FileCheck --check-prefixes=COMMON,STATIC %s
|
|
|
|
; RUN: llc -mtriple x86_64-pc-linux -relocation-model=pic < %s | \
|
|
|
|
; RUN: FileCheck --check-prefixes=COMMON,CHECK %s
|
|
|
|
; RUN: llc -mtriple x86_64-pc-linux -relocation-model=dynamic-no-pic < %s | \
|
|
|
|
; RUN: FileCheck --check-prefixes=COMMON,CHECK %s
|
2017-10-26 23:00:26 +08:00
|
|
|
|
|
|
|
; 32 bits
|
|
|
|
|
|
|
|
; RUN: llc -mtriple i386-pc-linux \
|
|
|
|
; RUN: -relocation-model=pic < %s | FileCheck --check-prefix=CHECK32 %s
|
|
|
|
|
|
|
|
; globals
|
|
|
|
|
|
|
|
@strong_default_global = global i32 42
|
|
|
|
define i32* @get_strong_default_global() {
|
|
|
|
ret i32* @strong_default_global
|
|
|
|
}
|
|
|
|
; CHECK: movq strong_default_global@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $strong_default_global, %eax
|
|
|
|
; CHECK32: movl strong_default_global@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@weak_default_global = weak global i32 42
|
|
|
|
define i32* @get_weak_default_global() {
|
|
|
|
ret i32* @weak_default_global
|
|
|
|
}
|
|
|
|
; CHECK: movq weak_default_global@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $weak_default_global, %eax
|
|
|
|
; CHECK32: movl weak_default_global@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@external_default_global = external global i32
|
|
|
|
define i32* @get_external_default_global() {
|
|
|
|
ret i32* @external_default_global
|
|
|
|
}
|
|
|
|
; CHECK: movq external_default_global@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $external_default_global, %eax
|
|
|
|
; CHECK32: movl external_default_global@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@strong_local_global = dso_local global i32 42
|
|
|
|
define i32* @get_strong_local_global() {
|
|
|
|
ret i32* @strong_local_global
|
|
|
|
}
|
2020-01-23 04:27:17 +08:00
|
|
|
; CHECK: leaq .Lstrong_local_global$local(%rip), %rax
|
|
|
|
; STATIC: movl $.Lstrong_local_global$local, %eax
|
|
|
|
; CHECK32: leal .Lstrong_local_global$local@GOTOFF(%eax), %eax
|
2017-10-26 23:00:26 +08:00
|
|
|
|
|
|
|
@weak_local_global = weak dso_local global i32 42
|
|
|
|
define i32* @get_weak_local_global() {
|
|
|
|
ret i32* @weak_local_global
|
|
|
|
}
|
|
|
|
; CHECK: leaq weak_local_global(%rip), %rax
|
|
|
|
; STATIC: movl $weak_local_global, %eax
|
|
|
|
; CHECK32: leal weak_local_global@GOTOFF(%eax), %eax
|
|
|
|
|
|
|
|
@external_local_global = external dso_local global i32
|
|
|
|
define i32* @get_external_local_global() {
|
|
|
|
ret i32* @external_local_global
|
|
|
|
}
|
|
|
|
; CHECK: leaq external_local_global(%rip), %rax
|
|
|
|
; STATIC: movl $external_local_global, %eax
|
|
|
|
; CHECK32: leal external_local_global@GOTOFF(%eax), %eax
|
|
|
|
|
|
|
|
|
|
|
|
@strong_preemptable_global = dso_preemptable global i32 42
|
|
|
|
define i32* @get_strong_preemptable_global() {
|
|
|
|
ret i32* @strong_preemptable_global
|
|
|
|
}
|
|
|
|
; CHECK: movq strong_preemptable_global@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $strong_preemptable_global, %eax
|
|
|
|
; CHECK32: movl strong_preemptable_global@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@weak_preemptable_global = weak dso_preemptable global i32 42
|
|
|
|
define i32* @get_weak_preemptable_global() {
|
|
|
|
ret i32* @weak_preemptable_global
|
|
|
|
}
|
|
|
|
; CHECK ;ADD_LABEL_BACK; movq weak_preemptable_global@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC ;ADD_LABEL_BACK; movq weak_preemptable_global@GOTPCREL, %rax
|
|
|
|
; CHECK32 ;ADD_LABEL_BACK; movl weak_preemptable_global@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@external_preemptable_global = external dso_preemptable global i32
|
|
|
|
define i32* @get_external_preemptable_global() {
|
|
|
|
ret i32* @external_preemptable_global
|
|
|
|
}
|
|
|
|
; CHECK: movq external_preemptable_global@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $external_preemptable_global, %eax
|
|
|
|
; CHECK32: movl external_preemptable_global@GOT(%eax), %eax
|
|
|
|
|
|
|
|
; aliases
|
|
|
|
@aliasee = global i32 42
|
|
|
|
|
|
|
|
@strong_default_alias = alias i32, i32* @aliasee
|
|
|
|
define i32* @get_strong_default_alias() {
|
|
|
|
ret i32* @strong_default_alias
|
|
|
|
}
|
|
|
|
; CHECK: movq strong_default_alias@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $strong_default_alias, %eax
|
|
|
|
; CHECK32: movl strong_default_alias@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@weak_default_alias = weak alias i32, i32* @aliasee
|
|
|
|
define i32* @get_weak_default_alias() {
|
|
|
|
ret i32* @weak_default_alias
|
|
|
|
}
|
|
|
|
; CHECK: movq weak_default_alias@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $weak_default_alias, %eax
|
|
|
|
; CHECK32: movl weak_default_alias@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@strong_local_alias = dso_local alias i32, i32* @aliasee
|
|
|
|
define i32* @get_strong_local_alias() {
|
|
|
|
ret i32* @strong_local_alias
|
|
|
|
}
|
2020-02-12 08:07:06 +08:00
|
|
|
; CHECK: leaq .Lstrong_local_alias$local(%rip), %rax
|
|
|
|
; STATIC: movl $.Lstrong_local_alias$local, %eax
|
|
|
|
; CHECK32: leal .Lstrong_local_alias$local@GOTOFF(%eax), %eax
|
2017-10-26 23:00:26 +08:00
|
|
|
|
|
|
|
@weak_local_alias = weak dso_local alias i32, i32* @aliasee
|
|
|
|
define i32* @get_weak_local_alias() {
|
|
|
|
ret i32* @weak_local_alias
|
|
|
|
}
|
|
|
|
; CHECK: leaq weak_local_alias(%rip), %rax
|
|
|
|
; STATIC: movl $weak_local_alias, %eax
|
|
|
|
; CHECK32: leal weak_local_alias@GOTOFF(%eax), %eax
|
|
|
|
|
|
|
|
|
|
|
|
@strong_preemptable_alias = dso_preemptable alias i32, i32* @aliasee
|
|
|
|
define i32* @get_strong_preemptable_alias() {
|
|
|
|
ret i32* @strong_preemptable_alias
|
|
|
|
}
|
|
|
|
; CHECK: movq strong_preemptable_alias@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $strong_preemptable_alias, %eax
|
|
|
|
; CHECK32: movl strong_preemptable_alias@GOT(%eax), %eax
|
|
|
|
|
|
|
|
@weak_preemptable_alias = weak dso_preemptable alias i32, i32* @aliasee
|
|
|
|
define i32* @get_weak_preemptable_alias() {
|
|
|
|
ret i32* @weak_preemptable_alias
|
|
|
|
}
|
|
|
|
; CHECK: movq weak_preemptable_alias@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $weak_preemptable_alias, %eax
|
|
|
|
; CHECK32: movl weak_preemptable_alias@GOT(%eax), %eax
|
|
|
|
|
|
|
|
; functions
|
|
|
|
|
|
|
|
define void @strong_default_function() {
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define void()* @get_strong_default_function() {
|
|
|
|
ret void()* @strong_default_function
|
|
|
|
}
|
|
|
|
; CHECK: movq strong_default_function@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $strong_default_function, %eax
|
|
|
|
; CHECK32: movl strong_default_function@GOT(%eax), %eax
|
|
|
|
|
|
|
|
define weak void @weak_default_function() {
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define void()* @get_weak_default_function() {
|
|
|
|
ret void()* @weak_default_function
|
|
|
|
}
|
|
|
|
; CHECK: movq weak_default_function@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $weak_default_function, %eax
|
|
|
|
; CHECK32: movl weak_default_function@GOT(%eax), %eax
|
|
|
|
|
|
|
|
declare void @external_default_function()
|
|
|
|
define void()* @get_external_default_function() {
|
|
|
|
ret void()* @external_default_function
|
|
|
|
}
|
|
|
|
; CHECK: movq external_default_function@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $external_default_function, %eax
|
|
|
|
; CHECK32: movl external_default_function@GOT(%eax), %eax
|
|
|
|
|
|
|
|
define dso_local void @strong_local_function() {
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define void()* @get_strong_local_function() {
|
|
|
|
ret void()* @strong_local_function
|
|
|
|
}
|
[AsmPrinter][ELF] Define local aliases (.Lfoo$local) for GlobalObjects
For `MC_GlobalAddress` operands referencing **certain** GlobalObjects,
we can lower them to STB_LOCAL aliases to avoid costs brought by
assembler/linker's conservative decisions about symbol interposition:
* An assembler conservatively assumes a global default visibility symbol interposable (ELF
semantics). So relocations in object files are needed even if the code generator assumed
the definition exact and non-interposable.
* The relocations can cause the creation of PLT entries on some targets for -shared links.
A linker conservatively assumes a global default visibility symbol interposable (if not
otherwise constrained by -Bsymbolic/--dynamic-list/VER_NDX_LOCAL/etc).
"certain" refers to GlobalObjects in the intersection of
`hasExactDefinition() and !isInterposable()`: `external`, `appending`, `internal`, `private`.
Local linkages (`internal` and `private`) cannot be interposed. `appending` is for very
few objects LLVM interpret specially. So the set just includes `external`.
This patch emits STB_LOCAL aliases (.Lfoo$local) for such GlobalObjects, so that targets can lower
MC_GlobalAddress operands to STB_LOCAL aliases if applicable.
We may extend the scope and include GlobalAlias in the future.
LLVM's existing -fno-semantic-interposition behaviors give us license to do such optimizations:
* Various optimizations (ipconstprop, inliner, sccp, sroa, etc) treat normal ExternalLinkage
GlobalObjects as non-interposable.
* Before D72197, MC resolved a PC-relative VK_None fixup to a non-local symbol at assembly time (no
outstanding relocation), if the target is defined in the same section. Put it simply, even if IR
optimizations failed to optimize and allowed interposition for the function call in
`void foo() {} void bar() { foo(); }`, the assembler would disallow it.
This patch sets up AsmPrinter infrastructure to make -fno-semantic-interposition more so.
With and without the patch, the object file output should be identical:
`.Lfoo$local` does not take a symbol table entry.
Reviewed By: sfertile
Differential Revision: https://reviews.llvm.org/D73228
2020-01-23 04:26:04 +08:00
|
|
|
; COMMON: {{^}}strong_local_function:
|
|
|
|
; COMMON-NEXT .Lstrong_local_function:
|
2020-01-23 04:27:17 +08:00
|
|
|
; CHECK: leaq .Lstrong_local_function$local(%rip), %rax
|
|
|
|
; STATIC: movl $.Lstrong_local_function$local, %eax
|
|
|
|
; CHECK32: leal .Lstrong_local_function$local@GOTOFF(%eax), %eax
|
2017-10-26 23:00:26 +08:00
|
|
|
|
|
|
|
define weak dso_local void @weak_local_function() {
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define void()* @get_weak_local_function() {
|
|
|
|
ret void()* @weak_local_function
|
|
|
|
}
|
|
|
|
; CHECK: leaq weak_local_function(%rip), %rax
|
|
|
|
; STATIC: movl $weak_local_function, %eax
|
|
|
|
; CHECK32: leal weak_local_function@GOTOFF(%eax), %eax
|
|
|
|
|
|
|
|
declare dso_local void @external_local_function()
|
|
|
|
define void()* @get_external_local_function() {
|
|
|
|
ret void()* @external_local_function
|
|
|
|
}
|
|
|
|
; CHECK: leaq external_local_function(%rip), %rax
|
|
|
|
; STATIC: movl $external_local_function, %eax
|
|
|
|
; CHECK32: leal external_local_function@GOTOFF(%eax), %eax
|
|
|
|
|
|
|
|
|
|
|
|
define dso_preemptable void @strong_preemptable_function() {
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define void()* @get_strong_preemptable_function() {
|
|
|
|
ret void()* @strong_preemptable_function
|
|
|
|
}
|
|
|
|
; CHECK: movq strong_preemptable_function@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $strong_preemptable_function, %eax
|
|
|
|
; CHECK32: movl strong_preemptable_function@GOT(%eax), %eax
|
|
|
|
|
|
|
|
define weak dso_preemptable void @weak_preemptable_function() {
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define void()* @get_weak_preemptable_function() {
|
|
|
|
ret void()* @weak_preemptable_function
|
|
|
|
}
|
|
|
|
; CHECK: movq weak_preemptable_function@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $weak_preemptable_function, %eax
|
|
|
|
; CHECK32: movl weak_preemptable_function@GOT(%eax), %eax
|
|
|
|
|
|
|
|
declare dso_preemptable void @external_preemptable_function()
|
|
|
|
define void()* @get_external_preemptable_function() {
|
|
|
|
ret void()* @external_preemptable_function
|
|
|
|
}
|
|
|
|
; CHECK: movq external_preemptable_function@GOTPCREL(%rip), %rax
|
|
|
|
; STATIC: movl $external_preemptable_function, %eax
|
|
|
|
; CHECK32: movl external_preemptable_function@GOT(%eax), %eax
|
[AsmPrinter][ELF] Define local aliases (.Lfoo$local) for GlobalObjects
For `MC_GlobalAddress` operands referencing **certain** GlobalObjects,
we can lower them to STB_LOCAL aliases to avoid costs brought by
assembler/linker's conservative decisions about symbol interposition:
* An assembler conservatively assumes a global default visibility symbol interposable (ELF
semantics). So relocations in object files are needed even if the code generator assumed
the definition exact and non-interposable.
* The relocations can cause the creation of PLT entries on some targets for -shared links.
A linker conservatively assumes a global default visibility symbol interposable (if not
otherwise constrained by -Bsymbolic/--dynamic-list/VER_NDX_LOCAL/etc).
"certain" refers to GlobalObjects in the intersection of
`hasExactDefinition() and !isInterposable()`: `external`, `appending`, `internal`, `private`.
Local linkages (`internal` and `private`) cannot be interposed. `appending` is for very
few objects LLVM interpret specially. So the set just includes `external`.
This patch emits STB_LOCAL aliases (.Lfoo$local) for such GlobalObjects, so that targets can lower
MC_GlobalAddress operands to STB_LOCAL aliases if applicable.
We may extend the scope and include GlobalAlias in the future.
LLVM's existing -fno-semantic-interposition behaviors give us license to do such optimizations:
* Various optimizations (ipconstprop, inliner, sccp, sroa, etc) treat normal ExternalLinkage
GlobalObjects as non-interposable.
* Before D72197, MC resolved a PC-relative VK_None fixup to a non-local symbol at assembly time (no
outstanding relocation), if the target is defined in the same section. Put it simply, even if IR
optimizations failed to optimize and allowed interposition for the function call in
`void foo() {} void bar() { foo(); }`, the assembler would disallow it.
This patch sets up AsmPrinter infrastructure to make -fno-semantic-interposition more so.
With and without the patch, the object file output should be identical:
`.Lfoo$local` does not take a symbol table entry.
Reviewed By: sfertile
Differential Revision: https://reviews.llvm.org/D73228
2020-01-23 04:26:04 +08:00
|
|
|
|
|
|
|
; COMMON: {{^}}strong_local_global:
|
|
|
|
; COMMON-NEXT .Lstrong_local_global:
|
2020-02-12 09:17:08 +08:00
|
|
|
|
|
|
|
; COMMON: .globl strong_default_alias
|
|
|
|
; COMMON-NEXT: .set strong_default_alias, aliasee
|
|
|
|
; COMMON-NEXT: .weak weak_default_alias
|
|
|
|
; COMMON-NEXT: .set weak_default_alias, aliasee
|
|
|
|
; COMMON-NEXT: .globl strong_local_alias
|
|
|
|
; COMMON-NEXT: .set strong_local_alias, aliasee
|
2020-02-12 08:07:06 +08:00
|
|
|
; COMMON-NEXT: .set .Lstrong_local_alias$local, aliasee
|
2020-02-12 09:17:08 +08:00
|
|
|
; COMMON-NEXT: .weak weak_local_alias
|
|
|
|
; COMMON-NEXT: .set weak_local_alias, aliasee
|
|
|
|
; COMMON-NEXT: .globl strong_preemptable_alias
|
|
|
|
; COMMON-NEXT: .set strong_preemptable_alias, aliasee
|
|
|
|
; COMMON-NEXT: .weak weak_preemptable_alias
|
|
|
|
; COMMON-NEXT: .set weak_preemptable_alias, aliasee
|