aboutsummaryrefslogtreecommitdiff
path: root/lld/test
diff options
context:
space:
mode:
authorJacek Caban <jacek@codeweavers.com>2024-06-18 11:14:01 +0200
committerGitHub <noreply@github.com>2024-06-18 11:14:01 +0200
commitfed8e38c195af5b4806b1088c3ef4d772c0ff450 (patch)
tree7ba4c63060663bb3b4d577acb825196954d45f58 /lld/test
parentaabf6df644d1906aaa8ebe95868e4ef0c262d428 (diff)
downloadllvm-fed8e38c195af5b4806b1088c3ef4d772c0ff450.zip
llvm-fed8e38c195af5b4806b1088c3ef4d772c0ff450.tar.gz
llvm-fed8e38c195af5b4806b1088c3ef4d772c0ff450.tar.bz2
[LLD][COFF] Add support for ARM64EC entry thunks. (#88132)
For x86_64 callable functions, ARM64EC requires an entry thunk generated by the compiler. The linker interprets .hybmp sections to associate function chunks with their entry points and writes an offset to thunks preceding function section contents. Additionally, ICF needs to be aware of entry thunks to not consider chunks to be equal when they have different entry thunks, and GC needs to mark entry thunks together with function chunks. I used a new SectionChunkEC class instead of storing entry thunks in SectionChunk, following the guideline to keep SectionChunk as compact as possible. This way, there is no memory usage increase on non-EC targets.
Diffstat (limited to 'lld/test')
-rw-r--r--lld/test/COFF/arm64ec-entry-thunk.s375
-rw-r--r--lld/test/COFF/arm64ec-hybmp.s114
2 files changed, 489 insertions, 0 deletions
diff --git a/lld/test/COFF/arm64ec-entry-thunk.s b/lld/test/COFF/arm64ec-entry-thunk.s
new file mode 100644
index 0000000..164e6cc
--- /dev/null
+++ b/lld/test/COFF/arm64ec-entry-thunk.s
@@ -0,0 +1,375 @@
+// REQUIRES: aarch64
+// RUN: split-file %s %t.dir && cd %t.dir
+
+#--- test-simple.s
+// Build a simple function with an entry thunk.
+
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ mov w0, #10
+ ret
+
+ .section .hybmp$x, "yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+
+ .data
+ .rva func
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadcfg.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-simple.s -o test-simple.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-simple.dll loadcfg.obj test-simple.obj
+// RUN: llvm-objdump -d out-simple.dll | FileCheck --check-prefix=DISASM %s
+
+// DISASM: Disassembly of section .text:
+// DISASM-EMPTY:
+// DISASM-NEXT: 0000000180001000 <.text>:
+// DISASM-NEXT: 180001000: 00000009 udf #0x9
+// DISASM-NEXT: 180001004: 52800020 mov w0, #0x1 // =1
+// DISASM-NEXT: 180001008: d65f03c0 ret
+// DISASM-NEXT: 18000100c: 52800140 mov w0, #0xa // =10
+// DISASM-NEXT: 180001010: d65f03c0 ret
+
+// RUN: llvm-readobj --sections out-simple.dll | FileCheck --check-prefix=HYBMP %s
+// HYBMP-NOT: .hybmp
+
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out-simplex.dll loadcfg.obj test-simple.obj
+// RUN: llvm-objdump -d out-simplex.dll | FileCheck --check-prefix=DISASM %s
+
+#--- test-split-func.s
+// Build a simple function with an entry thunk, but pass it in multiple files.
+
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+#--- test-split-thunk.s
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ mov w0, #10
+ ret
+
+#--- test-split-hybmp.s
+ .section .hybmp$x, "yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+
+#--- test-split-data.s
+ .data
+ .rva func
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-split-func.s -o test-split-func.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-split-thunk.s -o test-split-thunk.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-split-hybmp.s -o test-split-hybmp.obj
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-split-data.s -o test-split-data.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-split.dll loadcfg.obj \
+// RUN: test-split-func.obj test-split-thunk.obj test-split-data.obj test-split-hybmp.obj
+// RUN: llvm-objdump -d out-split.dll | FileCheck --check-prefix=DISASM %s
+
+#--- test-align.s
+// Build multiple functions with thunks and various alignments and check that entry thunk offsets
+// are correctly placed.
+
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ nop
+ ret
+
+ .section .text,"xr",discard,func2
+ .globl func2
+ .p2align 2
+func2:
+ mov w0, #2
+ ret
+
+ .section .text,"xr",discard,func3
+ .globl func3
+ .p2align 3
+func3:
+ mov w0, #3
+ nop
+ ret
+
+ .section .text,"xr",discard,func4
+ .globl func4
+ .p2align 3
+func4:
+ mov w0, #4
+ ret
+
+ .section .text,"xr",discard,func5
+ .globl func5
+ .p2align 3
+func5:
+ mov w0, #5
+ ret
+
+ .section .text,"xr",discard,func6
+ .globl func6
+ .p2align 4
+func6:
+ mov w0, #6
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ mov w0, #10
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk2
+ .globl thunk2
+ .p2align 2
+thunk2:
+ mov w0, #20
+ ret
+
+ .section .hybmp$x, "yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func2
+ .symidx thunk2
+ .word 1 // entry thunk
+ .symidx func3
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func4
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func5
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func6
+ .symidx thunk
+ .word 1 // entry thunk
+
+ .data
+ .rva func
+ .rva func2
+ .rva func3
+ .rva func4
+ .rva func5
+ .rva func6
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-align.s -o test-align.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-align.dll loadcfg.obj test-align.obj
+// RUN: llvm-objdump -d out-align.dll | FileCheck --check-prefix=ALIGN %s
+
+// ALIGN: Disassembly of section .text:
+// ALIGN-EMPTY:
+// ALIGN-NEXT: 0000000180001000 <.text>:
+// ALIGN-NEXT: 180001000: 00000055 udf #0x55
+// ALIGN-NEXT: 180001004: 52800020 mov w0, #0x1 // =1
+// ALIGN-NEXT: 180001008: d503201f nop
+// ALIGN-NEXT: 18000100c: d65f03c0 ret
+// ALIGN-NEXT: 180001010: 0000004d udf #0x4d
+// ALIGN-NEXT: 180001014: 52800040 mov w0, #0x2 // =2
+// ALIGN-NEXT: 180001018: d65f03c0 ret
+// ALIGN-NEXT: 18000101c: 00000039 udf #0x39
+// ALIGN-NEXT: 180001020: 52800060 mov w0, #0x3 // =3
+// ALIGN-NEXT: 180001024: d503201f nop
+// ALIGN-NEXT: 180001028: d65f03c0 ret
+// ALIGN-NEXT: 18000102c: 00000029 udf #0x29
+// ALIGN-NEXT: 180001030: 52800080 mov w0, #0x4 // =4
+// ALIGN-NEXT: 180001034: d65f03c0 ret
+// ALIGN-NEXT: 180001038: 00000000 udf #0x0
+// ALIGN-NEXT: 18000103c: 00000019 udf #0x19
+// ALIGN-NEXT: 180001040: 528000a0 mov w0, #0x5 // =5
+// ALIGN-NEXT: 180001044: d65f03c0 ret
+// ALIGN-NEXT: 180001048: 00000000 udf #0x0
+// ALIGN-NEXT: 18000104c: 00000009 udf #0x9
+// ALIGN-NEXT: 180001050: 528000c0 mov w0, #0x6 // =6
+// ALIGN-NEXT: 180001054: d65f03c0 ret
+// ALIGN-NEXT: 180001058: 52800140 mov w0, #0xa // =10
+// ALIGN-NEXT: 18000105c: d65f03c0 ret
+// ALIGN-NEXT: 180001060: 52800280 mov w0, #0x14 // =20
+// ALIGN-NEXT: 180001064: d65f03c0 ret
+
+#--- test-icf-thunk.s
+// Build two functions with identical entry thunks and check that thunks are merged by ICF.
+
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+ .section .text,"xr",discard,func2
+ .globl func2
+ .p2align 2
+func2:
+ mov w0, #2
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ mov w0, #10
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk2
+ .globl thunk2
+ .p2align 2
+thunk2:
+ mov w0, #10
+ ret
+
+ .section .hybmp$x, "yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func2
+ .symidx thunk2
+ .word 1 // entry thunk
+
+ .data
+ .rva func
+ .rva func2
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-icf-thunk.s -o test-icf-thunk.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-icf-thunk.dll loadcfg.obj test-icf-thunk.obj
+// RUN: llvm-objdump -d out-icf-thunk.dll | FileCheck --check-prefix=ICF-THUNK %s
+
+// ICF-THUNK: Disassembly of section .text:
+// ICF-THUNK-EMPTY:
+// ICF-THUNK-NEXT: 0000000180001000 <.text>:
+// ICF-THUNK-NEXT: 180001000: 00000015 udf #0x15
+// ICF-THUNK-NEXT: 180001004: 52800020 mov w0, #0x1 // =1
+// ICF-THUNK-NEXT: 180001008: d65f03c0 ret
+// ICF-THUNK-NEXT: 18000100c: 00000009 udf #0x9
+// ICF-THUNK-NEXT: 180001010: 52800040 mov w0, #0x2 // =2
+// ICF-THUNK-NEXT: 180001014: d65f03c0 ret
+// ICF-THUNK-NEXT: 180001018: 52800140 mov w0, #0xa // =10
+// ICF-THUNK-NEXT: 18000101c: d65f03c0 ret
+
+#--- test-icf-diff-thunk.s
+// Build two identical functions with different entry thunks and check that they are not merged by ICF.
+
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+ .section .text,"xr",discard,func2
+ .globl func2
+ .p2align 2
+func2:
+ mov w0, #1
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ mov w0, #10
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk2
+ .globl thunk2
+ .p2align 2
+thunk2:
+ mov w0, #20
+ ret
+
+ .section .hybmp$x, "yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func2
+ .symidx thunk2
+ .word 1 // entry thunk
+
+ .data
+ .rva func
+ .rva func2
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-icf-diff-thunk.s -o test-icf-diff-thunk.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-icf-diff-thunk.dll loadcfg.obj test-icf-diff-thunk.obj
+// RUN: llvm-objdump -d out-icf-diff-thunk.dll | FileCheck --check-prefix=ICF-DIFF-THUNK %s
+
+// ICF-DIFF-THUNK: Disassembly of section .text:
+// ICF-DIFF-THUNK-EMPTY:
+// ICF-DIFF-THUNK-NEXT: 0000000180001000 <.text>:
+// ICF-DIFF-THUNK-NEXT: 180001000: 00000015 udf #0x15
+// ICF-DIFF-THUNK-NEXT: 180001004: 52800020 mov w0, #0x1 // =1
+// ICF-DIFF-THUNK-NEXT: 180001008: d65f03c0 ret
+// ICF-DIFF-THUNK-NEXT: 18000100c: 00000011 udf #0x11
+// ICF-DIFF-THUNK-NEXT: 180001010: 52800020 mov w0, #0x1 // =1
+// ICF-DIFF-THUNK-NEXT: 180001014: d65f03c0 ret
+// ICF-DIFF-THUNK-NEXT: 180001018: 52800140 mov w0, #0xa // =10
+// ICF-DIFF-THUNK-NEXT: 18000101c: d65f03c0 ret
+// ICF-DIFF-THUNK-NEXT: 180001020: 52800280 mov w0, #0x14 // =20
+// ICF-DIFF-THUNK-NEXT: 180001024: d65f03c0 ret
+
+#--- test-icf-both.s
+// Build two identical functions with identical entry thunks and check that they are merged by ICF.
+
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+ .section .text,"xr",discard,func2
+ .globl func2
+ .p2align 2
+func2:
+ mov w0, #1
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ mov w0, #10
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk2
+ .globl thunk2
+ .p2align 2
+thunk2:
+ mov w0, #10
+ ret
+
+ .section .hybmp$x, "yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+ .symidx func2
+ .symidx thunk2
+ .word 1 // entry thunk
+
+ .data
+ .rva func
+ .rva func2
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test-icf-both.s -o test-icf-both.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:out-icf-both.dll loadcfg.obj test-icf-both.obj
+// RUN: llvm-objdump -d out-icf-both.dll | FileCheck --check-prefix=DISASM %s
+
diff --git a/lld/test/COFF/arm64ec-hybmp.s b/lld/test/COFF/arm64ec-hybmp.s
new file mode 100644
index 0000000..5fc24d4
--- /dev/null
+++ b/lld/test/COFF/arm64ec-hybmp.s
@@ -0,0 +1,114 @@
+REQUIRES: aarch64
+RUN: split-file %s %t.dir && cd %t.dir
+
+#--- text-func.s
+ .text
+ .globl func
+ .p2align 2, 0x0
+func:
+ mov w0, #1
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ ret
+
+ .section .hybmp$x,"yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows text-func.s -o text-func.obj
+// RUN: not lld-link -machine:arm64ec -dll -noentry -out:test.dll text-func.obj 2>&1 | FileCheck -check-prefix=FUNC-NON-COMDAT %s
+// FUNC-NON-COMDAT: error: non COMDAT symbol 'func' in hybrid map
+
+#--- offset-func.s
+ .section .text,"xr",discard,func
+ // Add an instruction before func label to make adding entry thunk offset in the padding impossible.
+ mov w0, #2
+ .globl func
+ .p2align 2, 0x0
+func:
+ mov w0, #1
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ ret
+
+ .section .hybmp$x,"yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows offset-func.s -o offset-func.obj
+// RUN: not lld-link -machine:arm64ec -dll -noentry -out:test.dll offset-func.obj 2>&1 | FileCheck -check-prefix=FUNC-NON-COMDAT %s
+
+#--- undef-func.s
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ ret
+
+ .section .hybmp$x,"yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows undef-func.s -o undef-func.obj
+// RUN: not lld-link -machine:arm64ec -dll -noentry -out:test.dll undef-func.obj 2>&1 | FileCheck -check-prefix=UNDEF-FUNC %s
+// UNDEF-FUNC: error: undefined symbol: func
+
+#--- undef-thunk.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2, 0x0
+func:
+ mov w0, #1
+ ret
+
+ .section .hybmp$x,"yi"
+ .symidx func
+ .symidx thunk
+ .word 1 // entry thunk
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows undef-thunk.s -o undef-thunk.obj
+// RUN: not lld-link -machine:arm64ec -dll -noentry -out:test.dll undef-thunk.obj 2>&1 | FileCheck -check-prefix=UNDEF-THUNK %s
+// UNDEF-THUNK: error: undefined symbol: thunk
+
+#--- invalid-type.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2, 0x0
+func:
+ mov w0, #1
+ ret
+
+ .section .wowthk$aa,"xr",discard,thunk
+ .globl thunk
+ .p2align 2
+thunk:
+ ret
+
+ .section .hybmp$x,"yi"
+ .symidx func
+ .symidx thunk
+ .word 3
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows invalid-type.s -o invalid-type.obj
+// RUN: lld-link -machine:arm64ec -dll -noentry -out:test.dll invalid-type.obj 2>&1 | FileCheck -check-prefix=INVALID-TYPE %s
+// INVALID-TYPE: warning: Ignoring unknown EC thunk type 3
+
+#--- invalid-size.s
+ .section .hybmp$x,"yi"
+ .symidx func
+ .symidx thunk
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows invalid-size.s -o invalid-size.obj
+// RUN: not lld-link -machine:arm64ec -dll -noentry -out:test.dll invalid-size.obj 2>&1 | FileCheck -check-prefix=INVALID-SIZE %s
+// INVALID-SIZE: error: Invalid .hybmp chunk size 8