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