[mach-o] add support for arm64 compact unwind info

Tim previously added generic compact unwind processing and x86_64 support.
This patch adds arm64 support.

llvm-svn: 223103
This commit is contained in:
Nick Kledzik 2014-12-02 01:50:38 +00:00
parent bdf7e1dd4b
commit a441b7b050
2 changed files with 348 additions and 11 deletions

View File

@ -51,6 +51,9 @@ public:
case gotOffset12: case gotOffset12:
canBypassGOT = true; canBypassGOT = true;
return true; return true;
case imageOffsetGot:
canBypassGOT = false;
return true;
default: default:
return false; return false;
} }
@ -72,6 +75,9 @@ public:
const_cast<Reference *>(ref)->setKindValue(targetNowGOT ? const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
offset12scale8 : addOffset12); offset12scale8 : addOffset12);
break; break;
case imageOffsetGot:
const_cast<Reference *>(ref)->setKindValue(imageOffset);
break;
default: default:
llvm_unreachable("Not a GOT reference"); llvm_unreachable("Not a GOT reference");
} }
@ -88,30 +94,29 @@ public:
bool isPairedReloc(const normalized::Relocation &) override; bool isPairedReloc(const normalized::Relocation &) override;
bool needsCompactUnwind() override { bool needsCompactUnwind() override {
return false; return true;
} }
Reference::KindValue imageOffsetKind() override { Reference::KindValue imageOffsetKind() override {
return invalid; return imageOffset;
} }
Reference::KindValue imageOffsetKindIndirect() override { Reference::KindValue imageOffsetKindIndirect() override {
return invalid; return imageOffsetGot;
} }
Reference::KindValue unwindRefToCIEKind() override { Reference::KindValue unwindRefToCIEKind() override {
return invalid; return negDelta32;
} }
Reference::KindValue unwindRefToFunctionKind() override { Reference::KindValue unwindRefToFunctionKind() override {
return invalid; return unwindFDEToFunction;
} }
Reference::KindValue unwindRefToEhFrameKind() override { Reference::KindValue unwindRefToEhFrameKind() override {
return invalid; return unwindInfoToEhFrame;
} }
uint32_t dwarfCompactUnwindType() override { uint32_t dwarfCompactUnwindType() override {
// FIXME return 0x03000000;
return -1;
} }
std::error_code getReferenceInfo(const normalized::Relocation &reloc, std::error_code getReferenceInfo(const normalized::Relocation &reloc,
@ -176,6 +181,7 @@ private:
pointer64, /// ex: .quad _foo pointer64, /// ex: .quad _foo
delta64, /// ex: .quad _foo - . delta64, /// ex: .quad _foo - .
delta32, /// ex: .long _foo - . delta32, /// ex: .long _foo - .
negDelta32, /// ex: .long . - _foo
pointer64ToGOT, /// ex: .quad _foo@GOT pointer64ToGOT, /// ex: .quad _foo@GOT
delta32ToGOT, /// ex: .long _foo@GOT - . delta32ToGOT, /// ex: .long _foo@GOT - .
@ -183,11 +189,19 @@ private:
addOffset12, /// Location contains LDR to change into ADD. addOffset12, /// Location contains LDR to change into ADD.
lazyPointer, /// Location contains a lazy pointer. lazyPointer, /// Location contains a lazy pointer.
lazyImmediateLocation, /// Location contains immediate value used in stub. lazyImmediateLocation, /// Location contains immediate value used in stub.
imageOffset, /// Location contains offset of atom in final image
imageOffsetGot, /// Location contains offset of GOT entry for atom in
/// final image (typically personality function).
unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in
/// relocatable object (yay for implicit contracts!).
unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
/// refer to __eh_frame entry.
}; };
void applyFixupFinal(const Reference &ref, uint8_t *location, void applyFixupFinal(const Reference &ref, uint8_t *location,
uint64_t fixupAddress, uint64_t targetAddress, uint64_t fixupAddress, uint64_t targetAddress,
uint64_t inAtomAddress); uint64_t inAtomAddress, uint64_t imageBaseAddress,
FindAddressForAtom findSectionAddress);
void applyFixupRelocatable(const Reference &ref, uint8_t *location, void applyFixupRelocatable(const Reference &ref, uint8_t *location,
uint64_t fixupAddress, uint64_t targetAddress, uint64_t fixupAddress, uint64_t targetAddress,
@ -220,12 +234,17 @@ const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64),
LLD_KIND_STRING_ENTRY(delta64), LLD_KIND_STRING_ENTRY(delta64),
LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta32),
LLD_KIND_STRING_ENTRY(negDelta32),
LLD_KIND_STRING_ENTRY(pointer64ToGOT), LLD_KIND_STRING_ENTRY(pointer64ToGOT),
LLD_KIND_STRING_ENTRY(delta32ToGOT), LLD_KIND_STRING_ENTRY(delta32ToGOT),
LLD_KIND_STRING_ENTRY(addOffset12), LLD_KIND_STRING_ENTRY(addOffset12),
LLD_KIND_STRING_ENTRY(lazyPointer), LLD_KIND_STRING_ENTRY(lazyPointer),
LLD_KIND_STRING_ENTRY(lazyImmediateLocation), LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_ENTRY(imageOffset),
LLD_KIND_STRING_ENTRY(imageOffsetGot),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
LLD_KIND_STRING_END LLD_KIND_STRING_END
}; };
@ -498,7 +517,8 @@ void ArchHandler_arm64::generateAtomContent(
targetAddress, atomAddress, targetUnnamed); targetAddress, atomAddress, targetUnnamed);
} else { } else {
applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress, applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
targetAddress, atomAddress); targetAddress, atomAddress, imageBaseAddress,
findSectionAddress);
} }
} }
} }
@ -506,7 +526,9 @@ void ArchHandler_arm64::generateAtomContent(
void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc, void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
uint64_t fixupAddress, uint64_t fixupAddress,
uint64_t targetAddress, uint64_t targetAddress,
uint64_t inAtomAddress) { uint64_t inAtomAddress,
uint64_t imageBaseAddress,
FindAddressForAtom findSectionAddress) {
if (ref.kindNamespace() != Reference::KindNamespace::mach_o) if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return; return;
assert(ref.kindArch() == Reference::KindArch::AArch64); assert(ref.kindArch() == Reference::KindArch::AArch64);
@ -515,6 +537,7 @@ void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
int32_t displacement; int32_t displacement;
uint32_t instruction; uint32_t instruction;
uint32_t value32; uint32_t value32;
uint32_t value64;
switch (static_cast<Arm64_Kinds>(ref.kindValue())) { switch (static_cast<Arm64_Kinds>(ref.kindValue())) {
case branch26: case branch26:
displacement = (targetAddress - fixupAddress) + ref.addend(); displacement = (targetAddress - fixupAddress) + ref.addend();
@ -571,18 +594,33 @@ void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
*loc64 = targetAddress + ref.addend(); *loc64 = targetAddress + ref.addend();
return; return;
case delta64: case delta64:
case unwindFDEToFunction:
*loc64 = (targetAddress - fixupAddress) + ref.addend(); *loc64 = (targetAddress - fixupAddress) + ref.addend();
return; return;
case delta32: case delta32:
case delta32ToGOT: case delta32ToGOT:
*loc32 = (targetAddress - fixupAddress) + ref.addend(); *loc32 = (targetAddress - fixupAddress) + ref.addend();
return; return;
case negDelta32:
*loc32 = fixupAddress - targetAddress + ref.addend();
return;
case lazyPointer: case lazyPointer:
// Do nothing // Do nothing
return; return;
case lazyImmediateLocation: case lazyImmediateLocation:
*loc32 = ref.addend(); *loc32 = ref.addend();
return; return;
case imageOffset:
*loc32 = (targetAddress - imageBaseAddress) + ref.addend();
return;
case imageOffsetGot:
llvm_unreachable("imageOffsetGot should have been changed to imageOffset");
break;
case unwindInfoToEhFrame:
value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
assert(value64 < 0xffffffU && "offset in __eh_frame too large");
*loc32 = (*loc32 & 0xff000000U) | value64;
return;
case invalid: case invalid:
// Fall into llvm_unreachable(). // Fall into llvm_unreachable().
break; break;
@ -631,6 +669,9 @@ void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
case delta32: case delta32:
*loc32 = ref.addend() + inAtomAddress - fixupAddress; *loc32 = ref.addend() + inAtomAddress - fixupAddress;
return; return;
case negDelta32:
*loc32 = fixupAddress - inAtomAddress + ref.addend();
return;
case pointer64ToGOT: case pointer64ToGOT:
*loc64 = 0; *loc64 = 0;
return; return;
@ -642,6 +683,14 @@ void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
case lazyPointer: case lazyPointer:
case lazyImmediateLocation: case lazyImmediateLocation:
llvm_unreachable("lazy reference kind implies Stubs pass was run"); llvm_unreachable("lazy reference kind implies Stubs pass was run");
case imageOffset:
case imageOffsetGot:
case unwindInfoToEhFrame:
llvm_unreachable("fixup implies __unwind_info");
return;
case unwindFDEToFunction:
// Do nothing for now
return;
case invalid: case invalid:
// Fall into llvm_unreachable(). // Fall into llvm_unreachable().
break; break;
@ -751,6 +800,14 @@ void ArchHandler_arm64::appendSectionRelocations(
case lazyPointer: case lazyPointer:
case lazyImmediateLocation: case lazyImmediateLocation:
llvm_unreachable("lazy reference kind implies Stubs pass was run"); llvm_unreachable("lazy reference kind implies Stubs pass was run");
case imageOffset:
case imageOffsetGot:
llvm_unreachable("deltas from mach_header can only be in final images");
case unwindFDEToFunction:
case unwindInfoToEhFrame:
case negDelta32:
// Do nothing.
return;
case invalid: case invalid:
// Fall into llvm_unreachable(). // Fall into llvm_unreachable().
break; break;

View File

@ -0,0 +1,280 @@
# RUN: lld -flavor darwin -arch arm64 %s -o %t -e _main %p/Inputs/libSystem.yaml
# RUN: llvm-objdump -unwind-info %t | FileCheck %s
--- !mach-o
arch: arm64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
alignment: 2
address: 0x0000000000000000
content: [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
0x3F, 0x04, 0x00, 0x71, 0x81, 0x00, 0x00, 0x54,
0x00, 0x00, 0x00, 0x94, 0xFD, 0x7B, 0xC1, 0xA8,
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x94,
0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
0x00, 0x00, 0x00, 0x94 ]
relocations:
- offset: 0x00000070
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 5
- offset: 0x00000064
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 7
- offset: 0x00000060
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 12
- offset: 0x00000058
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 11
- offset: 0x0000004C
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 13
- offset: 0x00000048
type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
length: 2
pc-rel: false
extern: true
symbol: 8
- offset: 0x00000044
type: ARM64_RELOC_GOT_LOAD_PAGE21
length: 2
pc-rel: true
extern: true
symbol: 8
- offset: 0x00000034
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 10
- offset: 0x00000024
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 13
- offset: 0x00000020
type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
length: 2
pc-rel: false
extern: true
symbol: 8
- offset: 0x0000001C
type: ARM64_RELOC_GOT_LOAD_PAGE21
length: 2
pc-rel: true
extern: true
symbol: 8
- offset: 0x0000000C
type: ARM64_RELOC_BRANCH26
length: 2
pc-rel: true
extern: true
symbol: 10
- segment: __TEXT
section: __gcc_except_tab
type: S_REGULAR
attributes: [ ]
alignment: 2
address: 0x0000000000000074
content: [ 0xFF, 0x9B, 0xAF, 0x80, 0x00, 0x03, 0x27, 0x00,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x01, 0x28, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0xD0, 0xFF, 0xFF, 0xFF ]
relocations:
- offset: 0x00000030
type: ARM64_RELOC_POINTER_TO_GOT
length: 2
pc-rel: true
extern: true
symbol: 9
- segment: __LD
section: __compact_unwind
type: S_REGULAR
attributes: [ ]
alignment: 3
address: 0x00000000000000A8
content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
relocations:
- offset: 0x00000040
type: ARM64_RELOC_UNSIGNED
length: 3
pc-rel: false
extern: false
symbol: 1
- offset: 0x00000038
type: ARM64_RELOC_UNSIGNED
length: 3
pc-rel: false
extern: false
symbol: 2
- offset: 0x00000030
type: ARM64_RELOC_UNSIGNED
length: 3
pc-rel: false
extern: true
symbol: 14
- offset: 0x00000020
type: ARM64_RELOC_UNSIGNED
length: 3
pc-rel: false
extern: false
symbol: 1
- offset: 0x00000000
type: ARM64_RELOC_UNSIGNED
length: 3
pc-rel: false
extern: false
symbol: 1
local-symbols:
- name: ltmp0
type: N_SECT
sect: 1
value: 0x0000000000000000
- name: ltmp14
type: N_SECT
sect: 2
value: 0x0000000000000074
- name: GCC_except_table1
type: N_SECT
sect: 2
value: 0x0000000000000074
- name: ltmp21
type: N_SECT
sect: 3
value: 0x00000000000000A8
global-symbols:
- name: __Z3barv
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000028
- name: __Z3foov
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
- name: _main
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000068
undefined-symbols:
- name: __Unwind_Resume
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: __ZTIi
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: __ZTIl
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: ___cxa_allocate_exception
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: ___cxa_begin_catch
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: ___cxa_end_catch
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: ___cxa_throw
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
- name: ___gxx_personality_v0
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
--- !mach-o
arch: arm64
file-type: MH_DYLIB
install-name: /usr/lib/libc++.dylib
exports:
- name: __Unwind_Resume
- name: __ZTIl
- name: __ZTIi
- name: ___cxa_end_catch
- name: ___cxa_begin_catch
- name: ___cxa_allocate_exception
- name: ___cxa_throw
- name: ___gxx_personality_v0
...
# CHECK: Contents of __unwind_info section:
# CHECK: Version: 0x1
# CHECK: Common encodings array section offset: 0x1c
# CHECK: Number of common encodings in array: 0x0
# CHECK: Personality function array section offset: 0x1c
# CHECK: Number of personality functions in array: 0x1
# CHECK: Index array section offset: 0x20
# CHECK: Number of indices in array: 0x2
# CHECK: Common encodings: (count = 0)
# CHECK: Personality functions: (count = 1)
# CHECK: personality[1]: 0x00004018
# CHECK: Top level indices: (count = 2)
# CHECK: [0]: function offset=0x00003e68, 2nd level page offset=0x00000040, LSDA offset=0x00000038
# CHECK: [1]: function offset=0x00003edc, 2nd level page offset=0x00000000, LSDA offset=0x00000040
# CHECK: LSDA descriptors:
# CHECK: [0]: function offset=0x00003e90, LSDA offset=0x00003f6c
# CHECK: Second level indices:
# CHECK: Second level index[0]: offset in section=0x00000040, base function offset=0x00003e68
# CHECK: [0]: function offset=0x00003e68, encoding=0x04000000
# CHECK: [1]: function offset=0x00003e90, encoding=0x54000000
# CHECK: [2]: function offset=0x00003ed0, encoding=0x04000000
# CHECK-NOT: Contents of __compact_unwind section