diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -361,6 +361,18 @@ if (i == opcodes.size()) opcodes[pWrite] = opcodes[i - 1]; opcodes.resize(pWrite + 1); + + // Pass 3: Use immediate encodings + size_t offsetWidth = + target->wordSize == 8 ? sizeof(uint64_t) : sizeof(uint32_t); + for (BindIR *p = &opcodes[0]; p->opcode != BIND_OPCODE_DONE; ++p) { + if ((p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) && + (p->data < (BIND_IMMEDIATE_MASK * offsetWidth)) && + ((p->data % offsetWidth) == 0)) { + p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED; + p->data = p->data / offsetWidth; + } + } } static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) { @@ -384,6 +396,9 @@ encodeULEB128(op.consecutiveCount, os); encodeULEB128(op.data, os); break; + case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: + os << static_cast(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 --- a/lld/test/MachO/bind-opcodes.s +++ b/lld/test/MachO/bind-opcodes.s @@ -1,16 +1,79 @@ # REQUIRES: x86 # 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 %t/test-x86_64.s -o %t/test-x86_64.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-x86_64.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 %t/check-x86_64.s +# RUN: llvm-objdump --macho --bind %t/test-x86_64 | FileCheck %s --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-EMPTY: + +# 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 %t/test-arm64_32.s -o %t/test-arm64_32.o +# RUN: %lld-arm64_32 -O2 -dylib %t/foo.o -o %t/libfoo.dylib +# RUN: %lld-arm64_32 -O2 -dylib %t/test-arm64_32.o %t/libfoo.dylib -o %t/libtest-arm-64_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-arm-64_32.dylib | FileCheck %t/check-arm64_32.s + +#--- foo.s +.globl _foo, _bar +_foo: + .space 4 +_bar: + .space 4 + +#--- test-x86_64.s +.data +.quad _foo +.quad _bar +.quad _foo +.quad _bar +.quad _foo+1 +.zero 0x1000 +.quad _bar +.quad _foo + +.globl _main +.text +_main: + +#--- test-arm64_32.s +.data +.int _foo +.int _bar +.int _foo +.int _bar +.int _foo+1 +.zero 0x1000 +.int _bar +.int _foo + +.globl _main +.text +_main: + +#--- check-x86_64.s # CHECK: BindOpcodes: # CHECK-NEXT: Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM # CHECK-NEXT: Imm: 0 @@ -54,9 +117,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,36 +131,60 @@ # CHECK-NEXT: Imm: 0 # CHECK-NEXT: Symbol: '' -# RUN: llvm-objdump --macho --bind %t/test | FileCheck %s --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-EMPTY: - -#--- foo.s -.globl _foo, _bar -_foo: - .space 4 -_bar: - .space 4 - -#--- test.s -.data -.quad _foo -.quad _bar -.quad _foo -.quad _bar -.quad _foo+1 -.zero 0x1000 -.quad _bar -.quad _foo - -.globl _main -.text -_main: +#--- check-arm64_32.s +# CHECK: BindOpcodes: +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: Symbol: _foo +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_TYPE_IMM +# CHECK-NEXT: Imm: 1 +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM +# CHECK-NEXT: Imm: 1 +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB +# CHECK-NEXT: Imm: 1 +# CHECK-NEXT: ULEBExtraData: [ 0x0 ] +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: ULEBExtraData: [ 0x2, 0x4 ] +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_ADDEND_SLEB +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: SLEBExtraData: [ 1 ] +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: ULEBExtraData: [ 0x1004 ] +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_ADDEND_SLEB +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: SLEBExtraData: [ 0 ] +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_DO_BIND +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: Symbol: _bar +# CHECK-NEXT: Opcode: BIND_OPCODE_SET_TYPE_IMM +# CHECK-NEXT: Imm: 1 +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_ADD_ADDR_ULEB +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: ULEBExtraData: [ 0xFFFFFFFFFFFFEFE8 ] +# CHECK-NEXT: Symbol: '' +# 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 +# CHECK-NEXT: ULEBExtraData: [ 0x1004 ] +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_DO_BIND +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: Symbol: '' +# CHECK-NEXT: Opcode: BIND_OPCODE_DONE +# CHECK-NEXT: Imm: 0 +# CHECK-NEXT: Symbol: '' diff --git a/lld/test/MachO/lit.local.cfg b/lld/test/MachO/lit.local.cfg --- a/lld/test/MachO/lit.local.cfg +++ b/lld/test/MachO/lit.local.cfg @@ -15,8 +15,13 @@ os.path.join(config.test_source_root, "MachO", "Inputs", "WatchOS.sdk"))) # Since most of our tests are written around x86_64, we give this platform the -# shortest substitution of "%lld". -lld = ('ld64.lld -arch x86_64 -platform_version macos 10.15 11.0 -syslibroot ' + - os.path.join(config.test_source_root, "MachO", "Inputs", "MacOSX.sdk")) +# shortest substitution of "%lld". However, there are some tests running with +# arm64_32, so provide two command variations. +lld_base = 'ld64.lld -platform_version macos 10.15 11.0' + +lld_arm_64 = lld_base + ' -arch arm64_32' +config.substitutions.append(('%lld-arm64_32', lld_arm_64 + ' -fatal_warnings')) + +lld = lld_base + ' -arch x86_64 -syslibroot ' + os.path.join(config.test_source_root, "MachO", "Inputs", "MacOSX.sdk") config.substitutions.append(('%lld', lld + ' -fatal_warnings')) config.substitutions.append(('%no_fatal_warnings_lld', lld))