[lld] 6503a68 - [lld/mac] Don't assert when ICFing arm64 code

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 27 11:02:20 PDT 2021


Author: Nico Weber
Date: 2021-10-27T14:02:07-04:00
New Revision: 6503a68565f6ba4e13935ee614a732b6fcb2b30b

URL: https://github.com/llvm/llvm-project/commit/6503a68565f6ba4e13935ee614a732b6fcb2b30b
DIFF: https://github.com/llvm/llvm-project/commit/6503a68565f6ba4e13935ee614a732b6fcb2b30b.diff

LOG: [lld/mac] Don't assert when ICFing arm64 code

WordLiteralSection dedupes literals by content.
WordLiteralInputSection::getOffset() used to read a literal at the passed-in
offset and look up this value in the deduping map to find the offset of the
deduped value.

But it's possible that (e.g.) a 16-byte literal's value is accessed 4 bytes in.
To get the offset at that address, we have to get the deduped value at offset 0
and then apply the offset 4 to the result.

(See also WordLiteralSection::finalizeContents() which fills in those maps.)

Only a problem on arm64 because in x86_64 the offset is part of the instruction
instead of a separate ARM64_RELOC_ADDEND relocation. (See bug for more details.)

Fixes PR51999.

Differential Revision: https://reviews.llvm.org/D112584

Added: 
    lld/test/MachO/icf-arm64.s

Modified: 
    lld/MachO/InputSection.cpp
    lld/MachO/SyntheticSections.h

Removed: 
    


################################################################################
diff  --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index bd75a22878db9..879f7da1c45c5 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -227,14 +227,14 @@ WordLiteralInputSection::WordLiteralInputSection(StringRef segname,
 
 uint64_t WordLiteralInputSection::getOffset(uint64_t off) const {
   auto *osec = cast<WordLiteralSection>(parent);
-  const uint8_t *buf = data.data();
+  const uintptr_t buf = reinterpret_cast<uintptr_t>(data.data());
   switch (sectionType(getFlags())) {
   case S_4BYTE_LITERALS:
-    return osec->getLiteral4Offset(buf + off);
+    return osec->getLiteral4Offset(buf + (off & ~3LLU)) | (off & 3);
   case S_8BYTE_LITERALS:
-    return osec->getLiteral8Offset(buf + off);
+    return osec->getLiteral8Offset(buf + (off & ~7LLU)) | (off & 7);
   case S_16BYTE_LITERALS:
-    return osec->getLiteral16Offset(buf + off);
+    return osec->getLiteral16Offset(buf + (off & ~15LLU)) | (off & 15);
   default:
     llvm_unreachable("invalid literal section type");
   }

diff  --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 0495ee433d3e2..cc7af64a69818 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -562,16 +562,16 @@ class WordLiteralSection final : public SyntheticSection {
            !literal8Map.empty();
   }
 
-  uint64_t getLiteral16Offset(const uint8_t *buf) const {
+  uint64_t getLiteral16Offset(uintptr_t buf) const {
     return literal16Map.at(*reinterpret_cast<const UInt128 *>(buf)) * 16;
   }
 
-  uint64_t getLiteral8Offset(const uint8_t *buf) const {
+  uint64_t getLiteral8Offset(uintptr_t buf) const {
     return literal16Map.size() * 16 +
            literal8Map.at(*reinterpret_cast<const uint64_t *>(buf)) * 8;
   }
 
-  uint64_t getLiteral4Offset(const uint8_t *buf) const {
+  uint64_t getLiteral4Offset(uintptr_t buf) const {
     return literal16Map.size() * 16 + literal8Map.size() * 8 +
            literal4Map.at(*reinterpret_cast<const uint32_t *>(buf)) * 4;
   }

diff  --git a/lld/test/MachO/icf-arm64.s b/lld/test/MachO/icf-arm64.s
new file mode 100644
index 0000000000000..7d74af8ce5bf8
--- /dev/null
+++ b/lld/test/MachO/icf-arm64.s
@@ -0,0 +1,109 @@
+# REQUIRES: aarch64
+# RUN: rm -rf %t; split-file %s %t
+
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin19.0.0 %t/main.s -o %t/main.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin19.0.0 %t/f2.s -o %t/f2.o
+# RUN: %lld -arch arm64 -lSystem --icf=all -o %t/main %t/main.o %t/f2.o
+# RUN: llvm-objdump -d --syms --print-imm-hex %t/main | FileCheck %s
+
+# CHECK-LABEL: SYMBOL TABLE:
+# CHECK: [[#%x,F1_REF:]]                 g     F __TEXT,__text _f1
+# CHECK: [[#%x,F1_REF:]]                 g     F __TEXT,__text _f2
+
+# CHECK-LABEL: Disassembly of section __TEXT,__text:
+# CHECK:        <_main>:
+# CHECK: bl 0x[[#%x,F1_REF:]]
+# CHECK: bl 0x[[#%x,F1_REF:]]
+
+#--- main.s
+
+.subsections_via_symbols
+
+.literal16
+.p2align 3
+L_align16:
+.quad 0xffffffffffffffff
+.short 0xaaaa
+.short 0xaaaa
+.space 4, 0xaa
+
+.literal8
+.p2align 3
+L_align8:
+.quad 0xeeeeeeeeeeeeeeee
+
+.literal4
+.p2align 2
+L_align4:
+.short 0xbbbb
+.short 0xbbbb
+
+
+.text
+.p2align 2
+
+.globl _main, _f1, _f2
+
+## Test that loading from __literalN sections at non-literal boundaries
+## doesn't confuse ICF. This function should be folded with the identical
+## _f2 in f2 (which uses literals of the same value in a 
diff erent isec).
+_f1:
+  adrp x9, L_align16 at PAGE + 4
+  add x9, x9, L_align16 at PAGEOFF + 4
+  ldr x10, [x9]
+
+  adrp x9, L_align8 at PAGE + 4
+  add x9, x9, L_align8 at PAGEOFF + 4
+  ldr w11, [x9]
+
+  adrp x9, L_align4 at PAGE + 2
+  add x9, x9, L_align4 at PAGEOFF + 2
+  ldrh w12, [x9]
+
+  ret
+
+_main:
+  bl _f1
+  bl _f2
+
+#--- f2.s
+
+.subsections_via_symbols
+
+.literal16
+.p2align 3
+L_align16:
+.quad 0xffffffffffffffff
+.short 0xaaaa
+.short 0xaaaa
+.space 4, 170
+
+.literal8
+.p2align 3
+L_align8:
+.quad 0xeeeeeeeeeeeeeeee
+
+.literal4
+.p2align 2
+L_align4:
+.short 0xbbbb
+.short 0xbbbb
+
+.text
+.p2align 2
+
+.globl _f2
+_f2:
+  adrp x9, L_align16 at PAGE + 4
+  add x9, x9, L_align16 at PAGEOFF + 4
+  ldr x10, [x9]
+
+  adrp x9, L_align8 at PAGE + 4
+  add x9, x9, L_align8 at PAGEOFF + 4
+  ldr w11, [x9]
+
+  adrp x9, L_align4 at PAGE + 2
+  add x9, x9, L_align4 at PAGEOFF + 2
+  ldrh w12, [x9]
+
+  ret


        


More information about the llvm-commits mailing list