This commit adds support for chained fixups, which were introduced in Apple's late 2020 OS releases. This format replaces the dyld opcodes used for supplying rebase and binding information, and encodes most of that data directly in the memory location that will have the fixup applied. This reduces binary size and is a requirement for page-in linking, which will be available starting with macOS 13. A high-level overview of the format and my implementation can be found in SyntheticSections.h. This feature is currently gated behind the `-fixup_chains` flag, and will be enabled by default for supported targets in a later commit. Like in ld64, lazy binding is disabled when chained fixups are in use, and the `-init_offsets` transformation is performed by default. Differential Revision: https://reviews.llvm.org/D132560
172 lines
7.1 KiB
ArmAsm
172 lines
7.1 KiB
ArmAsm
# REQUIRES: x86
|
|
# RUN: rm -rf %t; split-file %s %t
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
|
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o
|
|
# RUN: %lld -dylib %t/libfoo.o -o %t/libfoo.dylib
|
|
# RUN: %lld %t/test.o -L%t -lfoo -o %t/test -lSystem
|
|
# RUN: llvm-objdump -d --no-show-raw-insn --rebase --bind --lazy-bind --weak-bind \
|
|
# RUN: --full-contents %t/test | FileCheck --check-prefixes=COMMON,CHECK %s
|
|
|
|
# RUN: %lld -fixup_chains %t/test.o -L%t -lfoo -o %t/chained -lSystem
|
|
# RUN: llvm-objdump -d --no-show-raw-insn --syms --full-contents %t/chained > %t/chained.objdump
|
|
# RUN: llvm-objdump --macho --dyld-info %t/chained >> %t/chained.objdump
|
|
# RUN: FileCheck %s --check-prefixes=COMMON,CHAINED < %t/chained.objdump
|
|
|
|
# CHAINED: SYMBOL TABLE:
|
|
# CHAINED: [[#%x,WEAK_INT:]] l F __TEXT,__text _weak_internal{{$}}
|
|
|
|
# COMMON: Contents of section __DATA_CONST,__got:
|
|
## Check that this section contains a nonzero pointer. It should point to
|
|
## _weak_external_for_gotpcrel.
|
|
# COMMON-NEXT: {{[0-9a-f]+}} {{[0-9a-f ]*[1-9a-f]+[0-9a-f ]*}}
|
|
|
|
# CHECK: Contents of section __DATA,__la_symbol_ptr:
|
|
## Check that this section contains a nonzero pointer. It should point to
|
|
## _weak_external_fn, but we don't have a good way of testing the exact value as
|
|
## the bytes here are in little-endian order.
|
|
# CHECK-NEXT: {{[0-9a-f]+}} {{[0-9a-f ]*[1-9a-f]+[0-9a-f ]*}}
|
|
|
|
# COMMON-LABEL: <_main>:
|
|
# COMMON-NEXT: movq [[#]](%rip), %rax ## 0x[[#%X,WEAK_DY_GOT_ADDR:]]
|
|
# COMMON-NEXT: movq [[#]](%rip), %rax ## 0x[[#%X,WEAK_EXT_GOT_ADDR:]]
|
|
# COMMON-NEXT: leaq [[#]](%rip), %rax ## 0x[[#%X,WEAK_INT_GOT_ADDR:]]
|
|
# COMMON-NEXT: movq [[#]](%rip), %rax ## 0x[[#%X,WEAK_TLV_ADDR:]]
|
|
# COMMON-NEXT: movq [[#]](%rip), %rax ## 0x[[#%X,WEAK_DY_TLV_ADDR:]]
|
|
# COMMON-NEXT: leaq [[#]](%rip), %rax ## 0x[[#%X,WEAK_INT_TLV_ADDR:]]
|
|
# COMMON-NEXT: callq 0x{{[0-9a-f]*}}
|
|
# COMMON-NEXT: callq 0x{{[0-9a-f]*}}
|
|
# COMMON-NEXT: callq 0x{{[0-9a-f]*}}
|
|
|
|
# CHECK-LABEL: Rebase table:
|
|
# CHECK: __DATA __la_symbol_ptr 0x[[#%x,WEAK_EXT_FN:]] pointer
|
|
|
|
# CHECK-LABEL: Bind table:
|
|
# CHECK-DAG: __DATA_CONST __got 0x[[#WEAK_DY_GOT_ADDR]] pointer 0 libfoo _weak_dysym_for_gotpcrel
|
|
# CHECK-DAG: __DATA __la_symbol_ptr 0x[[#%x,WEAK_DY_FN:]] pointer 0 libfoo _weak_dysym_fn
|
|
# CHECK-DAG: __DATA __data 0x[[#%x,WEAK_DY:]] pointer 0 libfoo _weak_dysym
|
|
# CHECK-DAG: __DATA __thread_vars 0x{{[0-9a-f]*}} pointer 0 libSystem __tlv_bootstrap
|
|
# CHECK-DAG: __DATA __thread_vars 0x{{[0-9a-f]*}} pointer 0 libSystem __tlv_bootstrap
|
|
# CHECK-DAG: __DATA __thread_ptrs 0x[[#WEAK_DY_TLV_ADDR]] pointer 0 libfoo _weak_dysym_tlv
|
|
## Check that we don't have any other bindings
|
|
# CHECK-EMPTY:
|
|
|
|
# CHECK-LABEL: Lazy bind table:
|
|
# CHECK-NEXT: segment section address dylib symbol
|
|
## Verify that we have no lazy bindings
|
|
# CHECK-EMPTY:
|
|
|
|
# CHECK-LABEL: Weak bind table:
|
|
# CHECK-DAG: __DATA_CONST __got 0x[[#WEAK_DY_GOT_ADDR]] pointer 0 _weak_dysym_for_gotpcrel
|
|
# CHECK-DAG: __DATA_CONST __got 0x[[#WEAK_EXT_GOT_ADDR]] pointer 0 _weak_external_for_gotpcrel
|
|
# CHECK-DAG: __DATA __data 0x[[#WEAK_DY]] pointer 0 _weak_dysym
|
|
# CHECK-DAG: __DATA __thread_ptrs 0x[[#WEAK_TLV_ADDR]] pointer 0 _weak_tlv
|
|
# CHECK-DAG: __DATA __thread_ptrs 0x[[#WEAK_DY_TLV_ADDR]] pointer 0 _weak_dysym_tlv
|
|
# CHECK-DAG: __DATA __data 0x{{[0-9a-f]*}} pointer 2 _weak_external
|
|
# CHECK-DAG: __DATA __la_symbol_ptr 0x[[#WEAK_DY_FN]] pointer 0 _weak_dysym_fn
|
|
# CHECK-DAG: __DATA __la_symbol_ptr 0x[[#WEAK_EXT_FN]] pointer 0 _weak_external_fn
|
|
## Check that we don't have any other bindings
|
|
# CHECK-EMPTY:
|
|
|
|
## Weak internal symbols don't get bindings
|
|
# RUN: llvm-objdump --macho --bind --lazy-bind --weak-bind %t/test | FileCheck %s --check-prefix=WEAK-INTERNAL
|
|
# WEAK-INTERNAL-NOT: _weak_internal
|
|
# WEAK-INTERNAL-NOT: _weak_internal_fn
|
|
# WEAK-INTERNAL-NOT: _weak_internal_tlv
|
|
|
|
# CHAINED-LABEL: dyld information:
|
|
# CHAINED-NEXT: segment section address pointer type addend dylib symbol/vm address
|
|
# CHAINED-DAG: __DATA_CONST __got 0x{{[0-9a-f]*}} {{.*}} bind 0x0 weak _weak_external_fn
|
|
# CHAINED-DAG: __DATA_CONST __got 0x{{[0-9a-f]*}} {{.*}} bind 0x0 weak _weak_dysym_fn
|
|
# CHAINED-DAG: __DATA_CONST __got 0x[[#WEAK_EXT_GOT_ADDR]] {{.*}} bind 0x0 weak _weak_external_for_gotpcrel
|
|
# CHAINED-DAG: __DATA_CONST __got 0x[[#WEAK_DY_GOT_ADDR]] {{.*}} bind 0x0 weak _weak_dysym_for_gotpcrel
|
|
# CHAINED-DAG: __DATA __data 0x{{[0-9a-f]*}} {{.*}} bind 0x0 weak _weak_dysym
|
|
# CHAINED-DAG: __DATA __data 0x{{[0-9a-f]*}} {{.*}} bind 0x2 weak _weak_external
|
|
# CHAINED-DAG: __DATA __data 0x{{[0-9a-f]*}} {{.*}} rebase 0x[[#%X,WEAK_INT]]
|
|
# CHAINED-DAG: __DATA __thread_vars 0x{{[0-9a-f]*}} {{.*}} bind 0x0 libSystem __tlv_bootstrap
|
|
# CHAINED-DAG: __DATA __thread_vars 0x{{[0-9a-f]*}} {{.*}} bind 0x0 libSystem __tlv_bootstrap
|
|
# CHAINED-DAG: __DATA __thread_ptrs 0x[[#WEAK_DY_TLV_ADDR]] {{.*}} bind 0x0 weak _weak_dysym_tlv
|
|
# CHAINED-DAG: __DATA __thread_ptrs 0x[[#WEAK_TLV_ADDR]] {{.*}} bind 0x0 weak _weak_tlv
|
|
# CHAINED-EMPTY:
|
|
|
|
#--- libfoo.s
|
|
|
|
.globl _weak_dysym
|
|
.weak_definition _weak_dysym
|
|
_weak_dysym:
|
|
.quad 0x1234
|
|
|
|
.globl _weak_dysym_for_gotpcrel
|
|
.weak_definition _weak_dysym_for_gotpcrel
|
|
_weak_dysym_for_gotpcrel:
|
|
.quad 0x1234
|
|
|
|
.globl _weak_dysym_fn
|
|
.weak_definition _weak_dysym_fn
|
|
_weak_dysym_fn:
|
|
ret
|
|
|
|
.section __DATA,__thread_vars,thread_local_variables
|
|
|
|
.globl _weak_dysym_tlv
|
|
.weak_definition _weak_dysym_tlv
|
|
_weak_dysym_tlv:
|
|
.quad 0x1234
|
|
|
|
#--- test.s
|
|
|
|
.globl _main, _weak_external, _weak_external_for_gotpcrel, _weak_external_fn
|
|
.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_external_fn, _weak_internal, _weak_internal_for_gotpcrel, _weak_internal_fn
|
|
|
|
_main:
|
|
mov _weak_dysym_for_gotpcrel@GOTPCREL(%rip), %rax
|
|
mov _weak_external_for_gotpcrel@GOTPCREL(%rip), %rax
|
|
mov _weak_internal_for_gotpcrel@GOTPCREL(%rip), %rax
|
|
mov _weak_tlv@TLVP(%rip), %rax
|
|
mov _weak_dysym_tlv@TLVP(%rip), %rax
|
|
mov _weak_internal_tlv@TLVP(%rip), %rax
|
|
callq _weak_dysym_fn
|
|
callq _weak_external_fn
|
|
callq _weak_internal_fn
|
|
mov $0, %rax
|
|
ret
|
|
|
|
_weak_external:
|
|
.quad 0x1234
|
|
|
|
_weak_external_for_gotpcrel:
|
|
.quad 0x1234
|
|
|
|
_weak_external_fn:
|
|
ret
|
|
|
|
_weak_internal:
|
|
.quad 0x1234
|
|
|
|
_weak_internal_for_gotpcrel:
|
|
.quad 0x1234
|
|
|
|
_weak_internal_fn:
|
|
ret
|
|
|
|
.data
|
|
.quad _weak_dysym
|
|
.quad _weak_external + 2
|
|
.quad _weak_internal
|
|
|
|
.tbss _weak_tlv$tlv$init, 4, 2
|
|
.tbss _weak_internal_tlv$tlv$init, 4, 2
|
|
|
|
.section __DATA,__thread_vars,thread_local_variables
|
|
.globl _weak_tlv
|
|
.weak_definition _weak_tlv, _weak_internal_tlv
|
|
|
|
_weak_tlv:
|
|
.quad __tlv_bootstrap
|
|
.quad 0
|
|
.quad _weak_tlv$tlv$init
|
|
|
|
_weak_internal_tlv:
|
|
.quad __tlv_bootstrap
|
|
.quad 0
|
|
.quad _weak_internal_tlv$tlv$init
|