]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/compact_unwind.cpp
ad8a504fde004a7f5d7764ec97fcd542d4d7259e
[apple/ld64.git] / src / ld / passes / compact_unwind.cpp
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
42 namespace ld {
43 namespace passes {
44 namespace compact_unwind {
45
46
47 struct 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
61 struct LSDAEntry {
62 const ld::Atom* func;
63 const ld::Atom* lsda;
64 };
65
66
67 template <typename A>
68 class UnwindInfoAtom : public ld::Atom {
69 public:
70 UnwindInfoAtom(const std::vector<UnwindEntry>& entries,uint64_t ehFrameSize);
71 ~UnwindInfoAtom();
72
73 virtual const ld::File* file() const { return NULL; }
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
82 private:
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;
111 uint8_t* _pages;
112 uint64_t _pagesSize;
113 uint8_t* _header;
114 uint64_t _headerSize;
115 std::vector<ld::Fixup> _fixups;
116
117 static bool _s_log;
118 static ld::Section _s_section;
119 };
120
121 template <typename A>
122 bool UnwindInfoAtom<A>::_s_log = false;
123
124 template <typename A>
125 ld::Section UnwindInfoAtom<A>::_s_section("__TEXT", "__unwind_info", ld::Section::typeUnwindInfo);
126
127
128 template <typename A>
129 UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint64_t ehFrameSize)
130 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
131 ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
132 symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
133 _pagesForDelete(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
134 {
135 // build new compressed list by removing entries where next function has same encoding
136 std::vector<UnwindEntry> uniqueEntries;
137 compressDuplicates(entries, uniqueEntries);
138
139 // reserve room so _fixups vector is not reallocated a bunch of times
140 _fixups.reserve(uniqueEntries.size()*3);
141
142 // build personality index, update encodings with personality index
143 std::map<const ld::Atom*, uint32_t> personalityIndexMap;
144 makePersonalityIndexes(uniqueEntries, personalityIndexMap);
145 if ( personalityIndexMap.size() > 3 ) {
146 warning("too many personality routines for compact unwind to encode");
147 return;
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
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);
162 const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 2;
163 _pagesForDelete = (uint8_t*)calloc(pageCount,4096);
164 if ( _pagesForDelete == NULL ) {
165 warning("could not allocate space for compact unwind info");
166 return;
167 }
168
169 // make last second level page smaller so that all other second level pages can be page aligned
170 uint32_t maxLastPageSize = 4096 - (ehFrameSize % 4096);
171 uint32_t tailPad = 0;
172 if ( maxLastPageSize < 128 ) {
173 tailPad = maxLastPageSize;
174 maxLastPageSize = 4096;
175 }
176
177 // fill in pages in reverse order
178 const ld::Atom* secondLevelFirstFuncs[pageCount*3];
179 uint8_t* secondLevelPagesStarts[pageCount*3];
180 unsigned int endIndex = uniqueEntries.size();
181 unsigned int secondLevelPageCount = 0;
182 uint8_t* pageEnd = &_pagesForDelete[pageCount*4096];
183 uint32_t pageSize = maxLastPageSize;
184 while ( endIndex > 0 ) {
185 endIndex = makeCompressedSecondLevelPage(uniqueEntries, commonEncodings, pageSize, endIndex, pageEnd);
186 secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
187 secondLevelFirstFuncs[secondLevelPageCount] = uniqueEntries[endIndex].func;
188 ++secondLevelPageCount;
189 // if this requires more than one page, align so that next starts on page boundary
190 if ( (pageSize != 4096) && (endIndex > 0) ) {
191 pageEnd = (uint8_t*)((uintptr_t)(pageEnd) & -4096);
192 pageSize = 4096; // last page can be odd size, make rest up to 4096 bytes in size
193 }
194 }
195 _pages = pageEnd;
196 _pagesSize = &_pagesForDelete[pageCount*4096] - pageEnd;
197
198
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
215 const int32_t fixupSlide = headerEndSectionOffset + (_pagesForDelete - _pages);
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
272 template <typename A>
273 UnwindInfoAtom<A>::~UnwindInfoAtom()
274 {
275 free(_pagesForDelete);
276 free(_header);
277 }
278
279 template <typename A>
280 void 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
288 template <>
289 bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
290 {
291 return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
292 }
293
294 template <>
295 bool 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
300 template <>
301 bool UnwindInfoAtom<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
302 {
303 return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
304 }
305
306 template <typename A>
307 void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
308 {
309 // build new list removing entries where next function has same encoding
310 uniqueEntries.reserve(entries.size());
311 UnwindEntry last(NULL, 0, 0, NULL, NULL, NULL, 0xFFFFFFFF);
312 for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
313 const UnwindEntry& next = *it;
314 bool newNeedsDwarf = encodingMeansUseDwarf(next.encoding);
315 // remove entries which have same encoding and personalityPointer as last one
316 if ( newNeedsDwarf || (next.encoding != last.encoding) || (next.personalityPointer != last.personalityPointer)
317 || (next.lsda != NULL) || (last.lsda != NULL) ) {
318 uniqueEntries.push_back(next);
319 }
320 last = next;
321 }
322 if (_s_log) fprintf(stderr, "compressDuplicates() entries.size()=%lu, uniqueEntries.size()=%lu\n",
323 entries.size(), uniqueEntries.size());
324 }
325
326 template <typename A>
327 void UnwindInfoAtom<A>::makePersonalityIndexes(std::vector<UnwindEntry>& entries, std::map<const ld::Atom*, uint32_t>& personalityIndexMap)
328 {
329 for(std::vector<UnwindEntry>::iterator it=entries.begin(); it != entries.end(); ++it) {
330 if ( it->personalityPointer != NULL ) {
331 std::map<const ld::Atom*, uint32_t>::iterator pos = personalityIndexMap.find(it->personalityPointer);
332 if ( pos == personalityIndexMap.end() ) {
333 const uint32_t nextIndex = personalityIndexMap.size() + 1;
334 personalityIndexMap[it->personalityPointer] = nextIndex;
335 }
336 uint32_t personalityIndex = personalityIndexMap[it->personalityPointer];
337 it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
338 }
339 }
340 if (_s_log) fprintf(stderr, "makePersonalityIndexes() %lu personality routines used\n", personalityIndexMap.size());
341 }
342
343
344 template <typename A>
345 void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<UnwindEntry>& entries,
346 std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings)
347 {
348 // scan infos to get frequency counts for each encoding
349 std::map<compact_unwind_encoding_t, unsigned int> encodingsUsed;
350 unsigned int mostCommonEncodingUsageCount = 0;
351 for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
352 // never put dwarf into common table
353 if ( encodingMeansUseDwarf(it->encoding) )
354 continue;
355 std::map<compact_unwind_encoding_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
356 if ( pos == encodingsUsed.end() ) {
357 encodingsUsed[it->encoding] = 1;
358 }
359 else {
360 encodingsUsed[it->encoding] += 1;
361 if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
362 mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
363 }
364 }
365 // put the most common encodings into the common table, but at most 127 of them
366 for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
367 for (std::map<compact_unwind_encoding_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
368 if ( euit->second == usages ) {
369 unsigned int sz = commonEncodings.size();
370 if ( sz < 127 ) {
371 commonEncodings[euit->first] = sz;
372 }
373 }
374 }
375 }
376 if (_s_log) fprintf(stderr, "findCommonEncoding() %lu common encodings found\n", commonEncodings.size());
377 }
378
379
380 template <typename A>
381 void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex, std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap)
382 {
383 for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
384 lsdaIndexOffsetMap[it->func] = lsdaIndex.size() * sizeof(unwind_info_section_header_lsda_index_entry);
385 if ( it->lsda != NULL ) {
386 LSDAEntry entry;
387 entry.func = it->func;
388 entry.lsda = it->lsda;
389 lsdaIndex.push_back(entry);
390 }
391 }
392 if (_s_log) fprintf(stderr, "makeLsdaIndex() %lu LSDAs found\n", lsdaIndex.size());
393 }
394
395
396 template <>
397 void UnwindInfoAtom<x86>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
398 {
399 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
400 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
401 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
402 }
403
404 template <>
405 void UnwindInfoAtom<x86_64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
406 {
407 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
408 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
409 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
410 }
411
412 template <>
413 void UnwindInfoAtom<arm64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
414 {
415 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
416 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
417 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
418 }
419
420 template <>
421 void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
422 {
423 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
424 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
425 }
426
427 template <>
428 void UnwindInfoAtom<x86_64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
429 {
430 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
431 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
432 }
433
434 template <>
435 void UnwindInfoAtom<arm64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
436 {
437 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
438 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
439 }
440
441 template <>
442 void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
443 {
444 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
445 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
446 }
447
448 template <>
449 void UnwindInfoAtom<x86_64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
450 {
451 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
452 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
453 }
454
455 template <>
456 void UnwindInfoAtom<arm64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
457 {
458 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
459 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
460 }
461
462 template <>
463 void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
464 {
465 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
466 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
467 }
468
469 template <>
470 void UnwindInfoAtom<x86_64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
471 {
472 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
473 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
474 }
475
476 template <>
477 void UnwindInfoAtom<arm64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
478 {
479 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
480 _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
481 }
482
483 template <>
484 void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
485 {
486 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
487 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
488 }
489
490 template <>
491 void UnwindInfoAtom<x86_64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
492 {
493 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
494 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
495 }
496
497 template <>
498 void UnwindInfoAtom<arm64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
499 {
500 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
501 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
502 }
503
504 template <>
505 void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
506 {
507 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
508 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
509 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
510 }
511
512 template <>
513 void UnwindInfoAtom<x86_64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
514 {
515 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
516 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
517 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
518 }
519
520 template <>
521 void UnwindInfoAtom<arm64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
522 {
523 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
524 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
525 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
526 }
527
528
529
530
531 template <typename A>
532 unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,
533 unsigned int endIndex, uint8_t*& pageEnd)
534 {
535 const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
536 const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
537 uint8_t* pageStart = pageEnd
538 - entriesToAdd*sizeof(unwind_info_regular_second_level_entry)
539 - sizeof(unwind_info_regular_second_level_page_header);
540 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
541 page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
542 page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
543 page->set_entryCount(entriesToAdd);
544 macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
545 for (unsigned int i=0; i < entriesToAdd; ++i) {
546 const UnwindEntry& info = uniqueInfos[endIndex-entriesToAdd+i];
547 entryTable[i].set_functionOffset(0);
548 entryTable[i].set_encoding(info.encoding);
549 // add fixup for address part of entry
550 uint32_t offset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
551 this->addRegularAddressFixup(offset, info.func);
552 if ( encodingMeansUseDwarf(info.encoding) ) {
553 // add fixup for dwarf offset part of page specific encoding
554 uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
555 this->addRegularFDEOffsetFixup(encOffset, info.fde);
556 }
557 }
558 if (_s_log) fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
559 pageEnd = pageStart;
560 return endIndex - entriesToAdd;
561 }
562
563
564 template <typename A>
565 unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,
566 const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,
567 uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
568 {
569 if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
570 // first pass calculates how many compressed entries we could fit in this sized page
571 // keep adding entries to page until:
572 // 1) encoding table plus entry table plus header exceed page size
573 // 2) the file offset delta from the first to last function > 24 bits
574 // 3) custom encoding index reachs 255
575 // 4) run out of uniqueInfos to encode
576 std::map<compact_unwind_encoding_t, unsigned int> pageSpecificEncodings;
577 uint32_t space4 = (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
578 std::vector<uint8_t> encodingIndexes;
579 int index = endIndex-1;
580 int entryCount = 0;
581 uint64_t lastEntryAddress = uniqueInfos[index].funcTentAddress;
582 bool canDo = true;
583 while ( canDo && (index >= 0) ) {
584 const UnwindEntry& info = uniqueInfos[index--];
585 // compute encoding index
586 unsigned int encodingIndex;
587 std::map<compact_unwind_encoding_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
588 if ( pos != commonEncodings.end() ) {
589 encodingIndex = pos->second;
590 }
591 else {
592 // no commmon entry, so add one on this page
593 uint32_t encoding = info.encoding;
594 if ( encodingMeansUseDwarf(encoding) ) {
595 // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
596 encoding += (index+1);
597 }
598 std::map<compact_unwind_encoding_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
599 if ( ppos != pageSpecificEncodings.end() ) {
600 encodingIndex = pos->second;
601 }
602 else {
603 encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
604 if ( encodingIndex <= 255 ) {
605 pageSpecificEncodings[encoding] = encodingIndex;
606 if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): pageSpecificEncodings[%d]=0x%08X\n", encodingIndex, encoding);
607 }
608 else {
609 canDo = false; // case 3)
610 if (_s_log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n",
611 entryCount, pageSpecificEncodings.size());
612 }
613 }
614 }
615 if ( canDo )
616 encodingIndexes.push_back(encodingIndex);
617 // compute function offset
618 uint32_t funcOffsetWithInPage = lastEntryAddress - info.funcTentAddress;
619 if ( funcOffsetWithInPage > 0x00FFFF00 ) {
620 // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
621 canDo = false; // case 2)
622 if (_s_log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
623 }
624 else {
625 ++entryCount;
626 }
627 // check room for entry
628 if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
629 canDo = false; // case 1)
630 --entryCount;
631 if (_s_log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
632 }
633 //if (_s_log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
634 }
635
636 // check for cases where it would be better to use a regular (non-compressed) page
637 const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header)
638 + pageSpecificEncodings.size()*sizeof(uint32_t)
639 + entryCount*sizeof(uint32_t);
640 if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
641 const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
642 if ( entryCount < regularEntriesPerPage ) {
643 return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
644 }
645 }
646
647 // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
648 uint32_t pad = 0;
649 if ( compressPageUsed == (pageSize-4) )
650 pad = 4;
651
652 // second pass fills in page
653 uint8_t* pageStart = pageEnd - compressPageUsed - pad;
654 CSLP* page = (CSLP*)pageStart;
655 page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
656 page->set_entryPageOffset(sizeof(CSLP));
657 page->set_entryCount(entryCount);
658 page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
659 page->set_encodingsCount(pageSpecificEncodings.size());
660 uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
661 // fill in entry table
662 uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
663 const ld::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
664 for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
665 const UnwindEntry& info = uniqueInfos[i];
666 uint8_t encodingIndex;
667 if ( encodingMeansUseDwarf(info.encoding) ) {
668 // dwarf entries are always in page specific encodings
669 encodingIndex = pageSpecificEncodings[info.encoding+i];
670 }
671 else {
672 std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
673 if ( pos != commonEncodings.end() )
674 encodingIndex = pos->second;
675 else
676 encodingIndex = pageSpecificEncodings[info.encoding];
677 }
678 uint32_t entryIndex = i - endIndex + entryCount;
679 E::set32(entiresArray[entryIndex], encodingIndex << 24);
680 // add fixup for address part of entry
681 uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pagesForDelete;
682 this->addCompressedAddressOffsetFixup(offset, info.func, firstFunc);
683 if ( encodingMeansUseDwarf(info.encoding) ) {
684 // add fixup for dwarf offset part of page specific encoding
685 uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pagesForDelete;
686 this->addCompressedEncodingFixup(encOffset, info.fde);
687 }
688 }
689 // fill in encodings table
690 for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
691 E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
692 }
693
694 if (_s_log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
695
696 // update pageEnd;
697 pageEnd = pageStart;
698 return endIndex-entryCount; // endIndex for next page
699 }
700
701
702
703
704
705
706 static uint64_t calculateEHFrameSize(const ld::Internal& state)
707 {
708 uint64_t size = 0;
709 for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
710 ld::Internal::FinalSection* sect = *sit;
711 if ( sect->type() == ld::Section::typeCFI ) {
712 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
713 size += (*ait)->size();
714 }
715 }
716 }
717 return size;
718 }
719
720 static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry>& entries)
721 {
722 uint64_t address = 0;
723 for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
724 ld::Internal::FinalSection* sect = *sit;
725 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
726 const ld::Atom* atom = *ait;
727 // adjust address for atom alignment
728 uint64_t alignment = 1 << atom->alignment().powerOf2;
729 uint64_t currentModulus = (address % alignment);
730 uint64_t requiredModulus = atom->alignment().modulus;
731 if ( currentModulus != requiredModulus ) {
732 if ( requiredModulus > currentModulus )
733 address += requiredModulus-currentModulus;
734 else
735 address += requiredModulus+alignment-currentModulus;
736 }
737
738 if ( atom->beginUnwind() == atom->endUnwind() ) {
739 // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
740 if ( (atom->section().type() == ld::Section::typeCode) && (atom->size() !=0) ) {
741 entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
742 }
743 }
744 else {
745 // atom has unwind info(s), add entry for each
746 const ld::Atom* fde = NULL;
747 const ld::Atom* lsda = NULL;
748 const ld::Atom* personalityPointer = NULL;
749 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
750 switch ( fit->kind ) {
751 case ld::Fixup::kindNoneGroupSubordinateFDE:
752 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
753 fde = fit->u.target;
754 break;
755 case ld::Fixup::kindNoneGroupSubordinateLSDA:
756 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
757 lsda = fit->u.target;
758 break;
759 case ld::Fixup::kindNoneGroupSubordinatePersonality:
760 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
761 personalityPointer = fit->u.target;
762 assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
763 break;
764 default:
765 break;
766 }
767 }
768 if ( fde != NULL ) {
769 // find CIE for this FDE
770 const ld::Atom* cie = NULL;
771 for (ld::Fixup::iterator fit = fde->fixupsBegin(), end=fde->fixupsEnd(); fit != end; ++fit) {
772 if ( fit->kind != ld::Fixup::kindSubtractTargetAddress )
773 continue;
774 if ( fit->binding != ld::Fixup::bindingDirectlyBound )
775 continue;
776 cie = fit->u.target;
777 // CIE is only direct subtracted target in FDE
778 assert(cie->section().type() == ld::Section::typeCFI);
779 break;
780 }
781 if ( cie != NULL ) {
782 // if CIE can have just one fixup - to the personality pointer
783 for (ld::Fixup::iterator fit = cie->fixupsBegin(), end=cie->fixupsEnd(); fit != end; ++fit) {
784 if ( fit->kind == ld::Fixup::kindSetTargetAddress ) {
785 switch ( fit->binding ) {
786 case ld::Fixup::bindingsIndirectlyBound:
787 personalityPointer = state.indirectBindingTable[fit->u.bindingIndex];
788 assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
789 break;
790 case ld::Fixup::bindingDirectlyBound:
791 personalityPointer = fit->u.target;
792 assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
793 break;
794 default:
795 break;
796 }
797 }
798 }
799 }
800 }
801 for ( ld::Atom::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
802 entries.push_back(UnwindEntry(atom, address, uit->startOffset, fde, lsda, personalityPointer, uit->unwindInfo));
803 }
804 }
805 address += atom->size();
806 }
807 }
808 }
809
810
811 static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::Internal& state)
812 {
813 // walk every atom and gets its unwind info
814 std::vector<UnwindEntry> entries;
815 entries.reserve(64);
816 getAllUnwindInfos(state, entries);
817
818 // don't generate an __unwind_info section if there is no code in this linkage unit
819 if ( entries.size() == 0 )
820 return;
821
822 // calculate size of __eh_frame section, so __unwind_info can go before it and page align
823 uint64_t ehFrameSize = calculateEHFrameSize(state);
824
825 // create atom that contains the whole compact unwind table
826 switch ( opts.architecture() ) {
827 #if SUPPORT_ARCH_x86_64
828 case CPU_TYPE_X86_64:
829 state.addAtom(*new UnwindInfoAtom<x86_64>(entries, ehFrameSize));
830 break;
831 #endif
832 #if SUPPORT_ARCH_i386
833 case CPU_TYPE_I386:
834 state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
835 break;
836 #endif
837 #if SUPPORT_ARCH_arm64
838 case CPU_TYPE_ARM64:
839 state.addAtom(*new UnwindInfoAtom<arm64>(entries, ehFrameSize));
840 break;
841 #endif
842 default:
843 assert(0 && "no compact unwind for arch");
844 }
845 }
846
847
848
849 template <typename A>
850 class CompactUnwindAtom : public ld::Atom {
851 public:
852 CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom,
853 uint32_t startOffset, uint32_t len, uint32_t cui);
854 ~CompactUnwindAtom() {}
855
856 virtual const ld::File* file() const { return NULL; }
857 virtual const char* name() const { return "compact unwind info"; }
858 virtual uint64_t size() const { return sizeof(macho_compact_unwind_entry<P>); }
859 virtual uint64_t objectAddress() const { return 0; }
860 virtual void copyRawContent(uint8_t buffer[]) const;
861 virtual void setScope(Scope) { }
862 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
863 virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
864
865 private:
866 typedef typename A::P P;
867 typedef typename A::P::E E;
868 typedef typename A::P::uint_t pint_t;
869
870
871 const ld::Atom* _atom;
872 const uint32_t _startOffset;
873 const uint32_t _len;
874 const uint32_t _compactUnwindInfo;
875 std::vector<ld::Fixup> _fixups;
876
877 static ld::Fixup::Kind _s_pointerKind;
878 static ld::Fixup::Kind _s_pointerStoreKind;
879 static ld::Section _s_section;
880 };
881
882
883 template <typename A>
884 ld::Section CompactUnwindAtom<A>::_s_section("__LD", "__compact_unwind", ld::Section::typeDebug);
885
886 template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian32;
887 template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
888 template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
889 template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
890 #if SUPPORT_ARCH_arm64
891 template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
892 template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
893 #endif
894
895 template <typename A>
896 CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
897 uint32_t len, uint32_t cui)
898 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
899 ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
900 symbolTableNotIn, false, false, false, ld::Atom::Alignment(log2(sizeof(pint_t)))),
901 _atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
902 {
903 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
904 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k2of3, ld::Fixup::kindAddAddend, _startOffset));
905 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k3of3, _s_pointerKind));
906 // see if atom has subordinate personality function or lsda
907 for (ld::Fixup::iterator fit = funcAtom->fixupsBegin(), end=funcAtom->fixupsEnd(); fit != end; ++fit) {
908 switch ( fit->kind ) {
909 case ld::Fixup::kindNoneGroupSubordinatePersonality:
910 assert(fit->binding == ld::Fixup::bindingsIndirectlyBound);
911 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::personalityFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, state.indirectBindingTable[fit->u.bindingIndex]));
912 break;
913 case ld::Fixup::kindNoneGroupSubordinateLSDA:
914 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
915 _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::lsdaFieldOffset(), ld::Fixup::k1of1, _s_pointerStoreKind, fit->u.target));
916 break;
917 default:
918 break;
919 }
920 }
921
922 }
923
924 template <typename A>
925 void CompactUnwindAtom<A>::copyRawContent(uint8_t buffer[]) const
926 {
927 macho_compact_unwind_entry<P>* buf = (macho_compact_unwind_entry<P>*)buffer;
928 buf->set_codeStart(0);
929 buf->set_codeLen(_len);
930 buf->set_compactUnwindInfo(_compactUnwindInfo);
931 buf->set_personality(0);
932 buf->set_lsda(0);
933 }
934
935
936 static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, const ld::Atom* atom,
937 uint32_t startOffset, uint32_t endOffset, uint32_t cui)
938 {
939 switch ( opts.architecture() ) {
940 #if SUPPORT_ARCH_x86_64
941 case CPU_TYPE_X86_64:
942 state.addAtom(*new CompactUnwindAtom<x86_64>(state, atom, startOffset, endOffset-startOffset, cui));
943 break;
944 #endif
945 #if SUPPORT_ARCH_i386
946 case CPU_TYPE_I386:
947 state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
948 break;
949 #endif
950 #if SUPPORT_ARCH_arm64
951 case CPU_TYPE_ARM64:
952 state.addAtom(*new CompactUnwindAtom<arm64>(state, atom, startOffset, endOffset-startOffset, cui));
953 break;
954 #endif
955 }
956 }
957
958 static void makeRelocateableCompactUnwindSection(const Options& opts, ld::Internal& state)
959 {
960 // can't add CompactUnwindAtom atoms will iterating, so pre-scan
961 std::vector<const ld::Atom*> atomsWithUnwind;
962 for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
963 ld::Internal::FinalSection* sect = *sit;
964 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
965 const ld::Atom* atom = *ait;
966 if ( atom->beginUnwind() != atom->endUnwind() )
967 atomsWithUnwind.push_back(atom);
968 }
969 }
970 // make one CompactUnwindAtom for each compact unwind range in each atom
971 for (std::vector<const ld::Atom*>::iterator it = atomsWithUnwind.begin(); it != atomsWithUnwind.end(); ++it) {
972 const ld::Atom* atom = *it;
973 uint32_t lastOffset = 0;
974 uint32_t lastCUE = 0;
975 bool first = true;
976 for (ld::Atom::UnwindInfo::iterator uit=atom->beginUnwind(); uit != atom->endUnwind(); ++uit) {
977 if ( !first ) {
978 makeCompactUnwindAtom(opts, state, atom, lastOffset, uit->startOffset, lastCUE);
979 }
980 lastOffset = uit->startOffset;
981 lastCUE = uit->unwindInfo;
982 first = false;
983 }
984 makeCompactUnwindAtom(opts, state, atom, lastOffset, (uint32_t)atom->size(), lastCUE);
985 }
986 }
987
988
989 void doPass(const Options& opts, ld::Internal& state)
990 {
991 if ( opts.outputKind() == Options::kObjectFile )
992 makeRelocateableCompactUnwindSection(opts, state);
993
994 else if ( opts.needsUnwindInfoSection() )
995 makeFinalLinkedImageCompactUnwindSection(opts, state);
996 }
997
998
999 } // namespace compact_unwind
1000 } // namespace passes
1001 } // namespace ld