summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2023-03-07 11:42:20 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2023-03-08 01:24:58 -0500
commit4158722a6cff5d19e228356c525946b6c4b83396 (patch)
tree0bab715702184f609386d839ac347606edff2223
parent606793d424b08971f1eea4f1fae84b89297e1e63 (diff)
downloadhaskell-4158722a6cff5d19e228356c525946b6c4b83396.tar.gz
linker: fix linking with aligned sections (#23066)
Take section alignment into account instead of assuming 16 bytes (which is wrong when the section requires 32 bytes, cf #23066).
-rw-r--r--rts/linker/Elf.c14
-rw-r--r--testsuite/tests/rts/linker/Makefile5
-rw-r--r--testsuite/tests/rts/linker/T23066.stdout2
-rw-r--r--testsuite/tests/rts/linker/T23066_c.c42
-rw-r--r--testsuite/tests/rts/linker/all.T8
5 files changed, 65 insertions, 6 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index 3595a4c3d4..040107c7f1 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -872,12 +872,14 @@ ocGetNames_ELF ( ObjectCode* oc )
else if (!oc->imageMapped || size < getPageSize() / 3) {
bool executable = kind == SECTIONKIND_CODE_OR_RODATA;
m32_allocator *allocator = executable ? oc->rx_m32 : oc->rw_m32;
- // align on 16 bytes. The reason being that llvm will emit see
- // paddq statements for x86_64 under optimisation and load from
- // RODATA sections. Specifically .rodata.cst16. However we don't
- // handle the cst part in any way what so ever, so 16 seems
- // better than 8.
- start = m32_alloc(allocator, size, 16);
+ // Correctly align the section. This is particularly important for
+ // the alignment of .rodata.cstNN sections.
+ //
+ // llvm will emit see paddq statements for x86_64 under
+ // optimisation and load from RODATA sections, specifically
+ // .rodata.cst16. Also we may encounter .rodata.cst32 sections
+ // in objects using AVX instructions (see #23066).
+ start = m32_alloc(allocator, size, align);
if (start == NULL) goto fail;
memcpy(start, oc->image + offset, size);
alloc = SECTION_M32;
diff --git a/testsuite/tests/rts/linker/Makefile b/testsuite/tests/rts/linker/Makefile
index cc3e118243..c8e113c88c 100644
--- a/testsuite/tests/rts/linker/Makefile
+++ b/testsuite/tests/rts/linker/Makefile
@@ -12,6 +12,11 @@ section_alignment:
'$(TEST_HC)' $(TEST_HC_OPTS_NO_RTSOPTS) -v0 --make -no-rtsopts-suggestions -no-hs-main -o runner runner.c
./runner section_alignment.o isAligned
+T23066:
+ '$(TEST_CC)' $(TEST_CC_OPTS) -c -o T23066_c.o T23066_c.c
+ '$(TEST_HC)' $(TEST_HC_OPTS_NO_RTSOPTS) -v0 --make -no-rtsopts-suggestions -no-hs-main -o runner runner.c -static
+ ./runner T23066_c.o isAligned
+
T2615-prep:
$(RM) libfoo_T2615.so
'$(TEST_HC)' $(TEST_HC_OPTS) -fPIC -c libfoo_T2615.c -o libfoo_T2615.o
diff --git a/testsuite/tests/rts/linker/T23066.stdout b/testsuite/tests/rts/linker/T23066.stdout
new file mode 100644
index 0000000000..e33c5c1e49
--- /dev/null
+++ b/testsuite/tests/rts/linker/T23066.stdout
@@ -0,0 +1,2 @@
+Linking: path = T23066_c.o, symname = isAligned
+1
diff --git a/testsuite/tests/rts/linker/T23066_c.c b/testsuite/tests/rts/linker/T23066_c.c
new file mode 100644
index 0000000000..cd754597c5
--- /dev/null
+++ b/testsuite/tests/rts/linker/T23066_c.c
@@ -0,0 +1,42 @@
+#include<stdint.h>
+#include<stdio.h>
+
+extern int foo32_1, foo32_2;
+
+// The bug in #23066 was that we wouldn't correctly align 32-bytes aligned
+// sections, except by chance (we were always aligning on 16 bytes).
+//
+// Hence we intersperse two 16-bytes aligned sections with two 32-bytes aligned
+// sections to ensure that at least one of the 32-bytes aligned section
+// triggers the bug (the order of the sections seems to be preserved).
+
+__asm__(
+" .section pad16_1,\"aM\",@progbits,16\n\t"
+" .align 16\n\t"
+" .byte 0\n\t"
+"\n\t"
+" .global foo32_1\n\t"
+" .section sfoo32_1,\"aM\",@progbits,32\n\t"
+" .align 32\n\t"
+"foo32_1:\n\t"
+" .byte 0\n\t"
+"\n\t"
+" .section pad16_2,\"aM\",@progbits,16\n\t"
+" .align 16\n\t"
+" .byte 0\n\t"
+"\n\t"
+" .global foo32_2\n\t"
+" .section sfoo32_2,\"aM\",@progbits,32\n\t"
+" .align 32\n\t"
+"foo32_2:\n\t"
+" .byte 0\n\t"
+);
+
+
+#define ALIGN32(x) (((intptr_t)(&x) & 0x1F) == 0)
+
+int isAligned() {
+ //printf("%p\n", &foo32_1);
+ //printf("%p\n", &foo32_2);
+ return (ALIGN32(foo32_1) && ALIGN32(foo32_2));
+}
diff --git a/testsuite/tests/rts/linker/all.T b/testsuite/tests/rts/linker/all.T
index bd51b3ed95..ba17069fd5 100644
--- a/testsuite/tests/rts/linker/all.T
+++ b/testsuite/tests/rts/linker/all.T
@@ -17,6 +17,14 @@ test('section_alignment',
makefile_test, [])
######################################
+test('T23066',
+ [ unless(arch('x86_64'), skip)
+ , unless(opsys('linux'), skip)
+ , extra_files(['runner.c', 'T23066_c.c'])
+ ],
+ makefile_test, [])
+
+######################################
# Test to see if linker scripts link properly to real ELF files
test('T2615',
[extra_files(['libfoo_T2615.c', 'libfoo_script_T2615.so']),