[lld] 8d29f0f - [lld-macho] Emit REBASE_OPCODE_ADD_ADDR_IMM_SCALED if possible

Daniel Bertalan via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 29 13:29:08 PDT 2022


Author: Daniel Bertalan
Date: 2022-06-29T22:28:39+02:00
New Revision: 8d29f0fdb9c64087687ac80074876d47b16efeab

URL: https://github.com/llvm/llvm-project/commit/8d29f0fdb9c64087687ac80074876d47b16efeab
DIFF: https://github.com/llvm/llvm-project/commit/8d29f0fdb9c64087687ac80074876d47b16efeab.diff

LOG: [lld-macho] Emit REBASE_OPCODE_ADD_ADDR_IMM_SCALED if possible

An ADD_ADDR rebase opcode's argument can be encoded as an immediate if
the offset is less than 15 * word size. This change reduces the size of
chromium_framework by 100+ KiB.

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

Added: 
    lld/test/MachO/rebase-opcodes.s

Modified: 
    lld/MachO/SyntheticSections.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index dabe158d97f56..0a57de319994a 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -202,8 +202,18 @@ static void encodeRebase(const OutputSection *osec, uint64_t outSecOff,
       lastRebase.offset = offset;
     } else {
       assert(lastRebase.offset != offset);
-      os << static_cast<uint8_t>(REBASE_OPCODE_ADD_ADDR_ULEB);
-      encodeULEB128(offset - lastRebase.offset, os);
+      uint64_t delta = offset - lastRebase.offset;
+      // For unknown reasons, ld64 checks if the scaled offset is strictly less
+      // than REBASE_IMMEDIATE_MASK instead of allowing equality. We match this
+      // behavior as a precaution.
+      if ((delta % target->wordSize == 0) &&
+          (delta / target->wordSize < REBASE_IMMEDIATE_MASK)) {
+        os << static_cast<uint8_t>(REBASE_OPCODE_ADD_ADDR_IMM_SCALED |
+                                   (delta / target->wordSize));
+      } else {
+        os << static_cast<uint8_t>(REBASE_OPCODE_ADD_ADDR_ULEB);
+        encodeULEB128(delta, os);
+      }
       lastRebase.offset = offset;
     }
   }

diff  --git a/lld/test/MachO/rebase-opcodes.s b/lld/test/MachO/rebase-opcodes.s
new file mode 100644
index 0000000000000..21b68f7df4867
--- /dev/null
+++ b/lld/test/MachO/rebase-opcodes.s
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+# RUN: %lld -dylib %t.o -o %t.dylib
+# RUN: obj2yaml %t.dylib | FileCheck %s
+
+## Test that:
+## 1/ Consecutive rebases are encoded as REBASE_OPCODE_DO_REBASE_IMM_TIMES.
+## 2/ Gaps smaller than 15 words are encoded as REBASE_OPCODE_ADD_ADDR_IMM_SCALED.
+## 3/ Gaps larger than that become REBASE_OPCODE_ADD_ADDR_ULEB.
+## FIXME: The last rebase could be transformed into a REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB.
+
+# CHECK: RebaseOpcodes:
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_SET_TYPE_IMM
+# CHECK-NEXT: Imm:             1
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+# CHECK-NEXT: Imm:             1
+# CHECK-NEXT: ExtraData:       [ 0x0 ]
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+# CHECK-NEXT: Imm:             1
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+# CHECK-NEXT: Imm:             14
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+# CHECK-NEXT: Imm:             3
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_ADD_ADDR_ULEB
+# CHECK-NEXT: Imm:             0
+# CHECK-NEXT: ExtraData:       [ 0x78 ]
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+# CHECK-NEXT: Imm:             1
+# CHECK-NEXT: Opcode:          REBASE_OPCODE_DONE
+# CHECK-NEXT: Imm:             0
+
+
+.text
+.globl _foo
+_foo:
+
+.data
+.quad _foo
+.space 112
+.quad _foo
+.quad _foo
+.quad _foo
+.space 120
+.quad _foo


        


More information about the llvm-commits mailing list