should be an even multiple of 4KB, that is the last three hexadecimal digits should be zero.
.It Fl allow_stack_execute
Marks executable so that all stacks in the task will be given stack execution privilege. This includes pthread stacks.
+.It Fl export_dynamic
+Preserves all global symbols in main executables during LTO. Without this option, Link Time Optimization
+is allowed to inline and remove global functions. This option is used when a main executable may load
+a plug-in which requires certain symbols from the main executable.
.El
.Ss Options when creating a bundle
.Bl -tag
.Ss Obsolete Options
.Bl -tag
.It Fl segalign Ar value
-All segments must be page aligned. This option is obsolete.
+All segments must be page aligned.
.It Fl seglinkedit
Object files (MH_OBJECT) with a LINKEDIT segment are no longer supported. This option is obsolete.
.It Fl noseglinkedit
.It Fl fvmlib
Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete.
.It Fl preload
-Preload executables (MH_PRELOAD) are no longer supported. This option is obsolete.
+Preload executables (MH_PRELOAD) are no longer supported.
.It Fl sectobjectsymbols Ar segname Ar sectname
Adding a local label at a section start is no longer supported. This option is obsolete.
.It Fl nofixprebinding
/* Begin PBXBuildRule section */
F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
isa = PBXBuildRule;
- compilerSpec = com.apple.compilers.llvm.clang.1_0;
+ compilerSpec = com.apple.compilers.gcc;
fileType = sourcecode.c;
isEditable = 1;
outputFiles = (
F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F93A9BEC12C2E51900BAA11D /* stub_arm64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm64.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; };
F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F9AA65101051BD2B003E3539 /* stubs.cpp */,
F9AA650F1051BD2B003E3539 /* stub_arm.hpp */,
F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */,
+ F93A9BEC12C2E51900BAA11D /* stub_arm64.hpp */,
F9BA8A7F1096150F0097A440 /* stub_x86.hpp */,
F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */,
F989D0391062E6350014B60C /* stub_x86_64.hpp */,
GCC_MODEL_TUNING = G5;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
INSTALL_PATH = /usr/local/lib;
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
PREBINDING = NO;
PRODUCT_NAME = prunetrie;
};
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
INSTALL_PATH = /usr/local/lib;
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
PREBINDING = NO;
PRODUCT_NAME = prunetrie;
};
GCC_MODEL_TUNING = G5;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
INSTALL_PATH = /usr/local/lib;
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
PREBINDING = NO;
PRODUCT_NAME = prunetrie;
};
#include <mach-o/compact_unwind_encoding.h>
#include <mach/machine.h>
#include <stddef.h>
+#include <libunwind.h>
#include "FileAbstraction.hpp"
#ifndef LC_DATA_IN_CODE
#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
- struct data_in_code_entry {
+ struct data_in_code_entry {
uint32_t offset;
uint16_t length;
uint16_t kind;
#define LC_DYLIB_CODE_SIGN_DRS 0x2B
#endif
+#ifndef LC_ENCRYPTION_INFO_64
+ #define LC_ENCRYPTION_INFO_64 0x2C
+ struct encryption_info_command_64 {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ uint32_t cryptoff;
+ uint32_t cryptsize;
+ uint32_t cryptid;
+ uint32_t pad;
+ };
+#endif
+
+
+
#ifndef CPU_SUBTYPE_ARM_V7F
#define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10)
#endif
#endif
+
+// hack until arm64 headers are worked out
+#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
+#define CPU_SUBTYPE_ARM64_ALL 0
+#define CPU_SUBTYPE_ARM64_V8 1
+
+#define ARM64_RELOC_UNSIGNED 0 // for pointers
+#define ARM64_RELOC_SUBTRACTOR 1 // must be followed by a ARM64_RELOC_UNSIGNED
+#define ARM64_RELOC_BRANCH26 2 // a B/BL instruction with 26-bit displacement
+#define ARM64_RELOC_PAGE21 3 // pc-rel distance to page of target
+#define ARM64_RELOC_PAGEOFF12 4 // offset within page, scaled by r_length
+#define ARM64_RELOC_GOT_LOAD_PAGE21 5 // pc-rel distance to page of GOT slot
+#define ARM64_RELOC_GOT_LOAD_PAGEOFF12 6 // offset within page of GOT slot, scaled by r_length
+#define ARM64_RELOC_POINTER_TO_GOT 7 // for pointers to GOT slots
+#define ARM64_RELOC_TLVP_LOAD_PAGE21 8 // pc-rel distance to page of TLVP slot
+#define ARM64_RELOC_TLVP_LOAD_PAGEOFF12 9 // offset within page of TLVP slot, scaled by r_length
+#define ARM64_RELOC_ADDEND 10 // r_symbolnum is addend for next reloc
+
+
+
+#define UNW_ARM64_X0 0
+#define UNW_ARM64_X1 1
+#define UNW_ARM64_X2 2
+#define UNW_ARM64_X3 3
+#define UNW_ARM64_X4 4
+#define UNW_ARM64_X5 5
+#define UNW_ARM64_X6 6
+#define UNW_ARM64_X7 7
+#define UNW_ARM64_X8 8
+#define UNW_ARM64_X9 9
+#define UNW_ARM64_X10 10
+#define UNW_ARM64_X11 11
+#define UNW_ARM64_X12 12
+#define UNW_ARM64_X13 13
+#define UNW_ARM64_X14 14
+#define UNW_ARM64_X15 15
+#define UNW_ARM64_X16 16
+#define UNW_ARM64_X17 17
+#define UNW_ARM64_X18 18
+#define UNW_ARM64_X19 19
+#define UNW_ARM64_X20 20
+#define UNW_ARM64_X21 21
+#define UNW_ARM64_X22 22
+#define UNW_ARM64_X23 23
+#define UNW_ARM64_X24 24
+#define UNW_ARM64_X25 25
+#define UNW_ARM64_X26 26
+#define UNW_ARM64_X27 27
+#define UNW_ARM64_X28 28
+#define UNW_ARM64_X29 29
+#define UNW_ARM64_FP 29
+#define UNW_ARM64_X30 30
+#define UNW_ARM64_LR 30
+#define UNW_ARM64_X31 31
+#define UNW_ARM64_SP 31
+#define UNW_ARM64_D0 64
+#define UNW_ARM64_D1 65
+#define UNW_ARM64_D2 66
+#define UNW_ARM64_D3 67
+#define UNW_ARM64_D4 68
+#define UNW_ARM64_D5 69
+#define UNW_ARM64_D6 70
+#define UNW_ARM64_D7 71
+#define UNW_ARM64_D8 72
+#define UNW_ARM64_D9 73
+#define UNW_ARM64_D10 74
+#define UNW_ARM64_D11 75
+#define UNW_ARM64_D12 76
+#define UNW_ARM64_D13 77
+#define UNW_ARM64_D14 78
+#define UNW_ARM64_D15 79
+#define UNW_ARM64_D16 80
+#define UNW_ARM64_D17 81
+#define UNW_ARM64_D18 82
+#define UNW_ARM64_D19 83
+#define UNW_ARM64_D20 84
+#define UNW_ARM64_D21 85
+#define UNW_ARM64_D22 86
+#define UNW_ARM64_D23 87
+#define UNW_ARM64_D24 88
+#define UNW_ARM64_D25 89
+#define UNW_ARM64_D26 90
+#define UNW_ARM64_D27 91
+#define UNW_ARM64_D28 92
+#define UNW_ARM64_D29 93
+#define UNW_ARM64_D30 94
+#define UNW_ARM64_D31 95
+
+#define UNWIND_ARM64_MODE_MASK 0x0F000000
+#define UNWIND_ARM64_MODE_FRAME_OLD 0x01000000
+#define UNWIND_ARM64_MODE_FRAMELESS 0x02000000
+#define UNWIND_ARM64_MODE_DWARF 0x03000000
+#define UNWIND_ARM64_MODE_FRAME 0x04000000
+
+#define UNWIND_ARM64_FRAME_X19_X20_PAIR 0x00000001
+#define UNWIND_ARM64_FRAME_X21_X22_PAIR 0x00000002
+#define UNWIND_ARM64_FRAME_X23_X24_PAIR 0x00000004
+#define UNWIND_ARM64_FRAME_X25_X26_PAIR 0x00000008
+#define UNWIND_ARM64_FRAME_X27_X28_PAIR 0x00000010
+#define UNWIND_ARM64_FRAME_D8_D9_PAIR 0x00000100
+#define UNWIND_ARM64_FRAME_D10_D11_PAIR 0x00000200
+#define UNWIND_ARM64_FRAME_D12_D13_PAIR 0x00000400
+#define UNWIND_ARM64_FRAME_D14_D15_PAIR 0x00000800
+
+#define UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK 0x00FFF000
+
+#define UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD 0x00000001
+#define UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD 0x00000002
+#define UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD 0x00000004
+#define UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD 0x00000008
+#define UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD 0x00000010
+#define UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD 0x00000020
+#define UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD 0x00000040
+#define UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD 0x00000080
+
+
+#define UNWIND_ARM64_DWARF_SECTION_OFFSET 0x00FFFFFF
+
#ifndef LC_SOURCE_VERSION
#define LC_SOURCE_VERSION 0x2A
struct source_version_command {
#define LC_DYLIB_CODE_SIGN_DRS 0x2B
#endif
+#ifndef LC_LINKER_OPTION
+ #define LC_LINKER_OPTION 0x2D
+
+ struct linker_option_command {
+ uint32_t cmd; /*LC_LINKER_OPTION only used in MH_OBJECT filetypes */
+ uint32_t cmdsize;
+ uint32_t count; /* number of strings */
+ /* concatenation of zero terminated UTF8 strings. Zero filled at end to align */
+ };
+#endif
+
+#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
+ #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
+#endif
+
+
+#ifndef CPU_SUBTYPE_ARM_V8
+ #define CPU_SUBTYPE_ARM_V8 ((cpu_subtype_t) 13)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V6M
+ #define CPU_SUBTYPE_ARM_V6M ((cpu_subtype_t) 14)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V7M
+ #define CPU_SUBTYPE_ARM_V7M ((cpu_subtype_t) 15)
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V7EM
+ #define CPU_SUBTYPE_ARM_V7EM ((cpu_subtype_t) 16)
+#endif
+
struct ArchInfo {
const char* archName;
#if SUPPORT_ARCH_armv7s
{ "armv7s", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S, "thumbv7s-", "armv7s", true, true },
#define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv6m
+ { "armv6m", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6M, "thumbv6m-", "", true, false },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7m
+ { "armv7m", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7M, "thumbv7m-", "armv7m", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7em
+ { "armv7em", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7EM, "thumbv7em-", "armv7em", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv8
+ { "armv8", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V8, "thumbv8-", "armv8", true, true },
+ #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_arm64
+ { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, "arm64-", "", false, false },
+#endif
+#if SUPPORT_ARCH_arm64v8
+ { "arm64v8", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8, "arm64v8-", "", true, false },
#endif
{ NULL, 0, 0, NULL, NULL, false, false }
};
-
+
// weird, but this include must wait until after SUPPORT_ARCH_arm_any is set up
#if SUPPORT_ARCH_arm_any
#include <mach-o/arm/reloc.h>
//
// mach-o encyrption info load command
//
+template <typename P> struct macho_encryption_info_content {};
+template <> struct macho_encryption_info_content<Pointer32<BigEndian> > { struct encryption_info_command fields; };
+template <> struct macho_encryption_info_content<Pointer64<BigEndian> > { struct encryption_info_command_64 fields; };
+template <> struct macho_encryption_info_content<Pointer32<LittleEndian> > { struct encryption_info_command fields; };
+template <> struct macho_encryption_info_content<Pointer64<LittleEndian> > { struct encryption_info_command_64 fields; };
+
+
template <typename P>
class macho_encryption_info_command {
public:
- uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
- void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+ uint32_t cmd() const INLINE { return E::get32(entry.fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(entry.fields.cmd, value); }
- uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
- void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+ uint32_t cmdsize() const INLINE { return E::get32(entry.fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(entry.fields.cmdsize, value); }
- uint32_t cryptoff() const INLINE { return E::get32(fields.cryptoff); }
- void set_cryptoff(uint32_t value) INLINE { E::set32(fields.cryptoff, value); }
+ uint32_t cryptoff() const INLINE { return E::get32(entry.fields.cryptoff); }
+ void set_cryptoff(uint32_t value) INLINE { E::set32(entry.fields.cryptoff, value); }
- uint32_t cryptsize() const INLINE { return E::get32(fields.cryptsize); }
- void set_cryptsize(uint32_t value) INLINE { E::set32(fields.cryptsize, value); }
+ uint32_t cryptsize() const INLINE { return E::get32(entry.fields.cryptsize); }
+ void set_cryptsize(uint32_t value) INLINE { E::set32(entry.fields.cryptsize, value); }
- uint32_t cryptid() const INLINE { return E::get32(fields.cryptid); }
- void set_cryptid(uint32_t value) INLINE { E::set32(fields.cryptid, value); }
+ uint32_t cryptid() const INLINE { return E::get32(entry.fields.cryptid); }
+ void set_cryptid(uint32_t value) INLINE { E::set32(entry.fields.cryptid, value); }
+ uint32_t pad() const INLINE { return E::get32(entry.fields.pad); }
+ void set_pad(uint32_t value) INLINE { E::set32(entry.fields.pad, value); }
+
typedef typename P::E E;
private:
- encryption_info_command fields;
+ macho_encryption_info_content<P> entry;
};
data_in_code_entry fields;
};
+#ifndef DICE_KIND_DATA
+ #define DICE_KIND_DATA 0x0001
+ #define DICE_KIND_JUMP_TABLE8 0x0002
+ #define DICE_KIND_JUMP_TABLE16 0x0003
+ #define DICE_KIND_JUMP_TABLE32 0x0004
+ #define DICE_KIND_ABS_JUMP_TABLE32 0x0005
+#endif
+
+template <typename P>
+class macho_linker_option_command {
+public:
+ uint32_t cmd() const INLINE { return E::get32(fields.cmd); }
+ void set_cmd(uint32_t value) INLINE { E::set32(fields.cmd, value); }
+
+ uint32_t cmdsize() const INLINE { return E::get32(fields.cmdsize); }
+ void set_cmdsize(uint32_t value) INLINE { E::set32(fields.cmdsize, value); }
+
+ uint64_t count() const INLINE { return fields.count; }
+ void set_count(uint32_t value) INLINE { E::set32(fields.count, value); }
+
+ const char* buffer() const INLINE { return ((char*)&fields) + sizeof(linker_option_command); }
+ char* buffer() INLINE { return ((char*)&fields) + sizeof(linker_option_command); }
+
+ typedef typename P::E E;
+private:
+ linker_option_command fields;
+};
+
+
+
#endif // __MACH_O_FILE_ABSTRACTION__
fi
if [ -z "${RC_SUPPORTED_ARCHS}" ]; then
- RC_SUPPORTED_ARCHS="i386 x86_64 armv7 armv7s"
+ RC_SUPPORTED_ARCHS="i386 x86_64 armv7 armv7s arm64"
fi
for ANARCH in ${RC_SUPPORTED_ARCHS}
do
- KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,i386,x86_64,"
+ KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,armv6m,armv7m,armv7em,armv8,arm64,arm64v8,i386,x86_64,"
FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
if [ $FOUND ]; then
echo "#define SUPPORT_ARCH_$ANARCH 1" >> ${DERIVED_FILE_DIR}/configure.h
else
- echo "#error uknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
+ echo "#error unknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
fi
done
typedef Pointer32<LittleEndian> P;
};
+struct arm64
+{
+ typedef Pointer64<LittleEndian> P;
+};
+
#endif // __ARCHITECTURES__
uint8_t* copyDataInCodeLoadCommand(uint8_t* p) const;
uint8_t* copyDependentDRLoadCommand(uint8_t* p) const;
uint8_t* copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
-
+ uint8_t* copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>&) const;
+
uint32_t sectionFlags(ld::Internal::FinalSection* sect) const;
bool sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
std::vector<const char*> _subUmbrellaNames;
uint8_t _uuid[16];
mutable macho_uuid_command<P>* _uuidCmdInOutputBuffer;
+ std::vector< std::vector<const char*> > _linkerOptions;
static ld::Section _s_section;
static ld::Section _s_preload_section;
break;
}
}
+ for (CStringSet::const_iterator it = _state.linkerOptionFrameworks.begin(); it != _state.linkerOptionFrameworks.end(); ++it) {
+ const char* frameWorkName = *it;
+ std::vector<const char*>* lo = new std::vector<const char*>();
+ lo->push_back("-framework");
+ lo->push_back(frameWorkName);
+ _linkerOptions.push_back(*lo);
+ };
+ for (CStringSet::const_iterator it = _state.linkerOptionLibraries.begin(); it != _state.linkerOptionLibraries.end(); ++it) {
+ const char* libName = *it;
+ std::vector<const char*>* lo = new std::vector<const char*>();
+ char * s = new char[strlen(libName)+3];
+ strcpy(s, "-l");
+ strcat(s, libName);
+ lo->push_back(s);
+ _linkerOptions.push_back(*lo);
+ };
break;
case Options::kStaticExecutable:
_hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
_dylibLoadCommmandsCount = _writer.dylibCount();
_allowableClientLoadCommmandsCount = _options.allowableClients().size();
_dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
+
if ( ! _options.useSimplifiedDylibReExports() ) {
// target OS does not support LC_REEXPORT_DYLIB, so use old complicated load commands
for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
if ( _hasDataInCodeLoadCommand )
sz += sizeof(macho_linkedit_data_command<P>);
+ if ( !_linkerOptions.empty() ) {
+ for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+ uint32_t s = sizeof(macho_linker_option_command<P>);
+ const std::vector<const char*>& options = *it;
+ for (std::vector<const char*>::const_iterator t=options.begin(); t != options.end(); ++t) {
+ s += (strlen(*t) + 1);
+ }
+ sz += alignedSize(s);
+ }
+ }
+
if ( _hasDependentDRInfo )
sz += sizeof(macho_linkedit_data_command<P>);
if ( _hasDataInCodeLoadCommand )
++count;
+ if ( !_linkerOptions.empty() ) {
+ for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+ ++count;
+ }
+ }
+
if ( _hasDependentDRInfo )
++count;
template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const { return MH_MAGIC; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const { return MH_MAGIC_64; }
template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const { return MH_MAGIC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm64>::magic() const { return MH_MAGIC_64; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const { return CPU_TYPE_I386; }
template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const { return CPU_TYPE_X86_64; }
template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const { return CPU_TYPE_ARM; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuType() const { return CPU_TYPE_ARM64; }
return _state.cpuSubType;
}
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuSubType() const
+{
+ return CPU_SUBTYPE_ARM64_ALL;
+}
+
template <typename A>
}
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::threadLoadCommandSize() const
+{
+ return this->alignedSize(16 + 34 * 8); // base size + ARM_EXCEPTION_STATE64_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<arm64>::copyThreadsLoadCommand(uint8_t* p) const
+{
+ assert(_state.entryPoint != NULL);
+ pint_t start = _state.entryPoint->finalAddress();
+ macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+ cmd->set_cmd(LC_UNIXTHREAD);
+ cmd->set_cmdsize(threadLoadCommandSize());
+ cmd->set_flavor(6); // ARM_THREAD_STATE64
+ cmd->set_count(68); // ARM_EXCEPTION_STATE64_COUNT
+ cmd->set_thread_register(32, start); // pc
+ if ( _options.hasCustomStack() )
+ cmd->set_thread_register(31, _options.customStackAddr()); // sp
+ return p + threadLoadCommandSize();
+}
+
template <typename A>
uint8_t* HeaderAndLoadCommandsAtom<A>::copyEntryPointLoadCommand(uint8_t* p) const
uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
{
macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)p;
- cmd->set_cmd(LC_ENCRYPTION_INFO);
+ cmd->set_cmd(sizeof(typename A::P::uint_t) == 4 ? LC_ENCRYPTION_INFO : LC_ENCRYPTION_INFO_64);
cmd->set_cmdsize(sizeof(macho_encryption_info_command<P>));
assert(_writer.encryptedTextStartOffset() != 0);
assert(_writer.encryptedTextEndOffset() != 0);
}
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>& options) const
+{
+ macho_linker_option_command<P>* cmd = (macho_linker_option_command<P>*)p;
+ cmd->set_cmd(LC_LINKER_OPTION);
+ cmd->set_count(options.size());
+ char* buffer = cmd->buffer();
+ uint32_t sz = sizeof(macho_linker_option_command<P>);
+ for (std::vector<const char*>::const_iterator it=options.begin(); it != options.end(); ++it) {
+ const char* opt = *it;
+ uint32_t len = strlen(opt);
+ strcpy(buffer, opt);
+ sz += (len + 1);
+ buffer += (len + 1);
+ }
+ sz = alignedSize(sz);
+ cmd->set_cmdsize(sz);
+ return p + sz;
+}
+
+
template <typename A>
uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
{
if ( _hasSplitSegInfoLoadCommand )
p = this->copySplitSegInfoLoadCommand(p);
- for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+ for (uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord));
}
if ( _hasDataInCodeLoadCommand )
p = this->copyDataInCodeLoadCommand(p);
+
+ if ( !_linkerOptions.empty() ) {
+ for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+ p = this->copyLinkerOptionsLoadCommand(p, *it);
+ }
+ }
if ( _hasDependentDRInfo )
p = this->copyDependentDRLoadCommand(p);
+
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
*
* Copyright (c) 2009-2011 Apple Inc. All rights reserved.
#include "archive_file.h"
#include "lto_file.h"
#include "opaque_section_file.h"
+#include "MachOFileAbstraction.hpp"
#include "Snapshot.h"
const bool _s_logPThreads = false;
const char* result = mach_o::relocatable::archName(p);
if ( result != NULL )
return result;
-
+
+ result = mach_o::dylib::archName(p);
+ if ( result != NULL )
+ return result;
+
result = lto::archName(p, len);
if ( result != NULL )
return result;
strcpy(unsupported, "unsupported file format (");
for (unsigned i=0; i<len && i < 16; i++) {
char buf[8];
- sprintf(buf, " 0x%2x", p[i]);
+ sprintf(buf, " 0x%02X", p[i]);
strcat(unsupported, buf);
}
strcat(unsupported, " )");
if ( fd == -1 )
throwf("can't open file, errno=%d", errno);
if ( info.fileLen < 20 )
- throw "file too small";
+ throwf("file too small (length=%llu)", info.fileLen);
uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
if ( p == (uint8_t*)(-1) )
objOpts.architecture = _options.architecture();
objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
objOpts.logAllFiles = _options.logAllFiles();
- objOpts.convertUnwindInfo = _options.needsUnwindInfoSection();
+ objOpts.warnUnwindConversionProblems = _options.needsUnwindInfoSection();
+ objOpts.keepDwarfUnwind = _options.keepDwarfUnwind();
+ objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld);
objOpts.subType = _options.subArchitecture();
ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
if ( objResult != NULL ) {
logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
}
else {
- if ( indirect )
+ if ( indirect )
logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
- else
+ else
logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
}
}
+
+ if ( _options.dumpDependencyInfo() ) {
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file);
+ if ( file == _bundleLoader ) {
+ _options.dumpDependency(Options::depBundleLoader, file->path());
+ }
+ else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
+ if ( indirect )
+ _options.dumpDependency(Options::depUpwardIndirectDylib, file->path());
+ else
+ _options.dumpDependency(Options::depUpwardDirectDylib, file->path());
+ }
+ else {
+ if ( indirect )
+ _options.dumpDependency(Options::depIndirectDylib, file->path());
+ else
+ _options.dumpDependency(Options::depDirectDylib, file->path());
+ }
+ }
}
void InputFiles::logArchive(ld::File* file) const
if ( trace_file_path != NULL ) {
trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
if ( trace_file == -1 )
- throwf("Could not open or create trace file: %s", trace_file_path);
+ throwf("Could not open or create trace file (errno=%d): %s", errno, trace_file_path);
}
else {
trace_file = fileno(stderr);
}
}
+
ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
{
//fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
Options::FileInfo info = _options.findFile(dit->useInstead);
_indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
info.ordinal = _indirectDylibOrdinal;
+ info.options.fIndirectDylib = true;
ld::File* reader = this->makeFile(info, true);
ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
if ( dylibReader != NULL ) {
Options::FileInfo info = _options.findFileUsingPaths(installPath);
_indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
info.ordinal = _indirectDylibOrdinal;
+ info.options.fIndirectDylib = true;
try {
ld::File* reader = this->makeFile(info, true);
ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
}
-
-void InputFiles::createIndirectDylibs()
-{
- _allDirectDylibsLoaded = true;
- _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase();
-
- // mark all dylibs initially specified as required and check if they can be used
+// mark all dylibs initially specified as required, and check if they can be used
+void InputFiles::markExplicitlyLinkedDylibs()
+{
for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
it->second->setExplicitlyLinked();
this->checkDylibClientRestrictions(it->second);
}
-
+}
+
+bool InputFiles::libraryAlreadyLoaded(const char* path)
+{
+ for (std::vector<ld::File*>::const_iterator it = _inputFiles.begin(); it != _inputFiles.end(); ++it) {
+ if ( strcmp(path, (*it)->path()) == 0 )
+ return true;
+ }
+ return false;
+}
+
+
+void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
+{
+ if ( _options.outputKind() == Options::kObjectFile )
+ return;
+
+ // process frameworks specified in .o linker options
+ for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) {
+ const char* frameworkName = *it;
+ Options::FileInfo info = _options.findFramework(frameworkName);
+ if ( ! this->libraryAlreadyLoaded(info.path) ) {
+ info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+ try {
+ ld::File* reader = this->makeFile(info, true);
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+ if ( dylibReader != NULL ) {
+ if ( ! dylibReader->installPathVersionSpecific() ) {
+ dylibReader->setImplicitlyLinked();
+ this->addDylib(dylibReader, info);
+ }
+ }
+ else {
+ throwf("framework linker option at %s is not a dylib", info.path);
+ }
+ }
+ catch (const char* msg) {
+ throwf("in '%s', %s", info.path, msg);
+ }
+ }
+ }
+ // process libraries specified in .o linker options
+ for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) {
+ const char* libName = *it;
+ Options::FileInfo info = _options.findLibrary(libName);
+ if ( ! this->libraryAlreadyLoaded(info.path) ) {
+ info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+ try {
+ ld::File* reader = this->makeFile(info, true);
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+ ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
+ if ( dylibReader != NULL ) {
+ dylibReader->setImplicitlyLinked();
+ this->addDylib(dylibReader, info);
+ }
+ else if ( archiveReader != NULL ) {
+ _searchLibraries.push_back(LibraryInfo(archiveReader));
+ if ( _options.dumpDependencyInfo() )
+ _options.dumpDependency(Options::depArchive, archiveReader->path());
+ }
+ else {
+ throwf("linker option dylib at %s is not a dylib", info.path);
+ }
+ }
+ catch (const char* msg) {
+ throwf("in '%s', %s", info.path, msg);
+ }
+ }
+ }
+}
+
+void InputFiles::createIndirectDylibs()
+{
// keep processing dylibs until no more dylibs are added
unsigned long lastMapSize = 0;
std::set<ld::dylib::File*> dylibsProcessed;
void InputFiles::createOpaqueFileSections()
{
- // extra command line section always at end
+ // extra command line sections always at end
for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
_inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
+ if ( _options.dumpDependencyInfo() )
+ _options.dumpDependency(Options::depSection, it->path);
}
}
: _totalObjectSize(0), _totalArchiveSize(0),
_totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
_options(opts), _bundleLoader(NULL),
- _allDirectDylibsLoaded(false), _inferredArch(false),
- _exception(NULL)
+ _inferredArch(false),
+ _exception(NULL),
+ _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()),
+ _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase())
{
// fStartCreateReadersTime = mach_absolute_time();
if ( opts.architecture() == 0 ) {
if (_s_logPThreads) printf("parsing index %u\n", slot);
try {
file = makeFile(entry, false);
- } catch (const char *msg) {
+ }
+ catch (const char *msg) {
if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
if ( _options.ignoreOtherArchInputFiles() ) {
// ignore, because this is about an architecture not in use
else {
warning("ignoring file %s, %s", entry.path, msg);
}
- } else {
- exception = msg;
+ }
+ else {
+ asprintf((char**)&exception, "%s file '%s'", msg, entry.path);
}
file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
}
// We are about to die, so set to zero to stop other threads from doing unneeded work.
_remainingInputFiles = 0;
_exception = exception;
- } else {
+ }
+ else {
_inputFiles[slot] = file;
if (_neededFileSlot == slot)
pthread_cond_signal(&_newFileAvailable);
}
// remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
//if ( !dylibOnCommandLineTwice && !isSymlink )
- // warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+ // warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path());
}
}
else if ( info.options.fBundleLoader )
_bundleLoader = reader;
// log direct readers
- if ( !_allDirectDylibsLoaded )
+ if ( ! info.options.fIndirectDylib )
this->logDylib(reader, false);
// update stats
_totalDylibsLoaded++;
// just add direct libraries to search-first list
- if ( !_allDirectDylibsLoaded )
+ if ( ! info.options.fIndirectDylib )
_searchLibraries.push_back(LibraryInfo(reader));
+
return reader;
}
if (it == fileMap.end())
throwf("pipelined linking error - not in file list: %s\n", path_buf);
Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
- if (!inputInfo->checkFileExists())
+ if (!inputInfo->checkFileExists(_options))
throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
pthread_mutex_lock(&_parseLock);
if (_idleWorkers)
#endif
-void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
+void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state)
{
// add all direct object, archives, and dylibs
const std::vector<Options::FileInfo>& files = _options.getInputFiles();
{
ld::relocatable::File* reloc = (ld::relocatable::File*)file;
_options.snapshot().recordObjectFile(reloc->path());
+ if ( _options.dumpDependencyInfo() )
+ _options.dumpDependency(Options::depObjectFile, reloc->path());
}
break;
case ld::File::Dylib:
if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() )
logArchive(archive);
_searchLibraries.push_back(LibraryInfo(archive));
+ if ( _options.dumpDependencyInfo() )
+ _options.dumpDependency(Options::depArchive, archive->path());
}
break;
case ld::File::Other:
file->forEachAtom(handler);
}
+ markExplicitlyLinkedDylibs();
+ addLinkerOptionLibraries(state);
createIndirectDylibs();
createOpaqueFileSections();
logArchive(archiveFile);
_options.snapshot().recordArchive(archiveFile->path());
// found data definition in static library, done
- return true;
+ return true;
}
}
else {
bool InputFiles::searchWeakDefInDylib(const char* name) const
{
- // search all relevant dylibs to see if any of a weak-def with this name
+ // search all relevant dylibs to see if any have a weak-def with this name
for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
ld::dylib::File* dylibFile = it->second;
if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
} // namespace tool
} // namespace ld
-
virtual ld::dylib::File* findDylib(const char* installPath, const char* fromPath);
// iterates all atoms in initial files
- void forEachInitialAtom(ld::File::AtomHandler&);
+ void forEachInitialAtom(ld::File::AtomHandler&, ld::Internal& state);
// searches libraries for name
bool searchLibraries(const char* name, bool searchDylibs, bool searchArchives,
bool dataSymbolOnly, ld::File::AtomHandler&) const;
void logTraceInfo (const char* format, ...) const;
void logDylib(ld::File*, bool indirect);
void logArchive(ld::File*) const;
+ void markExplicitlyLinkedDylibs();
void createIndirectDylibs();
void checkDylibClientRestrictions(ld::dylib::File*);
void createOpaqueFileSections();
+ void addLinkerOptionLibraries(ld::Internal& state);
+ bool libraryAlreadyLoaded(const char* path);
// for pipelined linking
- void waitForInputFiles();
+ void waitForInputFiles();
static void waitForInputFiles(InputFiles *inputFiles);
// for threaded input file processing
InstallNameToDylib _installPathToDylibs;
std::set<ld::dylib::File*> _allDylibs;
ld::dylib::File* _bundleLoader;
- bool _allDirectDylibsLoaded;
bool _inferredArch;
struct strcompclass {
bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
int _remainingInputFiles; // number of input files still to parse
ld::File::Ordinal _indirectDylibOrdinal;
+ ld::File::Ordinal _linkerOptionOrdinal;
class LibraryInfo {
ld::File* _lib;
entries.push_back(entry);
//fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
}
+ else if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+ entry.name = atom->name();
+ entry.flags = _options.canUseAbsoluteSymbols() ? EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+ entry.address = address;
+ entry.other = other;
+ entry.importName = NULL;
+ entries.push_back(entry);
+ }
else {
if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
mutable std::vector<uint64_t> _thumbHi16Locations[16];
mutable std::vector<uint64_t> _armLo16Locations;
mutable std::vector<uint64_t> _armHi16Locations[16];
+ mutable std::vector<uint64_t> _adrpLocations;
static ld::Section _s_section;
case ld::Fixup::kindStoreTargetAddressX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
_32bitPointerLocations.push_back(address);
break;
case ld::Fixup::kindStoreLittleEndian64:
switch (kind) {
case ld::Fixup::kindStoreLittleEndian32:
case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
_32bitPointerLocations.push_back(address);
break;
default:
}
}
-
+#if SUPPORT_ARCH_arm64
+template <>
+void SplitSegInfoAtom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+{
+ switch (kind) {
+ case ld::Fixup::kindStoreARM64Page21:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ _adrpLocations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ _32bitPointerLocations.push_back(address);
+ break;
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ _64bitPointerLocations.push_back(address);
+ break;
+ default:
+ warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+ break;
+ }
+}
+#endif
template <typename A>
void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
this->_encodedData.append_byte(0); // terminator
}
+ if ( _adrpLocations.size() != 0 ) {
+ this->_encodedData.append_byte(3);
+ //fprintf(stderr, "type 3:\n");
+ std::sort(_adrpLocations.begin(), _adrpLocations.end());
+ this->uleb128EncodeAddresses(_adrpLocations);
+ this->_encodedData.append_byte(0); // terminator
+ }
+
if ( _thumbLo16Locations.size() != 0 ) {
this->_encodedData.append_byte(5);
//fprintf(stderr, "type 5:\n");
return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
}
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::pointerReloc() { return ARM64_RELOC_UNSIGNED; }
+#endif
#if SUPPORT_ARCH_arm_any
template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
#endif
template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::callReloc() { return ARM64_RELOC_BRANCH26; }
+#endif
+
template <typename A>
uint32_t ExternalRelocationsAtom<A>::callReloc()
{
}
#endif
+#if SUPPORT_ARCH_arm64
+template <>
+void SectionRelocationsAtom<arm64>::encodeSectionReloc(ld::Internal::FinalSection* sect,
+ const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+ macho_relocation_info<P> reloc1;
+ macho_relocation_info<P> reloc2;
+ uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+ bool external = entry.toTargetUsesExternalReloc;
+ uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+ bool fromExternal = false;
+ uint32_t fromSymbolNum = 0;
+ if ( entry.fromTarget != NULL ) {
+ fromExternal = entry.fromTargetUsesExternalReloc;
+ fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+ }
+
+
+ switch ( entry.kind ) {
+ case ld::Fixup::kindStoreARM64Branch26:
+ if ( entry.toAddend != 0 ) {
+ assert(entry.toAddend < 0x400000);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(entry.toAddend);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM64_RELOC_ADDEND);
+ relocs.push_back(reloc2);
+ }
+ // fall into next case
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_BRANCH26);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreARM64Page21:
+ if ( entry.toAddend != 0 ) {
+ assert(entry.toAddend < 0x400000);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(entry.toAddend);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM64_RELOC_ADDEND);
+ relocs.push_back(reloc2);
+ }
+ // fall into next case
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_PAGE21);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreARM64PageOff12:
+ if ( entry.toAddend != 0 ) {
+ assert(entry.toAddend < 0x400000);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(entry.toAddend);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(false);
+ reloc2.set_r_type(ARM64_RELOC_ADDEND);
+ relocs.push_back(reloc2);
+ }
+ // fall into next case
+ case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_PAGEOFF12);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGE21);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+ relocs.push_back(reloc1);
+ break;
+
+
+ case ld::Fixup::kindStoreLittleEndian64:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(fromSymbolNum);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(3);
+ reloc2.set_r_extern(fromExternal);
+ reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+ relocs.push_back(reloc2);
+ relocs.push_back(reloc1);
+ }
+ else {
+ // regular pointer
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ relocs.push_back(reloc1);
+ }
+ break;
+
+ case ld::Fixup::kindStoreLittleEndian32:
+ case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+ if ( entry.fromTarget != NULL ) {
+ // this is a pointer-diff
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ reloc2.set_r_address(address);
+ reloc2.set_r_symbolnum(fromSymbolNum);
+ reloc2.set_r_pcrel(false);
+ reloc2.set_r_length(2);
+ reloc2.set_r_extern(fromExternal);
+ reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+ relocs.push_back(reloc2);
+ relocs.push_back(reloc1);
+ }
+ else {
+ // regular pointer
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+ relocs.push_back(reloc1);
+ }
+ break;
+
+ case ld::Fixup::kindStoreARM64PointerToGOT:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(false);
+ reloc1.set_r_length(3);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+ relocs.push_back(reloc1);
+ break;
+
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ reloc1.set_r_address(address);
+ reloc1.set_r_symbolnum(symbolNum);
+ reloc1.set_r_pcrel(true);
+ reloc1.set_r_length(2);
+ reloc1.set_r_extern(external);
+ reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+ relocs.push_back(reloc1);
+ break;
+
+ default:
+ assert(0 && "need to handle arm64 -r reloc");
+
+ }
+
+}
+#endif // SUPPORT_ARCH_arm64
template <typename A>
throw t;
}
-bool Options::FileInfo::checkFileExists(const char *p)
+
+bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
{
struct stat statBuffer;
- if (p == NULL) p = path;
+ if (p == NULL)
+ p = path;
if ( stat(p, &statBuffer) == 0 ) {
if (p != path) path = strdup(p);
fileLen = statBuffer.st_size;
modTime = statBuffer.st_mtime;
return true;
}
+ if ( options.dumpDependencyInfo() )
+ options.dumpDependency(Options::depNotFound, p);
return false;
}
+
Options::Options(int argc, const char* argv[])
: fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable),
fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
fClientName(NULL),
fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL),
- fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL),
+ fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false),
fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
fMinimumHeaderPad(32), fSegmentAlignment(4096),
fSourceVersionLoadCommand(false),
fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false),
fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
+ fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
+ fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
+ fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
+ fGenerateDtraceDOF(true),
fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
- fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL)
+ fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
+ fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
{
this->checkForClassic(argc, argv);
this->parsePreCommandLineEnvironmentSettings();
this->parsePostCommandLineEnvironmentSettings();
this->reconfigureDefaults();
this->checkIllegalOptionCombinations();
+
+ if ( this->dumpDependencyInfo() ) {
+ this->dumpDependency(depOutputFile, fOutputFile);
+ if ( fMapPath != NULL )
+ this->dumpDependency(depOutputFile, fMapPath);
+ }
}
Options::~Options()
{
+ if ( fDependencyFileDescriptor != -1 )
+ ::close(fDependencyFileDescriptor);
}
bool Options::errorBecauseOfWarnings() const
//
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
+ // <rdar://problem/12839986> Add the -export_dynamic flag
+ return fExportDynamic;
case Options::kStaticExecutable:
+ // <rdar://problem/13361218> Support the -export_dynamic flag for xnu
+ return fExportDynamic;
case Options::kPreload:
// by default unused globals in a main executable are stripped
return false;
return fExecutablePath;
}
-
uint32_t Options::initialSegProtection(const char* segName) const
{
for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
return fForceNotWeakSymbols.containsNonWildcard(symbolName);
}
+bool Options::forceCoalesce(const char* symbolName) const
+{
+ return fForceCoalesceSymbols.contains(symbolName);
+}
+
bool Options::shouldExport(const char* symbolName) const
{
fMacVersionMin = ld::mac10_6;
#endif
}
- if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
- fMakeCompressedDyldInfo = true;
break;
case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM64:
if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
#if defined(DEFAULT_IPHONEOS_MIN_VERSION)
warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
- #elif defined(DEFAULT_MACOSX_MIN_VERSION)
- warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
- setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
#else
- warning("-macosx_version_min not specified, assuming 10.6");
- fMacVersionMin = ld::mac10_6;
+ warning("-ios_version_min not specified, assuming 6.0");
+ setIOSVersionMin("6.0");
#endif
}
- if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
- fMakeCompressedDyldInfo = true;
break;
}
fLinkSnapshot.recordArch(fArchitectureName);
+ // only use compressed LINKEDIT for:
+ // Mac OS X 10.6 or later
+ // iOS 3.1 or later
+ if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+ fMakeCompressedDyldInfo = true;
+ // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
+ if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+ fUseSimplifiedDylibReExports = true;
return;
}
}
{
char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
sprintf(possiblePath, format, dir, rootName);
- bool found = result.checkFileExists(possiblePath);
+ bool found = result.checkFileExists(*this, possiblePath);
if ( fTraceDylibSearching )
printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath);
return found;
}
-Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
+Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) const
{
FileInfo result;
const int rootNameLen = strlen(rootName);
// if rootName ends in .o there is no .a vs .dylib choice
if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
case kSearchAllDirsForDylibsThenAllDirsForArchives:
// first look in all directories for just for dylibs
if ( lookForDylibs ) {
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
return result;
}
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
}
// next look in all directories for just for archives
if ( !dylibsOnly ) {
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
case kSearchDylibAndArchiveInEachDir:
// look in each directory for just for a dylib then for an archive
- for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+ for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
throwf("library not found for -l%s", rootName);
}
-Options::FileInfo Options::findFramework(const char* frameworkName)
+Options::FileInfo Options::findFramework(const char* frameworkName) const
{
if ( frameworkName == NULL )
throw "-framework missing next argument";
return findFramework(name, suffix);
}
-Options::FileInfo Options::findFramework(const char* rootName, const char* suffix)
+Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) const
{
- for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
+ for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
it != fFrameworkSearchPaths.end();
it++) {
// ??? Shouldn't we be using String here and just initializing it?
}
}
FileInfo result;
- bool found = result.checkFileExists(possiblePath);
+ bool found = result.checkFileExists(*this, possiblePath);
if ( fTraceDylibSearching )
printf("[Logging for XBS]%sfound framework: '%s'\n",
(found ? " " : " not "), possiblePath);
if ( possiblePath[sdkPathDirLen-1] == '/' )
possiblePath[sdkPathDirLen-1] = '\0';
strcat(possiblePath, path);
- if ( result.checkFileExists(possiblePath) ) {
+ if ( result.checkFileExists(*this, possiblePath) ) {
return result;
}
}
}
// try raw path
- if ( result.checkFileExists(path) ) {
+ if ( result.checkFileExists(*this, path) ) {
return result;
}
strcpy(&addPoint[1], &path[17]);
else
strcpy(newPath, &path[17]);
- if ( result.checkFileExists(newPath) ) {
+ if ( result.checkFileExists(*this, newPath) ) {
return result;
}
}
// If we didn't find it fall back to findFile.
return findFile(path);
}
-
+
+
void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
{
file = fopen(realFileOfPaths, "r");
if ( file == NULL )
throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno));
+ if ( this->dumpDependencyInfo() )
+ this->dumpDependency(Options::depFileList, realFileOfPaths);
}
}
else {
file = fopen(fileOfPaths, "r");
if ( file == NULL )
throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno));
+ if ( this->dumpDependencyInfo() )
+ this->dumpDependency(Options::depFileList, fileOfPaths);
}
char path[PATH_MAX];
if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
throwf("can't read %s file: %s", option, fileOfExports);
+ if ( this->dumpDependencyInfo() )
+ this->dumpDependency(Options::depMisc, fileOfExports);
+
::close(fd);
// parse into symbols and add to unordered_set
throwf("can't read alias file: %s", fileOfAliases);
p[stat_buf.st_size] = '\n';
::close(fd);
+ if ( this->dumpDependencyInfo() )
+ this->dumpDependency(Options::depMisc, fileOfAliases);
// parse into symbols and add to fAliases
AliasPair pair;
throw "-macosx_version_min argument missing";
if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
- unsigned int minorVersion = version[3] - '0';
+ unsigned int minorVersion = 0;
+ for (int i=3; isdigit(version[i]); ++i) {
+ minorVersion = minorVersion*10 + (version[i] - '0');
+ }
+ if ( minorVersion > 255 ) {
+ warning("Mac OS X minor version > 255 in '%s'", version);
+ minorVersion = 255;
+ }
fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
}
else {
throwf("can't read order file: %s", path);
::close(fd);
p[stat_buf.st_size] = '\n';
+ if ( this->dumpDependencyInfo() )
+ this->dumpDependency(Options::depMisc, path);
// parse into vector of pairs
char * const end = &p[stat_buf.st_size+1];
objFileName = symbolStart;
symbolStart = &colon[3];
}
+ else {
+ colon = strstr(symbolStart, ".o):");
+ if ( colon != NULL ) {
+ colon[3] = '\0';
+ objFileName = symbolStart;
+ symbolStart = &colon[4];
+ }
+ }
// trim leading spaces
while ( isspace(*symbolStart) )
++symbolStart;
}
// Use this flag to set default behavior for deployement targets.
else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
- setMacOSXVersionMin(argv[++i]);
+ const char* macVers = argv[++i];
+ const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
+ const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
+ if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
+ // <rdar://problem/13774329> when conflicting deployments set, break tie by looking at syslibroot
+ warning("both MACOSX_DEPLOYMENT_TARGET and IPHONEOS_DEPLOYMENT_TARGET are set");
+ if ( !fSDKPaths.empty() ) {
+ const char* sysrootPath = fSDKPaths.back();
+ const char* lastSlash = strrchr(sysrootPath, '/');
+ if ( strstr(lastSlash, "Simulator") != NULL )
+ setIOSVersionMin(enviPhoneVers);
+ else
+ setMacOSXVersionMin(macVers);
+ }
+ else {
+ setMacOSXVersionMin(macVers);
+ }
+ }
+ else {
+ setMacOSXVersionMin(macVers);
+ }
}
else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
setIOSVersionMin(argv[++i]);
}
else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
setIOSVersionMin(argv[++i]);
+ fTargetIOSSimulator = true;
}
else if ( strcmp(arg, "-multiply_defined") == 0 ) {
//warnObsolete(arg);
throw "missing argument to -mllvm";
fLLVMOptions.push_back(opts);
}
+ else if ( strcmp(arg, "-mcpu") == 0 ) {
+ const char* cpu = argv[++i];
+ if ( cpu == NULL )
+ throw "missing argument to -mcpu";
+ fLtoCpu = cpu;
+ }
else if ( strcmp(arg, "-no_order_inits") == 0 ) {
fAutoOrderInitializers = false;
}
else if (strcmp(arg, "-debug_snapshot") == 0) {
fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
fSnapshotRequested = true;
+ }
+ else if (strcmp(arg, "-snapshot_dir") == 0) {
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "-snapshot_dir missing path";
+ fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+ fLinkSnapshot.setSnapshotPath(path);
+ fSnapshotRequested = true;
}
else if ( strcmp(arg, "-new_main") == 0 ) {
fEntryPointLoadCommandForceOn = true;
else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
fKextsUseStubs = true;
}
+ else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+ ++i;
+ // previously handled by buildSearchPaths()
+ }
+ else if ( strcmp(arg, "-export_dynamic") == 0 ) {
+ fExportDynamic = true;
+ }
+ else if ( strcmp(arg, "-force_symbols_coalesce_list") == 0 ) {
+ snapshotFileArgIndex = 1;
+ loadExportFile(argv[++i], "-force_symbols_coalesce_list", fForceCoalesceSymbols);
+ }
+ else if ( strcmp(arg, "-add_linker_option") == 0 ) {
+ // ex: -add_linker_option '-framework Foundation'
+ const char* optString = argv[++i];
+ if ( optString == NULL )
+ throw "-add_linker_option missing <option>";
+ // break up into list of tokens at whitespace
+ std::vector<const char*> opts;
+ char* buffer = strdup(optString);
+ char* start = buffer;
+ for (char* s = buffer; ; ++s) {
+ if ( isspace(*s) ) {
+ *s = '\0';
+ opts.push_back(start);
+ start = s+1;
+ }
+ else if ( *s == '\0' ) {
+ opts.push_back(start);
+ break;
+ }
+ }
+ fLinkerOptions.push_back(opts);
+ }
+ else if ( strcmp(arg, "-allow_simulator_linking_to_macosx_dylibs") == 0 ) {
+ fAllowSimulatorToLinkWithMacOSX = true;
+ }
+ else if ( strcmp(arg, "-keep_dwarf_unwind") == 0 ) {
+ fKeepDwarfUnwindForcedOn = true;
+ fKeepDwarfUnwindForcedOff = false;
+ }
+ else if ( strcmp(arg, "-no_keep_dwarf_unwind") == 0 ) {
+ fKeepDwarfUnwindForcedOn = false;
+ fKeepDwarfUnwindForcedOff = true;
+ }
+ else if ( strcmp(arg, "-no_dtrace_dof") == 0 ) {
+ fGenerateDtraceDOF = false;
+ }
else {
throwf("unknown option: %s", arg);
}
else if ( strcmp(argv[i], "-fatal_warnings") == 0 ) {
sFatalWarnings = true;
}
+ else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "-dependency_info missing <path>";
+ fDependencyInfoPath = path;
+ }
}
int standardLibraryPathsStartIndex = libraryPaths.size();
int standardFrameworkPathsStartIndex = frameworkPaths.size();
#if defined(DEFAULT_IPHONEOS_MIN_VERSION)
warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
- #elif defined(DEFAULT_MACOSX_MIN_VERSION)
- warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
- setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
#else
- warning("-macosx_version_min not specified, assuming 10.6");
- fMacVersionMin = ld::mac10_6;
+ warning("-ios_version_min not specified, assuming 6.0");
+ setIOSVersionMin("6.0");
#endif
}
break;
default:
- // architecture will be infered ;ater by examining .o files
+ // architecture will be infered later by examining .o files
break;
}
}
fMacVersionMin = ld::mac10_4;
}
break;
+ case CPU_TYPE_ARM64:
+ if ( fIOSVersionMin < ld::iOS_7_0 ) {
+ //warning("-mios_version_min should be 7.0 or later for arm64");
+ fIOSVersionMin = ld::iOS_7_0;
+ }
+ break;
}
// default to adding functions start for dynamic code, static code must opt-in
fAllowTextRelocs = true;
fUndefinedTreatment = kUndefinedDynamicLookup;
break;
+ case CPU_TYPE_ARM64:
+ // arm64 uses new MH_KEXT_BUNDLE type
+ fMakeCompressedDyldInfo = false;
+ fMakeCompressedDyldInfoForceOff = true;
+ fAllowTextRelocs = false;
+ fKextsUseStubs = true;
+ fUndefinedTreatment = kUndefinedDynamicLookup;
+ break;
case CPU_TYPE_ARM:
if ( fIOSVersionMin >= ld::iOS_5_0 ) {
// iOS 5.0 and later use new MH_KEXT_BUNDLE type
switch ( fArchitecture ) {
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
+ case CPU_TYPE_ARM64:
switch ( fOutputKind ) {
case Options::kObjectFile:
case Options::kStaticExecutable:
break;
}
- // only ARM main executables can be encrypted
+ // only iOS main executables should be encrypted
if ( fOutputKind != Options::kDynamicExecutable )
fEncryptable = false;
- if ( fArchitecture != CPU_TYPE_ARM )
+ if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
fEncryptable = false;
// don't move inits in dyld because dyld wants certain
fMakeCompressedDyldInfo = false;
}
-
// only ARM enforces that cpu-sub-types must match
if ( fArchitecture != CPU_TYPE_ARM )
fAllowCpuSubtypeMismatches = true;
if ( fDisablePositionIndependentExecutable )
fPositionIndependentExecutable = false;
+ // arm64 is always PIE
+ if ( (fArchitecture == CPU_TYPE_ARM64) && (fOutputKind == kDynamicExecutable) ) {
+ fPositionIndependentExecutable = true;
+ }
+
// set fOutputSlidable
switch ( fOutputKind ) {
case Options::kObjectFile:
case Options::kDynamicBundle:
if ( !fVersionLoadCommandForcedOff )
fVersionLoadCommand = true;
- // <rdar://problem/9945513> for now, don't create version load commands for iOS simulator builds
- if ( fVersionLoadCommand && (fArchitecture == CPU_TYPE_I386) ) {
- for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
- if ( strstr(*sdkit, "/iPhoneSimulator.platform/") != NULL )
- fVersionLoadCommand = false;
- }
- }
break;
}
fNeedsThreadLoadCommand = true;
}
else {
- if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture == CPU_TYPE_I386) ) {
- // don't use LC_MAIN for simulator until min host OS is 10.8 for simulator
- fNeedsThreadLoadCommand = true;
- fEntryPointLoadCommand = false;
- }
- else if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+ if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
fEntryPointLoadCommand = true;
fEntryName = "_main";
}
}
}
+ // allow trie based absolute symbols if targeting new enough OS
+ if ( fMakeCompressedDyldInfo ) {
+ if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
+ // <rdar://problem/13179029> Allow absolute symbols in export trie for device but not simulator
+ if ( !fTargetIOSSimulator )
+ fAbsoluteSymbols = true;
+ }
+ }
+
+ // <rdar://problem/12959510> iOS main executables now default to 16KB page size
+ if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fOutputKind == Options::kDynamicExecutable) ) {
+ // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
+ if ( fEncryptable ) {
+ if ( fSegmentAlignment == 4096 )
+ fSegmentAlignment = 4096*4;
+ }
+ }
+
+ // <rdar://problem/12258065> ARM64 needs 16KB page size for user land code
+ if ( fArchitecture == CPU_TYPE_ARM64 ) {
+ if ( fSegmentAlignment == 4096 ) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ fSegmentAlignment = 4096*4;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kKextBundle:
+ case Options::kObjectFile:
+ case Options::kPreload:
+ break;
+ }
+ }
+ }
+
+ // <rdar://problem/13624134> linker should not convert dwarf unwind if .o file has compact unwind section
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ if ( fKeepDwarfUnwindForcedOn ) {
+ fKeepDwarfUnwind = true;
+ }
+ else if ( fKeepDwarfUnwindForcedOff ) {
+ fKeepDwarfUnwind = false;
+ }
+ else {
+ if ( minOS(ld::mac10_9, ld::iOS_7_0) )
+ fKeepDwarfUnwind = false;
+ else
+ fKeepDwarfUnwind = true;
+ }
+ break;
+ case Options::kKextBundle:
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kPreload:
+ fKeepDwarfUnwind = true;
+ break;
+ }
+
}
void Options::checkIllegalOptionCombinations()
throw "-stack_addr must be < 4G for 32-bit processes";
break;
case CPU_TYPE_X86_64:
+ case CPU_TYPE_ARM64:
break;
}
if ( (fStackAddr & -4096) != fStackAddr )
fStackAddr = 0x2F000000;
if ( fStackAddr > 0x30000000)
throw "-stack_addr must be < 0x30000000 for arm";
+ break;
case CPU_TYPE_X86_64:
if ( fStackAddr == 0 ) {
fStackAddr = 0x00007FFF5C000000LL;
}
break;
+ case CPU_TYPE_ARM64:
+ if ( fStackSize > 0x20000000 )
+ throw "-stack_size must be < 512MB";
+ if ( fStackAddr == 0 ) {
+ fStackAddr = 0x120000000;
+ }
+ break;
}
if ( (fStackSize & -4096) != fStackSize )
throw "-stack_size must be multiples of 4K";
if ( fSetuidSafe && (fOutputKind == Options::kObjectFile) )
throw "-setuid_safe cannot be used with -r";
+ // <rdar://problem/12781832> compiler driver no longer uses -objc_abi_version, it uses -ios_simulator_version_min instead
+ if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && fTargetIOSSimulator )
+ fObjCABIVersion2Override = true;
+
// rdar://problem/4718189 map ObjC class names to new runtime names
bool alterObjC1ClassNamesToObjC2 = false;
switch (fArchitecture) {
break;
case CPU_TYPE_X86_64:
case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM64:
alterObjC1ClassNamesToObjC2 = true;
break;
}
// first 4KB for 32-bit architectures
fZeroPageSize = 0x1000;
break;
+ case CPU_TYPE_ARM64:
case CPU_TYPE_X86_64:
// first 4GB for x86_64 on all OS's
fZeroPageSize = 0x100000000ULL;
return sym;
}
+
+void Options::dumpDependency(uint8_t opcode, const char* path) const
+{
+ if ( !this->dumpDependencyInfo() )
+ return;
+
+ // one time open() of -dependency_info file
+ if ( fDependencyFileDescriptor == -1 ) {
+ fDependencyFileDescriptor = open(this->dependencyInfoPath(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if ( fDependencyFileDescriptor == -1 )
+ throwf("Could not open or create -dependency_info file: %s", this->dependencyInfoPath());
+
+ // write header
+ uint8_t version = depLinkerVersion;
+ if ( write(fDependencyFileDescriptor, &version, 1) == -1 )
+ throwf("write() to -dependency_info failed, errno=%d", errno);
+ extern const char ldVersionString[];
+ if ( write(fDependencyFileDescriptor, ldVersionString, strlen(ldVersionString)+1) == -1 )
+ throwf("write() to -dependency_info failed, errno=%d", errno);
+ }
+
+ char realPath[PATH_MAX];
+ if ( path[0] != '/' ) {
+ if ( realpath(path, realPath) != NULL ) {
+ path = realPath;
+ }
+ }
+
+ if ( write(fDependencyFileDescriptor, &opcode, 1) == -1 )
+ throwf("write() to -dependency_info failed, errno=%d", errno);
+ if ( write(fDependencyFileDescriptor, path, strlen(path)+1) == -1 )
+ throwf("write() to -dependency_info failed, errno=%d", errno);
+
+ //fprintf(stderr, "0x%02X %s\n", opcode, path);
+}
+
+
+
{
public:
LibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false),
- fLazyLoad(false), fUpward(false), fForceLoad(false) {}
+ fLazyLoad(false), fUpward(false), fIndirectDylib(false),
+ fForceLoad(false) {}
// for dynamic libraries
bool fWeakImport;
bool fReExport;
bool fBundleLoader;
bool fLazyLoad;
bool fUpward;
+ bool fIndirectDylib;
// for static libraries
bool fForceLoad;
};
// If the object already has a path the p must be NULL.
// If the object does not have a path then p can be any candidate path, and if the file exists the object permanently remembers the path.
// Returns true if the file exists, false if not.
- bool checkFileExists(const char *p=NULL);
+ bool checkFileExists(const Options& options, const char *p=NULL);
// Returns true if a previous call to checkFileExists() succeeded.
// Returns false if the file does not exist of checkFileExists() has never been called.
bool missing() const { return modTime==0; }
-};
+ };
struct ExtraSection {
const char* segmentName;
const char* alias;
};
+ enum { depLinkerVersion=0x00, depObjectFile=0x10, depDirectDylib=0x10, depIndirectDylib=0x10,
+ depUpwardDirectDylib=0x10, depUpwardIndirectDylib=0x10, depArchive=0x10,
+ depFileList=0x10, depSection=0x10, depBundleLoader=0x10, depMisc=0x10, depNotFound=0x11,
+ depOutputFile = 0x40 };
+
+ void dumpDependency(uint8_t, const char* path) const;
+
typedef const char* const* UndefinesIterator;
// const ObjectFile::ReaderOptions& readerOptions();
bool canReExportSymbols() const { return fCanReExportSymbols; }
const char* tempLtoObjectPath() const { return fTempLtoObjectPath; }
const char* overridePathlibLTO() const { return fOverridePathlibLTO; }
+ const char* mcpuLTO() const { return fLtoCpu; }
bool objcCategoryMerging() const { return fObjcCategoryMerging; }
bool pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
+ bool keepDwarfUnwind() const { return fKeepDwarfUnwind; }
+ bool generateDtraceDOF() const { return fGenerateDtraceDOF; }
bool hasWeakBitTweaks() const;
bool forceWeak(const char* symbolName) const;
bool forceNotWeak(const char* symbolName) const;
bool forceWeakNonWildCard(const char* symbolName) const;
bool forceNotWeakNonWildcard(const char* symbolName) const;
+ bool forceCoalesce(const char* symbolName) const;
Snapshot& snapshot() const { return fLinkSnapshot; }
bool errorBecauseOfWarnings() const;
bool needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
bool needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
bool needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
bool needsDependentDRInfo() const { return fDependentDRInfo; }
+ bool canUseAbsoluteSymbols() const { return fAbsoluteSymbols; }
+ bool allowSimulatorToLinkWithMacOSX() const { return fAllowSimulatorToLinkWithMacOSX; }
uint64_t sourceVersion() const { return fSourceVersion; }
uint32_t sdkVersion() const { return fSDKVersion; }
const char* demangleSymbol(const char* sym) const;
bool pipelineEnabled() const { return fPipelineFifo != NULL; }
const char* pipelineFifo() const { return fPipelineFifo; }
-
+ bool dumpDependencyInfo() const { return (fDependencyInfoPath != NULL); }
+ const char* dependencyInfoPath() const { return fDependencyInfoPath; }
+ bool targetIOSSimulator() const { return fTargetIOSSimulator; }
+ ld::relocatable::File::LinkerOptionsList&
+ linkerOptions() const { return fLinkerOptions; }
+ FileInfo findFramework(const char* frameworkName) const;
+ FileInfo findLibrary(const char* rootName, bool dylibsOnly=false) const;
+
private:
typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals> NameSet;
void checkIllegalOptionCombinations();
void buildSearchPaths(int argc, const char* argv[]);
void parseArch(const char* architecture);
- FileInfo findLibrary(const char* rootName, bool dylibsOnly=false);
- FileInfo findFramework(const char* frameworkName);
- FileInfo findFramework(const char* rootName, const char* suffix);
+ FileInfo findFramework(const char* rootName, const char* suffix) const;
bool checkForFile(const char* format, const char* dir, const char* rootName,
FileInfo& result) const;
uint64_t parseVersionNumber64(const char*);
SetWithWildcards fForceWeakSymbols;
SetWithWildcards fForceNotWeakSymbols;
SetWithWildcards fReExportSymbols;
+ SetWithWildcards fForceCoalesceSymbols;
NameSet fRemovedExports;
NameToOrder fExportSymbolsOrder;
ExportMode fExportMode;
const char* fDyldInstallPath;
const char* fTempLtoObjectPath;
const char* fOverridePathlibLTO;
+ const char* fLtoCpu;
uint64_t fZeroPageSize;
uint64_t fStackSize;
uint64_t fStackAddr;
bool fDependentDRInfo;
bool fDependentDRInfoForcedOn;
bool fDependentDRInfoForcedOff;
+ bool fTargetIOSSimulator;
+ bool fExportDynamic;
+ bool fAbsoluteSymbols;
+ bool fAllowSimulatorToLinkWithMacOSX;
+ bool fKeepDwarfUnwind;
+ bool fKeepDwarfUnwindForcedOn;
+ bool fKeepDwarfUnwindForcedOff;
+ bool fGenerateDtraceDOF;
DebugInfoStripping fDebugInfoStripping;
const char* fTraceOutputFile;
ld::MacVersionMin fMacVersionMin;
std::vector<const char*> fFrameworkSearchPaths;
std::vector<const char*> fSDKPaths;
std::vector<const char*> fDyldEnvironExtras;
+ std::vector< std::vector<const char*> > fLinkerOptions;
bool fSaveTempFiles;
- mutable Snapshot fLinkSnapshot;
- bool fSnapshotRequested;
- const char * fPipelineFifo;
+ mutable Snapshot fLinkSnapshot;
+ bool fSnapshotRequested;
+ const char* fPipelineFifo;
+ const char* fDependencyInfoPath;
+ mutable int fDependencyFileDescriptor;
};
const ld::Atom* atom = *ait;
bool pagePerAtom = false;
uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+ uint32_t atomModulus = atom->alignment().modulus;
if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) {
+ // most objc sections cannot be padded
+ bool contiguousObjCSection = ( strncmp(atom->section().sectionName(), "__objc_", 7) == 0 );
+ if ( strcmp(atom->section().sectionName(), "__objc_const") == 0 )
+ contiguousObjCSection = false;
+ if ( strcmp(atom->section().sectionName(), "__objc_data") == 0 )
+ contiguousObjCSection = false;
switch ( atom->section().type() ) {
case ld::Section::typeUnclassified:
case ld::Section::typeTentativeDefs:
case ld::Section::typeZeroFill:
+ if ( contiguousObjCSection )
+ break;
pagePerAtom = true;
- if ( atomAlignmentPowerOf2 < 12 )
+ if ( atomAlignmentPowerOf2 < 12 ) {
atomAlignmentPowerOf2 = 12;
+ atomModulus = 0;
+ }
break;
default:
break;
// calculate section offset for this atom
uint64_t alignment = 1 << atomAlignmentPowerOf2;
uint64_t currentModulus = (offset % alignment);
- uint64_t requiredModulus = atom->alignment().modulus;
+ uint64_t requiredModulus = atomModulus;
if ( currentModulus != requiredModulus ) {
if ( requiredModulus > currentModulus )
offset += requiredModulus-currentModulus;
}
+void OutputFile::rangeCheckARM64Branch26(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t bl_128MegLimit = 0x07FFFFFF;
+ if ( (displacement > bl_128MegLimit) || (displacement < (-bl_128MegLimit)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("b(l) ARM64 branch out of range (%lld max is +/-128MB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+void OutputFile::rangeCheckARM64Page21(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t adrp_4GigLimit = 0x100000000ULL;
+ if ( (displacement > adrp_4GigLimit) || (displacement < (-adrp_4GigLimit)) ) {
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ throwf("ARM64 ADRP out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
uint16_t OutputFile::get16LE(uint8_t* loc) { return LittleEndian::get16(*(uint16_t*)loc); }
accumulator -= delta;
break;
case ld::Fixup::kindAddAddend:
- // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
- // into themselves such as jump tables. These .long should not have thumb bit set
- // even though the target is a thumb instruction. We can tell it is an interior pointer
- // because we are processing an addend.
- if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
- accumulator &= (-2);
- //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X",
- // atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+ if ( ! fit->contentIgnoresAddend ) {
+ // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
+ // into themselves such as jump tables. These .long should not have thumb bit set
+ // even though the target is a thumb instruction. We can tell it is an interior pointer
+ // because we are processing an addend.
+ if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
+ accumulator &= (-2);
+ //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X",
+ // atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+ }
+ accumulator += fit->u.addend;
}
- accumulator += fit->u.addend;
break;
case ld::Fixup::kindSubtractAddend:
accumulator -= fit->u.addend;
set32LE(fixUpLocation, 0x46C04040);
}
break;
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change call site to a NOP
+ set32LE(fixUpLocation, 0xD503201F);
+ }
+ break;
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+ if ( _options.outputKind() != Options::kObjectFile ) {
+ // change call site to 'MOVZ X0,0'
+ set32LE(fixUpLocation, 0xD2800000);
+ }
+ break;
case ld::Fixup::kindLazyTarget:
break;
case ld::Fixup::kindSetLazyOffset:
set32LE(fixUpLocation, newInstruction);
}
break;
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ accumulator = addressOf(state, fit, &toTarget);
+ // fall into kindStoreARM64Branch26 case
+ case ld::Fixup::kindStoreARM64Branch26:
+ if ( fit->contentAddendOnly )
+ delta = accumulator;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+ rangeCheckARM64Branch26(delta, state, atom, fit);
+ instruction = get32LE(fixUpLocation);
+ newInstruction = (instruction & 0xFC000000) | ((uint32_t)(delta >> 2) & 0x03FFFFFF);
+ set32LE(fixUpLocation, newInstruction);
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ accumulator = addressOf(state, fit, &toTarget);
+ // fall into kindStoreARM64Branch26 case
+ case ld::Fixup::kindStoreARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+ case ld::Fixup::kindStoreARM64Page21:
+ {
+ // the ADRP instruction adds the imm << 12 to the page that the pc is on
+ if ( fit->contentAddendOnly )
+ delta = 0;
+ else
+ delta = (accumulator & (-4096)) - ((atom->finalAddress() + fit->offsetInAtom) & (-4096));
+ rangeCheckARM64Page21(delta, state, atom, fit);
+ instruction = get32LE(fixUpLocation);
+ uint32_t immhi = (delta >> 9) & (0x00FFFFE0);
+ uint32_t immlo = (delta << 17) & (0x60000000);
+ newInstruction = (instruction & 0x9F00001F) | immlo | immhi;
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+ accumulator = addressOf(state, fit, &toTarget);
+ // fall into kindAddressARM64PageOff12 case
+ case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+ case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreARM64PageOff12:
+ {
+ uint32_t offset = accumulator & 0x00000FFF;
+ instruction = get32LE(fixUpLocation);
+ // LDR/STR instruction have implicit scale factor, need to compensate for that
+ if ( instruction & 0x08000000 ) {
+ uint32_t implictShift = ((instruction >> 30) & 0x3);
+ switch ( implictShift ) {
+ case 0:
+ if ( (instruction & 0x04800000) == 0x04800000 ) {
+ // vector and byte LDR/STR have same "size" bits, need to check other bits to differenciate
+ implictShift = 4;
+ if ( (offset & 0xF) != 0 ) {
+ throwf("128-bit LDR/STR not 16-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
+ atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit),
+ addressOf(state, fit, &toTarget));
+ }
+ }
+ break;
+ case 1:
+ if ( (offset & 0x1) != 0 ) {
+ throwf("16-bit LDR/STR not 2-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
+ atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit),
+ addressOf(state, fit, &toTarget));
+ }
+ break;
+ case 2:
+ if ( (offset & 0x3) != 0 ) {
+ throwf("32-bit LDR/STR not 4-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
+ atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit),
+ addressOf(state, fit, &toTarget));
+ }
+ break;
+ case 3:
+ if ( (offset & 0x7) != 0 ) {
+ throwf("64-bit LDR/STR not 8-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
+ atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit),
+ addressOf(state, fit, &toTarget));
+ }
+ break;
+ }
+ // compensate for implicit scale
+ offset >>= implictShift;
+ }
+ if ( fit->contentAddendOnly )
+ offset = 0;
+ uint32_t imm12 = offset << 10;
+ newInstruction = (instruction & 0xFFC003FF) | imm12;
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+ accumulator = addressOf(state, fit, &toTarget);
+ // fall into kindStoreARM64GOTLoadPage21 case
+ case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+ {
+ // GOT entry was optimized away, change LDR instruction to a ADD
+ instruction = get32LE(fixUpLocation);
+ if ( (instruction & 0xFFC00000) != 0xF9400000 )
+ throwf("GOT load reloc does not point to a LDR instruction in %s", atom->name());
+ uint32_t offset = accumulator & 0x00000FFF;
+ uint32_t imm12 = offset << 10;
+ newInstruction = 0x91000000 | imm12 | (instruction & 0x000003FF);
+ set32LE(fixUpLocation, newInstruction);
+ }
+ break;
+ case ld::Fixup::kindStoreARM64PointerToGOT:
+ set64LE(fixUpLocation, accumulator);
+ break;
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ if ( fit->contentAddendOnly )
+ delta = accumulator;
+ else
+ delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+ set32LE(fixUpLocation, delta);
+ break;
+#endif
}
}
}
fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
}
if ( fd == -1 )
- throwf("can't open output file for writing: %s, errno=%d", tmpOutput, errno);
- ftruncate(fd, _fileSize);
+ throwf("can't open output file for writing '%s', errno=%d", tmpOutput, errno);
+ if ( ftruncate(fd, _fileSize) == -1 ) {
+ int err = errno;
+ unlink(tmpOutput);
+ if ( err == ENOSPC )
+ throwf("not enough disk space for writing '%s'", _options.outputFilePath());
+ else
+ throwf("can't grow file for writing '%s', errno=%d", _options.outputFilePath(), err);
+ }
wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
if ( wholeBuffer == MAP_FAILED )
if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
}
+ ::close(fd);
+ // <rdar://problem/13118223> NFS: iOS incremental builds in Xcode 4.6 fail with codesign error
+ // NFS seems to pad the end of the file sometimes. Calling trunc seems to correct it...
+ ::truncate(_options.outputFilePath(), _fileSize);
}
}
// in -r mode, clarify symbolTableNotInFinalLinkedImages
if ( _options.outputKind() == Options::kObjectFile ) {
- if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+ if ( (_options.architecture() == CPU_TYPE_X86_64) || (_options.architecture() == CPU_TYPE_ARM64) ) {
// x86_64 .o files need labels on anonymous literal strings
if ( (sect->type() == ld::Section::typeCString) && (atom->combine() == ld::Atom::combineByNameAndContent) ) {
(const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
case ld::Atom::scopeLinkageUnit:
if ( _options.outputKind() == Options::kObjectFile ) {
if ( _options.keepPrivateExterns() ) {
- assert( (atom->combine() == ld::Atom::combineNever) || (atom->combine() == ld::Atom::combineByName) );
_exportedAtoms.push_back(atom);
}
else if ( _options.keepLocalSymbol(atom->name()) ) {
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<arm64>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
#endif
default:
- throw "architecture not supported for -preload";
+ throw "-preload not supported";
}
}
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( _hasSectionRelocations ) {
+ _sectionsRelocationsAtom = new SectionRelocationsAtom<arm64>(_options, state, *this);
+ sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+ }
+ if ( _hasDyldInfo ) {
+ _rebasingInfoAtom = new RebaseInfoAtom<arm64>(_options, state, *this);
+ rebaseSection = state.addAtom(*_rebasingInfoAtom);
+
+ _bindingInfoAtom = new BindingInfoAtom<arm64>(_options, state, *this);
+ bindingSection = state.addAtom(*_bindingInfoAtom);
+
+ _weakBindingInfoAtom = new WeakBindingInfoAtom<arm64>(_options, state, *this);
+ weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+
+ _lazyBindingInfoAtom = new LazyBindingInfoAtom<arm64>(_options, state, *this);
+ lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+
+ _exportInfoAtom = new ExportInfoAtom<arm64>(_options, state, *this);
+ exportSection = state.addAtom(*_exportInfoAtom);
+ }
+ if ( _hasLocalRelocations ) {
+ _localRelocsAtom = new LocalRelocationsAtom<arm64>(_options, state, *this);
+ localRelocationsSection = state.addAtom(*_localRelocsAtom);
+ }
+ if ( _hasSplitSegInfo ) {
+ _splitSegInfoAtom = new SplitSegInfoAtom<arm64>(_options, state, *this);
+ splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+ }
+ if ( _hasFunctionStartsInfo ) {
+ _functionStartsAtom = new FunctionStartsAtom<arm64>(_options, state, *this);
+ functionStartsSection = state.addAtom(*_functionStartsAtom);
+ }
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<arm64>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<arm64>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
+ symbolTableSection = state.addAtom(*_symbolTableAtom);
+ }
+ if ( _hasExternalRelocations ) {
+ _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
+ externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+ }
+ if ( _hasSymbolTable ) {
+ _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
+ indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+ _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+ stringPoolSection = state.addAtom(*_stringPoolAtom);
+ }
+ break;
#endif
default:
throw "unknown architecture";
headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
break;
#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm64>(_options, state, *this);
+ headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+ break;
+#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
_headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMLoad12:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreARM64Page21:
+ case ld::Fixup::kindStoreARM64PageOff12:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+#endif
return true;
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
return (_options.outputKind() != Options::kKextBundle);
default:
break;
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMLoad12:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+#endif
return true;
case ld::Fixup::kindStoreX86DtraceCallSiteNop:
case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreARMDtraceCallSiteNop:
case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
return (_options.outputKind() == Options::kObjectFile);
ld::Fixup* fixupWithTarget = NULL;
ld::Fixup* fixupWithMinusTarget = NULL;
ld::Fixup* fixupWithStore = NULL;
+ ld::Fixup* fixupWithAddend = NULL;
const ld::Atom* target = NULL;
const ld::Atom* minusTarget = NULL;
uint64_t targetAddend = 0;
switch ( fit->kind ) {
case ld::Fixup::kindAddAddend:
targetAddend = fit->u.addend;
+ fixupWithAddend = fit;
break;
case ld::Fixup::kindSubtractAddend:
minusTargetAddend = fit->u.addend;
+ fixupWithAddend = fit;
break;
case ld::Fixup::kindSubtractTargetAddress:
switch ( fit->binding ) {
if ( fit->lastInCluster() ) {
if ( (fixupWithStore != NULL) && (target != NULL) ) {
if ( _options.outputKind() == Options::kObjectFile ) {
- this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+ this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithAddend, fixupWithStore,
target, minusTarget, targetAddend, minusTargetAddend);
}
else {
else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable)
&& ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
if ( ! this->pieDisabled ) {
- warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
+#if SUPPORT_ARCH_arm64
+ if ( _options.architecture() == CPU_TYPE_ARM64 ) {
+ const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+ throwf("Absolute addressing not allowed in arm64 code but used in '%s' referencing '%s'", demangledName, _options.demangleSymbol(target->name()));
+ }
+ else
+#endif
+ {
+ warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
"but used in %s from %s. "
"To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie",
atom->name(), atom->file()->path());
+ }
}
this->pieDisabled = true;
}
throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
}
else {
- throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+ if ( (target->file() != NULL) && (atom->file() != NULL) )
+ throwf("illegal text-relocation to '%s' in %s from '%s' in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+ else
+ throwf("illegal text reloc in '%s' to '%s'", atom->name(), target->name());
}
}
// ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
return;
}
+ // <rdar://problem/13700961> spurious warning when weak function has reference to itself
+ if ( fixupWithTarget->binding == ld::Fixup::bindingDirectlyBound ) {
+ // ok to ignore pc-rel references within a weak function to itself
+ return;
+ }
// Have direct reference to weak-global. This should be an indrect reference
const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
// this will be done by other cluster on lazy pointer atom
}
}
- else if ( (target->contentType() == ld::Atom::typeResolver) && (target->scope() != ld::Atom::scopeGlobal) ) {
+ else if ( target->contentType() == ld::Atom::typeResolver ) {
// <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
+ // <rdar://problem/12629331> Resolver function run before initializers when overriding the dyld shared cache
+ // The lazy pointers used by stubs used when non-lazy binding to a resolver are not normal lazy pointers
+ // and should not be in lazy binding info.
needsLazyBinding = false;
}
else {
needsRebase = false;
needsBinding = true;
}
+ else if ( _options.forceCoalesce(target->name()) ) {
+ needsWeakBinding = true;
+ }
}
break;
case ld::Atom::definitionAbsolute:
}
}
+ // <rdar://problem/13828711> if target is an import alias, use base of alias
+ if ( target->isAlias() && (target->definition() == ld::Atom::definitionProxy) ) {
+ for (ld::Fixup::iterator fit = target->fixupsBegin(), end=target->fixupsEnd(); fit != end; ++fit) {
+ if ( fit->firstInCluster() ) {
+ if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+ if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+ //fprintf(stderr, "switching import of %s to import of %s\n", target->name(), fit->u.target->name());
+ target = fit->u.target;
+ }
+ }
+ }
+ }
+ }
+
// record dyld info for this cluster
if ( needsRebase ) {
if ( inReadOnlySeg ) {
sect->hasLocalRelocs = true; // so dyld knows to change permissions on __TEXT segment
rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
}
- if ( (addend != 0) && _options.sharedRegionEligible() ) {
- // make sure the addend does not cause the pointer to point outside the target's segment
- // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
- uint64_t targetAddress = target->finalAddress();
- for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
- ld::Internal::FinalSection* sct = *sit;
- uint64_t sctEnd = (sct->address+sct->size);
- if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
- if ( (targetAddress+addend) > sctEnd ) {
- warning("data symbol %s from %s has pointer to %s + 0x%08llX. "
- "That large of an addend may disable %s from being put in the dyld shared cache.",
- atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+ if ( _options.sharedRegionEligible() ) {
+ // <rdar://problem/13287063> when range checking, ignore high byte of arm64 addends
+ uint64_t checkAddend = addend;
+ if ( _options.architecture() == CPU_TYPE_ARM64 )
+ checkAddend &= 0x0FFFFFFFFFFFFFFFULL;
+ if ( checkAddend != 0 ) {
+ // make sure the addend does not cause the pointer to point outside the target's segment
+ // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+ uint64_t targetAddress = target->finalAddress();
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sct = *sit;
+ uint64_t sctEnd = (sct->address+sct->size);
+ if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+ if ( (targetAddress+checkAddend) > sctEnd ) {
+ warning("data symbol %s from %s has pointer to %s + 0x%08llX. "
+ "That large of an addend may disable %s from being put in the dyld shared cache.",
+ atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+ }
}
}
}
if ( (target->combine() == ld::Atom::combineByName)
&& (target->definition() == ld::Atom::definitionRegular)
&& (_options.outputKind() != Options::kStaticExecutable)
- && (_options.outputKind() != Options::kPreload) ) {
+ && (_options.outputKind() != Options::kPreload)
+ && (atom != target) ) {
needsExternReloc = true;
}
else if ( _options.outputKind() == Options::kDynamicExecutable ) {
}
break;
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
if ( _options.outputKind() == Options::kKextBundle ) {
assert(target != NULL);
if ( target->definition() == ld::Atom::definitionProxy ) {
bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, ld::Fixup* fixupWithTarget)
{
- if ( _options.architecture() == CPU_TYPE_X86_64 ) {
- // x86_64 uses external relocations for everthing that has a symbol
+ if ( (_options.architecture() == CPU_TYPE_X86_64) || (_options.architecture() == CPU_TYPE_ARM64) ) {
+ // x86_64 and ARM64 use external relocations for everthing that has a symbol
return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
}
return false;
}
+bool OutputFile::useSectionRelocAddend(ld::Fixup* fixupWithTarget)
+{
+#if SUPPORT_ARCH_arm64
+ if ( _options.architecture() == CPU_TYPE_ARM64 ) {
+ switch ( fixupWithTarget->kind ) {
+ case ld::Fixup::kindStoreARM64Branch26:
+ case ld::Fixup::kindStoreARM64Page21:
+ case ld::Fixup::kindStoreARM64PageOff12:
+ return true;
+ default:
+ return false;
+ }
+ }
+#endif
+ return false;
+}
+
void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom,
- ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget,
+ ld::Fixup* fixupWithAddend, ld::Fixup* fixupWithStore,
const ld::Atom* target, const ld::Atom* minusTarget,
uint64_t targetAddend, uint64_t minusTargetAddend)
{
bool targetUsesExternalReloc = this->useExternalSectionReloc(atom, target, fixupWithTarget);
bool minusTargetUsesExternalReloc = (minusTarget != NULL) && this->useExternalSectionReloc(atom, minusTarget, fixupWithMinusTarget);
- // in x86_64 .o files an external reloc means the content contains just the addend
- if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+ // in x86_64 and arm64 .o files an external reloc means the content contains just the addend
+ if ( (_options.architecture() == CPU_TYPE_X86_64) ||(_options.architecture() == CPU_TYPE_ARM64) ) {
if ( targetUsesExternalReloc ) {
fixupWithTarget->contentAddendOnly = true;
fixupWithStore->contentAddendOnly = true;
+ if ( this->useSectionRelocAddend(fixupWithStore) && (fixupWithAddend != NULL) )
+ fixupWithAddend->contentIgnoresAddend = true;
}
if ( minusTargetUsesExternalReloc )
fixupWithMinusTarget->contentAddendOnly = true;
case ld::Fixup::kindStoreX86PCRel32GOTLoad:
case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
case ld::Fixup::kindStoreX86PCRel32GOT:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
case ld::Fixup::kindStoreTargetAddressX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
case ld::Fixup::kindStoreARMLow16:
case ld::Fixup::kindStoreThumbLow16:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreARM64Page21:
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
assert(target != NULL);
if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
_splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
void setSectionSizesAndAlignments(ld::Internal& state);
void addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,
const ld::Atom* atom, ld::Fixup* fixupWithTarget,
- ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+ ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithAddend,
+ ld::Fixup* fixupWithStore,
const ld::Atom* target, const ld::Atom* minusTarget,
uint64_t targetAddend, uint64_t minusTargetAddend);
void addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect,
uint64_t targetAddend, uint64_t minusTargetAddend);
bool useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target,
ld::Fixup* fixupWithTarget);
+ bool useSectionRelocAddend(ld::Fixup* fixupWithTarget);
uint64_t pageAlign(uint64_t addr);
uint64_t pageAlign(uint64_t addr, uint64_t pageSize);
void setLoadCommandsPadding(ld::Internal& state);
const ld::Fixup* fixup);
void rangeCheckThumbBranch22(int64_t delta, ld::Internal& state, const ld::Atom* atom,
const ld::Fixup* fixup);
+ void rangeCheckARM64Branch26(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+ void rangeCheckARM64Page21(int64_t delta, ld::Internal& state, const ld::Atom* atom,
+ const ld::Fixup* fixup);
+
+
uint64_t sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
uint64_t tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
void dumpAtomsBySection(ld::Internal& state, bool);
void setFinalAliasOf() const {
(const_cast<AliasAtom*>(this))->setAttributesFromAtom(_aliasOf);
+ (const_cast<AliasAtom*>(this))->setScope(ld::Atom::scopeGlobal);
}
private:
_internal.objcObjectConstraint = ld::File::objcConstraintGC;
_internal.cpuSubType = _options.subArchitecture();
+
+ // In -r mode, look for -linker_option additions
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ ld::relocatable::File::LinkerOptionsList lo = _options.linkerOptions();
+ for (relocatable::File::LinkerOptionsList::const_iterator it=lo.begin(); it != lo.end(); ++it) {
+ doLinkerOption(*it, "command line");
+ }
+ }
}
void Resolver::buildAtomList()
{
// each input files contributes initial atoms
_atoms.reserve(1024);
- _inputFiles.forEachInitialAtom(*this);
+ _inputFiles.forEachInitialAtom(*this, _internal);
_completedInitialObjectFiles = true;
}
+void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName)
+{
+ if ( linkerOption.size() == 1 ) {
+ const char* lo1 = linkerOption.front();
+ if ( strncmp(lo1, "-l", 2) == 0 ) {
+ _internal.linkerOptionLibraries.insert(&lo1[2]);
+ }
+ else {
+ warning("unknown linker option from object file ignored: '%s' in %s", lo1, fileName);
+ }
+ }
+ else if ( linkerOption.size() == 2 ) {
+ const char* lo2a = linkerOption[0];
+ const char* lo2b = linkerOption[1];
+ if ( strcmp(lo2a, "-framework") == 0 ) {
+ _internal.linkerOptionFrameworks.insert(lo2b);
+ }
+ else {
+ warning("unknown linker option from object file ignored: '%s' '%s' from %s", lo2a, lo2b, fileName);
+ }
+ }
+ else {
+ warning("unknown linker option from object file ignored, starting with: '%s' from %s", linkerOption.front(), fileName);
+ }
+}
+
void Resolver::doFile(const ld::File& file)
{
const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
if ( objFile != NULL ) {
+ // if file has linker options, process them
+ ld::relocatable::File::LinkerOptionsList* lo = objFile->linkerOptions();
+ if ( lo != NULL ) {
+ for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
+ this->doLinkerOption(*it, file.path());
+ }
+ }
+
// update which form of ObjC is being used
switch ( file.objCConstraint() ) {
case ld::File::objcConstraintNone:
throwf("command line specified -objc_gc_only, but file is retain/release based: %s", file.path());
if ( _options.objcGc() )
throwf("command line specified -objc_gc, but file is retain/release based: %s", file.path());
- _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
+ if ( !_options.targetIOSSimulator() && (_internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator) )
+ _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
break;
case ld::File::objcConstraintRetainReleaseOrGC:
if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone )
_internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ if ( _options.targetIOSSimulator() )
+ warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
break;
case ld::File::objcConstraintGC:
if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
_internal.objcObjectConstraint = ld::File::objcConstraintGC;
+ if ( _options.targetIOSSimulator() )
+ warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
+ break;
+ case ld::File::objcConstraintRetainReleaseForSimulator:
+ if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone ) {
+ if ( !_options.targetIOSSimulator() && (_options.outputKind() != Options::kObjectFile) )
+ warning("ObjC object file (%s) was compiled for iOS Simulator, but linking for MacOSX", file.path());
+ _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+ }
+ else if ( _internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
+ _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+ }
break;
}
throwf("command line specified -objc_gc_only, but dylib is retain/release based: %s", file.path());
if ( _options.objcGc() )
throwf("command line specified -objc_gc, but dylib is retain/release based: %s", file.path());
+ if ( _options.targetIOSSimulator() )
+ warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
_internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
break;
case ld::File::objcConstraintRetainReleaseOrGC:
if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
_internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ if ( _options.targetIOSSimulator() )
+ warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
break;
case ld::File::objcConstraintGC:
if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
- _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+ if ( _options.targetIOSSimulator() )
+ warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
+ _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+ break;
+ case ld::File::objcConstraintRetainReleaseForSimulator:
+ if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
+ _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+ else if ( _internal.objcDylibConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
+ warning("ObjC dylib (%s) was compiled for iOS Simulator, but dylibs others were compiled for MacOSX", file.path());
+ _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+ }
break;
}
}
case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreARMDtraceCallSiteNop:
case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
case ld::Fixup::kindDtraceExtra:
}
}
}
-
+
+ // Use linker options to resolve an remaining undefined symbols
+ if ( !_internal.linkerOptionLibraries.empty() || !_internal.linkerOptionFrameworks.empty() ) {
+ std::vector<const char*> undefineNames;
+ _symbolTable.undefines(undefineNames);
+ if ( undefineNames.size() != 0 ) {
+ for (std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+ const char* undef = *it;
+ if ( ! _symbolTable.hasName(undef) ) {
+ _inputFiles.searchLibraries(undef, true, true, false, *this);
+ }
+ }
+ }
+ }
+
// create proxies as needed for undefined symbols
if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
std::vector<const char*> undefineNames;
case ld::Fixup::kindNoneGroupSubordinate:
case ld::Fixup::kindNoneGroupSubordinateFDE:
case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
case ld::Fixup::kindSetTargetAddress:
case ld::Fixup::kindSubtractTargetAddress:
case ld::Fixup::kindStoreTargetAddressLittleEndian32:
case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+#endif
if ( fit->binding == ld::Fixup::bindingByContentBound ) {
// normally this was done in convertReferencesToIndirect()
// but a archive loaded .o file may have a forward reference
optOpt.relocatable = (_options.outputKind() == Options::kObjectFile);
optOpt.allowTextRelocs = _options.allowTextRelocs();
optOpt.linkerDeadStripping = _options.deadCodeStrip();
+ optOpt.needsUnwindInfoSection = _options.needsUnwindInfoSection();
+ optOpt.keepDwarfUnwind = _options.keepDwarfUnwind();
optOpt.arch = _options.architecture();
+ optOpt.mcpu = _options.mcpuLTO();
optOpt.llvmOptions = &_options.llvmOptions();
std::vector<const ld::Atom*> newAtoms;
void fillInInternalState();
void fillInHelpersInInternalState();
void removeCoalescedAwayAtoms();
- void fillInEntryPoint();
+ void fillInEntryPoint();
void linkTimeOptimize();
void convertReferencesToIndirect(const ld::Atom& atom);
const ld::Atom* entryPoint(bool searchArchives);
void remainingUndefines(std::vector<const char*>&);
bool printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
void tweakWeakness();
+ void doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName);
typedef std::unordered_set<const char*, CStringHash, CStringEquals> StringSet;
}
void pickAtom() {
+ //fprintf(stderr, "pickAtom(), a=%p, def=%d, b=%p, def=%d\n", &_atomA, _atomA.definition(), &_atomB, _atomB.definition());
// First, discriminate by definition
switch (_atomA.definition()) {
case ld::Atom::definitionRegular:
pickBetweenRegularAtoms();
break;
case ld::Atom::definitionTentative:
+ if ( _atomB.size() > _atomA.size() ) {
+ const char* atomApath = (_atomA.file() != NULL) ? _atomA.file()->path() : "<internal>";
+ const char* atomBpath = (_atomB.file() != NULL) ? _atomB.file()->path() : "<internal>";
+ warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
+ _atomA.name(), _atomB.size(), atomBpath, _atomA.size(), atomApath);
+ }
pickAtomA();
break;
case ld::Atom::definitionAbsolute:
case ld::Atom::definitionTentative:
switch (_atomB.definition()) {
case ld::Atom::definitionRegular:
+ if ( _atomA.size() > _atomB.size() ) {
+ const char* atomApath = (_atomA.file() != NULL) ? _atomA.file()->path() : "<internal>";
+ const char* atomBpath = (_atomB.file() != NULL) ? _atomB.file()->path() : "<internal>";
+ warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
+ _atomA.name(), _atomA.size(),atomApath, _atomB.size(), atomBpath);
+ }
pickAtomB();
break;
case ld::Atom::definitionTentative:
DW_FORM_ref4,
DW_FORM_ref8,
DW_FORM_ref_udata,
- DW_FORM_indirect /* 22 */
+ DW_FORM_indirect,
+ /* new in Dwarf 4 */
+ DW_FORM_sec_offset,
+ DW_FORM_exprloc,
+ DW_FORM_flag_present,
+ DW_FORM_ref_sig8
};
+
enum {
DW_LNS_extended_op = 0,
DW_LNS_copy,
else
return INT_MAX-2;
default:
+ // <rdar://problem/14348664> __DATA,__const section should be near __mod_init_func not __data
+ if ( strcmp(sect.sectionName(), "__const") == 0 )
+ return 14;
// <rdar://problem/7435296> Reorder sections to reduce page faults in object files
- if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 )
+ else if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 )
return 20;
else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 )
return 21;
static uint64_t sUnitsPerSecond = 0;
if ( sUnitsPerSecond == 0 ) {
struct mach_timebase_info timeBaseInfo;
- if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
- sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
- //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
- }
+ if ( mach_timebase_info(&timeBaseInfo) != KERN_SUCCESS )
+ return;
+ sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
}
if ( partTime < sUnitsPerSecond ) {
uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
#include <assert.h>
#include <vector>
-#include <set>
+#include <unordered_set>
+#include "configure.h"
namespace ld {
class File
{
public:
- enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC };
+ enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease,
+ objcConstraintRetainReleaseOrGC, objcConstraintGC,
+ objcConstraintRetainReleaseForSimulator };
class AtomHandler {
public:
Ordinal (uint64_t ordinal) : _ordinal(ordinal) {}
- enum { ArgListPartition=0, IndirectDylibPartition=1, LTOPartition = 2, InvalidParition=0xffff };
+ enum { kArgListPartition=0, kIndirectDylibPartition=1, kLTOPartition = 2, kLinkerOptionPartition = 2, InvalidParition=0xffff };
Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) {
_ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0);
}
// The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list.
// The counter is used for .a files and the value is the index of the object in the archive.
// Thus, an object pulled in from a .a that was listed in a file list could use all three fields.
- static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(ArgListPartition, argIndex, 0, 0); };
+ static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(kArgListPartition, argIndex, 0, 0); };
const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); }
- const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(ArgListPartition, majorIndex(), minorIndex(), index); }
+ const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(kArgListPartition, majorIndex(), minorIndex(), index); }
// For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries.
- static const ld::File::Ordinal indirectDylibBase() { return Ordinal(IndirectDylibPartition, 0, 0, 0); }
+ static const ld::File::Ordinal indirectDylibBase() { return Ordinal(kIndirectDylibPartition, 0, 0, 0); }
const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); }
// For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed.
- static const ld::File::Ordinal LTOOrdinal() { return Ordinal(LTOPartition, 0, 0, 0); }
+ static const ld::File::Ordinal LTOOrdinal() { return Ordinal(kLTOPartition, 0, 0, 0); }
+
+ // For linker options embedded in object files
+ static const ld::File::Ordinal linkeOptionBase() { return Ordinal(kIndirectDylibPartition, 1, 0, 0); }
+ const Ordinal nextLinkerOptionOrdinal() { nextCounter(); return *this; };
+
};
typedef enum { Reloc, Dylib, Archive, Other } Type;
//
enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500,
mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800,
- mac10_Future=0x10000000 };
+ mac10_9=0x000A0900, mac10_Future=0x10000000 };
enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100,
iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000,
- iOS_6_0=0x00060000, iOS_Future=0x10000000};
+ iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_Future=0x10000000};
namespace relocatable {
//
uint32_t value;
const char* string;
};
+ typedef const std::vector< std::vector<const char*> > LinkerOptionsList;
File(const char* pth, time_t modTime, Ordinal ord)
: ld::File(pth, modTime, ord, Reloc) { }
virtual const std::vector<Stab>* stabs() const = 0;
virtual bool canScatterAtoms() const = 0;
virtual bool hasLongBranchStubs() { return false; }
+ virtual LinkerOptionsList* linkerOptions() const = 0;
};
} // namespace relocatable
virtual bool hasPublicInstallName() const = 0;
virtual bool allSymbolsAreWeakImported() const = 0;
virtual const void* codeSignatureDR() const = 0;
+ virtual bool installPathVersionSpecific() const { return false; }
protected:
const char* _dylibInstallPath;
uint32_t _dylibTimeStamp;
kindStoreARMLoad12,
kindStoreARMLow16, kindStoreARMHigh16,
kindStoreThumbLow16, kindStoreThumbHigh16,
+#if SUPPORT_ARCH_arm64
+ // ARM64 specific store kinds
+ kindStoreARM64Branch26,
+ kindStoreARM64Page21, kindStoreARM64PageOff12,
+ kindStoreARM64GOTLoadPage21, kindStoreARM64GOTLoadPageOff12,
+ kindStoreARM64GOTLeaPage21, kindStoreARM64GOTLeaPageOff12,
+ kindStoreARM64TLVPLoadPage21, kindStoreARM64TLVPLoadPageOff12,
+ kindStoreARM64PointerToGOT, kindStoreARM64PCRelToGOT,
+#endif
// dtrace probes
kindDtraceExtra,
kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear,
kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear,
+ kindStoreARM64DtraceCallSiteNop, kindStoreARM64DtraceIsEnableSiteClear,
kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
// lazy binding
kindLazyTarget, kindSetLazyOffset,
kindStoreTargetAddressARMBranch24, // kindSetTargetAddress + kindStoreARMBranch24
kindStoreTargetAddressThumbBranch22, // kindSetTargetAddress + kindStoreThumbBranch22
kindStoreTargetAddressARMLoad12, // kindSetTargetAddress + kindStoreARMLoad12
+#if SUPPORT_ARCH_arm64
+ // ARM64 value calculation and store combinations
+ kindStoreTargetAddressARM64Branch26, // kindSetTargetAddress + kindStoreARM64Branch26
+ kindStoreTargetAddressARM64Page21, // kindSetTargetAddress + kindStoreARM64Page21
+ kindStoreTargetAddressARM64PageOff12, // kindSetTargetAddress + kindStoreARM64PageOff12
+ kindStoreTargetAddressARM64GOTLoadPage21, // kindSetTargetAddress + kindStoreARM64GOTLoadPage21
+ kindStoreTargetAddressARM64GOTLoadPageOff12,// kindSetTargetAddress + kindStoreARM64GOTLoadPageOff12
+ kindStoreTargetAddressARM64GOTLeaPage21, // kindSetTargetAddress + kindStoreARM64GOTLeaPage21
+ kindStoreTargetAddressARM64GOTLeaPageOff12, // kindSetTargetAddress + kindStoreARM64GOTLeaPageOff12
+#endif
};
union {
TargetBinding binding : 3;
bool contentAddendOnly : 1;
bool contentDetlaToAddendOnly : 1;
+ bool contentIgnoresAddend : 1;
typedef Fixup* iterator;
Fixup() :
offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false),
binding(bindingNone),
- contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; }
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { u.target = NULL; }
Fixup(Kind k, Atom* targetAtom) :
offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false),
binding(Fixup::bindingDirectlyBound),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ assert(targetAtom != NULL); u.target = targetAtom; }
Fixup(uint32_t off, Cluster c, Kind k) :
offsetInAtom(off), kind(k), clusterSize(c), weakImport(false),
binding(Fixup::bindingNone),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ u.addend = 0; }
Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) :
offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm),
binding(Fixup::bindingByNameUnbound),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ assert(name != NULL); u.name = name; }
Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) :
offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ assert(name != NULL); u.name = name; }
Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) :
offsetInAtom(off), kind(k), clusterSize(c), weakImport(false),
binding(Fixup::bindingDirectlyBound),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ assert(targetAtom != NULL); u.target = targetAtom; }
Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) :
offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ assert(targetAtom != NULL); u.target = targetAtom; }
Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) :
offsetInAtom(off), kind(k), clusterSize(c), weakImport(false),
binding(Fixup::bindingNone),
- contentAddendOnly(false), contentDetlaToAddendOnly(false)
+ contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)
{ u.addend = addend; }
bool firstInCluster() const {
switch ( _combine ) {
case combineByNameAndContent:
case combineByNameAndReferences:
- assert(_symbolTableInclusion == symbolTableNotIn);
+ assert(_symbolTableInclusion != symbolTableIn);
assert(_scope != scopeGlobal);
break;
case combineByName:
_combine = a._combine;
_dontDeadStrip = a._dontDeadStrip;
_thumb = a._thumb;
- _alias = a._alias;
_autoHide = a._autoHide;
_contentType = a._contentType;
_symbolTableInclusion = a._symbolTableInclusion;
};
+
+// utility classes for using std::unordered_map with c-strings
+struct CStringHash {
+ size_t operator()(const char* __s) const {
+ size_t __h = 0;
+ for ( ; *__s; ++__s)
+ __h = 5 * __h + *__s;
+ return __h;
+ };
+};
+struct CStringEquals
+{
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals> CStringSet;
+
class Internal
{
public:
bool hasExternalRelocs;
};
+
virtual ld::Internal::FinalSection* addAtom(const Atom&) = 0;
virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0;
virtual ~Internal() {}
std::vector<FinalSection*> sections;
std::vector<ld::dylib::File*> dylibs;
std::vector<ld::relocatable::File::Stab> stabs;
+ CStringSet linkerOptionLibraries;
+ CStringSet linkerOptionFrameworks;
std::vector<const ld::Atom*> indirectBindingTable;
const ld::dylib::File* bundleLoader;
const Atom* entryPoint;
-
-// utility classes for using std::unordered_map with c-strings
-struct CStringHash {
- size_t operator()(const char* __s) const {
- size_t __h = 0;
- for ( ; *__s; ++__s)
- __h = 5 * __h + *__s;
- return __h;
- };
-};
-struct CStringEquals
-{
- bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-};
-
};
- struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint16_t index;};
+ struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint32_t index;};
bool loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
typedef std::unordered_map<const char*, const struct ranlib*, ld::CStringHash, ld::CStringEquals> NameToEntryMap;
template <> cpu_type_t File<x86>::architecture() { return CPU_TYPE_I386; }
template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
template <> cpu_type_t File<arm>::architecture() { return CPU_TYPE_ARM; }
+template <> cpu_type_t File<arm64>::architecture() { return CPU_TYPE_ARM64; }
template <typename A>
template <typename A>
typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
{
- uint16_t memberIndex = 0;
+ uint32_t memberIndex = 0;
// in case member was instantiated earlier but not needed yet
typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
if ( pos == _instantiatedEntries.end() ) {
// Have to find the index of this member
const Entry* start;
- uint16_t index;
+ uint32_t index;
if (_instantiatedEntries.size() == 0) {
start = (Entry*)&_archiveFileContent[8];
index = 1;
if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( archive::Parser<arm64>::validFile(fileContent, fileLength, opts.objOpts) )
+ return archive::Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
#endif
}
return NULL;
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
typedef typename A::sint_t sint_t;
static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
- CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
+ const pint_t cuStarts[], uint32_t cuCount, bool keepDwarfWhichHasCU, bool forceDwarfConversion,
+ CFI_Atom_Info<A>* infos, uint32_t& infosCount, void* ref, WarnFunc warn);
static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart,
static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
char warningBuffer[1024]);
+
+ // arm64 specific variants
+ static bool isReturnAddressRegister(int regNum, const Registers_arm64&);
+ static int lastRestoreReg(const Registers_arm64&);
+ static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_arm64&);
+ static bool checkRegisterPair(uint32_t reg, const typename CFI_Parser<A>::PrologInfo& prolog,
+ int& offset, char warningBuffer[1024]);
+ static compact_unwind_encoding_t encodeToUseDwarf(const Registers_arm64&);
+ static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_arm64&, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024]);
+
};
template <typename A, typename R>
const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
- CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
+ const pint_t cuStarts[], uint32_t cuCount, bool keepDwarfWhichHasCU, bool forceDwarfConversion,
+ CFI_Atom_Info<A>* infos, uint32_t& infosCount, void* ref, WarnFunc warn)
{
typename CFI_Parser<A>::CIE_Info cieInfo;
CFI_Atom_Info<A>* entry = infos;
pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
//fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
- // test if pc is within the function this FDE covers
entry->u.fdeInfo.function.targetAddress = pcStart;
entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
}
p = endOfAug;
}
- // compute compact unwind encoding
- typename CFI_Parser<A>::FDE_Info fdeInfo;
- fdeInfo.fdeStart = currentCFI;
- fdeInfo.fdeLength = nextCFI - currentCFI;
- fdeInfo.fdeInstructions = p;
- fdeInfo.pcStart = pcStart;
- fdeInfo.pcEnd = pcStart + pcRange;
- fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
- typename CFI_Parser<A>::PrologInfo prolog;
- R dummy; // for proper selection of architecture specific functions
- if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
- char warningBuffer[1024];
- entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
- if ( fdeInfo.lsda != CFI_INVALID_ADDRESS )
- entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
- if ( warningBuffer[0] != '\0' )
- warn(ref, fdeInfo.pcStart, warningBuffer);
+ // See if already is a compact unwind for this address.
+ bool alreadyHaveCU = false;
+ for (uint32_t i=0; i < cuCount; ++i) {
+ if (cuStarts[i] == entry->u.fdeInfo.function.targetAddress) {
+ alreadyHaveCU = true;
+ break;
+ }
+ }
+ //fprintf(stderr, "FDE for func at 0x%08X, alreadyHaveCU=%d\n", (uint32_t)entry->u.fdeInfo.function.targetAddress, alreadyHaveCU);
+ if ( alreadyHaveCU && !forceDwarfConversion ) {
+ if ( keepDwarfWhichHasCU )
+ ++entry;
}
else {
- warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
- entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+ if ( (cuCount != 0) && !forceDwarfConversion ) {
+ // Have some compact unwind, so this is a new .o file, therefore anything without
+ // compact unwind must be something not expressable in compact unwind.
+ R dummy;
+ entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+ }
+ else {
+ // compute compact unwind encoding by parsing dwarf
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ fdeInfo.fdeStart = currentCFI;
+ fdeInfo.fdeLength = nextCFI - currentCFI;
+ fdeInfo.fdeInstructions = p;
+ fdeInfo.pcStart = pcStart;
+ fdeInfo.pcEnd = pcStart + pcRange;
+ fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
+ typename CFI_Parser<A>::PrologInfo prolog;
+ R dummy; // for proper selection of architecture specific functions
+ if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+ char warningBuffer[1024];
+ entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+ if ( fdeInfo.lsda != CFI_INVALID_ADDRESS )
+ entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
+ if ( warningBuffer[0] != '\0' )
+ warn(ref, fdeInfo.pcStart, warningBuffer);
+ }
+ else {
+ warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
+ entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+ }
+ }
+ ++entry;
}
- ++entry;
}
p = nextCFI;
}
- if ( entry != end )
- return "wrong entry count for parseCFIs";
+ if ( entry != end ) {
+ //fprintf(stderr, "DwarfInstructions<A,R>::parseCFIs() infosCount was %d on input, now %ld\n", infosCount, entry - infos);
+ infosCount = (entry - infos);
+ }
+
return NULL; // success
}
for (int i=0; i < 64; ++i) {
if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
- sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ sprintf(warningBuffer, "register %d saved somewhere other than in frame", i);
return UNWIND_X86_64_MODE_DWARF;
}
switch (i) {
strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
return UNWIND_X86_64_MODE_DWARF;
}
- pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+ #if __EXCEPTIONS
try {
+ #endif
uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
+ #if __EXCEPTIONS
}
catch (...) {
strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
return UNWIND_X86_64_MODE_DWARF;
}
+ #endif
stackValue = functionContentAdjustStackIns - funcAddr;
immedStackSize = false;
if ( stackAdjust > 7 ) {
for (int i=0; i < 64; ++i) {
if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
- sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+ sprintf(warningBuffer, "register %d saved somewhere other than in frame", i);
return UNWIND_X86_MODE_DWARF;
}
switch (i) {
if ( stackValue > stackMaxImmedValue ) {
// stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
- uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
- stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+ #if __EXCEPTIONS
+ try {
+ #endif
+ uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+ stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+ #if __EXCEPTIONS
+ }
+ catch (...) {
+ strcpy(warningBuffer, "stack size is large but stack subl instruction not found");
+ return UNWIND_X86_MODE_DWARF;
+ }
+ #endif
stackValue = functionContentAdjustStackIns - funcAddr;
immedStackSize = false;
if ( stackAdjust > 7 ) {
- strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+ strcpy(warningBuffer, "stack subl instruction is too different from dwarf stack size");
return UNWIND_X86_MODE_DWARF;
}
encoding = UNWIND_X86_MODE_STACK_IND;
+//
+// arm64 specific functions
+//
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_arm64&)
+{
+ return UNWIND_ARM64_MODE_DWARF;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_arm64&)
+{
+ return (regNum == UNW_ARM64_LR);
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_arm64&)
+{
+ COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_ARM64_D31 );
+ return UNW_ARM64_D31;
+}
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog,
+ const Registers_arm64& registers)
+{
+ if ( prolog.cfaRegister != 0 )
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else
+ ABORT("getCFA(): unsupported location for arm64 cfa");
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::checkRegisterPair(uint32_t reg, const typename CFI_Parser<A>::PrologInfo& prolog,
+ int& offset, char warningBuffer[1024])
+{
+ if ( (prolog.savedRegisters[reg].location != CFI_Parser<A>::kRegisterUnused)
+ || (prolog.savedRegisters[reg+1].location != CFI_Parser<A>::kRegisterUnused) ) {
+ if ( prolog.savedRegisters[reg].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other than in frame", reg);
+ return false;
+ }
+ if ( prolog.savedRegisters[reg+1].location != CFI_Parser<A>::kRegisterInCFA ) {
+ sprintf(warningBuffer, "register %d saved somewhere other than in frame", reg+1);
+ return false;
+ }
+ if ( prolog.savedRegisters[reg].value != prolog.savedRegisters[reg+1].value + 8 ) {
+ sprintf(warningBuffer, "registers %d and %d not saved contiguously in frame", reg, reg+1);
+ return false;
+ }
+ if ( prolog.savedRegisters[reg].value != offset ) {
+ sprintf(warningBuffer, "registers %d not saved contiguously in frame", reg);
+ return false;
+ }
+ offset -= 16;
+ return true;
+ }
+ return false;
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+ const Registers_arm64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+ char warningBuffer[1024])
+{
+ warningBuffer[0] = '\0';
+
+ if ( prolog.registerSavedTwiceInCIE == UNW_ARM64_LR ) {
+ warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ // don't create compact unwind info for unsupported dwarf kinds
+ if ( prolog.registerSavedMoreThanOnce ) {
+ strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ if ( prolog.spExtraArgSize != 0 ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ if ( prolog.sameValueUsed ) {
+ strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+
+ compact_unwind_encoding_t encoding = 0;
+ int offset = 0;
+
+ // figure out which kind of frame this function uses
+ bool standardFPframe = (
+ (prolog.cfaRegister == UNW_ARM64_FP)
+ && (prolog.cfaRegisterOffset == 16)
+ && (prolog.savedRegisters[UNW_ARM64_FP].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_ARM64_FP].value == -16)
+ && (prolog.savedRegisters[UNW_ARM64_LR].location == CFI_Parser<A>::kRegisterInCFA)
+ && (prolog.savedRegisters[UNW_ARM64_LR].value == -8) );
+
+ bool standardFrameless = ( prolog.cfaRegister == UNW_ARM64_SP );
+
+ if ( standardFrameless ) {
+ // verify enough space for registers saved
+ int count = 0;
+ for (int i=0; i < 96; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused )
+ ++count;
+ }
+ if ( count * 8 > prolog.cfaRegisterOffset ) {
+ strcpy(warningBuffer, "saved registers do not fit in stack size");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ if ( (prolog.cfaRegisterOffset % 16) != 0 ) {
+ strcpy(warningBuffer, "stack size is not 16-byte multiple");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ const int32_t maxStack = (UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK >> __builtin_ctz(UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK));
+ if ( (prolog.cfaRegisterOffset / 16) > maxStack ) {
+ strcpy(warningBuffer, "stack size is too large for frameless function");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ encoding = UNWIND_ARM64_MODE_FRAMELESS | ((prolog.cfaRegisterOffset/16) << __builtin_ctz(UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK));
+ offset = -16;
+ }
+ else if ( standardFPframe ) {
+ encoding = UNWIND_ARM64_MODE_FRAME;
+ offset = -24;
+ }
+ else {
+ // no compact encoding for this
+ strcpy(warningBuffer, "does not use standard frame");
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+
+ // make sure no volatile registers are saved
+ for (int i=UNW_ARM64_X0; i < UNW_ARM64_X19; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ sprintf(warningBuffer, "non standard register %d saved in frame", i);
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ }
+ for (int i=UNW_ARM64_SP+1; i < UNW_ARM64_D8; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ sprintf(warningBuffer, "non standard register %d saved in frame", i);
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ }
+ for (int i=UNW_ARM64_D16; i < UNW_ARM64_D31+1; ++i) {
+ if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+ sprintf(warningBuffer, "non standard register %d saved in frame", i);
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+ }
+
+ // compute encoding
+ bool X19_X20_saved = checkRegisterPair(UNW_ARM64_X19, prolog, offset, warningBuffer);
+ bool X21_X22_saved = checkRegisterPair(UNW_ARM64_X21, prolog, offset, warningBuffer);
+ bool X23_X24_saved = checkRegisterPair(UNW_ARM64_X23, prolog, offset, warningBuffer);
+ bool X25_X26_saved = checkRegisterPair(UNW_ARM64_X25, prolog, offset, warningBuffer);
+ bool X27_X28_saved = checkRegisterPair(UNW_ARM64_X27, prolog, offset, warningBuffer);
+ bool D8_D9_saved = checkRegisterPair(UNW_ARM64_D8, prolog, offset, warningBuffer);
+ bool D10_D11_saved = checkRegisterPair(UNW_ARM64_D10, prolog, offset, warningBuffer);
+ bool D12_D13_saved = checkRegisterPair(UNW_ARM64_D12, prolog, offset, warningBuffer);
+ bool D14_D15_saved = checkRegisterPair(UNW_ARM64_D14, prolog, offset, warningBuffer);
+ if ( warningBuffer[0] != '\0' )
+ return UNWIND_ARM64_MODE_DWARF;
+
+ if ( X19_X20_saved )
+ encoding |= UNWIND_ARM64_FRAME_X19_X20_PAIR;
+ if ( X21_X22_saved )
+ encoding |= UNWIND_ARM64_FRAME_X21_X22_PAIR;
+ if ( X23_X24_saved )
+ encoding |= UNWIND_ARM64_FRAME_X23_X24_PAIR;
+ if ( X25_X26_saved )
+ encoding |= UNWIND_ARM64_FRAME_X25_X26_PAIR;
+ if ( X27_X28_saved )
+ encoding |= UNWIND_ARM64_FRAME_X27_X28_PAIR;
+ if ( D8_D9_saved )
+ encoding |= UNWIND_ARM64_FRAME_D8_D9_PAIR;
+ if ( D10_D11_saved )
+ encoding |= UNWIND_ARM64_FRAME_D10_D11_PAIR;
+ if ( D12_D13_saved )
+ encoding |= UNWIND_ARM64_FRAME_D12_D13_PAIR;
+ if ( D14_D15_saved )
+ encoding |= UNWIND_ARM64_FRAME_D14_D15_PAIR;
+
+ return encoding;
+}
} // namespace libunwind
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
return "unknown register";
}
+}
+
+
+
+
+
+struct arm_thread_state64_t
+{
+ __uint64_t __x[29]; /* General purpose registers x0-x28 */
+ __uint64_t __fp; /* Frame pointer x29 */
+ __uint64_t __lr; /* Link register x30 */
+ __uint64_t __sp; /* Stack pointer x31 */
+ __uint64_t __pc; /* Program counter */
+ __uint32_t __cpsr; /* Current program status register */
+ __uint32_t padding[3]; /* round up struct size to be 0x110 */
+};
+
+
+///
+/// Registers_arm64 holds the register state of a thread in a 64-bit intel process.
+///
+class Registers_arm64
+{
+public:
+ Registers_arm64();
+ Registers_arm64(const void* registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char* getRegisterName(int num);
+ void jumpto();
+ uint64_t getSP() const { return fRegisters.__sp; }
+ void setSP(uint64_t value) { fRegisters.__sp = value; }
+ uint64_t getIP() const { return fRegisters.__pc; }
+ void setIP(uint64_t value) { fRegisters.__pc = value; }
+ uint64_t getFP() const { return fRegisters.__fp; }
+ void setFP(uint64_t value) { fRegisters.__fp = value; }
+private:
+ arm_thread_state64_t fRegisters;
+ double fHalfVectorRegisters[32];
+ // Currently only the lower double in 128-bit vectore registers
+ // is perserved during unwinding. We could define new register
+ // numbers (> 96) which mean whole vector registers, then this
+ // struct would need to change to contain whole vector registers.
+};
+
+inline Registers_arm64::Registers_arm64(const void* registers)
+{
+ COMPILE_TIME_ASSERT( sizeof(Registers_arm64) < sizeof(unw_context_t) );
+ fRegisters = *((arm_thread_state64_t*)registers);
+}
+
+inline Registers_arm64::Registers_arm64()
+{
+ bzero(&fRegisters, sizeof(fRegisters));
+ bzero(&fRegisters, sizeof(fHalfVectorRegisters));
+}
+
+
+inline bool Registers_arm64::validRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return true;
+ if ( regNum == UNW_REG_SP )
+ return true;
+ if ( regNum < 0 )
+ return false;
+ if ( regNum > 95 )
+ return false;
+ if ( (regNum > 31) && (regNum < 64) )
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_arm64::getRegister(int regNum) const
+{
+ if ( regNum == UNW_REG_IP )
+ return fRegisters.__pc;
+ if ( regNum == UNW_REG_SP )
+ return fRegisters.__sp;
+ if ( (regNum >= 0) && (regNum < 32) )
+ return fRegisters.__x[regNum];
+ ABORT("unsupported arm64 register");
+}
+
+inline void Registers_arm64::setRegister(int regNum, uint64_t value)
+{
+ if ( regNum == UNW_REG_IP )
+ fRegisters.__pc = value;
+ else if ( regNum == UNW_REG_SP )
+ fRegisters.__sp = value;
+ else if ( (regNum >= 0) && (regNum < 32) )
+ fRegisters.__x[regNum] = value;
+ else
+ ABORT("unsupported arm64 register");
+}
+
+inline const char* Registers_arm64::getRegisterName(int regNum)
+{
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "pc";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_ARM64_X0:
+ return "x0";
+ case UNW_ARM64_X1:
+ return "x1";
+ case UNW_ARM64_X2:
+ return "x2";
+ case UNW_ARM64_X3:
+ return "x3";
+ case UNW_ARM64_X4:
+ return "x4";
+ case UNW_ARM64_X5:
+ return "x5";
+ case UNW_ARM64_X6:
+ return "x6";
+ case UNW_ARM64_X7:
+ return "x7";
+ case UNW_ARM64_X8:
+ return "x8";
+ case UNW_ARM64_X9:
+ return "x9";
+ case UNW_ARM64_X10:
+ return "x10";
+ case UNW_ARM64_X11:
+ return "x11";
+ case UNW_ARM64_X12:
+ return "x12";
+ case UNW_ARM64_X13:
+ return "x13";
+ case UNW_ARM64_X14:
+ return "x14";
+ case UNW_ARM64_X15:
+ return "x15";
+ case UNW_ARM64_X16:
+ return "x16";
+ case UNW_ARM64_X17:
+ return "x17";
+ case UNW_ARM64_X18:
+ return "x18";
+ case UNW_ARM64_X19:
+ return "x19";
+ case UNW_ARM64_X20:
+ return "x20";
+ case UNW_ARM64_X21:
+ return "x21";
+ case UNW_ARM64_X22:
+ return "x22";
+ case UNW_ARM64_X23:
+ return "x23";
+ case UNW_ARM64_X24:
+ return "x24";
+ case UNW_ARM64_X25:
+ return "x25";
+ case UNW_ARM64_X26:
+ return "x26";
+ case UNW_ARM64_X27:
+ return "x27";
+ case UNW_ARM64_X28:
+ return "x28";
+ case UNW_ARM64_X29:
+ return "fp";
+ case UNW_ARM64_X30:
+ return "lr";
+ case UNW_ARM64_X31:
+ return "sp";
+ case UNW_ARM64_D0:
+ return "d0";
+ case UNW_ARM64_D1:
+ return "d1";
+ case UNW_ARM64_D2:
+ return "d2";
+ case UNW_ARM64_D3:
+ return "d3";
+ case UNW_ARM64_D4:
+ return "d4";
+ case UNW_ARM64_D5:
+ return "d5";
+ case UNW_ARM64_D6:
+ return "d6";
+ case UNW_ARM64_D7:
+ return "d7";
+ case UNW_ARM64_D8:
+ return "d8";
+ case UNW_ARM64_D9:
+ return "d9";
+ case UNW_ARM64_D10:
+ return "d10";
+ case UNW_ARM64_D11:
+ return "d11";
+ case UNW_ARM64_D12:
+ return "d12";
+ case UNW_ARM64_D13:
+ return "d13";
+ case UNW_ARM64_D14:
+ return "d14";
+ case UNW_ARM64_D15:
+ return "d15";
+ case UNW_ARM64_D16:
+ return "d16";
+ case UNW_ARM64_D17:
+ return "d17";
+ case UNW_ARM64_D18:
+ return "d18";
+ case UNW_ARM64_D19:
+ return "d19";
+ case UNW_ARM64_D20:
+ return "d20";
+ case UNW_ARM64_D21:
+ return "d21";
+ case UNW_ARM64_D22:
+ return "d22";
+ case UNW_ARM64_D23:
+ return "d23";
+ case UNW_ARM64_D24:
+ return "d24";
+ case UNW_ARM64_D25:
+ return "d25";
+ case UNW_ARM64_D26:
+ return "d26";
+ case UNW_ARM64_D27:
+ return "d27";
+ case UNW_ARM64_D28:
+ return "d28";
+ case UNW_ARM64_D29:
+ return "d29";
+ case UNW_ARM64_D30:
+ return "d30";
+ case UNW_ARM64_D31:
+ return "d31";
+ default:
+ return "unknown register";
+ }
+}
+
+bool Registers_arm64::validFloatRegister(int regNum) const
+{
+ if ( regNum < UNW_ARM64_D0 )
+ return false;
+ if ( regNum > UNW_ARM64_D31 )
+ return false;
+ return true;
+}
+
+double Registers_arm64::getFloatRegister(int regNum) const
+{
+ assert(validFloatRegister(regNum));
+ return fHalfVectorRegisters[regNum-UNW_ARM64_D0];
+}
+
+void Registers_arm64::setFloatRegister(int regNum, double value)
+{
+ assert(validFloatRegister(regNum));
+ fHalfVectorRegisters[regNum-UNW_ARM64_D0] = value;
}
+inline bool Registers_arm64::validVectorRegister(int regNum) const
+{
+ return false;
+}
+
+inline v128 Registers_arm64::getVectorRegister(int regNum) const
+{
+ ABORT("no arm64 vector register support yet");
+}
+
+inline void Registers_arm64::setVectorRegister(int regNum, v128 value)
+{
+ ABORT("no arm64 vector register support yet");
+}
+
+
} // namespace libunwind
{ return _debugInfoModTime; }
virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return NULL; }
virtual bool canScatterAtoms() const { return true; }
+ virtual LinkerOptionsList* linkerOptions() const { return NULL; }
+
lto_module_t module() { return _module; }
class InternalAtom& internalAtom() { return _internalAtom; }
objOpts.architecture = options.arch;
objOpts.objSubtypeMustMatch = false;
objOpts.logAllFiles = false;
- objOpts.convertUnwindInfo = true;
+ objOpts.warnUnwindConversionProblems = options.needsUnwindInfoSection;
+ objOpts.keepDwarfUnwind = options.keepDwarfUnwind;
+ objOpts.forceDwarfConversion = false;
objOpts.subType = 0;
// mach-o parsing is done in-memory, but need path for debug notes
+// <rdar://problem/12379604> The order that files are merged must match command line order
+struct CommandLineOrderFileSorter
+{
+ bool operator()(File* left, File* right)
+ {
+ return ( left->ordinal() < right->ordinal() );
+ }
+};
+
+
bool Parser::optimize( const std::vector<const ld::Atom*>& allAtoms,
ld::Internal& state,
const OptimizeOptions& options,
// create optimizer and add each Reader
lto_code_gen_t generator = ::lto_codegen_create();
+ // <rdar://problem/12379604> The order that files are merged must match command line order
+ std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter());
+ ld::File::Ordinal lastOrdinal;
for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
- if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", (*it)->path());
- if ( ::lto_codegen_add_module(generator, (*it)->module()) )
- throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", (*it)->path(), ::lto_get_error_message(), ::lto_get_version());
+ File* f = *it;
+ assert(f->ordinal() > lastOrdinal);
+ if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path());
+ if ( ::lto_codegen_add_module(generator, f->module()) )
+ throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version());
+ lastOrdinal = f->ordinal();
}
// add any -mllvm command line options
::lto_codegen_debug_options(generator, *it);
}
+ // <rdar://problem/13687397> Need a way for LTO to get cpu variants (until that info is in bitcode)
+ if ( options.mcpu != NULL )
+ ::lto_codegen_set_cpu(generator, options.mcpu);
+
// The atom graph uses directed edges (references). Collect all references where
// originating atom is not part of any LTO Reader. This allows optimizer to optimize an
// external (i.e. not originated from same .o file) reference if all originating atoms are also
fit->u.target = pos->second;
}
else {
- if ( _deadllvmAtoms.find(targetName) != _deadllvmAtoms.end() ) {
+ // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference
+ if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) ) {
// target was coalesed away and replace by mach-o atom from a non llvm .o file
fit->binding = ld::Fixup::bindingByNameUnbound;
fit->u.name = targetName;
bool relocatable;
bool allowTextRelocs;
bool linkerDeadStripping;
+ bool needsUnwindInfoSection;
+ bool keepDwarfUnwind;
cpu_type_t arch;
+ const char* mcpu;
const std::vector<const char*>* llvmOptions;
};
+
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2005-2011 Apple Inc. All rights reserved.
File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
- ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool addVers,
+ ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool allowSimToMacOSX, bool addVers,
bool logAllFiles, const char* installPath, bool indirectDylib);
virtual ~File() {}
virtual bool hasWeakDefinition(const char* name) const;
virtual bool allSymbolsAreWeakImported() const;
virtual const void* codeSignatureDR() const { return _codeSignatureDR; }
+ virtual bool installPathVersionSpecific() const { return _installPathOverride; }
protected:
bool containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
bool isPublicLocation(const char* pth);
+ bool wrongOS() { return _wrongOS; }
void addSymbol(const char* name, bool weak, bool tlv, pint_t address);
void addDyldFastStub();
void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
const ld::MacVersionMin _macVersionMin;
const ld::IOSVersionMin _iOSVersionMin;
+ const bool _allowSimToMacOSXLinking;
const bool _addVersionLoadCommand;
bool _linkingFlat;
bool _implicitlyLinkPublicDylibs;
bool _hasPublicInstallName;
mutable bool _providedAtom;
bool _explictReExportFound;
-
+ bool _wrongOS;
+ bool _installPathOverride;
+
static bool _s_logHashtable;
};
template <typename A>
File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
- ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool addVers,
+ ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool allowSimToMacOSX, bool addVers,
bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
: ld::dylib::File(strdup(pth), mTime, ord),
- _macVersionMin(macMin), _iOSVersionMin(iOSMin), _addVersionLoadCommand(addVers),
+ _macVersionMin(macMin), _iOSVersionMin(iOSMin), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers),
_linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
_objcContraint(ld::File::objcConstraintNone),
_importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
_parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL),
_noRexports(false), _hasWeakExports(false),
_deadStrippable(false), _hasPublicInstallName(false),
- _providedAtom(false), _explictReExportFound(false)
+ _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false)
{
const macho_header<P>* header = (const macho_header<P>*)fileContent;
const uint32_t cmd_count = header->ncmds();
_allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
break;
case LC_VERSION_MIN_MACOSX:
- if ( _addVersionLoadCommand && !indirectDylib && (_iOSVersionMin != ld::iOSVersionUnset) )
- warning("building for iOS, but linking against dylib built for MacOSX: %s", pth);
+ if ( (_iOSVersionMin != ld::iOSVersionUnset) && !_allowSimToMacOSXLinking ) {
+ _wrongOS = true;
+ if ( _addVersionLoadCommand && !indirectDylib )
+ throw "building for iOS Simulator, but linking against dylib built for MacOSX";
+ }
break;
case LC_VERSION_MIN_IPHONEOS:
- if ( _addVersionLoadCommand && !indirectDylib && (_macVersionMin != ld::macVersionUnset) )
- warning("building for MacOSX, but linking against dylib built for iOS: %s", pth);
+ if ( _macVersionMin != ld::macVersionUnset ) {
+ _wrongOS = true;
+ if ( _addVersionLoadCommand && !indirectDylib )
+ throw "building for MacOSX, but linking against dylib built for iOS Simulator";
+ }
break;
case LC_CODE_SIGNATURE:
codeSignature = (macho_linkedit_data_command<P>* )cmd;
// };
// #define OBJC_IMAGE_SUPPORTS_GC 2
// #define OBJC_IMAGE_GC_ONLY 4
+ // #define OBJC_IMAGE_IS_SIMULATED 32
//
const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
if ( (sect->size() >= 8) && (contents[0] == 0) ) {
_objcContraint = ld::File::objcConstraintGC;
else if ( (flags & 2) == 2 )
_objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
+ else if ( (flags & 32) == 32 )
+ _objcContraint = ld::File::objcConstraintRetainReleaseForSimulator;
else
_objcContraint = ld::File::objcConstraintRetainRelease;
}
}
else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
_dylibInstallPath = symName;
+ _installPathOverride = true;
return;
}
else {
if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
// a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
- if ( it->dylib->hasPublicInstallName() ) {
+ if ( it->dylib->hasPublicInstallName() && !it->dylib->wrongOS() ) {
// promote this child to be automatically added as a direct dependent if this already is
if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
typedef typename A::P P;
static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
+ static const char* fileKind(const uint8_t* fileContent);
static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
const char* path, time_t mTime,
ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
opts.implicitlyLinkIndirectPublicDylibs(),
opts.macosxVersionMin(),
opts.iOSVersionMin(),
+ opts.allowSimulatorToLinkWithMacOSX(),
opts.addVersionLoadCommand(),
opts.logAllFiles(),
opts.installPath(),
+template <>
+bool Parser<arm64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return false;
+ switch ( header->filetype() ) {
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ return true;
+ case MH_BUNDLE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+ case MH_EXECUTE:
+ if ( executableOrDyliborBundle )
+ return true;
+ else
+ throw "can't link with a main executable";
+ default:
+ return false;
+ }
+}
+
+
+bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
+{
+ if ( Parser<x86_64>::validFile(fileContent, false) ) {
+ *result = CPU_TYPE_X86_64;
+ *subResult = CPU_SUBTYPE_X86_64_ALL;
+ return true;
+ }
+ if ( Parser<x86>::validFile(fileContent, false) ) {
+ *result = CPU_TYPE_I386;
+ *subResult = CPU_SUBTYPE_X86_ALL;
+ return true;
+ }
+ if ( Parser<arm>::validFile(fileContent, false) ) {
+ *result = CPU_TYPE_ARM;
+ const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
+ *subResult = header->cpusubtype();
+ return true;
+ }
+ if ( Parser<arm64>::validFile(fileContent, false) ) {
+ *result = CPU_TYPE_ARM64;
+ *subResult = CPU_SUBTYPE_ARM64_ALL;
+ return true;
+ }
+ if ( Parser<ppc>::validFile(fileContent, false) ) {
+ *result = CPU_TYPE_POWERPC;
+ const macho_header<Pointer32<BigEndian> >* header = (const macho_header<Pointer32<BigEndian> >*)fileContent;
+ *subResult = header->cpusubtype();
+ return true;
+ }
+ if ( Parser<ppc64>::validFile(fileContent, false) ) {
+ *result = CPU_TYPE_POWERPC64;
+ *subResult = CPU_SUBTYPE_POWERPC_ALL;
+ return true;
+ }
+ return false;
+}
+
+template <>
+const char* Parser<x86>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_I386 )
+ return NULL;
+ return "i386";
+}
+
+template <>
+const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_X86_64 )
+ return NULL;
+ return "x86_64";
+}
+
+template <>
+const char* Parser<arm>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_ARM )
+ return NULL;
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) {
+ return t->archName;
+ }
+ }
+ return "arm???";
+}
+
+#if SUPPORT_ARCH_arm64
+template <>
+const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return NULL;
+ return "arm64";
+}
+#endif
+
+//
+// used by linker is error messages to describe mismatched files
+//
+const char* archName(const uint8_t* fileContent)
+{
+ if ( Parser<x86_64>::validFile(fileContent, true) ) {
+ return Parser<x86_64>::fileKind(fileContent);
+ }
+ if ( Parser<x86>::validFile(fileContent, true) ) {
+ return Parser<x86>::fileKind(fileContent);
+ }
+ if ( Parser<arm>::validFile(fileContent, true) ) {
+ return Parser<arm>::fileKind(fileContent);
+ }
+#if SUPPORT_ARCH_arm64
+ if ( Parser<arm64>::validFile(fileContent, false) ) {
+ return Parser<arm64>::fileKind(fileContent);
+ }
+#endif
+ return NULL;
+}
+
+
//
// main function used by linker to instantiate ld::Files
//
if ( Parser<arm>::validFile(fileContent, bundleLoader) )
return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( Parser<arm64>::validFile(fileContent, bundleLoader) )
+ return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+ break;
#endif
}
return NULL;
namespace mach_o {
namespace dylib {
+
+extern bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult);
+
+extern const char* archName(const uint8_t* fileContent);
+
+
extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
bool bundleLoader, bool indirectDylib);
virtual ObjcConstraint objCConstraint() const { return _objConstraint; }
virtual uint32_t cpuSubType() const { return _cpuSubType; }
virtual DebugInfoKind debugInfo() const { return _debugInfoKind; }
- virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return &_stabs; }
+ virtual const std::vector<ld::relocatable::File::Stab>* stabs() const { return &_stabs; }
virtual bool canScatterAtoms() const { return _canScatterAtoms; }
virtual const char* translationUnitSource() const;
+ virtual LinkerOptionsList* linkerOptions() const { return &_linkerOptions; }
const uint8_t* fileContent() { return _fileContent; }
private:
ld::File::ObjcConstraint _objConstraint;
uint32_t _cpuSubType;
bool _canScatterAtoms;
+ std::vector<std::vector<const char*> > _linkerOptions;
};
virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const { return 0; }
virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
const ld::IndirectBindingTable& ind) const { return false; }
+ virtual bool ignoreLabel(const char* label) const { return false; }
static const char* makeSectionName(const macho_section<typename A::P>* s);
protected:
typedef typename A::P::uint_t pint_t;
typedef libunwind::CFI_Atom_Info<OAS> CFI_Atom_Info;
- void cfiParse(class Parser<A>& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t cfiCount);
+ void cfiParse(class Parser<A>& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t& cfiCount, const pint_t cuStarts[], uint32_t cuCount);
bool needsRelocating();
static bool bigEndian();
uint32_t count();
void parse(class Parser<A>& parser, uint32_t cnt, Info array[]);
+ static bool encodingMeansUseDwarf(compact_unwind_encoding_t enc);
private:
virtual bool addFollowOnFixups() const { return false; }
virtual const char* unlabeledAtomName(Parser<A>& parser, pint_t addr) = 0;
- virtual ld::Atom::SymbolTableInclusion symbolTableInclusion() { return ld::Atom::symbolTableNotIn; }
+ virtual ld::Atom::SymbolTableInclusion symbolTableInclusion();
virtual pint_t elementSizeAtAddress(pint_t addr) = 0;
virtual ld::Atom::Scope scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeLinkageUnit; }
virtual bool useElementAt(Parser<A>& parser,
struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr) = 0;
virtual ld::Atom::Definition definition() { return ld::Atom::definitionRegular; }
virtual ld::Atom::Combine combine(Parser<A>& parser, pint_t addr) = 0;
- virtual bool ignoreLabel(const char* label) { return (label[0] == 'L'); }
+ virtual bool ignoreLabel(const char* label) const { return (label[0] == 'L'); }
};
+
template <typename A>
class FixedSizeSection : public ImplicitSizeSection<A>
{
virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
virtual ld::Atom::Scope scopeAtAddress(Parser<A>& parser, pint_t addr);
virtual ld::Atom::Combine combine(Parser<A>&, pint_t);
- virtual bool ignoreLabel(const char* label) { return true; }
+ virtual bool ignoreLabel(const char* label) const { return true; }
virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
const ld::IndirectBindingTable& ind) const;
virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "CFString"; }
virtual pint_t elementSizeAtAddress(pint_t addr) { return 4*sizeof(pint_t); }
virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndReferences; }
- virtual bool ignoreLabel(const char* label) { return true; }
+ virtual bool ignoreLabel(const char* label) const { return true; }
virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
const ld::IndirectBindingTable& ind) const;
virtual ld::Atom::SymbolTableInclusion symbolTableInclusion() { return ld::Atom::symbolTableIn; }
virtual pint_t elementSizeAtAddress(pint_t addr);
virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineNever; }
- virtual bool ignoreLabel(const char* label) { return true; }
+ virtual bool ignoreLabel(const char* label) const { return true; }
virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
{ return 0; }
virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "objc-class-ref"; }
virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndReferences; }
- virtual bool ignoreLabel(const char* label) { return true; }
+ virtual bool ignoreLabel(const char* label) const { return true; }
virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
const ld::IndirectBindingTable& ind) const;
virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "objc-cat-list"; }
virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineNever; }
- virtual bool ignoreLabel(const char* label) { return true; }
+ virtual bool ignoreLabel(const char* label) const { return true; }
private:
const char* targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
};
virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "pointer-to-literal-cstring"; }
virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); }
virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndReferences; }
- virtual bool ignoreLabel(const char* label) { return true; }
+ virtual bool ignoreLabel(const char* label) const { return true; }
virtual unsigned long contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
virtual bool canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
const ld::IndirectBindingTable& ind) const;
virtual Atom<A>* findAtomByAddress(pint_t addr);
virtual const char* unlabeledAtomName(Parser<A>&, pint_t) { return "cstring"; }
virtual pint_t elementSizeAtAddress(pint_t addr);
- virtual bool ignoreLabel(const char* label);
+ virtual bool ignoreLabel(const char* label) const;
virtual bool useElementAt(Parser<A>& parser,
struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr);
virtual ld::Atom::Combine combine(Parser<A>&, pint_t) { return ld::Atom::combineByNameAndContent; }
const char* path, time_t modTime, ld::File::Ordinal ordinal,
const ParserOptions& opts) {
Parser p(fileContent, fileLength, path, modTime,
- ordinal, opts.convertUnwindInfo);
+ ordinal, opts.warnUnwindConversionProblems,
+ opts.keepDwarfUnwind, opts.forceDwarfConversion);
return p.parse(opts);
}
_allFixups.push_back(FixupInAtom(src, c, k));
}
-
+ const char* path() { return _path; }
uint32_t symbolCount() { return _symbolCount; }
uint32_t indirectSymbol(uint32_t indirectIndex);
const macho_nlist<P>& symbolFromIndex(uint32_t index);
unsigned int stubsSectionNum() { return _stubsSectionNum; }
void addDtraceExtraInfos(const SourceLocation& src, const char* provider);
const char* scanSymbolTableForAddress(uint64_t addr);
- bool convertUnwindInfo() { return _convertUnwindInfo; }
+ bool warnUnwindConversionProblems() { return _warnUnwindConversionProblems; }
bool hasDataInCodeLabels() { return _hasDataInCodeLabels; }
-
+ bool keepDwarfUnwind() { return _keepDwarfUnwind; }
+ bool forceDwarfConversion() { return _forceDwarfConversion; }
+
macho_data_in_code_entry<P>* dataInCodeStart() { return _dataInCodeStart; }
macho_data_in_code_entry<P>* dataInCodeEnd() { return _dataInCodeEnd; }
: sortedSymbolIndexes(ssa), sortedSymbolCount(ssc), cfiStartsArray(cfisa),
cfiStartsCount(cfisc), fileHasOverlappingSymbols(ols),
newSection(false), cfiIndex(0), symIndex(0) {}
- bool next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr,
+ bool next(Parser<A>& parser, const Section<A>& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr,
pint_t* addr, pint_t* size, const macho_nlist<P>** sym);
pint_t peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr);
void beginSection() { newSection = true; symIndex = 0; }
Parser(const uint8_t* fileContent, uint64_t fileLength,
- const char* path, time_t modTime,
- ld::File::Ordinal ordinal, bool convertUnwindInfo);
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ bool warnUnwindConversionProblems, bool keepDwarfUnwind, bool forceDwarfConversion);
ld::relocatable::File* parse(const ParserOptions& opts);
uint8_t loadCommandSizeMask();
bool parseLoadCommands();
bool _hasLongBranchStubs;
bool _AppleObjc; // FSF has objc that uses different data layout
bool _overlappingSymbols;
- bool _convertUnwindInfo;
+ bool _warnUnwindConversionProblems;
bool _hasDataInCodeLabels;
+ bool _keepDwarfUnwind;
+ bool _forceDwarfConversion;
unsigned int _stubsSectionNum;
const macho_section<P>* _stubsMachOSection;
std::vector<const char*> _dtraceProviderInfo;
template <typename A>
Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime,
- ld::File::Ordinal ordinal, bool convertDUI)
+ ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion)
: _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
_ordinal(ordinal), _file(NULL),
_symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
_EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
_tentativeDefinitionCount(0), _absoluteSymbolCount(0),
_symbolsInSections(0), _hasLongBranchStubs(false), _AppleObjc(false),
- _overlappingSymbols(false), _convertUnwindInfo(convertDUI), _hasDataInCodeLabels(false),
+ _overlappingSymbols(false), _warnUnwindConversionProblems(convertDUI), _hasDataInCodeLabels(false),
+ _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion),
_stubsSectionNum(0), _stubsMachOSection(NULL)
{
}
}
+template <>
+bool Parser<arm64>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return false;
+ if ( header->filetype() != MH_OBJECT )
+ return false;
+ return true;
+}
+
template <>
const char* Parser<x86>::fileKind(const uint8_t* fileContent)
return "arm???";
}
+#if SUPPORT_ARCH_arm64
+template <>
+const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC )
+ return NULL;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return NULL;
+ return "arm64";
+}
+#endif
template <typename A>
bool Parser<A>::hasObjC2Categories(const uint8_t* fileContent)
// was becuase of a label, the symbol). Returns false when no more chunks.
//
template <typename A>
-bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr,
+bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, const Section<A>& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr,
pint_t* addr, pint_t* size, const macho_nlist<P>** symbol)
{
// may not be a label on start of section, but need atom demarcation there
// advance symIndex until we get to the first label at or past the start of this section
while ( symIndex < sortedSymbolCount ) {
const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
- pint_t nextSymbolAddr = sym.n_value();
- //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym));
- if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) )
- break;
+ if ( ! sect.ignoreLabel(parser.nameFromSymbol(sym)) ) {
+ pint_t nextSymbolAddr = sym.n_value();
+ //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym));
+ if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) )
+ break;
+ }
++symIndex;
}
if ( symIndex < sortedSymbolCount ) {
*symbol = NULL;
return true;
}
- // no symbols left in whole file, so entire section is one chunk
+ // no symbols in section, check CFI
+ if ( cfiIndex < cfiStartsCount ) {
+ pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+ if ( nextCfiAddr < endAddr ) {
+ // use cfi
+ ++cfiIndex;
+ *addr = nextCfiAddr;
+ *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+ *symbol = NULL;
+ return true;
+ }
+ }
+ // no cfi, so whole section is one chunk
*addr = startAddr;
*size = endAddr - startAddr;
*symbol = NULL;
return false;
}
+#define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \
+ _type* _name = NULL; \
+ uint32_t _name##_count = 1; \
+ if ( _actual_count > _maxCount ) \
+ _name = (_type*)malloc(sizeof(_type) * _actual_count); \
+ else \
+ _name##_count = _actual_count; \
+ _type _name##_buffer[_name##_count]; \
+ if ( _name == NULL ) \
+ _name = _name##_buffer;
template <typename A>
if ( ! parseLoadCommands() )
return _file;
- // make array of
+ // make array of
uint32_t sortedSectionIndexes[_machOSectionsCount];
this->makeSortedSectionsArray(sortedSectionIndexes);
uint32_t countOfCUs = 0;
if ( _compactUnwindSection != NULL )
countOfCUs = _compactUnwindSection->count();
- uint8_t cuInfoBuffer[sizeof(typename CUSection<A>::Info) * countOfCUs];
- typename CUSection<A>::Info* cuInfoArray = (typename CUSection<A>::Info*)cuInfoBuffer;
+ // stack allocate (if not too large) cuInfoBuffer
+ STACK_ALLOC_IF_SMALL(typename CUSection<A>::Info, cuInfoArray, countOfCUs, 1024);
if ( countOfCUs != 0 )
_compactUnwindSection->parse(*this, countOfCUs, cuInfoArray);
+
+ // create lists of address that already have compact unwind and thus don't need the dwarf parsed
+ unsigned cuLsdaCount = 0;
+ pint_t cuStarts[countOfCUs];
+ for (uint32_t i=0; i < countOfCUs; ++i) {
+ if ( CUSection<A>::encodingMeansUseDwarf(cuInfoArray[i].compactUnwindInfo) )
+ cuStarts[i] = -1;
+ else
+ cuStarts[i] = cuInfoArray[i].functionStartAddress;
+ if ( cuInfoArray[i].lsdaAddress != 0 )
+ ++cuLsdaCount;
+ }
+
// if it exists, do special early parsing of __eh_frame section
- // stack allocate array of CFI_Atom_Info
+ // stack allocate (if not too large) array of CFI_Atom_Info
uint32_t countOfCFIs = 0;
if ( _EHFrameSection != NULL )
countOfCFIs = _EHFrameSection->cfiCount();
- typename CFISection<A>::CFI_Atom_Info cfiArray[countOfCFIs];
+ STACK_ALLOC_IF_SMALL(typename CFISection<A>::CFI_Atom_Info, cfiArray, countOfCFIs, 1024);
+
// stack allocate (if not too large) a copy of __eh_frame to apply relocations to
- uint8_t* ehBuffer = NULL;
- uint32_t stackAllocSize = 0;
- if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) {
- uint32_t sectSize = _EHFrameSection->machoSection()->size();
- if ( sectSize > 50*1024 )
- ehBuffer = (uint8_t*)malloc(sectSize);
- else
- stackAllocSize = sectSize;
- }
- uint32_t ehStackBuffer[1+stackAllocSize/4]; // make 4-byte aligned stack bufffer
- if ( ehBuffer == NULL )
- ehBuffer = (uint8_t*)&ehStackBuffer;
+ uint32_t sectSize = 4;
+ if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() )
+ sectSize = _EHFrameSection->machoSection()->size()+4;
+ STACK_ALLOC_IF_SMALL(uint8_t, ehBuffer, sectSize, 50*1024);
uint32_t cfiStartsCount = 0;
if ( countOfCFIs != 0 ) {
- _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs);
+ _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs, cuStarts, countOfCUs);
// count functions and lsdas
for(uint32_t i=0; i < countOfCFIs; ++i) {
if ( cfiArray[i].isCIE )
continue;
- //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n",
- // (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress,
- // (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress,
+ //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n",
+ // (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress,
+ // (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress,
// cfiArray[i].u.fdeInfo.compactUnwindInfo);
if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
++cfiStartsCount;
CFI_CU_InfoArrays cfis(cfiArray, countOfCFIs, cuInfoArray, countOfCUs);
// create sorted array of function starts and lsda starts
- pint_t cfiStartsArray[cfiStartsCount];
+ pint_t cfiStartsArray[cfiStartsCount+cuLsdaCount];
uint32_t countOfFDEs = 0;
+ uint32_t cfiStartsArrayCount = 0;
if ( countOfCFIs != 0 ) {
- int index = 0;
for(uint32_t i=0; i < countOfCFIs; ++i) {
if ( cfiArray[i].isCIE )
continue;
if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
- cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.function.targetAddress;
+ cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.function.targetAddress;
if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
- cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
+ cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
++countOfFDEs;
}
- ::qsort(cfiStartsArray, cfiStartsCount, sizeof(pint_t), pointerSorter);
+ }
+ if ( cuLsdaCount != 0 ) {
+ // merge in an lsda info from compact unwind
+ for (uint32_t i=0; i < countOfCUs; ++i) {
+ if ( cuInfoArray[i].lsdaAddress == 0 )
+ continue;
+ // append to cfiStartsArray if not already in that list
+ bool found = false;
+ for(uint32_t j=0; j < cfiStartsArrayCount; ++j) {
+ if ( cfiStartsArray[j] == cuInfoArray[i].lsdaAddress )
+ found = true;
+ }
+ if ( ! found ) {
+ cfiStartsArray[cfiStartsArrayCount++] = cuInfoArray[i].lsdaAddress;
+ }
+ }
+ }
+ if ( cfiStartsArrayCount != 0 ) {
+ ::qsort(cfiStartsArray, cfiStartsArrayCount, sizeof(pint_t), pointerSorter);
#ifndef NDEBUG
// scan for FDEs claming the same function
- for(int i=1; i < index; ++i) {
+ for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}
#endif
// figure out how many atoms will be allocated and allocate
LabelAndCFIBreakIterator breakIterator(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray,
- cfiStartsCount, _overlappingSymbols);
+ cfiStartsArrayCount, _overlappingSymbols);
uint32_t computedAtomCount = 0;
for (uint32_t i=0; i < sectionsCount; ++i ) {
breakIterator.beginSection();
// have each section append atoms to _atomsArray
LabelAndCFIBreakIterator breakIterator2(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray,
- cfiStartsCount, _overlappingSymbols);
+ cfiStartsArrayCount, _overlappingSymbols);
for (uint32_t i=0; i < sectionsCount; ++i ) {
uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom<A>);
breakIterator2.beginSection();
_file->_unwindInfos.push_back(info);
Atom<A>* func = findAtomByAddress(cfiArray[i].u.fdeInfo.function.targetAddress);
func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+ //fprintf(stderr, "cu from dwarf =0x%08X, atom=%s\n", info.unwindInfo, func->name());
}
}
// apply compact infos in __LD,__compact_unwind section to each function
assert(info->function != NULL);
ld::Atom::UnwindInfo ui;
ui.startOffset = info->functionStartAddress - info->function->objectAddress();
- ui.unwindInfo = info->compactUnwindInfo;
+ ui.unwindInfo = info->compactUnwindInfo;
_file->_unwindInfos.push_back(ui);
- // if previous is for same function, extend range
- if ( info->function == lastFunc ) {
- if ( lastEnd != ui.startOffset ) {
- if ( lastEnd < ui.startOffset )
- warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd);
- else
- warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd);
+ // don't override with converted cu with "use dwarf" cu, if forcing dwarf conversion
+ if ( !_forceDwarfConversion || !CUSection<A>::encodingMeansUseDwarf(info->compactUnwindInfo) ) {
+ //fprintf(stderr, "cu=0x%08X, atom=%s\n", ui.unwindInfo, info->function->name());
+ // if previous is for same function, extend range
+ if ( info->function == lastFunc ) {
+ if ( lastEnd != ui.startOffset ) {
+ if ( lastEnd < ui.startOffset )
+ warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd);
+ else
+ warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd);
+ }
+ lastFunc->extendUnwindInfoRange();
}
- lastFunc->extendUnwindInfoRange();
+ else
+ info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+ lastFunc = info->function;
+ lastEnd = ui.startOffset + info->rangeLength;
}
- else
- info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
- lastFunc = info->function;
- lastEnd = ui.startOffset + info->rangeLength;
}
// parse dwarf debug info to get line info
template <> uint8_t Parser<x86>::loadCommandSizeMask() { return 0x03; }
template <> uint8_t Parser<x86_64>::loadCommandSizeMask() { return 0x07; }
template <> uint8_t Parser<arm>::loadCommandSizeMask() { return 0x03; }
+template <> uint8_t Parser<arm64>::loadCommandSizeMask() { return 0x07; }
template <typename A>
bool Parser<A>::parseLoadCommands()
if ( _dataInCodeEnd > (macho_data_in_code_entry<P>*)endOfFile )
throw "LC_DATA_IN_CODE table extends beyond end of file";
}
+ break;
+ case LC_LINKER_OPTION:
+ {
+ const macho_linker_option_command<P>* loc = (macho_linker_option_command<P>*)cmd;
+ const char* buffer = loc->buffer();
+ _file->_linkerOptions.resize(_file->_linkerOptions.size() + 1);
+ std::vector<const char*>& vec = _file->_linkerOptions.back();
+ for (uint32_t j=0; j < loc->count(); ++j) {
+ vec.push_back(buffer);
+ buffer += strlen(buffer) + 1;
+ }
+ if ( buffer > ((char*)cmd + loc->cmdsize()) )
+ throw "malformed LC_LINKER_OPTION";
+ }
+ break;
default:
if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
if ( segment != NULL )
}
}
-
template <typename A>
void Parser<A>::makeSections()
{
// };
// #define OBJC_IMAGE_SUPPORTS_GC 2
// #define OBJC_IMAGE_GC_ONLY 4
+ // #define OBJC_IMAGE_IS_SIMULATED 32
//
const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
if ( (sect->size() >= 8) && (contents[0] == 0) ) {
_file->_objConstraint = ld::File::objcConstraintGC;
else if ( (flags & 2) == 2 )
_file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+ else if ( (flags & 32) == 32 )
+ _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
else
_file->_objConstraint = ld::File::objcConstraintRetainRelease;
if ( sect->size() > 8 ) {
continue;
// return with exact match
- if ( sym.n_value() == addr )
- return nameFromSymbol(sym);
+ if ( sym.n_value() == addr ) {
+ const char* name = nameFromSymbol(sym);
+ if ( strncmp(name, "ltmp", 4) != 0 )
+ return name;
+ // treat 'ltmp*' labels as close match
+ closestSymAddr = sym.n_value();
+ closestSymName = name;
+ }
// record closest seen so far
if ( (sym.n_value() < addr) && ((sym.n_value() > closestSymAddr) || (closestSymName == NULL)) )
case ld::Fixup::kindStoreThumbBranch22:
firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22;
break;
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreARM64Branch26:
+ firstKind = ld::Fixup::kindStoreTargetAddressARM64Branch26;
+ break;
+ case ld::Fixup::kindStoreARM64Page21:
+ firstKind = ld::Fixup::kindStoreTargetAddressARM64Page21;
+ break;
+ case ld::Fixup::kindStoreARM64PageOff12:
+ firstKind = ld::Fixup::kindStoreTargetAddressARM64PageOff12;
+ break;
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21;
+ break;
+ case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+ firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12;
+ break;
+#endif
default:
combined = false;
cl = ld::Fixup::k1of2;
// backing string in CFStrings should always be direct
addFixup(src, cl, firstKind, target.atom);
}
+ else if ( (src.atom == target.atom) && (target.atom->combine() == ld::Atom::combineByName) ) {
+ // reference to self should always be direct
+ addFixup(src, cl, firstKind, target.atom);
+ }
else {
// change direct fixup to by-name fixup
addFixup(src, cl, firstKind, false, target.atom->name());
sz = 4;
break;
+ case DW_FORM_sec_offset:
+ sz = sizeof(typename A::P::uint_t);
+ break;
+
+ case DW_FORM_exprloc:
+ sz = read_uleb128 (offset, end);
+ break;
+
+ case DW_FORM_flag_present:
+ sz = 0;
+ break;
+
+ case DW_FORM_ref_sig8:
+ sz = 8;
+ break;
+
default:
return false;
}
void CFISection<A>::warnFunc(void* ref, uint64_t funcAddr, const char* msg)
{
Parser<A>* parser = (Parser<A>*)ref;
- if ( ! parser->convertUnwindInfo() )
+ if ( ! parser->warnUnwindConversionProblems() )
return;
if ( funcAddr != CFI_INVALID_ADDRESS ) {
// atoms are not constructed yet, so scan symbol table for labels
return true;
}
+template <>
+bool CFISection<arm64>::needsRelocating()
+{
+ return true;
+}
+
template <typename A>
bool CFISection<A>::needsRelocating()
{
}
template <>
-void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
+void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[],
- uint32_t count)
+ uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
{
// copy __eh_frame data to buffer
memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
}
}
-
// create ObjectAddressSpace object for use by libunwind
OAS oas(*this, buffer);
const char* msg;
msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86_64>::parseCFIs(
oas, this->_machOSection->addr(), this->_machOSection->size(),
- cfiArray, count, (void*)&parser, warnFunc);
+ cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc);
if ( msg != NULL )
throwf("malformed __eh_frame section: %s", msg);
}
template <>
void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer,
libunwind::CFI_Atom_Info<CFISection<x86>::OAS>::CFI_Atom_Info cfiArray[],
- uint32_t count)
+ uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
{
// create ObjectAddressSpace object for use by libunwind
OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
const char* msg;
msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86>::parseCFIs(
oas, this->_machOSection->addr(), this->_machOSection->size(),
- cfiArray, count, (void*)&parser, warnFunc);
+ cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc);
if ( msg != NULL )
throwf("malformed __eh_frame section: %s", msg);
}
template <>
void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer,
libunwind::CFI_Atom_Info<CFISection<arm>::OAS>::CFI_Atom_Info cfiArray[],
- uint32_t count)
+ uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
{
// arm does not use zero cost exceptions
assert(count == 0);
}
+template <>
+void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer,
+ libunwind::CFI_Atom_Info<CFISection<arm64>::OAS>::CFI_Atom_Info cfiArray[],
+ uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
+{
+ // copy __eh_frame data to buffer
+ memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
+
+ // and apply relocations
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + this->_machOSection->reloff());
+ const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
+ for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+ uint64_t* p64 = (uint64_t*)&buffer[reloc->r_address()];
+ uint32_t* p32 = (uint32_t*)&buffer[reloc->r_address()];
+ uint32_t addend32 = E::get32(*p32);
+ uint64_t addend64 = E::get64(*p64);
+ uint64_t value = 0;
+ switch ( reloc->r_type() ) {
+ case ARM64_RELOC_SUBTRACTOR:
+ value = 0 - parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+ ++reloc;
+ if ( reloc->r_extern() )
+ value += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+ break;
+ case ARM64_RELOC_UNSIGNED:
+ value = parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+ break;
+ case ARM64_RELOC_POINTER_TO_GOT:
+ // this is used for the reference to the personality function in CIEs
+ // store the symbol number of the personality function for later use as a Fixup
+ value = reloc->r_symbolnum();
+ addend32 = 0;
+ addend64 = 0;
+ break;
+ default:
+ fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address());
+ break;
+ }
+ switch ( reloc->r_length() ) {
+ case 3:
+ E::set64(*p64, value + addend64);
+ break;
+ case 2:
+ E::set32(*p32, value + addend32);
+ break;
+ default:
+ fprintf(stderr, "CFISection::cfiParse() unexpected relocation size at r_address=0x%08X\n", reloc->r_address());
+ break;
+ }
+ }
+
+
+ // create ObjectAddressSpace object for use by libunwind
+ OAS oas(*this, buffer);
+
+ // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+ const char* msg;
+ msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_arm64>::parseCFIs(
+ oas, this->_machOSection->addr(), this->_machOSection->size(),
+ cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(),
+ cfiArray, count, (void*)&parser, warnFunc);
+ if ( msg != NULL )
+ throwf("malformed __eh_frame section: %s", msg);
+}
template <typename A>
template <> bool CFISection<x86_64>::bigEndian() { return false; }
template <> bool CFISection<x86>::bigEndian() { return false; }
template <> bool CFISection<arm>::bigEndian() { return false; }
+template <> bool CFISection<arm64>::bigEndian() { return false; }
template <>
}
+
+#if SUPPORT_ARCH_arm64
+template <>
+void CFISection<arm64>::addCiePersonalityFixups(class Parser<arm64>& parser, const CFI_Atom_Info* cieInfo)
+{
+ uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+ if ( personalityEncoding == 0x9B ) {
+ // compiler always produces ARM64_RELOC_GOT r_pcrel=1 to personality function
+ // CFISection<arm64>::cfiParse() set targetAddress to be symbolIndex + addressInCIE
+ uint32_t symbolIndex = cieInfo->u.cieInfo.personality.targetAddress
+ - cieInfo->address - cieInfo->u.cieInfo.personality.offsetInCFI;
+ const macho_nlist<P>& sym = parser.symbolFromIndex(symbolIndex);
+ const char* personalityName = parser.nameFromSymbol(sym);
+
+ Atom<arm64>* cieAtom = this->findAtomByAddress(cieInfo->address);
+ Parser<arm64>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+ parser.addFixup(src, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, false, personalityName);
+ parser.addFixup(src, ld::Fixup::k2of2, ld::Fixup::kindStoreARM64PCRelToGOT);
+ }
+ else if ( personalityEncoding != 0 ) {
+ throwf("unsupported address encoding (%02X) of personality function in CIE",
+ personalityEncoding);
+ }
+}
+#endif
+
template <typename A>
void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
{
- // FIX ME
- assert(0);
+ assert(0 && "addCiePersonalityFixups() not implemented for arch");
}
template <typename A>
template <>
const char* CUSection<x86_64>::personalityName(class Parser<x86_64>& parser, const macho_relocation_info<x86_64::P>* reloc)
{
- assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
- assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
- const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
- return parser.nameFromSymbol(sym);
+ if ( reloc->r_extern() ) {
+ assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ return parser.nameFromSymbol(sym);
+ }
+ else {
+ const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
+ pint_t personalityAddr = *content;
+ Section<x86_64>* personalitySection = parser.sectionForAddress(personalityAddr);
+ assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
+ // atoms may not be constructed yet, so scan symbol table for labels
+ const char* name = parser.scanSymbolTableForAddress(personalityAddr);
+ return name;
+ }
}
template <>
const char* CUSection<x86>::personalityName(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
{
- assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
- assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
- const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
- return parser.nameFromSymbol(sym);
+ if ( reloc->r_extern() ) {
+ assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ return parser.nameFromSymbol(sym);
+ }
+ else {
+ // support __LD, __compact_unwind personality entries which are pointer to personality non-lazy pointer
+ const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
+ pint_t nlPointerAddr = *content;
+ Section<x86>* nlSection = parser.sectionForAddress(nlPointerAddr);
+ if ( nlSection->type() == ld::Section::typeCode ) {
+ // personality function is defined in this .o file, so this is a direct reference to it
+ // atoms may not be constructed yet, so scan symbol table for labels
+ const char* name = parser.scanSymbolTableForAddress(nlPointerAddr);
+ return name;
+ }
+ else {
+ uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(nlPointerAddr, nlSection->machoSection());
+ const macho_nlist<P>& nlSymbol = parser.symbolFromIndex(symIndex);
+ return parser.nameFromSymbol(nlSymbol);
+ }
+ }
}
+#if SUPPORT_ARCH_arm64
+template <>
+const char* CUSection<arm64>::personalityName(class Parser<arm64>& parser, const macho_relocation_info<arm64::P>* reloc)
+{
+ if ( reloc->r_extern() ) {
+ assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ return parser.nameFromSymbol(sym);
+ }
+ else {
+ const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
+ pint_t personalityAddr = *content;
+ Section<arm64>* personalitySection = parser.sectionForAddress(personalityAddr);
+ assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
+ // atoms may not be constructed yet, so scan symbol table for labels
+ const char* name = parser.scanSymbolTableForAddress(personalityAddr);
+ return name;
+ }
+}
+#endif
+
template <typename A>
const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
{
return NULL;
}
+template <>
+bool CUSection<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
+}
+
+template <>
+bool CUSection<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+bool CUSection<arm>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return false;
+}
+#endif
+
+#if SUPPORT_ARCH_arm64
+template <>
+bool CUSection<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
+}
+#endif
template <typename A>
int CUSection<A>::infoSorter(const void* l, const void* r)
}
}
- // scan relocs, local relocs are useless - ignore them
- // extern relocs are needed for personality references (possibly for function/lsda refs??)
+ // scan relocs, extern relocs are needed for personality references (possibly for function/lsda refs??)
const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(this->file().fileContent() + this->_machOSection->reloff());
const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::codeStartFieldOffset() ) {
uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
array[entryIndex].functionSymbolIndex = reloc->r_symbolnum();
+ array[entryIndex].functionStartAddress += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
}
else {
warning("unexpected extern relocation in __compact_unwind section");
}
}
+ else {
+ if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::personalityFieldOffset() ) {
+ uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+ array[entryIndex].personality = this->personalityName(parser, reloc);
+ }
+ }
}
// sort array by function start address so unwind infos will be contiguous for a given function
Info* const arrayStart = cus.cuArray;
Info* const arrayEnd = &cus.cuArray[cus.cuCount];
for (Info* info=arrayStart; info < arrayEnd; ++info) {
- // if external reloc was used, real address is symbol n_value + addend
- if ( info->functionSymbolIndex != 0xFFFFFFFF )
- info->functionStartAddress += parser.symbolFromIndex(info->functionSymbolIndex).n_value();
// find function atom from address
info->function = parser.findAtomByAddress(info->functionStartAddress);
// find lsda atom from address
pint_t addr;
pint_t size;
const macho_nlist<P>* sym;
- while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &sym) ) {
+ while ( it.next(parser, *this, sectNum, startAddr, endAddr, &addr, &size, &sym) ) {
++count;
}
//fprintf(stderr, "computeAtomCount(%s,%s) => %d\n", this->segmentName(), this->sectionName(), count);
template <typename A>
uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
- struct Parser<A>::LabelAndCFIBreakIterator& it,
+ struct Parser<A>::LabelAndCFIBreakIterator& it,
const struct Parser<A>::CFI_CU_InfoArrays&)
{
this->_beginAtoms = (Atom<A>*)p;
pint_t addr;
pint_t size;
const macho_nlist<P>* label;
- while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &label) ) {
+ while ( it.next(parser, *this, sectNum, startAddr, endAddr, &addr, &size, &label) ) {
Atom<A>* allocatedSpace = (Atom<A>*)p;
// is break because of label or CFI?
if ( label != NULL ) {
ld::Atom::ContentType ctype = this->contentType();
if ( ctype == ld::Atom::typeLSDA )
inclusion = ld::Atom::symbolTableInWithRandomAutoStripLabel;
- new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever,
ld::Atom::scopeTranslationUnit, ctype, inclusion,
this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
}
}
+template <>
+ld::Atom::SymbolTableInclusion ImplicitSizeSection<arm64>::symbolTableInclusion()
+{
+ return ld::Atom::symbolTableInWithRandomAutoStripLabel;
+}
+
+template <typename A>
+ld::Atom::SymbolTableInclusion ImplicitSizeSection<A>::symbolTableInclusion()
+{
+ return ld::Atom::symbolTableNotIn;
+}
+
+
template <typename A>
uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser,
struct Parser<A>::LabelAndCFIBreakIterator& it,
// if there are multiple labels in this section for the same address, then clone them into multi atoms
pint_t prevSymbolAddr = (pint_t)(-1);
uint8_t prevSymbolSectNum = 0;
+ bool prevIgnore = false;
for(uint32_t i=0; i < it.sortedSymbolCount; ++i) {
const macho_nlist<P>& sym = parser.symbolFromIndex(it.sortedSymbolIndexes[i]);
const pint_t symbolAddr = sym.n_value();
- const pint_t symbolSectNum = sym.n_sect();
- if ( (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) {
+ const uint8_t symbolSectNum = sym.n_sect();
+ const bool ignore = this->ignoreLabel(parser.nameFromSymbol(sym));
+ if ( !ignore && !prevIgnore && (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) {
++count;
}
prevSymbolAddr = symbolAddr;
prevSymbolSectNum = symbolSectNum;
+ prevIgnore = ignore;
}
}
return count;
pint_t size;
const macho_nlist<P>* foundLabel;
Atom<A>* allocatedSpace;
- while ( it.next(parser, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
+ while ( it.next(parser, *this, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
if ( foundLabel != NULL ) {
+ bool skip = false;
pint_t labeledAtomSize = this->elementSizeAtAddress(foundAddr);
allocatedSpace = (Atom<A>*)p;
if ( this->ignoreLabel(parser.nameFromSymbol(*foundLabel)) ) {
- //fprintf(stderr, " 0x%08llX make annon\n", (uint64_t)foundAddr);
- new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr,
+ if ( size == 0 ) {
+ // <rdar://problem/10018737>
+ // a size of zero means there is another label at same location
+ // and we are supposed to ignore this label
+ skip = true;
+ }
+ else {
+ //fprintf(stderr, " 0x%08llX make annon, size=%lld\n", (uint64_t)foundAddr, (uint64_t)size);
+ new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr,
this->elementSizeAtAddress(foundAddr), this->definition(),
this->combine(parser, foundAddr), this->scopeAtAddress(parser, foundAddr),
this->contentType(), this->symbolTableInclusion(),
this->dontDeadStrip(), false, false, this->alignmentForAddress(foundAddr));
+ }
}
else {
// make named atom for label
//fprintf(stderr, " 0x%08llX make labeled\n", (uint64_t)foundAddr);
new (allocatedSpace) Atom<A>(*this, parser, *foundLabel, labeledAtomSize);
}
- ++count;
- p += sizeof(Atom<A>);
- foundAddr += labeledAtomSize;
- size -= labeledAtomSize;
+ if ( !skip ) {
+ ++count;
+ p += sizeof(Atom<A>);
+ foundAddr += labeledAtomSize;
+ size -= labeledAtomSize;
+ }
}
// some number of anonymous atoms
for (pint_t addr = foundAddr; addr < (foundAddr+size); addr += elementSizeAtAddress(addr) ) {
// make anon atoms for area before label
if ( this->useElementAt(parser, it, addr) ) {
- //fprintf(stderr, " 0x%08llX make annon\n", (uint64_t)addr);
+ //fprintf(stderr, " 0x%08llX make annon, size=%lld\n", (uint64_t)addr, (uint64_t)elementSizeAtAddress(addr));
allocatedSpace = (Atom<A>*)p;
new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, addr), addr, this->elementSizeAtAddress(addr),
this->definition(), this->combine(parser, addr), this->scopeAtAddress(parser, addr),
}
template <typename A>
-bool CStringSection<A>::ignoreLabel(const char* label)
+bool CStringSection<A>::ignoreLabel(const char* label) const
{
return (label[0] == 'L') || (label[0] == 'l');
}
+
template <typename A>
Atom<A>* CStringSection<A>::findAtomByAddress(pint_t addr)
{
return ld::Fixup::kindStoreLittleEndian32;
}
+template <>
+ld::Fixup::Kind NonLazyPointerSection<arm64>::fixupKind()
+{
+ return ld::Fixup::kindStoreLittleEndian64;
+}
+
template <>
void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFI_CU_InfoArrays&)
case ld::Fixup::bindingsIndirectlyBound:
targetAtom = ind.indirectAtom(fit->u.bindingIndex);
break;
+ case ld::Fixup::bindingDirectlyBound:
+ targetAtom = fit->u.target;
+ break;
default:
- assert(0);
+ assert(0 && "unsupported reference to selector");
}
assert(targetAtom != NULL);
const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
- assert(target != NULL);
+ assert(target != NULL);
+ assert(target->contentType() == ld::Atom::typeCString);
return (char*)target->contentPointer();
}
#endif
-
-
+#if SUPPORT_ARCH_arm64
+template <>
+bool Section<arm64>::addRelocFixup(class Parser<arm64>& parser, const macho_relocation_info<P>* reloc)
+{
+ bool result = false;
+ Parser<arm64>::SourceLocation src;
+ Parser<arm64>::TargetDesc target = { NULL, NULL, false, 0 };
+ Parser<arm64>::TargetDesc toTarget;
+ int32_t prefixRelocAddend = 0;
+ if ( reloc->r_type() == ARM64_RELOC_ADDEND ) {
+ uint32_t rawAddend = reloc->r_symbolnum();
+ prefixRelocAddend = rawAddend;
+ if ( rawAddend & 0x00800000 )
+ prefixRelocAddend |= 0xFF000000; // sign extend 24-bit signed int to 32-bits
+ uint32_t addendAddress = reloc->r_address();
+ ++reloc; //advance to next reloc record
+ result = true;
+ if ( reloc->r_address() != addendAddress )
+ throw "ARM64_RELOC_ADDEND r_address does not match next reloc's r_address";
+ }
+ const macho_section<P>* sect = this->machoSection();
+ uint64_t srcAddr = sect->addr() + reloc->r_address();
+ src.atom = this->findAtomByAddress(srcAddr);
+ src.offsetInAtom = srcAddr - src.atom->_objAddress;
+ const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+ uint64_t contentValue = 0;
+ const macho_relocation_info<arm64::P>* nextReloc = &reloc[1];
+ bool useDirectBinding;
+ uint32_t instruction;
+ uint32_t encodedAddend;
+ switch ( reloc->r_length() ) {
+ case 0:
+ contentValue = *fixUpPtr;
+ break;
+ case 1:
+ contentValue = (int64_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr));
+ break;
+ case 2:
+ contentValue = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr));
+ break;
+ case 3:
+ contentValue = E::get64(*((uint64_t*)fixUpPtr));
+ break;
+ }
+ if ( reloc->r_extern() ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+ const char* symbolName = parser.nameFromSymbol(sym);
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (symbolName[0] == 'L') || (symbolName[0] == 'l')) ) {
+ // use direct reference for local symbols
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ //target.addend += contentValue;
+ }
+ else if ( ((sym.n_type() & N_TYPE) == N_SECT) && (src.atom->_objAddress <= sym.n_value()) && (sym.n_value() < (src.atom->_objAddress+src.atom->size())) ) {
+ // <rdar://problem/13700961> spurious warning when weak function has reference to itself
+ // use direct reference when atom targets itself
+ target.atom = src.atom;
+ target.name = NULL;
+ }
+ else {
+ target.name = symbolName;
+ target.weakImport = parser.weakImportFromSymbol(sym);
+ //target.addend = contentValue;
+ }
+ // cfstrings should always use direct reference to backing store
+ if ( (this->type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+ //target.addend = contentValue;
+ }
+ }
+ else {
+ if ( reloc->r_pcrel() )
+ contentValue += srcAddr;
+ parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+ }
+ switch ( reloc->r_type() ) {
+ case ARM64_RELOC_UNSIGNED:
+ if ( reloc->r_pcrel() )
+ throw "pcrel and ARM64_RELOC_UNSIGNED not supported";
+ target.addend = contentValue;
+ switch ( reloc->r_length() ) {
+ case 0:
+ case 1:
+ throw "length < 2 and ARM64_RELOC_UNSIGNED not supported";
+ case 2:
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+ break;
+ case 3:
+ parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target);
+ break;
+ }
+ break;
+ case ARM64_RELOC_BRANCH26:
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and ARM64_RELOC_BRANCH26 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_BRANCH26 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "r_length != 2 and ARM64_RELOC_BRANCH26 not supported";
+ if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreARM64DtraceCallSiteNop, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[16]);
+ }
+ else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+ parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear, false, target.name);
+ parser.addDtraceExtraInfos(src, &target.name[20]);
+ }
+ else {
+ target.addend = prefixRelocAddend;
+ instruction = contentValue;
+ encodedAddend = (instruction & 0x03FFFFFF) << 2;
+ if ( encodedAddend != 0 ) {
+ if ( prefixRelocAddend == 0 ) {
+ warning("branch26 instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address());
+ target.addend = encodedAddend;
+ }
+ else {
+ throwf("branch26 instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address());
+ }
+ }
+ parser.addFixups(src, ld::Fixup::kindStoreARM64Branch26, target);
+ }
+ break;
+ case ARM64_RELOC_PAGE21:
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and ARM64_RELOC_PAGE21 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_PAGE21 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and ARM64_RELOC_PAGE21 not supported";
+ target.addend = prefixRelocAddend;
+ instruction = contentValue;
+ encodedAddend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3);
+ encodedAddend *= 4096; // internally addend is in bytes, so scale
+ if ( encodedAddend != 0 ) {
+ if ( prefixRelocAddend == 0 ) {
+ warning("adrp instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address());
+ target.addend = encodedAddend;
+ }
+ else {
+ throwf("adrp instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address());
+ }
+ }
+ parser.addFixups(src, ld::Fixup::kindStoreARM64Page21, target);
+ break;
+ case ARM64_RELOC_PAGEOFF12:
+ if ( reloc->r_pcrel() )
+ throw "pcrel and ARM64_RELOC_PAGEOFF12 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_PAGEOFF12 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and ARM64_RELOC_PAGEOFF12 not supported";
+ target.addend = prefixRelocAddend;
+ instruction = contentValue;
+ encodedAddend = ((instruction & 0x003FFC00) >> 10);
+ // internally addend is in bytes. Some instructions have an implicit scale factor
+ if ( (instruction & 0x3B000000) == 0x39000000 ) {
+ switch ( instruction & 0xC0000000 ) {
+ case 0x00000000:
+ break;
+ case 0x40000000:
+ encodedAddend *= 2;
+ break;
+ case 0x80000000:
+ encodedAddend *= 4;
+ break;
+ case 0xC0000000:
+ encodedAddend *= 8;
+ break;
+ }
+ }
+ if ( encodedAddend != 0 ) {
+ if ( prefixRelocAddend == 0 ) {
+ warning("pageoff12 instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address());
+ target.addend = encodedAddend;
+ }
+ else {
+ throwf("pageoff12 instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address());
+ }
+ }
+ parser.addFixups(src, ld::Fixup::kindStoreARM64PageOff12, target);
+ break;
+ case ARM64_RELOC_GOT_LOAD_PAGE21:
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+ if ( prefixRelocAddend != 0 )
+ throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+ instruction = contentValue;
+ target.addend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3);
+ if ( target.addend != 0 )
+ throw "non-zero addend with ARM64_RELOC_GOT_LOAD_PAGE21 is not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreARM64GOTLoadPage21, target);
+ break;
+ case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ if ( reloc->r_pcrel() )
+ throw "pcrel and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+ if ( prefixRelocAddend != 0 )
+ throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+ instruction = contentValue;
+ target.addend = ((instruction & 0x003FFC00) >> 10);
+ parser.addFixups(src, ld::Fixup::kindStoreARM64GOTLoadPageOff12, target);
+ break;
+ case ARM64_RELOC_TLVP_LOAD_PAGE21:
+ if ( ! reloc->r_pcrel() )
+ throw "not pcrel and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+ if ( prefixRelocAddend != 0 )
+ throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+ instruction = contentValue;
+ target.addend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3);
+ if ( target.addend != 0 )
+ throw "non-zero addend with ARM64_RELOC_GOT_LOAD_PAGE21 is not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreARM64TLVPLoadPage21, target);
+ break;
+ case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
+ if ( reloc->r_pcrel() )
+ throw "pcrel and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+ if ( reloc->r_length() != 2 )
+ throw "length != 2 and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+ if ( prefixRelocAddend != 0 )
+ throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+ instruction = contentValue;
+ target.addend = ((instruction & 0x003FFC00) >> 10);
+ parser.addFixups(src, ld::Fixup::kindStoreARM64TLVPLoadPageOff12, target);
+ break;
+ case ARM64_RELOC_SUBTRACTOR:
+ if ( reloc->r_pcrel() )
+ throw "ARM64_RELOC_SUBTRACTOR cannot be pc-relative";
+ if ( reloc->r_length() < 2 )
+ throw "ARM64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
+ if ( !reloc->r_extern() )
+ throw "ARM64_RELOC_SUBTRACTOR must have r_extern=1";
+ if ( nextReloc->r_type() != ARM64_RELOC_UNSIGNED )
+ throw "ARM64_RELOC_SUBTRACTOR must be followed by ARM64_RELOC_UNSIGNED";
+ if ( prefixRelocAddend != 0 )
+ throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_SUBTRACTOR not supported";
+ result = true;
+ if ( nextReloc->r_pcrel() )
+ throw "ARM64_RELOC_UNSIGNED following a ARM64_RELOC_SUBTRACTOR cannot be pc-relative";
+ if ( nextReloc->r_length() != reloc->r_length() )
+ throw "ARM64_RELOC_UNSIGNED following a ARM64_RELOC_SUBTRACTOR must have same r_length";
+ if ( nextReloc->r_extern() ) {
+ const macho_nlist<P>& sym = parser.symbolFromIndex(nextReloc->r_symbolnum());
+ // use direct reference for local symbols
+ if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) {
+ parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), toTarget);
+ toTarget.addend = contentValue;
+ useDirectBinding = true;
+ }
+ else {
+ toTarget.name = parser.nameFromSymbol(sym);
+ toTarget.weakImport = parser.weakImportFromSymbol(sym);
+ toTarget.addend = contentValue;
+ useDirectBinding = false;
+ }
+ }
+ else {
+ parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget);
+ useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit);
+ }
+ if ( useDirectBinding )
+ parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
+ else
+ parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.weakImport, toTarget.name);
+ parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, toTarget.addend);
+ if ( target.atom == NULL )
+ parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, false, target.name);
+ else
+ parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, target.atom);
+ if ( reloc->r_length() == 2 )
+ parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32);
+ else
+ parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian64);
+ break;
+ case ARM64_RELOC_POINTER_TO_GOT:
+ if ( ! reloc->r_extern() )
+ throw "r_extern == 0 and ARM64_RELOC_POINTER_TO_GOT not supported";
+ if ( prefixRelocAddend != 0 )
+ throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_POINTER_TO_GOT not supported";
+ if ( reloc->r_pcrel() ) {
+ if ( reloc->r_length() != 2 )
+ throw "r_length != 2 and r_extern = 1 and ARM64_RELOC_POINTER_TO_GOT not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreARM64PCRelToGOT, target);
+ }
+ else {
+ if ( reloc->r_length() != 3 )
+ throw "r_length != 3 and r_extern = 0 and ARM64_RELOC_POINTER_TO_GOT not supported";
+ parser.addFixups(src, ld::Fixup::kindStoreARM64PointerToGOT, target);
+ }
+ break;
+ default:
+ throwf("unknown relocation type %d", reloc->r_type());
+ }
+ return result;
+}
+#endif
template <typename A>
bool ObjC1ClassSection<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
return mach_o::relocatable::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
+ return mach_o::relocatable::Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+ break;
#endif
}
return NULL;
return ( mach_o::relocatable::Parser<x86>::validFile(fileContent) );
case CPU_TYPE_ARM:
return ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
+ case CPU_TYPE_ARM64:
+ return ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
}
return false;
}
*subResult = header->cpusubtype();
return true;
}
+ if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
+ *result = CPU_TYPE_ARM64;
+ *subResult = CPU_SUBTYPE_ARM64_ALL;
+ return true;
+ }
return false;
}
else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
return mach_o::relocatable::Parser<x86>::hasObjC2Categories(fileContent);
}
+#if SUPPORT_ARCH_arm64
+ else if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
+ return mach_o::relocatable::Parser<arm64>::hasObjC2Categories(fileContent);
+ }
+#endif
return false;
}
uint32_t architecture;
bool objSubtypeMustMatch;
bool logAllFiles;
- bool convertUnwindInfo;
+ bool warnUnwindConversionProblems;
+ bool keepDwarfUnwind;
+ bool forceDwarfConversion;
uint32_t subType;
};
std::vector<LSDAEntry> lsdaIndex;
makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
-
// calculate worst case size for all unwind info pages when allocating buffer
const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
assert(uniqueEntries.size() > 0);
return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
}
+template <>
+bool UnwindInfoAtom<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+ return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
+}
+
template <typename A>
void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
}
+template <>
+void UnwindInfoAtom<arm64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
template <>
void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
+template <>
+void UnwindInfoAtom<arm64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
template <>
void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
+template <>
+void UnwindInfoAtom<arm64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
template <>
void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
{
_fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
}
+template <>
+void UnwindInfoAtom<arm64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
+{
+ _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+ _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
template <>
void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
}
+template <>
+void UnwindInfoAtom<arm64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
template <>
void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
{
_fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
}
+template <>
+void UnwindInfoAtom<arm64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
+{
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
+ _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
+}
encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
if ( encodingIndex <= 255 ) {
pageSpecificEncodings[encoding] = encodingIndex;
+ if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): pageSpecificEncodings[%d]=0x%08X\n", encodingIndex, encoding);
}
else {
canDo = false; // case 3)
if ( atom->beginUnwind() == atom->endUnwind() ) {
// be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
- if ( atom->section().type() == ld::Section::typeCode ) {
+ if ( (atom->section().type() == ld::Section::typeCode) && (atom->size() !=0) ) {
entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
}
}
case CPU_TYPE_I386:
state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ state.addAtom(*new UnwindInfoAtom<arm64>(entries, ehFrameSize));
+ break;
#endif
default:
assert(0 && "no compact unwind for arch");
template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+#if SUPPORT_ARCH_arm64
+template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
+template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+#endif
template <typename A>
CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
uint32_t len, uint32_t cui)
: ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
- symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(log2(sizeof(pint_t)))),
_atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
{
_fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
case CPU_TYPE_I386:
state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ state.addAtom(*new CompactUnwindAtom<arm64>(state, atom, startOffset, endOffset-startOffset, cui));
+ break;
#endif
}
}
#include <unordered_set>
#include "ld.hpp"
+#include "MachOFileAbstraction.hpp"
#include "dtrace_dof.h"
// prototype for entry point in libdtrace.dylib
// only make __dof section in final linked images
if ( opts.outputKind() == Options::kObjectFile )
return;
+
+ // skip making __dof section if command line option said not to
+ if ( ! opts.generateDtraceDOF() )
+ return;
// scan all atoms looking for dtrace probes
std::vector<DTraceProbeInfo> probeSites;
case ld::Fixup::kindStoreX86DtraceCallSiteNop:
case ld::Fixup::kindStoreARMDtraceCallSiteNop:
case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
break;
case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
break;
case ld::Fixup::kindDtraceExtra:
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM64:
storeKind = ld::Fixup::kindStoreLittleEndian32;
break;
default:
#include <vector>
#include <map>
+#include "MachOFileAbstraction.hpp"
#include "ld.hpp"
#include "got.h"
+#include "configure.h"
namespace ld {
namespace passes {
class GOTEntryAtom : public ld::Atom {
public:
- GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport)
+ GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool is64)
: ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
- symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
- _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
- _target(target)
+ symbolTableNotIn, false, false, false, (is64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2))),
+ _fixup(0, ld::Fixup::k1of1, (is64 ? ld::Fixup::kindStoreTargetAddressLittleEndian64 : ld::Fixup::kindStoreTargetAddressLittleEndian32), target),
+ _target(target),
+ _is64(is64)
{ _fixup.weakImport = weakImport; internal.addAtom(*this); }
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return _target->name(); }
- virtual uint64_t size() const { return 8; }
+ virtual uint64_t size() const { return (_is64 ? 8 : 4); }
virtual uint64_t objectAddress() const { return 0; }
virtual void copyRawContent(uint8_t buffer[]) const { }
virtual void setScope(Scope) { }
private:
mutable ld::Fixup _fixup;
const ld::Atom* _target;
+ bool _is64;
static ld::Section _s_section;
};
{
switch (fixup->kind) {
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+#endif
// start by assuming this can be optimized
*optimizable = true;
// cannot do LEA optimization if target is in another dylib
}
return true;
case ld::Fixup::kindStoreX86PCRel32GOT:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
*optimizable = false;
return true;
case ld::Fixup::kindNoneGroupSubordinatePersonality:
case ld::Fixup::bindingDirectlyBound:
fit->binding = ld::Fixup::bindingDirectlyBound;
fit->u.target = targetOfGOT;
- fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
+ switch ( fit->kind ) {
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+ fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
+ break;
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ fit->kind = ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21;
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ fit->kind = ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12;
+ break;
+#endif
+ default:
+ assert(0 && "unsupported GOT reference kind");
+ break;
+ }
break;
default:
assert(0 && "unsupported GOT reference");
}
}
+ bool is64 = false;
+ switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_i386
+ case CPU_TYPE_I386:
+ is64 = false;
+ break;
+#endif
+#if SUPPORT_ARCH_x86_64
+ case CPU_TYPE_X86_64:
+ is64 = true;
+ break;
+#endif
+#if SUPPORT_ARCH_arm_any
+ case CPU_TYPE_ARM:
+ is64 = false;
+ break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ is64 = true;
+ break;
+#endif
+ }
+
// make GOT entries
for (std::map<const ld::Atom*,ld::Atom*>::iterator it = gotMap.begin(); it != gotMap.end(); ++it) {
- it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first]);
+ it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first], is64);
}
// update atoms to use GOT entries
#define OBJC_IMAGE_REQUIRES_GC (1<<2)
#define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
#define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
+#define OBJC_IMAGE_IS_SIMULATED (1<<5)
if ( compaction )
value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
break;
+ case ld::File::objcConstraintRetainReleaseForSimulator:
+ value |= OBJC_IMAGE_IS_SIMULATED;
+ break;
}
_content.version = 0;
opts.objCABIVersion2POverride() ? true : false));
break;
#endif
+#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction,
true));
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ state.addAtom(*new ObjCImageInfoAtom<arm64>(state.objcObjectConstraint, compaction,
+ true));
+ break;
+#endif
default:
assert(0 && "unknown objc arch");
}
#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
- // disable optimization until fully tested
if ( opts.objCABIVersion2POverride() )
OptimizeCategories<x86>::doit(opts, state);
break;
#endif
#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
- // disable optimization until fully tested
OptimizeCategories<arm>::doit(opts, state);
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ // disabled until tested
+ break;
#endif
default:
assert(0 && "unknown objc arch");
#include <vector>
#include <map>
+#include <set>
#include <unordered_map>
#include "ld.hpp"
{
if ( left == right )
return false;
-
+
// magic section$start symbol always sorts to the start of its section
if ( left->contentType() == ld::Atom::typeSectionStart )
return true;
if ( right->contentType() == ld::Atom::typeSectionEnd )
return true;
+ // aliases sort before their target
+ bool leftIsAlias = left->isAlias();
+ if ( leftIsAlias ) {
+ for (ld::Fixup::iterator fit=left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+ if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ if ( fit->u.target == right )
+ return true; // left already before right
+ left = fit->u.target; // sort as if alias was its target
+ break;
+ }
+ }
+ }
+ bool rightIsAlias = right->isAlias();
+ if ( rightIsAlias ) {
+ for (ld::Fixup::iterator fit=right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+ if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+ assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+ if ( fit->u.target == left )
+ return false; // need to swap, alias is after target
+ right = fit->u.target; // continue with sort as if right was target
+ break;
+ }
+ }
+ }
+
// the __common section can have real or tentative definitions
// we want the real ones to sort before tentative ones
bool leftIsTent = (left->definition() == ld::Atom::definitionTentative);
int64_t addrDiff = left->objectAddress() - right->objectAddress();
if ( addrDiff == 0 ) {
// have same address so one might be an alias, and aliases need to sort before target
- bool leftIsAlias = left->isAlias();
- bool rightIsAlias = right->isAlias();
if ( leftIsAlias != rightIsAlias )
return leftIsAlias;
// sort atoms in each section
for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
+ //fprintf(stderr, "sorting section %s\n", sect->sectionName());
std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
}
// ld::Internal::FinalSection* sect = *sit;
// for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
// const ld::Atom* atom = *ait;
- // fprintf(stderr, "\t%s\t%s\n", sect->sectionName(), atom->name());
+ // fprintf(stderr, "\t%p\t%s\t%s\n", atom, sect->sectionName(), atom->name());
// }
//}
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace arm64 {
+
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+ FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
+ pass.internal()->compressedFastBinderProxy)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "fast binder pointer"; }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+ mutable ld::Fixup _fixup;
+
+ static ld::Section _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+ ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "image cache pointer"; }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+
+private:
+
+ static ld::Section _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+
+
+
+//
+// The stub-helper-helper is the common code factored out of each helper function.
+// It is in the same section as the stub-helpers.
+// Similar to the PLT0 entry in ELF.
+//
+class StubHelperHelperAtom : public ld::Atom {
+public:
+ StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, compressedImageCache(pass)),
+ _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedImageCache(pass)),
+ _fixup3(12, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, compressedFastBinder(pass)),
+ _fixup4(16, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedFastBinder(pass))
+ { pass.addAtom(*this); }
+
+ virtual ld::File* file() const { return NULL; }
+ virtual const char* name() const { return "helper helper"; }
+ virtual uint64_t size() const { return 24; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); // ADRP X17, dyld_mageLoaderCache@page
+ OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); // ADD X17, X17, dyld_mageLoaderCache@pageoff
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xA9BF47F0); // STP X16/X17, [SP, #-16]!
+ OSWriteLittleInt32(&buffer[12], 0, 0x90000010); // ADRP X16, _fast_lazy_bind@page
+ OSWriteLittleInt32(&buffer[16], 0, 0xF9400210); // LDR X16, [X16,_fast_lazy_bind@pageoff]
+ OSWriteLittleInt32(&buffer[20], 0, 0xD61F0200); // BR X16
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+ static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedImageCache == NULL )
+ pass.compressedImageCache = new ImageCachePointerAtom(pass);
+ return pass.compressedImageCache;
+ }
+ static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedFastBinderPointer == NULL )
+ pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+ return pass.compressedFastBinderPointer;
+ }
+
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+ ld::Fixup _fixup4;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+ StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+ const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, helperHelper(pass)),
+ _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+ _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[0], 0, 0x18000050); // LDR W16, L0
+ OSWriteLittleInt32(&buffer[4], 0, 0x14000000); // B helperhelper
+ OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // L0: .long 0
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+ static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+ if ( pass.compressedHelperHelper == NULL )
+ pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+ return pass.compressedHelperHelper;
+ }
+
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+ ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+ const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _fixup1(24, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, &stubTo),
+ _fixup2(28, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, lazyPointer),
+ _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, lazyPointer) { }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 68; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xa9bf7bfd); // stp fp, lr, [sp, #-16]!
+ OSWriteLittleInt32(&buffer[ 4], 0, 0x910003fd); // mov fp, sp
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xa9bf03e1); // stp x1, x0, [sp, #-16]!
+ OSWriteLittleInt32(&buffer[12], 0, 0xa9bf0be3); // stp x3, x2, [sp, #-16]!
+ OSWriteLittleInt32(&buffer[16], 0, 0xa9bf13e5); // stp x5, x4, [sp, #-16]!
+ OSWriteLittleInt32(&buffer[20], 0, 0xa9bf1be7); // stp x7, x6, [sp, #-16]!
+ OSWriteLittleInt32(&buffer[24], 0, 0x94000000); // bl _foo
+ OSWriteLittleInt32(&buffer[28], 0, 0x90000010); // adrp x16, lazy_pointer@PAGE
+ OSWriteLittleInt32(&buffer[32], 0, 0x91000210); // add x16, x16, lazy_pointer@PAGEOFF
+ OSWriteLittleInt32(&buffer[36], 0, 0xf9000200); // str x0, [x16]
+ OSWriteLittleInt32(&buffer[40], 0, 0xaa0003f0); // mov x16, x0
+ OSWriteLittleInt32(&buffer[44], 0, 0xa8c11be7); // ldp x7, x6, [sp], #16
+ OSWriteLittleInt32(&buffer[48], 0, 0xa8c113e5); // ldp x5, x4, [sp], #16
+ OSWriteLittleInt32(&buffer[52], 0, 0xa8c10be3); // ldp x3, x2, [sp], #16
+ OSWriteLittleInt32(&buffer[56], 0, 0xa8c103e1); // ldp x1, x0, [sp], #16
+ OSWriteLittleInt32(&buffer[60], 0, 0xa8c17bfd); // ldp fp, lr, [sp], #16
+ OSWriteLittleInt32(&buffer[64], 0, 0xd61f0200); // br x16
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+
+ const ld::Atom& _stubTo;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+ ld::Fixup _fixup3;
+
+ static ld::Section _s_section;
+};
+
+ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+ LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _stubTo(stubTo),
+ _helper(pass, this, stubTo),
+ _resolverHelper(pass, this, stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
+ stubToResolver ? &_resolverHelper :
+ (stubToGlobalWeakDef ? &stubTo : &_helper)),
+ _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
+ _fixup2.weakImport = weakImport; pass.addAtom(*this);
+ if ( stubToResolver )
+ pass.addAtom(_resolverHelper);
+ else if ( !stubToGlobalWeakDef )
+ pass.addAtom(_helper);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ StubHelperAtom _helper;
+ ResolverHelperAtom _resolverHelper;
+ mutable ld::Fixup _fixup1;
+ ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+
+
+class StubAtom : public ld::Atom {
+public:
+ StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+ bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
+ _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer)
+ { pass.addAtom(*this); }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, lazy_pointer@page
+ OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, lazy_pointer@pageoff]
+ OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ LazyPointerAtom _lazyPointer;
+ mutable ld::Fixup _fixup1;
+ mutable ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+
+class NonLazyPointerAtom : public ld::Atom {
+public:
+ NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular,
+ ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+ _stubTo(stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
+ pass.addAtom(*this);
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _stubTo.name(); }
+ virtual uint64_t size() const { return 8; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ ld::Fixup _fixup1;
+
+ static ld::Section _s_section;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+class KextStubAtom : public ld::Atom {
+public:
+ KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+ : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
+ symbolTableIn, false, false, false, ld::Atom::Alignment(1)),
+ _stubTo(stubTo),
+ _nonLazyPointer(pass, stubTo),
+ _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
+ _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) {
+ pass.addAtom(*this);
+ asprintf((char**)&_name, "%s.stub", _stubTo.name());
+ }
+
+ virtual const ld::File* file() const { return _stubTo.file(); }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return 12; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const {
+ OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, non_lazy_pointer@page
+ OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, non_lazy_pointer@pageoff]
+ OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
+ }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+ const ld::Atom& _stubTo;
+ const char* _name;
+ NonLazyPointerAtom _nonLazyPointer;
+ mutable ld::Fixup _fixup1;
+ mutable ld::Fixup _fixup2;
+
+ static ld::Section _s_section;
+};
+
+ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeCode);
+
+
+} // namespace x86_64
+
#include <map>
#include "Options.h"
-#include "ld.hpp"
#include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
#include "make_stubs.h"
#include "stub_x86_classic.hpp"
#include "stub_arm.hpp"
#include "stub_arm_classic.hpp"
-
-
+#if SUPPORT_ARCH_arm64
+#include "stub_arm64.hpp"
+#endif
Pass::Pass(const Options& opts)
: compressedHelperHelper(NULL),
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
assert(target != NULL);
// create stub if target is in a dylib
if ( target->definition() == ld::Atom::definitionProxy )
return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
}
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() )
+ return new ld::passes::stubs::arm64::KextStubAtom(*this, target);
+ else
+ return new ld::passes::stubs::arm64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+ break;
#endif
}
throw "unsupported arch for stub";
case ld::Fixup::kindStoreThumbHigh16:
printf(", then store high-16 in Thumb movt");
break;
+ case ld::Fixup::kindStoreARM64Branch26:
+ printf(", then store as ARM64 26-bit pcrel branch");
+ break;
+ case ld::Fixup::kindStoreARM64Page21:
+ printf(", then store as ARM64 21-bit pcrel ADRP");
+ break;
+ case ld::Fixup::kindStoreARM64PageOff12:
+ printf(", then store as ARM64 12-bit offset");
+ break;
+ case ld::Fixup::kindStoreARM64GOTLoadPage21:
+ printf(", then store as ARM64 21-bit pcrel ADRP of GOT");
+ break;
+ case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+ printf(", then store as ARM64 12-bit page offset of GOT");
+ break;
+ case ld::Fixup::kindStoreARM64GOTLeaPage21:
+ printf(", then store as ARM64 21-bit pcrel ADRP of GOT lea");
+ break;
+ case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+ printf(", then store as ARM64 12-bit page offset of GOT lea");
+ break;
+ case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+ printf(", then store as ARM64 21-bit pcrel ADRP of TLVP");
+ break;
+ case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+ printf(", then store as ARM64 12-bit page offset of TLVP");
+ break;
+ case ld::Fixup::kindStoreARM64PointerToGOT:
+ printf(", then store as 64-bit pointer to GOT entry");
+ break;
+ case ld::Fixup::kindStoreARM64PCRelToGOT:
+ printf(", then store as 32-bit delta to GOT entry");
+ break;
case ld::Fixup::kindDtraceExtra:
printf("dtrace static probe extra info");
break;
case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
printf("Thumb dtrace static is-enabled site");
break;
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ printf("ARM64 dtrace static probe site");
+ break;
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+ printf("ARM64 dtrace static is-enabled site");
+ break;
case ld::Fixup::kindLazyTarget:
printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
break;
case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
printf("tlv template offset of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ printf("ARM64 store 26-bit pcrel branch to %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ printf("ARM64 store 21-bit pcrel ADRP to %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+ printf("ARM64 store 12-bit page offset of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ printf("ARM64 store 21-bit pcrel ADRP to GOT for %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+ printf("ARM64 store 12-bit page offset of GOT of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ printf("ARM64 store 21-bit pcrel ADRP for lea of %s", referenceTargetAtomName(ref));
+ break;
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+ printf("ARM64 store 12-bit page offset of lea of %s", referenceTargetAtomName(ref));
+ break;
//default:
// printf("unknown fixup");
// break;
objOpts.architecture = sPreferredArch;
objOpts.objSubtypeMustMatch = false;
objOpts.logAllFiles = false;
- objOpts.convertUnwindInfo = true;
+ objOpts.warnUnwindConversionProblems = true;
+ objOpts.keepDwarfUnwind = false;
+ objOpts.forceDwarfConversion = false;
objOpts.subType = sPreferredSubArch;
#if 1
if ( ! foundFatSlice ) {
// success
return NULL;
}
+
+
+// <rdar://problem/12764051> Switch libprunetrie to use libc++ instead of libstdc++
+// The one undefined when building libprunetrie.a with libc++ is throw_length_error().
+// Adding this define here resolves that and means libprunetrie.a can be linked
+// by cctools with libc++ or libstdc++.
+extern "C" void foobar() __asm("__ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv");
+void foobar()
+{
+ throw "Size of vecor cannot be grown";
+}
+
+
}
#endif
+#if SUPPORT_ARCH_arm64
+template <>
+bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+#endif
+
template <typename A>
DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
: fHeader(NULL), fLength(fileLength),
uint64_t segOffset = 0;
uint32_t count;
uint32_t skip;
- int segIndex;
+ int segIndex = 0;
pint_t segStartAddr = 0;
const char* segName = "??";
const char* typeName = "??";
const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+ const bool abs = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
if ( reExport )
printf("[re-export] ");
else
printf("0x%08llX ", fBaseAddress+it->address);
printf("%s", it->name);
- if ( weakDef || threadLocal || resolver ) {
+ if ( weakDef || threadLocal || resolver || abs ) {
bool needComma = false;
printf(" [");
if ( weakDef ) {
printf("per-thread");
needComma = true;
}
+ if ( abs ) {
+ if ( needComma )
+ printf(", ");
+ printf("absolute");
+ needComma = true;
+ }
if ( resolver ) {
if ( needComma )
printf(", ");
printf("[addr=0x%06llX] ", address);
else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
+ else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE)
+ printf("[flags=ABSOLUTE addr=0x%06llX] ", address);
else
printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
}
kindStr = "64-bit pointer";
break;
case 3:
- kindStr = "ppc hi16";
+#if SUPPORT_ARCH_arm64
+ if ( fHeader->cputype() == CPU_TYPE_ARM64 )
+ kindStr = "arm64 ADRP";
+ else
+#endif
+ kindStr = "ppc hi16";
break;
case 4:
kindStr = "32-bit offset to IMPORT";
template <>
x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
{
- // check for split-seg
return fFirstWritableSegment->vmaddr();
}
}
#endif
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t DyldInfoPrinter<arm64>::relocBase()
+{
+ return fFirstWritableSegment->vmaddr();
+}
+#endif
template <>
const char* DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
}
#endif
+#if SUPPORT_ARCH_arm64
+template <>
+const char* DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == ARM64_RELOC_UNSIGNED )
+ return "pointer";
+ return "??";
+}
+#endif
+
template <typename A>
void DyldInfoPrinter<A>::printRelocRebaseInfo()
{
else
throw "in universal file, arm slice does not contain arm mach-o";
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( DyldInfoPrinter<arm64>::validFile(p + offset) )
+ DyldInfoPrinter<arm64>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, arm64 slice does not contain arm mach-o";
+ break;
#endif
default:
throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
else if ( DyldInfoPrinter<arm>::validFile(p) ) {
DyldInfoPrinter<arm>::make(p, length, path, false);
}
+#endif
+#if SUPPORT_ARCH_arm64
+ else if ( DyldInfoPrinter<arm64>::validFile(p) ) {
+ DyldInfoPrinter<arm64>::make(p, length, path, false);
+ }
#endif
else {
throw "not a known file type";
sPreferredArch = CPU_TYPE_I386;
else if ( strcmp(arch, "x86_64") == 0 )
sPreferredArch = CPU_TYPE_X86_64;
+#if SUPPORT_ARCH_arm64
+ else if ( strcmp(arch, "arm64") == 0 )
+ sPreferredArch = CPU_TYPE_ARM64;
+#endif
else {
if ( arch == NULL )
throw "-arch missing architecture name";
return false;
}
+#if SUPPORT_ARCH_arm64
+template <>
+bool MachOChecker<arm64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+#endif
+
template <> uint8_t MachOChecker<ppc>::loadCommandSizeMask() { return 0x03; }
template <> uint8_t MachOChecker<ppc64>::loadCommandSizeMask() { return 0x07; }
template <> uint8_t MachOChecker<x86>::loadCommandSizeMask() { return 0x03; }
template <> uint8_t MachOChecker<x86_64>::loadCommandSizeMask() { return 0x07; }
template <> uint8_t MachOChecker<arm>::loadCommandSizeMask() { return 0x03; }
+#if SUPPORT_ARCH_arm64
+template <> uint8_t MachOChecker<arm64>::loadCommandSizeMask() { return 0x07; }
+#endif
template <>
return threadInfo->thread_register(13);
}
-
-
-
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t MachOChecker<arm64>::getInitialStackPointer(const macho_thread_command<arm64::P>* threadInfo)
+{
+ throw "LC_UNIXTHREAD not supported for arm64";
+}
+#endif
template <>
ppc::P::uint_t MachOChecker<ppc>::getEntryPoint(const macho_thread_command<ppc::P>* threadInfo)
return threadInfo->thread_register(15);
}
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t MachOChecker<arm64>::getEntryPoint(const macho_thread_command<arm64::P>* threadInfo)
+{
+ throw "LC_UNIXTHREAD not supported for arm64";
+}
+#endif
template <typename A>
MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
fDyldInfo = (macho_dyld_info_command<P>*)cmd;
break;
case LC_ENCRYPTION_INFO:
+ case LC_ENCRYPTION_INFO_64:
encryption_info = (macho_encryption_info_command<P>*)cmd;
break;
case LC_SUB_UMBRELLA:
return fFirstSegment->vmaddr();
}
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t MachOChecker<arm64>::relocBase()
+{
+ return fFirstWritableSegment->vmaddr();
+}
+#endif
+
+
template <typename A>
bool MachOChecker<A>::addressInWritableSegment(pint_t address)
}
#endif
+#if SUPPORT_ARCH_arm64
+template <>
+void MachOChecker<arm64>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+ throw "external relocations not used for arm64";
+}
+#endif
+
template <>
void MachOChecker<ppc>::checkLocalReloation(const macho_relocation_info<P>* reloc)
}
#endif
+#if SUPPORT_ARCH_arm64
+template <>
+void MachOChecker<arm64>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+ throw "local relocations not used for arm64";
+}
+#endif
+
+
template <typename A>
void MachOChecker<A>::checkRelocations()
{
else if ( MachOChecker<arm>::validFile(p) ) {
MachOChecker<arm>::make(p, length, path);
}
+#endif
+#if SUPPORT_ARCH_arm64
+ else if ( MachOChecker<arm64>::validFile(p) ) {
+ MachOChecker<arm64>::make(p, length, path);
+ }
#endif
else {
throw "not a known file type";
#include <set>
#include <unordered_set>
-
+#include "configure.h"
#include "MachOFileAbstraction.hpp"
#include "Architectures.hpp"
template <> const char* UnwindPrinter<x86>::archName() { return "i386"; }
template <> const char* UnwindPrinter<x86_64>::archName() { return "x86_64"; }
template <> const char* UnwindPrinter<arm>::archName() { return "arm"; }
-
+#if SUPPORT_ARCH_arm64
+template <> const char* UnwindPrinter<arm64>::archName() { return "arm64"; }
+#endif
template <>
bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
}
+#if SUPPORT_ARCH_arm64
+template <>
+bool UnwindPrinter<arm64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ case MH_OBJECT:
+ return true;
+ }
+ return false;
+}
+#endif
+
template <typename A>
UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
: fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
}
-
+#if SUPPORT_ARCH_arm64
+template <>
+void UnwindPrinter<arm64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ uint32_t stackSize;
+ switch ( encoding & UNWIND_ARM64_MODE_MASK ) {
+ case UNWIND_ARM64_MODE_FRAMELESS:
+ stackSize = EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+ if ( stackSize == 0 )
+ strcpy(str, "no frame, no saved registers ");
+ else
+ sprintf(str, "stack size=%d: ", 16 * stackSize);
+ if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+ strcat(str, "x19/20 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+ strcat(str, "x21/22 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+ strcat(str, "x23/24 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+ strcat(str, "x25/26 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+ strcat(str, "x27/28 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+ strcat(str, "d8/9 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+ strcat(str, "d10/11 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+ strcat(str, "d12/13 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+ strcat(str, "d14/15 ");
+ break;
+ break;
+ case UNWIND_ARM64_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ break;
+ case UNWIND_ARM64_MODE_FRAME:
+ strcpy(str, "std frame: ");
+ if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+ strcat(str, "x19/20 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+ strcat(str, "x21/22 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+ strcat(str, "x23/24 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+ strcat(str, "x25/26 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+ strcat(str, "x27/28 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+ strcat(str, "d8/9 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+ strcat(str, "d10/11 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+ strcat(str, "d12/13 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+ strcat(str, "d14/15 ");
+ break;
+ case UNWIND_ARM64_MODE_FRAME_OLD:
+ strcpy(str, "old frame: ");
+ if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD )
+ strcat(str, "x21/22 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD )
+ strcat(str, "x23/24 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD )
+ strcat(str, "x25/26 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD )
+ strcat(str, "x27/28 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD )
+ strcat(str, "d8/9 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD )
+ strcat(str, "d10/11 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD )
+ strcat(str, "d12/13 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD )
+ strcat(str, "d14/15 ");
+ break;
+ }
+}
+#endif
template <>
const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
return &fStrings[sym.n_strx()];
}
+#if SUPPORT_ARCH_arm64
+template <>
+const char* UnwindPrinter<arm64>::personalityName(const macho_relocation_info<arm64::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+#endif
+
template <typename A>
bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
{
printf(" lsda: 0x%08llX %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
}
}
-
}
char encodingString[100];
decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
- printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n",
+ printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-56s) %s\n",
j, funcOffset, entry[j].encoding(), encodingString, name);
}
}
fprintf(stderr, "MISSING LSDA entry for %s\n", name);
}
}
- printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n",
+ printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-56s) %s\n",
j, funcOff, encodingIndex, encoding, encodingString, name);
}
}
else
throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
break;
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( UnwindPrinter<arm64>::validFile(p + offset) )
+ UnwindPrinter<arm64>::make(p + offset, size, path, showFunctionNames);
+ else
+ throw "in universal file, arm64 slice does not contain arm mach-o";
+ break;
+#endif
default:
throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
}
else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
}
+#if SUPPORT_ARCH_arm64
+ else if ( UnwindPrinter<arm64>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM64) ) {
+ UnwindPrinter<arm64>::make(p, length, path, showFunctionNames);
+ }
+#endif
else {
throw "not a known file type";
}
onlyArchs.insert(CPU_TYPE_I386);
else if ( strcmp(arch, "x86_64") == 0 )
onlyArchs.insert(CPU_TYPE_X86_64);
+#if SUPPORT_ARCH_arm64
+ else if ( strcmp(arch, "arm64") == 0 )
+ onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
else
throwf("unknown architecture %s", arch);
}
if ( onlyArchs.size() == 0 ) {
onlyArchs.insert(CPU_TYPE_I386);
onlyArchs.insert(CPU_TYPE_X86_64);
+#if SUPPORT_ARCH_arm64
+ onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
}
// process each file
FILEARCH = $(ARCH)
endif
+ifeq ($(ARCH),arm64)
+ LDFLAGS := -syslibroot $(IOS_SDK)
+ CC = $(shell xcrun --sdk iphoneos.internal -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+ CXX = $(shell xcrun --sdk iphoneos.internal -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+ VERSION_NEW_LINKEDIT = -miphoneos-version-min=7.0
+ VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+ LD_SYSROOT = -syslibroot $(IOS_SDK)
+ LD_NEW_LINKEDIT = -ios_version_min 7.0
+else
+ FILEARCH = $(ARCH)
+endif
RM = rm
RMFLAGS = -rf
--- /dev/null
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test -force_symbols_coalesce_list
+#
+
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${DYLDINFO} -weak_bind libfoo.dylib | grep _foo1 | ${FAIL_IF_STDIN}
+ ${DYLDINFO} -weak_bind libfoo.dylib | grep _wildcheck | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib -Wl,-force_symbols_coalesce_list,foo.exp
+ ${DYLDINFO} -weak_bind libfoo2.dylib | grep _foo1 | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -weak_bind libfoo2.dylib | grep _wildcheck | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+
+
+
+clean:
+ rm -rf libfoo.dylib libfoo2.dylib
--- /dev/null
+
+
+void foo1() {}
+void foo3() {}
+
+
+__attribute__((weak)) void foo2() {}
+__attribute__((weak)) void foo4() {}
+
+
+void wildcheck() {}
+void willnot() {}
+
+
+
+__attribute__((weak)) void patterncheck() {}
+__attribute__((weak)) void patnot() {}
+
+
+void* pointers[] = { &foo1, &foo2, &foo3, &foo4, &wildcheck, &willnot, &patterncheck, &patnot };
+
--- /dev/null
+_foo1
+_wild*
all:
${CC} ${CCFLAGS} -c test.s -o test.o
+ ${CC} ${CCFLAGS} test.o -dynamiclib -o libtest.dylib
+ dyldinfo -arch ${ARCH} -data_in_code libtest.dylib| ${FAIL_IF_EMPTY}
${LD} -r -arch ${ARCH} test.o -o test2.o
- #nm main | grep _dtrace_probe | ${FAIL_IF_EMPTY}
- #${PASS_IFF_GOOD_MACHO} main
+ ${CC} ${CCFLAGS} test2.o -dynamiclib -o libtest2.dylib
+ dyldinfo -arch ${ARCH} -data_in_code libtest2.dylib| ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} libtest.dylib
clean:
- rm -rf test.o test2.o
+ rm -rf test.o test2.o libtest.dylib libtest2.dylib
+++ /dev/null
-
-#include <stdio.h>
-
-#define DTRACE_STRINGIFY(s) #s
-#define DTRACE_TOSTRING(s) DTRACE_STRINGIFY(s)
-
-#define DTRACE_NOPS \
- "nop" "\n\t" \
- "nop" "\n\t" \
- "nop" "\n\t"
-
-
-#define DTRACE_LAB(p, n) \
- "__dtrace_probe$" DTRACE_TOSTRING(%=__LINE__) DTRACE_STRINGIFY(_##p##___##n)
-
-#define DTRACE_LABEL(p, n) \
- ".section __DATA, __data\n\t" \
- ".globl " DTRACE_LAB(p, n) "\n\t" \
- DTRACE_LAB(p, n) ":\n\t" ".long 1f""\n\t" \
- ".text" "\n\t" \
- "1:"
-
-#define DTRACE_CALL(p,n) \
- DTRACE_LABEL(p,n) \
- DTRACE_NOPS
-
-#define DTRACE_CALL0ARGS(provider, name) \
- __asm volatile ( \
- DTRACE_CALL(provider, name) \
- : \
- : \
- );
-
-int deadwood()
-{
- DTRACE_CALL0ARGS(__foo__, test2)
- return 0;
-}
-
-
-int main() {
- int a = 1;
-
- while(a) {
- DTRACE_CALL0ARGS(__foo__, test1)
- }
-
- return 0;
-}
_foo:
nop
nop
-l$start$data$1:
+ .data_region
nop
nop
nop
-l$start$jt8$2:
+ .data_region jt8
nop
nop
-l$start$jt16$3:
+.data_region jt16
nop
nop
-l$start$code$n4:
+.data_region jt32
nop
nop
-
-
+.end_data_region
+ nop
+ nop
+
.subsections_via_symbols
--- /dev/null
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check linker options work for -framework
+#
+
+run: all
+
+all:
+ mkdir -p Foo.framework
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o Foo.framework/Foo
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${LD} -r main.o -add_linker_option '-framework Foo' -o main2.o
+ ${CC} ${CCFLAGS} main2.o -o main -F.
+ ${DYLDINFO} -lazy_bind main | grep _foo | grep Foo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -rf main libfoo.dylib main.o main2.o Foo.framework
+
--- /dev/null
+
+
+void foo() { }
--- /dev/null
+
+extern void foo();
+
+int main()
+{
+ foo();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check linker options work for -l
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} bar.c -c -o bar.o
+ libtool -static bar.o -o libbar.a
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${LD} -r main.o -add_linker_option -lfoo -add_linker_option -lbar -o main2.o
+ ${CC} ${CCFLAGS} main2.o -o main -L.
+ ${DYLDINFO} -lazy_bind main | grep _foo | grep libfoo | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+ rm -f main libfoo.dylib main.o main2.o bar.o libbar.a
+
--- /dev/null
+void bar() { }
--- /dev/null
+
+
+void foo() { }
--- /dev/null
+
+extern void foo();
+extern void bar();
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify -preload -pie produces relocations
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o -o main
+ nm -g main | grep _bar | ${FAIL_IF_STDIN}
+ ${CC} ${CCFLAGS} main.o -o main-de -Wl,-export_dynamic
+ nm -g main-de | grep _bar | ${FAIL_IF_EMPTY}
+ ${PASS_IFF_GOOD_MACHO} main-de
+
+
+clean:
+ rm main.o main main-de
--- /dev/null
+
+__attribute__((visibility("hidden")))
+void foo() { }
+
+void bar() { }
+
+
+int main()
+{
+ foo();
+ bar();
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify order files can pick file in archives
+#
+
+run: all
+
+all:
+ ${CC} ${CCFLAGS} foo.c -c -o foo.o
+ libtool -static foo.o -o libfoo.a
+ ${CC} ${CCFLAGS} main.c -c -o main.o
+ ${CC} ${CCFLAGS} main.o libfoo.a -Wl,-order_file,main.order -o main
+ ${FAIL_IF_BAD_MACHO} main
+ nm -n -j main | egrep "_main|_foo" > main.actual
+ ${PASS_IFF} diff main.actual main.expected
+
+
+clean:
+ rm -rf *.o libfoo.a main main.actual
--- /dev/null
+void foo1() { }
+void foo2() {}
+void foo3() {}
+
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern void foo1();
+
+int main()
+{
+ foo1();
+ return 0;
+}
--- /dev/null
+_foo2
+_main
+_foo3
+_foo1
--- /dev/null
+_foo2
+_main
+libfoo.a(foo.o):_foo3
+_foo1
+
${DYLDINFO} -bind -lazy_bind main1 | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
${DYLDINFO} -bind -lazy_bind main1 | grep _bar_weak | grep libfoo | ${FAIL_IF_EMPTY}
- # build library the re-exports _bar from base library as _mybar
- ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp
+ # build library that re-exports _bar from base library as _mybar
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp -DUSE_MY
${FAIL_IF_BAD_MACHO} libfoo2.dylib
${DYLDINFO} -export libfoo2.dylib | grep _mybar | grep 're-export' | grep _bar | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -lazy_bind libfoo2.dylib | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
+ ${DYLDINFO} -bind libfoo2.dylib | grep _bar | grep libbar | ${FAIL_IF_EMPTY}
# link against dylib and verify _mybar is marked as coming from libfoo
${CC} ${CCFLAGS} main2.c libfoo2.dylib -o main2
${DYLDINFO} -bind -lazy_bind main2 | grep _mybar | grep libfoo2 | ${FAIL_IF_EMPTY}
+
+#if USE_MY
+ extern int mybar();
+#else
+ extern int bar();
+#endif
+
int foo(void)
{
- return 1;
+#if USE_MY
+ return mybar() + 1;
+#else
+ return bar() + 1;
+#endif
}
+
+#if USE_MY
+ void* p = &mybar;
+#else
+ void* p = &bar;
+#endif