[lld] 321b2be - [lld-macho] Use DO_BIND_ADD_ADDR_IMM_SCALED for bind opcodes

Vincent Lee via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 19 16:19:01 PDT 2021


Author: Vincent Lee
Date: 2021-07-19T16:18:33-07:00
New Revision: 321b2bef098553ec648e4174aae92c63a6e1a810

URL: https://github.com/llvm/llvm-project/commit/321b2bef098553ec648e4174aae92c63a6e1a810
DIFF: https://github.com/llvm/llvm-project/commit/321b2bef098553ec648e4174aae92c63a6e1a810.diff

LOG: [lld-macho] Use DO_BIND_ADD_ADDR_IMM_SCALED for bind opcodes

Implement pass 3 of bind opcodes from ld64 (which supports both 32-bit and 64-bit).
Pass 3 implementation condenses BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB opcode
to BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED.  This change is already behind an
O2 flag so it shouldn't impact current performance. I verified ld64's output with x86_64 LLD
and they were both emitting the same optimized bind opcodes (although in a slightly different
order). Tested with arm64_32 LLD and compared that with x86 LLD that the order of the bind
opcodes are the same (offset values are different which should be expected).

Reviewed By: int3, #lld-macho

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

Added: 
    

Modified: 
    lld/MachO/SyntheticSections.cpp
    lld/test/MachO/bind-opcodes.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index d65cc9c3ced2..47a9b2b6c608 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -360,6 +360,23 @@ static void optimizeOpcodes(std::vector<BindIR> &opcodes) {
   if (i == opcodes.size())
     opcodes[pWrite] = opcodes[i - 1];
   opcodes.resize(pWrite + 1);
+
+  // Pass 3: Use immediate encodings
+  // Every binding is the size of one pointer. If the next binding is a
+  // multiple of wordSize away that is within BIND_IMMEDIATE_MASK, the
+  // opcode can be scaled by wordSize into a single byte and dyld will
+  // expand it to the correct address.
+  for (BindIR *p = &opcodes[0]; p->opcode != BIND_OPCODE_DONE; ++p) {
+    // It's unclear why the check needs to be less than BIND_IMMEDIATE_MASK,
+    // but ld64 currently does this. This could be a potential bug, but
+    // for now, perform the same behavior to prevent mysterious bugs.
+    if ((p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) &&
+        ((p->data / target->wordSize) < BIND_IMMEDIATE_MASK) &&
+        ((p->data % target->wordSize) == 0)) {
+      p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
+      p->data /= target->wordSize;
+    }
+  }
 }
 
 static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) {
@@ -383,6 +400,9 @@ static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) {
     encodeULEB128(op.consecutiveCount, os);
     encodeULEB128(op.data, os);
     break;
+  case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+    os << static_cast<uint8_t>(op.opcode | op.data);
+    break;
   default:
     llvm_unreachable("cannot bind to an unrecognized symbol");
   }

diff  --git a/lld/test/MachO/bind-opcodes.s b/lld/test/MachO/bind-opcodes.s
index b313afbef8e6..0f8467ac5c49 100644
--- a/lld/test/MachO/bind-opcodes.s
+++ b/lld/test/MachO/bind-opcodes.s
@@ -1,15 +1,16 @@
-# REQUIRES: x86
+# REQUIRES: x86, arm
 # RUN: rm -rf %t; split-file %s %t
 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin --defsym PTR64=0 %t/test.s -o %t/test.o
 # RUN: %lld -O2 -dylib %t/foo.o -o %t/libfoo.dylib
-# RUN: %lld -O2 -lSystem %t/test.o %t/libfoo.dylib -o %t/test
+# RUN: %lld -O2 -lSystem %t/test.o %t/libfoo.dylib -o %t/test-x86_64
 
-## Test:
+## Test (64-bit):
 ## 1/ We emit exactly one BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM per symbol.
 ## 2/ Combine BIND_OPCODE_DO_BIND and BIND_OPCODE_ADD_ADDR_ULEB pairs.
 ## 3/ Compact BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
-# RUN: obj2yaml %t/test | FileCheck %s
+## 4/ Use BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED if possible.
+# RUN: obj2yaml %t/test-x86_64 | FileCheck %s
 
 # CHECK:      BindOpcodes:
 # CHECK-NEXT:   Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
@@ -54,9 +55,8 @@
 # CHECK-NEXT:   Imm:             0
 # CHECK-NEXT:   ULEBExtraData:   [ 0xFFFFFFFFFFFFEFD0 ]
 # CHECK-NEXT:   Symbol:          ''
-# CHECK-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
-# CHECK-NEXT:   Imm:             0
-# CHECK-NEXT:   ULEBExtraData:   [ 0x8 ]
+# CHECK-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
+# CHECK-NEXT:   Imm:             1
 # CHECK-NEXT:   Symbol:          ''
 # CHECK-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
 # CHECK-NEXT:   Imm:             0
@@ -69,16 +69,86 @@
 # CHECK-NEXT:   Imm:             0
 # CHECK-NEXT:   Symbol:          ''
 
-# RUN: llvm-objdump --macho --bind %t/test | FileCheck %s --check-prefix=BIND
+# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-darwin %t/foo.s -o %t/foo.o
+# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-darwin --defsym PTR32=0 %t/test.s -o %t/test.o
+# RUN: %lld -arch arm64_32 -O2 -dylib %t/foo.o -o %t/libfoo.dylib
+# RUN: %lld -arch arm64_32 -O2 -dylib %t/test.o %t/libfoo.dylib -o %t/libtest-arm64_32.dylib
+
+## Test (32-bit):
+## 1/ We emit exactly one BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM per symbol.
+## 2/ Combine BIND_OPCODE_DO_BIND and BIND_OPCODE_ADD_ADDR_ULEB pairs.
+## 3/ Compact BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
+## 4/ Use BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED if possible.
+# RUN: obj2yaml %t/libtest-arm64_32.dylib | FileCheck %s --check-prefix=CHECK32
+
+# CHECK32:      BindOpcodes:
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   Symbol:          _foo
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_TYPE_IMM
+# CHECK32-NEXT:   Imm:             1
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+# CHECK32-NEXT:   Imm:             1
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+# CHECK32-NEXT:   Imm:             1
+# CHECK32-NEXT:   ULEBExtraData:   [ 0x0 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   ULEBExtraData:   [ 0x2, 0x4 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_ADDEND_SLEB
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   SLEBExtraData:   [ 1 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   ULEBExtraData:   [ 0x1004 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_ADDEND_SLEB
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   SLEBExtraData:   [ 0 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DO_BIND
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   Symbol:          _bar
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_SET_TYPE_IMM
+# CHECK32-NEXT:   Imm:             1
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_ADD_ADDR_ULEB
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   ULEBExtraData:   [ 0xFFFFFFFFFFFFEFE8 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
+# CHECK32-NEXT:   Imm:             1
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   ULEBExtraData:   [ 0x1004 ]
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DO_BIND
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   Symbol:          ''
+# CHECK32-NEXT:   Opcode:          BIND_OPCODE_DONE
+# CHECK32-NEXT:   Imm:             0
+# CHECK32-NEXT:   Symbol:          ''
+
+# RUN: llvm-objdump --macho --bind %t/test-x86_64 | FileCheck %s -D#PTR=8 --check-prefix=BIND
+# RUN: llvm-objdump --macho --bind %t/libtest-arm64_32.dylib | FileCheck %s -D#PTR=4 --check-prefix=BIND
 # BIND:       Bind table:
-# BIND-NEXT:  segment  section   address      type       addend dylib     symbol
-# BIND-NEXT:  __DATA   __data    0x100001000  pointer         0 libfoo    _foo
-# BIND-NEXT:  __DATA   __data    0x100001010  pointer         0 libfoo    _foo
-# BIND-NEXT:  __DATA   __data    0x100001020  pointer         1 libfoo    _foo
-# BIND-NEXT:  __DATA   __data    0x100002030  pointer         0 libfoo    _foo
-# BIND-NEXT:  __DATA   __data    0x100001008  pointer         0 libfoo    _bar
-# BIND-NEXT:  __DATA   __data    0x100001018  pointer         0 libfoo    _bar
-# BIND-NEXT:  __DATA   __data    0x100002028  pointer         0 libfoo    _bar
+# BIND-NEXT:  segment  section   address                               type       addend dylib     symbol
+# BIND-NEXT:  __DATA   __data    0x[[#%X,DATA:]]                       pointer         0 libfoo    _foo
+# BIND-NEXT:  __DATA   __data    0x[[#%.8X,DATA + mul(PTR, 2)]]        pointer         0 libfoo    _foo
+# BIND-NEXT:  __DATA   __data    0x[[#%.8X,DATA + mul(PTR, 4)]]        pointer         1 libfoo    _foo
+# BIND-NEXT:  __DATA   __data    0x[[#%.8X,DATA + 4096 + mul(PTR, 6)]] pointer         0 libfoo    _foo
+# BIND-NEXT:  __DATA   __data    0x[[#%.8X,DATA + PTR]]                pointer         0 libfoo    _bar
+# BIND-NEXT:  __DATA   __data    0x[[#%.8X,DATA + mul(PTR, 3)]]        pointer         0 libfoo    _bar
+# BIND-NEXT:  __DATA   __data    0x[[#%.8X,DATA + 4096 + mul(PTR, 5)]] pointer         0 libfoo    _bar
 # BIND-EMPTY:
 
 #--- foo.s
@@ -89,15 +159,27 @@ _bar:
   .space 4
 
 #--- test.s
+.ifdef PTR64
+.macro ptr val
+  .quad \val
+.endm
+.endif
+
+.ifdef PTR32
+.macro ptr val
+  .int \val
+.endm
+.endif
+
 .data
-.quad _foo
-.quad _bar
-.quad _foo
-.quad _bar
-.quad _foo+1
+ptr _foo
+ptr _bar
+ptr _foo
+ptr _bar
+ptr _foo+1
 .zero 0x1000
-.quad _bar
-.quad _foo
+ptr _bar
+ptr _foo
 
 .globl _main
 .text


        


More information about the llvm-commits mailing list