This patch extends the MachO linker's map file generation to include branch extension thunk symbols. Previously, thunks were omitted from the map file, making it difficult to understand the final layout of the binary, especially when debugging issues related to long branch thunks. This change ensures thunks are included and correctly interleaved with other symbols based on their address, providing an accurate representation of the linked output.
354 lines
8.9 KiB
ArmAsm
354 lines
8.9 KiB
ArmAsm
# REQUIRES: aarch64
|
|
|
|
## Check for the following:
|
|
## (1) address match between thunk definitions and call destinations
|
|
## (2) address match between thunk page+offset computations and function
|
|
## definitions
|
|
## (3) a second thunk is created when the first one goes out of range
|
|
## (4) early calls to a dylib stub use a thunk, and later calls the stub
|
|
## directly
|
|
## (5) Thunks are created for all sections in the text segment with branches.
|
|
## (6) Thunks are in the linker map file.
|
|
## Notes:
|
|
## 0x4000000 = 64 Mi = half the magnitude of the forward-branch range
|
|
|
|
# RUN: rm -rf %t; mkdir %t
|
|
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t/input.o
|
|
# RUN: %lld -arch arm64 -dead_strip -lSystem -U _extern_sym -map %t/thunk.map -o %t/thunk %t/input.o
|
|
# RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t/thunk | FileCheck %s
|
|
|
|
## Check that the thunks appear in the map file and that everything is sorted by address
|
|
# Because of the `.space` instructions, there will end up being a lot of dead symbols in the
|
|
# linker map (linker map will be ~2.7GB). So to avoid the test trying to (slowly) match regex
|
|
# across all the ~2.7GB of the linker map - generate a version of the linker map without dead symbols.
|
|
# RUN: awk '/# Dead Stripped Symbols:/ {exit} {print}' %t/thunk.map > %t/thunk_no_dead_syms.map
|
|
|
|
# RUN: FileCheck %s --input-file %t/thunk_no_dead_syms.map --check-prefix=MAP
|
|
|
|
# MAP: 0x{{[[:xdigit:]]+}} {{.*}} _b
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _c
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _d.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _e.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _f.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _g.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _h.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} ___nan.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _d
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _e
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _f
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _g
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _a.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _b.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _h
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _main
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _c.thunk.0
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _d.thunk.1
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _e.thunk.1
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _f.thunk.1
|
|
# MAP-NEXT: 0x{{[[:xdigit:]]+}} {{.*}} _z
|
|
|
|
|
|
# CHECK: Disassembly of section __TEXT,__text:
|
|
|
|
# CHECK: [[#%.13x, A_PAGE:]][[#%.3x, A_OFFSET:]] <_a>:
|
|
# CHECK: bl 0x[[#%x, A:]] <_a>
|
|
# CHECK: bl 0x[[#%x, B:]] <_b>
|
|
# CHECK: bl 0x[[#%x, C:]] <_c>
|
|
# CHECK: bl 0x[[#%x, D_THUNK_0:]] <_d.thunk.0>
|
|
# CHECK: bl 0x[[#%x, E_THUNK_0:]] <_e.thunk.0>
|
|
# CHECK: bl 0x[[#%x, F_THUNK_0:]] <_f.thunk.0>
|
|
# CHECK: bl 0x[[#%x, G_THUNK_0:]] <_g.thunk.0>
|
|
# CHECK: bl 0x[[#%x, H_THUNK_0:]] <_h.thunk.0>
|
|
# CHECK: bl 0x[[#%x, NAN_THUNK_0:]] <___nan.thunk.0>
|
|
|
|
# CHECK: [[#%.13x, B_PAGE:]][[#%.3x, B_OFFSET:]] <_b>:
|
|
# CHECK: bl 0x[[#%x, A]] <_a>
|
|
# CHECK: bl 0x[[#%x, B]] <_b>
|
|
# CHECK: bl 0x[[#%x, C]] <_c>
|
|
# CHECK: bl 0x[[#%x, D_THUNK_0]] <_d.thunk.0>
|
|
# CHECK: bl 0x[[#%x, E_THUNK_0]] <_e.thunk.0>
|
|
# CHECK: bl 0x[[#%x, F_THUNK_0]] <_f.thunk.0>
|
|
# CHECK: bl 0x[[#%x, G_THUNK_0]] <_g.thunk.0>
|
|
# CHECK: bl 0x[[#%x, H_THUNK_0]] <_h.thunk.0>
|
|
# CHECK: bl 0x[[#%x, NAN_THUNK_0]] <___nan.thunk.0>
|
|
|
|
# CHECK: [[#%.13x, C_PAGE:]][[#%.3x, C_OFFSET:]] <_c>:
|
|
# CHECK: bl 0x[[#%x, A]] <_a>
|
|
# CHECK: bl 0x[[#%x, B]] <_b>
|
|
# CHECK: bl 0x[[#%x, C]] <_c>
|
|
# CHECK: bl 0x[[#%x, D:]] <_d>
|
|
# CHECK: bl 0x[[#%x, E:]] <_e>
|
|
# CHECK: bl 0x[[#%x, F_THUNK_0]] <_f.thunk.0>
|
|
# CHECK: bl 0x[[#%x, G_THUNK_0]] <_g.thunk.0>
|
|
# CHECK: bl 0x[[#%x, H_THUNK_0]] <_h.thunk.0>
|
|
# CHECK: bl 0x[[#%x, NAN_THUNK_0]] <___nan.thunk.0>
|
|
|
|
# CHECK: [[#%x, D_THUNK_0]] <_d.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, D_PAGE:]]
|
|
# CHECK: add x16, x16, #[[#D_OFFSET:]]
|
|
|
|
# CHECK: [[#%x, E_THUNK_0]] <_e.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, E_PAGE:]]
|
|
# CHECK: add x16, x16, #[[#E_OFFSET:]]
|
|
|
|
# CHECK: [[#%x, F_THUNK_0]] <_f.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, F_PAGE:]]
|
|
# CHECK: add x16, x16, #[[#F_OFFSET:]]
|
|
|
|
# CHECK: [[#%x, G_THUNK_0]] <_g.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, G_PAGE:]]
|
|
# CHECK: add x16, x16, #[[#G_OFFSET:]]
|
|
|
|
# CHECK: [[#%x, H_THUNK_0]] <_h.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, H_PAGE:]]
|
|
# CHECK: add x16, x16, #[[#H_OFFSET:]]
|
|
|
|
# CHECK: [[#%x, NAN_THUNK_0]] <___nan.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, NAN_PAGE:]]
|
|
# CHECK: add x16, x16, #[[#NAN_OFFSET:]]
|
|
|
|
# CHECK: [[#%x, D_PAGE + D_OFFSET]] <_d>:
|
|
# CHECK: bl 0x[[#%x, A]] <_a>
|
|
# CHECK: bl 0x[[#%x, B]] <_b>
|
|
# CHECK: bl 0x[[#%x, C]] <_c>
|
|
# CHECK: bl 0x[[#%x, D]] <_d>
|
|
# CHECK: bl 0x[[#%x, E]] <_e>
|
|
# CHECK: bl 0x[[#%x, F_THUNK_0]] <_f.thunk.0>
|
|
# CHECK: bl 0x[[#%x, G_THUNK_0]] <_g.thunk.0>
|
|
# CHECK: bl 0x[[#%x, H_THUNK_0]] <_h.thunk.0>
|
|
# CHECK: bl 0x[[#%x, NAN_THUNK_0]] <___nan.thunk.0>
|
|
|
|
# CHECK: [[#%x, E_PAGE + E_OFFSET]] <_e>:
|
|
# CHECK: bl 0x[[#%x, A_THUNK_0:]] <_a.thunk.0>
|
|
# CHECK: bl 0x[[#%x, B_THUNK_0:]] <_b.thunk.0>
|
|
# CHECK: bl 0x[[#%x, C]] <_c>
|
|
# CHECK: bl 0x[[#%x, D]] <_d>
|
|
# CHECK: bl 0x[[#%x, E]] <_e>
|
|
# CHECK: bl 0x[[#%x, F:]] <_f>
|
|
# CHECK: bl 0x[[#%x, G:]] <_g>
|
|
# CHECK: bl 0x[[#%x, H_THUNK_0]] <_h.thunk.0>
|
|
# CHECK: bl 0x[[#%x, NAN_THUNK_0]] <___nan.thunk.0>
|
|
|
|
# CHECK: [[#%x, F_PAGE + F_OFFSET]] <_f>:
|
|
# CHECK: bl 0x[[#%x, A_THUNK_0]] <_a.thunk.0>
|
|
# CHECK: bl 0x[[#%x, B_THUNK_0]] <_b.thunk.0>
|
|
# CHECK: bl 0x[[#%x, C]] <_c>
|
|
# CHECK: bl 0x[[#%x, D]] <_d>
|
|
# CHECK: bl 0x[[#%x, E]] <_e>
|
|
# CHECK: bl 0x[[#%x, F]] <_f>
|
|
# CHECK: bl 0x[[#%x, G]] <_g>
|
|
# CHECK: bl 0x[[#%x, H_THUNK_0]] <_h.thunk.0>
|
|
# CHECK: bl 0x[[#%x, NAN_THUNK_0]] <___nan.thunk.0>
|
|
|
|
# CHECK: [[#%x, G_PAGE + G_OFFSET]] <_g>:
|
|
# CHECK: bl 0x[[#%x, A_THUNK_0]] <_a.thunk.0>
|
|
# CHECK: bl 0x[[#%x, B_THUNK_0]] <_b.thunk.0>
|
|
# CHECK: bl 0x[[#%x, C_THUNK_0:]] <_c.thunk.0>
|
|
# CHECK: bl 0x[[#%x, D_THUNK_1:]] <_d.thunk.1>
|
|
# CHECK: bl 0x[[#%x, E]] <_e>
|
|
# CHECK: bl 0x[[#%x, F]] <_f>
|
|
# CHECK: bl 0x[[#%x, G]] <_g>
|
|
# CHECK: bl 0x[[#%x, H:]] <_h>
|
|
# CHECK: bl 0x[[#%x, STUBS:]]
|
|
|
|
# CHECK: [[#%x, A_THUNK_0]] <_a.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, A_PAGE]]000
|
|
# CHECK: add x16, x16, #[[#%d, A_OFFSET]]
|
|
|
|
# CHECK: [[#%x, B_THUNK_0]] <_b.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, B_PAGE]]000
|
|
# CHECK: add x16, x16, #[[#%d, B_OFFSET]]
|
|
|
|
# CHECK: [[#%x, H_PAGE + H_OFFSET]] <_h>:
|
|
# CHECK: bl 0x[[#%x, A_THUNK_0]] <_a.thunk.0>
|
|
# CHECK: bl 0x[[#%x, B_THUNK_0]] <_b.thunk.0>
|
|
# CHECK: bl 0x[[#%x, C_THUNK_0]] <_c.thunk.0>
|
|
# CHECK: bl 0x[[#%x, D_THUNK_1]] <_d.thunk.1>
|
|
# CHECK: bl 0x[[#%x, E]] <_e>
|
|
# CHECK: bl 0x[[#%x, F]] <_f>
|
|
# CHECK: bl 0x[[#%x, G]] <_g>
|
|
# CHECK: bl 0x[[#%x, H]] <_h>
|
|
# CHECK: bl 0x[[#%x, STUBS]]
|
|
|
|
# CHECK: <_main>:
|
|
# CHECK: bl 0x[[#%x, A_THUNK_0]] <_a.thunk.0>
|
|
# CHECK: bl 0x[[#%x, B_THUNK_0]] <_b.thunk.0>
|
|
# CHECK: bl 0x[[#%x, C_THUNK_0]] <_c.thunk.0>
|
|
# CHECK: bl 0x[[#%x, D_THUNK_1]] <_d.thunk.1>
|
|
# CHECK: bl 0x[[#%x, E_THUNK_1:]] <_e.thunk.1>
|
|
# CHECK: bl 0x[[#%x, F_THUNK_1:]] <_f.thunk.1>
|
|
# CHECK: bl 0x[[#%x, G]] <_g>
|
|
# CHECK: bl 0x[[#%x, H]] <_h>
|
|
# CHECK: bl 0x[[#%x, STUBS]]
|
|
|
|
# CHECK: [[#%x, C_THUNK_0]] <_c.thunk.0>:
|
|
# CHECK: adrp x16, 0x[[#%x, C_PAGE]]000
|
|
# CHECK: add x16, x16, #[[#%d, C_OFFSET]]
|
|
|
|
# CHECK: [[#%x, D_THUNK_1]] <_d.thunk.1>:
|
|
# CHECK: adrp x16, 0x[[#%x, D_PAGE]]
|
|
# CHECK: add x16, x16, #[[#D_OFFSET]]
|
|
|
|
# CHECK: [[#%x, E_THUNK_1]] <_e.thunk.1>:
|
|
# CHECK: adrp x16, 0x[[#%x, E_PAGE]]
|
|
# CHECK: add x16, x16, #[[#E_OFFSET]]
|
|
|
|
# CHECK: [[#%x, F_THUNK_1]] <_f.thunk.1>:
|
|
# CHECK: adrp x16, 0x[[#%x, F_PAGE]]
|
|
# CHECK: add x16, x16, #[[#F_OFFSET]]
|
|
|
|
# CHECK: Disassembly of section __TEXT,__lcxx_override:
|
|
# CHECK: <_z>:
|
|
# CHECK: bl 0x[[#%x, A_THUNK_0]] <_a.thunk.0>
|
|
|
|
# CHECK: Disassembly of section __TEXT,__stubs:
|
|
|
|
# CHECK: [[#%x, NAN_PAGE + NAN_OFFSET]] <__stubs>:
|
|
|
|
.subsections_via_symbols
|
|
.text
|
|
|
|
.globl _a
|
|
.p2align 2
|
|
_a:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
ret
|
|
|
|
.globl _b
|
|
.p2align 2
|
|
_b:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
.space 0x4000000-0x3c
|
|
ret
|
|
|
|
.globl _c
|
|
.p2align 2
|
|
_c:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
ret
|
|
|
|
.globl _d
|
|
.p2align 2
|
|
_d:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
.space 0x4000000-0x38
|
|
ret
|
|
|
|
.globl _e
|
|
.p2align 2
|
|
_e:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
ret
|
|
|
|
.globl _f
|
|
.p2align 2
|
|
_f:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
.space 0x4000000-0x34
|
|
ret
|
|
|
|
.globl _g
|
|
.p2align 2
|
|
_g:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
ret
|
|
|
|
.globl _h
|
|
.p2align 2
|
|
_h:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
.space 0x4000000-0x30
|
|
ret
|
|
|
|
.globl _main
|
|
.p2align 2
|
|
_main:
|
|
bl _a
|
|
bl _b
|
|
bl _c
|
|
bl _d
|
|
bl _e
|
|
bl _f
|
|
bl _g
|
|
bl _h
|
|
bl ___nan
|
|
ret
|
|
|
|
.section __TEXT,__cstring
|
|
.space 0x4000000
|
|
|
|
.section __TEXT,__lcxx_override,regular,pure_instructions
|
|
|
|
.globl _z
|
|
.no_dead_strip _z
|
|
.p2align 2
|
|
_z:
|
|
bl _a
|
|
## Ensure calling into stubs works
|
|
bl _extern_sym
|
|
ret
|