]> git.saurik.com Git - apple/ld64.git/blame - src/ld/passes/compact_unwind.cpp
ld64-253.6.tar.gz
[apple/ld64.git] / src / ld / passes / compact_unwind.cpp
CommitLineData
a645023d
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26#include <stdint.h>
27#include <math.h>
28#include <unistd.h>
29#include <dlfcn.h>
30#include <mach/machine.h>
31#include <mach-o/compact_unwind_encoding.h>
32
33#include <vector>
34#include <map>
35
36#include "ld.hpp"
37#include "compact_unwind.h"
38#include "Architectures.hpp"
39#include "MachOFileAbstraction.hpp"
40
41
42namespace ld {
43namespace passes {
44namespace compact_unwind {
45
46
47struct UnwindEntry {
48 UnwindEntry(const ld::Atom* f, uint64_t a, uint32_t o, const ld::Atom* d,
49 const ld::Atom* l, const ld::Atom* p, uint32_t en)
50 : func(f), fde(d), lsda(l), personalityPointer(p), funcTentAddress(a),
51 functionOffset(o), encoding(en) { }
52 const ld::Atom* func;
53 const ld::Atom* fde;
54 const ld::Atom* lsda;
55 const ld::Atom* personalityPointer;
56 uint64_t funcTentAddress;
57 uint32_t functionOffset;
58 compact_unwind_encoding_t encoding;
59};
60
61struct LSDAEntry {
62 const ld::Atom* func;
63 const ld::Atom* lsda;
64};
65
66
67template <typename A>
68class UnwindInfoAtom : public ld::Atom {
69public:
70 UnwindInfoAtom(const std::vector<UnwindEntry>& entries,uint64_t ehFrameSize);
71 ~UnwindInfoAtom();
72
73 virtual const ld::File* file() const { return NULL; }
a645023d
A
74 virtual const char* name() const { return "compact unwind info"; }
75 virtual uint64_t size() const { return _headerSize+_pagesSize; }
76 virtual uint64_t objectAddress() const { return 0; }
77 virtual void copyRawContent(uint8_t buffer[]) const;
78 virtual void setScope(Scope) { }
79 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
80 virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
81
82private:
83 typedef typename A::P P;
84 typedef typename A::P::E E;
85 typedef typename A::P::uint_t pint_t;
86
87 typedef macho_unwind_info_compressed_second_level_page_header<P> CSLP;
88
89 bool encodingMeansUseDwarf(compact_unwind_encoding_t enc);
90 void compressDuplicates(const std::vector<UnwindEntry>& entries,
91 std::vector<UnwindEntry>& uniqueEntries);
92 void makePersonalityIndexes(std::vector<UnwindEntry>& entries,
93 std::map<const ld::Atom*, uint32_t>& personalityIndexMap);
94 void findCommonEncoding(const std::vector<UnwindEntry>& entries,
95 std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings);
96 void makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex,
97 std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap);
98 unsigned int makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
99 const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
100 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
101 unsigned int makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
102 unsigned int endIndex, uint8_t*& pageEnd);
103 void addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc);
104 void addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde);
105 void addRegularAddressFixup(uint32_t offset, const ld::Atom* func);
106 void addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde);
107 void addImageOffsetFixup(uint32_t offset, const ld::Atom* targ);
108 void addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend);
109
110 uint8_t* _pagesForDelete;
599556ff 111 uint8_t* _pageAlignedPages;
a645023d
A
112 uint8_t* _pages;
113 uint64_t _pagesSize;
114 uint8_t* _header;
115 uint64_t _headerSize;
116 std::vector<ld::Fixup> _fixups;
117
118 static bool _s_log;
119 static ld::Section _s_section;
120};
121
122template <typename A>
123bool UnwindInfoAtom<A>::_s_log = false;
124
125template <typename A>
126ld::Section UnwindInfoAtom<A>::_s_section("__TEXT", "__unwind_info", ld::Section::typeUnwindInfo);
127
128
129template <typename A>
130UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint64_t ehFrameSize)
131 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
132 ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
599556ff
A
133 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
134 _pagesForDelete(NULL), _pageAlignedPages(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
a645023d
A
135{
136 // build new compressed list by removing entries where next function has same encoding
137 std::vector<UnwindEntry> uniqueEntries;
138 compressDuplicates(entries, uniqueEntries);
139
140 // reserve room so _fixups vector is not reallocated a bunch of times
141 _fixups.reserve(uniqueEntries.size()*3);
142
143 // build personality index, update encodings with personality index
144 std::map<const ld::Atom*, uint32_t> personalityIndexMap;
145 makePersonalityIndexes(uniqueEntries, personalityIndexMap);
146 if ( personalityIndexMap.size() > 3 ) {
e667b16e 147 throw "too many personality routines for compact unwind to encode";
a645023d
A
148 }
149
150 // put the most common encodings into the common table, but at most 127 of them
151 std::map<compact_unwind_encoding_t, unsigned int> commonEncodings;
152 findCommonEncoding(uniqueEntries, commonEncodings);
153
154 // build lsda index
155 std::map<const ld::Atom*, uint32_t> lsdaIndexOffsetMap;
156 std::vector<LSDAEntry> lsdaIndex;
157 makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
158
a645023d
A
159 // calculate worst case size for all unwind info pages when allocating buffer
160 const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
161 assert(uniqueEntries.size() > 0);
9543cb2f 162 const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 2;
599556ff 163 _pagesForDelete = (uint8_t*)calloc(pageCount+1,4096);
a645023d
A
164 if ( _pagesForDelete == NULL ) {
165 warning("could not allocate space for compact unwind info");
166 return;
167 }
599556ff 168 _pageAlignedPages = (uint8_t*)((((uintptr_t)_pagesForDelete) + 4095) & -4096);
a645023d
A
169
170 // make last second level page smaller so that all other second level pages can be page aligned
171 uint32_t maxLastPageSize = 4096 - (ehFrameSize % 4096);
172 uint32_t tailPad = 0;
173 if ( maxLastPageSize < 128 ) {
174 tailPad = maxLastPageSize;
175 maxLastPageSize = 4096;
176 }
177
178 // fill in pages in reverse order
179 const ld::Atom* secondLevelFirstFuncs[pageCount*3];
180 uint8_t* secondLevelPagesStarts[pageCount*3];
181 unsigned int endIndex = uniqueEntries.size();
182 unsigned int secondLevelPageCount = 0;
599556ff 183 uint8_t* pageEnd = &_pageAlignedPages[pageCount*4096];
a645023d
A
184 uint32_t pageSize = maxLastPageSize;
185 while ( endIndex > 0 ) {
186 endIndex = makeCompressedSecondLevelPage(uniqueEntries, commonEncodings, pageSize, endIndex, pageEnd);
187 secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
188 secondLevelFirstFuncs[secondLevelPageCount] = uniqueEntries[endIndex].func;
189 ++secondLevelPageCount;
9543cb2f
A
190 // if this requires more than one page, align so that next starts on page boundary
191 if ( (pageSize != 4096) && (endIndex > 0) ) {
192 pageEnd = (uint8_t*)((uintptr_t)(pageEnd) & -4096);
193 pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
194 }
a645023d
A
195 }
196 _pages = pageEnd;
599556ff
A
197 _pagesSize = &_pageAlignedPages[pageCount*4096] - pageEnd;
198
a645023d
A
199 // calculate section layout
200 const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
201 const uint32_t commonEncodingsArrayCount = commonEncodings.size();
202 const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
203 const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
204 const uint32_t personalityArrayCount = personalityIndexMap.size();
205 const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
206 const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
207 const uint32_t indexCount = secondLevelPageCount+1;
208 const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
209 const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
210 const uint32_t lsdaIndexArrayCount = lsdaIndex.size();
211 const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
212 const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
213
214 // now that we know the size of the header, slide all existing fixups on the pages
599556ff 215 const int32_t fixupSlide = headerEndSectionOffset + (_pageAlignedPages - _pages);
a645023d
A
216 for(std::vector<ld::Fixup>::iterator it = _fixups.begin(); it != _fixups.end(); ++it) {
217 it->offsetInAtom += fixupSlide;
218 }
219
220 // allocate and fill in section header
221 _headerSize = headerEndSectionOffset;
222 _header = new uint8_t[_headerSize];
223 bzero(_header, _headerSize);
224 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)_header;
225 sectionHeader->set_version(UNWIND_SECTION_VERSION);
226 sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
227 sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
228 sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
229 sectionHeader->set_personalityArrayCount(personalityArrayCount);
230 sectionHeader->set_indexSectionOffset(indexSectionOffset);
231 sectionHeader->set_indexCount(indexCount);
232
233 // copy common encodings
234 uint32_t* commonEncodingsTable = (uint32_t*)&_header[commonEncodingsArraySectionOffset];
235 for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
236 E::set32(commonEncodingsTable[it->second], it->first);
237
238 // make references for personality entries
239 uint32_t* personalityArray = (uint32_t*)&_header[sectionHeader->personalityArraySectionOffset()];
240 for (std::map<const ld::Atom*, unsigned int>::iterator it=personalityIndexMap.begin(); it != personalityIndexMap.end(); ++it) {
241 uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - _header;
242 this->addImageOffsetFixup(offset, it->first);
243 }
244
245 // build first level index and references
246 macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&_header[indexSectionOffset];
247 uint32_t refOffset;
248 for (unsigned int i=0; i < secondLevelPageCount; ++i) {
249 unsigned int reverseIndex = secondLevelPageCount - 1 - i;
250 indexTable[i].set_functionOffset(0);
251 indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-_pages+headerEndSectionOffset);
252 indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset);
253 refOffset = (uint8_t*)&indexTable[i] - _header;
254 this->addImageOffsetFixup(refOffset, secondLevelFirstFuncs[reverseIndex]);
255 }
256 indexTable[secondLevelPageCount].set_functionOffset(0);
257 indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
258 indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize);
259 refOffset = (uint8_t*)&indexTable[secondLevelPageCount] - _header;
260 this->addImageOffsetFixupPlusAddend(refOffset, entries.back().func, entries.back().func->size()+1);
261
262 // build lsda references
263 uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
264 for (std::vector<LSDAEntry>::iterator it = lsdaIndex.begin(); it != lsdaIndex.end(); ++it) {
265 this->addImageOffsetFixup(lsdaEntrySectionOffset, it->func);
266 this->addImageOffsetFixup(lsdaEntrySectionOffset+4, it->lsda);
267 lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
268 }
269
270}
271
272template <typename A>
273UnwindInfoAtom<A>::~UnwindInfoAtom()
274{
275 free(_pagesForDelete);
276 free(_header);
277}
278
279template <typename A>
280void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
281{
282 // content is in two parts
283 memcpy(buffer, _header, _headerSize);
284 memcpy(&buffer[_headerSize], _pages, _pagesSize);
285}
286
287
288template <>
289bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
290{
291 return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
292}
293
294template <>
295bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
296{
297 return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
298}
299
f80fe69f
A
300template <>
301bool UnwindInfoAtom<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
302{
303 return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
304}
305
ba348e21
A
306template <>
307bool UnwindInfoAtom<arm>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
308{
309 return ((enc & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_DWARF);
310}
311
312
a645023d
A
313template <typename A>
314void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
315{
316 // build new list removing entries where next function has same encoding
317 uniqueEntries.reserve(entries.size());
318 UnwindEntry last(NULL, 0, 0, NULL, NULL, NULL, 0xFFFFFFFF);
319 for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
320 const UnwindEntry& next = *it;
321 bool newNeedsDwarf = encodingMeansUseDwarf(next.encoding);
322 // remove entries which have same encoding and personalityPointer as last one
323 if ( newNeedsDwarf || (next.encoding != last.encoding) || (next.personalityPointer != last.personalityPointer)
324 || (next.lsda != NULL) || (last.lsda != NULL) ) {
325 uniqueEntries.push_back(next);
326 }
327 last = next;
328 }
329 if (_s_log) fprintf(stderr, "compressDuplicates() entries.size()=%lu, uniqueEntries.size()=%lu\n",
330 entries.size(), uniqueEntries.size());
331}
332
333template <typename A>
334void UnwindInfoAtom<A>::makePersonalityIndexes(std::vector<UnwindEntry>& entries, std::map<const ld::Atom*, uint32_t>& personalityIndexMap)
335{
336 for(std::vector<UnwindEntry>::iterator it=entries.begin(); it != entries.end(); ++it) {
337 if ( it->personalityPointer != NULL ) {
338 std::map<const ld::Atom*, uint32_t>::iterator pos = personalityIndexMap.find(it->personalityPointer);
339 if ( pos == personalityIndexMap.end() ) {
340 const uint32_t nextIndex = personalityIndexMap.size() + 1;
341 personalityIndexMap[it->personalityPointer] = nextIndex;
342 }
343 uint32_t personalityIndex = personalityIndexMap[it->personalityPointer];
344 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
345 }
346 }
347 if (_s_log) fprintf(stderr, "makePersonalityIndexes() %lu personality routines used\n", personalityIndexMap.size());
348}
349
350
351template <typename A>
352void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<UnwindEntry>& entries,
353 std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings)
354{
355 // scan infos to get frequency counts for each encoding
356 std::map<compact_unwind_encoding_t, unsigned int> encodingsUsed;
357 unsigned int mostCommonEncodingUsageCount = 0;
358 for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
359 // never put dwarf into common table
360 if ( encodingMeansUseDwarf(it->encoding) )
361 continue;
362 std::map<compact_unwind_encoding_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
363 if ( pos == encodingsUsed.end() ) {
364 encodingsUsed[it->encoding] = 1;
365 }
366 else {
367 encodingsUsed[it->encoding] += 1;
368 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
369 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
370 }
371 }
372 // put the most common encodings into the common table, but at most 127 of them
373 for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
374 for (std::map<compact_unwind_encoding_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
375 if ( euit->second == usages ) {
376 unsigned int sz = commonEncodings.size();
377 if ( sz < 127 ) {
378 commonEncodings[euit->first] = sz;
379 }
380 }
381 }
382 }
383 if (_s_log) fprintf(stderr, "findCommonEncoding() %lu common encodings found\n", commonEncodings.size());
384}
385
386
387template <typename A>
388void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex, std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap)
389{
390 for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
391 lsdaIndexOffsetMap[it->func] = lsdaIndex.size() * sizeof(unwind_info_section_header_lsda_index_entry);
392 if ( it->lsda != NULL ) {
393 LSDAEntry entry;
394 entry.func = it->func;
395 entry.lsda = it->lsda;
396 lsdaIndex.push_back(entry);
397 }
398 }
399 if (_s_log) fprintf(stderr, "makeLsdaIndex() %lu LSDAs found\n", lsdaIndex.size());
400}
401
402
403template <>
404void UnwindInfoAtom<x86>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
405{
406 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
407 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
408 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
409}
410
411template <>
412void UnwindInfoAtom<x86_64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
413{
414 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
415 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
416 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
417}
418
f80fe69f
A
419template <>
420void UnwindInfoAtom<arm64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
421{
422 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
423 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
424 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
425}
426
ba348e21
A
427template <>
428void UnwindInfoAtom<arm>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
429{
430 if ( fromFunc->isThumb() ) {
431 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, func));
432 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fromFunc));
433 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 1));
434 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndianLow24of32));
435 }
436 else {
437 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
438 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
439 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
440 }
441}
442
a645023d
A
443template <>
444void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
445{
446 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
447 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
448}
449
450template <>
451void UnwindInfoAtom<x86_64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
452{
453 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
454 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
455}
456
f80fe69f
A
457template <>
458void UnwindInfoAtom<arm64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
459{
460 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
461 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
462}
a645023d 463
ba348e21
A
464template <>
465void UnwindInfoAtom<arm>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
466{
467 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
468 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
469}
470
a645023d
A
471template <>
472void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
473{
474 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
475 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
476}
477
478template <>
479void UnwindInfoAtom<x86_64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
480{
481 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
482 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
483}
484
f80fe69f
A
485template <>
486void UnwindInfoAtom<arm64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
487{
488 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
489 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
490}
491
ba348e21
A
492template <>
493void UnwindInfoAtom<arm>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
494{
495 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
496 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
497}
498
a645023d
A
499template <>
500void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
501{
502 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
503 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
504}
505
506template <>
507void UnwindInfoAtom<x86_64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
508{
509 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
510 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
511}
512
f80fe69f
A
513template <>
514void UnwindInfoAtom<arm64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
515{
516 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
517 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
518}
519
ba348e21
A
520template <>
521void UnwindInfoAtom<arm>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
522{
523 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
524 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
525}
526
a645023d
A
527template <>
528void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
529{
530 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
531 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
532}
533
534template <>
535void UnwindInfoAtom<x86_64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
536{
537 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
538 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
539}
540
f80fe69f
A
541template <>
542void UnwindInfoAtom<arm64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
543{
544 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
545 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
546}
547
ba348e21
A
548template <>
549void UnwindInfoAtom<arm>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
550{
551 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
552 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
553}
554
a645023d
A
555template <>
556void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
557{
558 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
559 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
560 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
561}
562
563template <>
564void UnwindInfoAtom<x86_64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
565{
566 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
567 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
568 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
569}
570
f80fe69f
A
571template <>
572void UnwindInfoAtom<arm64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
573{
574 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
575 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
576 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
577}
a645023d 578
ba348e21
A
579template <>
580void UnwindInfoAtom<arm>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
581{
582 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
583 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
584 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
585}
586
a645023d
A
587
588
589
590template <typename A>
591unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
592 unsigned int endIndex, uint8_t*& pageEnd)
593{
594 const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
595 const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
596 uint8_t* pageStart = pageEnd
597 - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
598 - sizeof(unwind_info_regular_second_level_page_header);
599 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
600 page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
601 page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
602 page->set_entryCount(entriesToAdd);
603 macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
604 for (unsigned int i=0; i < entriesToAdd; ++i) {
605 const UnwindEntry& info = uniqueInfos[endIndex-entriesToAdd+i];
606 entryTable[i].set_functionOffset(0);
607 entryTable[i].set_encoding(info.encoding);
608 // add fixup for address part of entry
599556ff 609 uint32_t offset = (uint8_t*)(&entryTable[i]) - _pageAlignedPages;
a645023d
A
610 this->addRegularAddressFixup(offset, info.func);
611 if ( encodingMeansUseDwarf(info.encoding) ) {
612 // add fixup for dwarf offset part of page specific encoding
599556ff 613 uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pageAlignedPages;
a645023d
A
614 this->addRegularFDEOffsetFixup(encOffset, info.fde);
615 }
616 }
617 if (_s_log) fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
618 pageEnd = pageStart;
619 return endIndex - entriesToAdd;
620}
621
622
623template <typename A>
624unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
625 const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
626 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
627{
628 if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
629 // first pass calculates how many compressed entries we could fit in this sized page
630 // keep adding entries to page until:
631 // 1) encoding table plus entry table plus header exceed page size
632 // 2) the file offset delta from the first to last function > 24 bits
633 // 3) custom encoding index reachs 255
634 // 4) run out of uniqueInfos to encode
635 std::map<compact_unwind_encoding_t, unsigned int> pageSpecificEncodings;
636 uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
637 std::vector<uint8_t> encodingIndexes;
638 int index = endIndex-1;
639 int entryCount = 0;
640 uint64_t lastEntryAddress = uniqueInfos[index].funcTentAddress;
641 bool canDo = true;
642 while ( canDo && (index >= 0) ) {
643 const UnwindEntry& info = uniqueInfos[index--];
644 // compute encoding index
645 unsigned int encodingIndex;
646 std::map<compact_unwind_encoding_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
647 if ( pos != commonEncodings.end() ) {
648 encodingIndex = pos->second;
649 }
650 else {
651 // no commmon entry, so add one on this page
652 uint32_t encoding = info.encoding;
653 if ( encodingMeansUseDwarf(encoding) ) {
654 // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
655 encoding += (index+1);
656 }
657 std::map<compact_unwind_encoding_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
658 if ( ppos != pageSpecificEncodings.end() ) {
659 encodingIndex = pos->second;
660 }
661 else {
662 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
663 if ( encodingIndex <= 255 ) {
664 pageSpecificEncodings[encoding] = encodingIndex;
f80fe69f 665 if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): pageSpecificEncodings[%d]=0x%08X\n", encodingIndex, encoding);
a645023d
A
666 }
667 else {
668 canDo = false; // case 3)
669 if (_s_log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
670 entryCount, pageSpecificEncodings.size());
671 }
672 }
673 }
674 if ( canDo )
675 encodingIndexes.push_back(encodingIndex);
676 // compute function offset
677 uint32_t funcOffsetWithInPage = lastEntryAddress - info.funcTentAddress;
678 if ( funcOffsetWithInPage > 0x00FFFF00 ) {
679 // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
680 canDo = false; // case 2)
681 if (_s_log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
682 }
683 else {
684 ++entryCount;
685 }
686 // check room for entry
687 if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
688 canDo = false; // case 1)
689 --entryCount;
690 if (_s_log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
691 }
692 //if (_s_log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
693 }
694
695 // check for cases where it would be better to use a regular (non-compressed) page
696 const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
697 + pageSpecificEncodings.size()*sizeof(uint32_t)
698 + entryCount*sizeof(uint32_t);
699 if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
700 const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
701 if ( entryCount < regularEntriesPerPage ) {
702 return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
703 }
704 }
705
706 // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
707 uint32_t pad = 0;
708 if ( compressPageUsed == (pageSize-4) )
709 pad = 4;
710
711 // second pass fills in page
712 uint8_t* pageStart = pageEnd - compressPageUsed - pad;
713 CSLP* page = (CSLP*)pageStart;
714 page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
715 page->set_entryPageOffset(sizeof(CSLP));
716 page->set_entryCount(entryCount);
717 page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
718 page->set_encodingsCount(pageSpecificEncodings.size());
719 uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
720 // fill in entry table
721 uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
722 const ld::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
723 for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
724 const UnwindEntry& info = uniqueInfos[i];
725 uint8_t encodingIndex;
726 if ( encodingMeansUseDwarf(info.encoding) ) {
727 // dwarf entries are always in page specific encodings
728 encodingIndex = pageSpecificEncodings[info.encoding+i];
729 }
730 else {
731 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
732 if ( pos != commonEncodings.end() )
733 encodingIndex = pos->second;
734 else
735 encodingIndex = pageSpecificEncodings[info.encoding];
736 }
737 uint32_t entryIndex = i - endIndex + entryCount;
738 E::set32(entiresArray[entryIndex], encodingIndex << 24);
739 // add fixup for address part of entry
599556ff 740 uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pageAlignedPages;
a645023d
A
741 this->addCompressedAddressOffsetFixup(offset, info.func, firstFunc);
742 if ( encodingMeansUseDwarf(info.encoding) ) {
743 // add fixup for dwarf offset part of page specific encoding
599556ff 744 uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pageAlignedPages;
a645023d
A
745 this->addCompressedEncodingFixup(encOffset, info.fde);
746 }
747 }
748 // fill in encodings table
749 for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
750 E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
751 }
752
753 if (_s_log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
754
755 // update pageEnd;
756 pageEnd = pageStart;
757 return endIndex-entryCount; // endIndex for next page
758}
759
760
761
762
763
764
765static uint64_t calculateEHFrameSize(const ld::Internal& state)
766{
767 uint64_t size = 0;
768 for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
769 ld::Internal::FinalSection* sect = *sit;
770 if ( sect->type() == ld::Section::typeCFI ) {
771 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
772 size += (*ait)->size();
773 }
774 }
775 }
776 return size;
777}
778
779static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry>& entries)
780{
781 uint64_t address = 0;
782 for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
783 ld::Internal::FinalSection* sect = *sit;
784 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
785 const ld::Atom* atom = *ait;
786 // adjust address for atom alignment
787 uint64_t alignment = 1 << atom->alignment().powerOf2;
788 uint64_t currentModulus = (address % alignment);
789 uint64_t requiredModulus = atom->alignment().modulus;
790 if ( currentModulus != requiredModulus ) {
791 if ( requiredModulus > currentModulus )
792 address += requiredModulus-currentModulus;
793 else
794 address += requiredModulus+alignment-currentModulus;
795 }
796
797 if ( atom->beginUnwind() == atom->endUnwind() ) {
798 // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
f80fe69f 799 if ( (atom->section().type() == ld::Section::typeCode) && (atom->size() !=0) ) {
a645023d
A
800 entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
801 }
802 }
803 else {
804 // atom has unwind info(s), add entry for each
805 const ld::Atom* fde = NULL;
806 const ld::Atom* lsda = NULL;
807 const ld::Atom* personalityPointer = NULL;
808 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
809 switch ( fit->kind ) {
810 case ld::Fixup::kindNoneGroupSubordinateFDE:
811 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
812 fde = fit->u.target;
813 break;
814 case ld::Fixup::kindNoneGroupSubordinateLSDA:
815 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
816 lsda = fit->u.target;
817 break;
afe874b1
A
818 case ld::Fixup::kindNoneGroupSubordinatePersonality:
819 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
820 personalityPointer = fit->u.target;
821 assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
822 break;
a645023d
A
823 default:
824 break;
825 }
826 }
827 if ( fde != NULL ) {
828 // find CIE for this FDE
829 const ld::Atom* cie = NULL;
830 for (ld::Fixup::iterator fit = fde->fixupsBegin(), end=fde->fixupsEnd(); fit != end; ++fit) {
831 if ( fit->kind != ld::Fixup::kindSubtractTargetAddress )
832 continue;
833 if ( fit->binding != ld::Fixup::bindingDirectlyBound )
834 continue;
835 cie = fit->u.target;
836 // CIE is only direct subtracted target in FDE
837 assert(cie->section().type() == ld::Section::typeCFI);
838 break;
839 }
840 if ( cie != NULL ) {
841 // if CIE can have just one fixup - to the personality pointer
842 for (ld::Fixup::iterator fit = cie->fixupsBegin(), end=cie->fixupsEnd(); fit != end; ++fit) {
843 if ( fit->kind == ld::Fixup::kindSetTargetAddress ) {
844 switch ( fit->binding ) {
845 case ld::Fixup::bindingsIndirectlyBound:
846 personalityPointer = state.indirectBindingTable[fit->u.bindingIndex];
847 assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
848 break;
849 case ld::Fixup::bindingDirectlyBound:
850 personalityPointer = fit->u.target;
851 assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
852 break;
853 default:
854 break;
855 }
856 }
857 }
858 }
859 }
860 for ( ld::Atom::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
861 entries.push_back(UnwindEntry(atom, address, uit->startOffset, fde, lsda, personalityPointer, uit->unwindInfo));
862 }
863 }
864 address += atom->size();
865 }
866 }
867}
868
869
afe874b1 870static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::Internal& state)
a645023d 871{
a645023d
A
872 // walk every atom and gets its unwind info
873 std::vector<UnwindEntry> entries;
874 entries.reserve(64);
875 getAllUnwindInfos(state, entries);
876
877 // don't generate an __unwind_info section if there is no code in this linkage unit
878 if ( entries.size() == 0 )
879 return;
880
881 // calculate size of __eh_frame section, so __unwind_info can go before it and page align
882 uint64_t ehFrameSize = calculateEHFrameSize(state);
883
884 // create atom that contains the whole compact unwind table
885 switch ( opts.architecture() ) {
ebf6f434 886#if SUPPORT_ARCH_x86_64
a645023d
A
887 case CPU_TYPE_X86_64:
888 state.addAtom(*new UnwindInfoAtom<x86_64>(entries, ehFrameSize));
889 break;
ebf6f434
A
890#endif
891#if SUPPORT_ARCH_i386
a645023d
A
892 case CPU_TYPE_I386:
893 state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
894 break;
f80fe69f
A
895#endif
896#if SUPPORT_ARCH_arm64
897 case CPU_TYPE_ARM64:
898 state.addAtom(*new UnwindInfoAtom<arm64>(entries, ehFrameSize));
899 break;
ba348e21
A
900#endif
901#if SUPPORT_ARCH_arm_any
902 case CPU_TYPE_ARM:
903 if ( opts.armUsesZeroCostExceptions() )
904 state.addAtom(*new UnwindInfoAtom<arm>(entries, ehFrameSize));
905 break;
ebf6f434 906#endif
a645023d
A
907 default:
908 assert(0 && "no compact unwind for arch");
909 }
910}
911
912
afe874b1
A
913
914template <typename A>
915class CompactUnwindAtom : public ld::Atom {
916public:
917 CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom,
918 uint32_t startOffset, uint32_t len, uint32_t cui);
919 ~CompactUnwindAtom() {}
920
921 virtual const ld::File* file() const { return NULL; }
afe874b1
A
922 virtual const char* name() const { return "compact unwind info"; }
923 virtual uint64_t size() const { return sizeof(macho_compact_unwind_entry<P>); }
924 virtual uint64_t objectAddress() const { return 0; }
925 virtual void copyRawContent(uint8_t buffer[]) const;
926 virtual void setScope(Scope) { }
927 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
928 virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
929
930private:
931 typedef typename A::P P;
932 typedef typename A::P::E E;
933 typedef typename A::P::uint_t pint_t;
934
935
936 const ld::Atom* _atom;
937 const uint32_t _startOffset;
938 const uint32_t _len;
939 const uint32_t _compactUnwindInfo;
940 std::vector<ld::Fixup> _fixups;
941
942 static ld::Fixup::Kind _s_pointerKind;
943 static ld::Fixup::Kind _s_pointerStoreKind;
944 static ld::Section _s_section;
945};
946
947
948template <typename A>
949ld::Section CompactUnwindAtom<A>::_s_section("__LD", "__compact_unwind", ld::Section::typeDebug);
950
951template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
952template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
953template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
954template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
f80fe69f
A
955#if SUPPORT_ARCH_arm64
956template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
957template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
958#endif
ba348e21
A
959template <> ld::Fixup::Kind CompactUnwindAtom<arm>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
960template <> ld::Fixup::Kind CompactUnwindAtom<arm>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
afe874b1
A
961
962template <typename A>
963CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
964 uint32_t len, uint32_t cui)
965 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
966 ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
f80fe69f 967 symbolTableNotIn, false, false, false, ld::Atom::Alignment(log2(sizeof(pint_t)))),
afe874b1
A
968 _atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
969{
970 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
971 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k2of3, ld::Fixup::kindAddAddend, _startOffset));
972 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k3of3, _s_pointerKind));
973 // see if atom has subordinate personality function or lsda
974 for (ld::Fixup::iterator fit = funcAtom->fixupsBegin(), end=funcAtom->fixupsEnd(); fit != end; ++fit) {
975 switch ( fit->kind ) {
976 case ld::Fixup::kindNoneGroupSubordinatePersonality:
977 assert(fit->binding == ld::Fixup::bindingsIndirectlyBound);
978 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::personalityFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, state.indirectBindingTable[fit->u.bindingIndex]));
979 break;
980 case ld::Fixup::kindNoneGroupSubordinateLSDA:
981 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
982 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::lsdaFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, fit->u.target));
983 break;
984 default:
985 break;
986 }
987 }
988
989}
990
991template <typename A>
992void CompactUnwindAtom<A>::copyRawContent(uint8_t buffer[]) const
993{
994 macho_compact_unwind_entry<P>* buf = (macho_compact_unwind_entry<P>*)buffer;
995 buf->set_codeStart(0);
996 buf->set_codeLen(_len);
997 buf->set_compactUnwindInfo(_compactUnwindInfo);
998 buf->set_personality(0);
999 buf->set_lsda(0);
1000}
1001
1002
1003static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, const ld::Atom* atom,
1004 uint32_t startOffset, uint32_t endOffset, uint32_t cui)
1005{
1006 switch ( opts.architecture() ) {
ebf6f434 1007#if SUPPORT_ARCH_x86_64
afe874b1
A
1008 case CPU_TYPE_X86_64:
1009 state.addAtom(*new CompactUnwindAtom<x86_64>(state, atom, startOffset, endOffset-startOffset, cui));
1010 break;
ebf6f434
A
1011#endif
1012#if SUPPORT_ARCH_i386
afe874b1
A
1013 case CPU_TYPE_I386:
1014 state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
1015 break;
f80fe69f
A
1016#endif
1017#if SUPPORT_ARCH_arm64
1018 case CPU_TYPE_ARM64:
1019 state.addAtom(*new CompactUnwindAtom<arm64>(state, atom, startOffset, endOffset-startOffset, cui));
1020 break;
ebf6f434 1021#endif
ba348e21
A
1022 case CPU_TYPE_ARM:
1023 state.addAtom(*new CompactUnwindAtom<arm>(state, atom, startOffset, endOffset-startOffset, cui));
1024 break;
afe874b1
A
1025 }
1026}
1027
1028static void makeRelocateableCompactUnwindSection(const Options& opts, ld::Internal& state)
1029{
1030 // can't add CompactUnwindAtom atoms will iterating, so pre-scan
1031 std::vector<const ld::Atom*> atomsWithUnwind;
1032 for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
1033 ld::Internal::FinalSection* sect = *sit;
1034 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
1035 const ld::Atom* atom = *ait;
1036 if ( atom->beginUnwind() != atom->endUnwind() )
1037 atomsWithUnwind.push_back(atom);
1038 }
1039 }
1040 // make one CompactUnwindAtom for each compact unwind range in each atom
1041 for (std::vector<const ld::Atom*>::iterator it = atomsWithUnwind.begin(); it != atomsWithUnwind.end(); ++it) {
1042 const ld::Atom* atom = *it;
1043 uint32_t lastOffset = 0;
1044 uint32_t lastCUE = 0;
1045 bool first = true;
1046 for (ld::Atom::UnwindInfo::iterator uit=atom->beginUnwind(); uit != atom->endUnwind(); ++uit) {
1047 if ( !first ) {
1048 makeCompactUnwindAtom(opts, state, atom, lastOffset, uit->startOffset, lastCUE);
1049 }
1050 lastOffset = uit->startOffset;
1051 lastCUE = uit->unwindInfo;
1052 first = false;
1053 }
1054 makeCompactUnwindAtom(opts, state, atom, lastOffset, (uint32_t)atom->size(), lastCUE);
1055 }
1056}
1057
1058
1059void doPass(const Options& opts, ld::Internal& state)
1060{
1061 if ( opts.outputKind() == Options::kObjectFile )
1062 makeRelocateableCompactUnwindSection(opts, state);
1063
1064 else if ( opts.needsUnwindInfoSection() )
1065 makeFinalLinkedImageCompactUnwindSection(opts, state);
1066}
1067
1068
a645023d
A
1069} // namespace compact_unwind
1070} // namespace passes
1071} // namespace ld