1// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/elf.h"
6
7#include "platform/elf.h"
8#include "vm/cpu.h"
9#include "vm/dwarf.h"
10#include "vm/hash_map.h"
11#include "vm/image_snapshot.h"
12#include "vm/thread.h"
13#include "vm/zone_text_buffer.h"
14
15namespace dart {
16
17// A wrapper around StreamingWriteStream that provides methods useful for
18// writing ELF files (e.g., using ELF definitions of data sizes).
19class ElfWriteStream : public ValueObject {
20 public:
21 explicit ElfWriteStream(StreamingWriteStream* stream)
22 : stream_(ASSERT_NOTNULL(stream)) {}
23
24 intptr_t position() const { return stream_->position(); }
25 void Align(const intptr_t alignment) {
26 ASSERT(Utils::IsPowerOfTwo(alignment));
27 stream_->Align(alignment);
28 }
29 void WriteBytes(const uint8_t* b, intptr_t size) {
30 stream_->WriteBytes(b, size);
31 }
32 void WriteByte(uint8_t value) {
33 stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
34 }
35 void WriteHalf(uint16_t value) {
36 stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
37 }
38 void WriteWord(uint32_t value) {
39 stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
40 }
41 void WriteAddr(compiler::target::uword value) {
42 stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
43 }
44 void WriteOff(compiler::target::uword value) {
45 stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
46 }
47#if defined(TARGET_ARCH_IS_64_BIT)
48 void WriteXWord(uint64_t value) {
49 stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
50 }
51#endif
52
53 private:
54 StreamingWriteStream* const stream_;
55};
56
57static constexpr intptr_t kLinearInitValue = -1;
58
59#define DEFINE_LINEAR_FIELD_METHODS(name) \
60 intptr_t name() const { \
61 ASSERT(name##_ != kLinearInitValue); \
62 return name##_; \
63 } \
64 bool name##_is_set() const { return name##_ != kLinearInitValue; } \
65 void set_##name(intptr_t value) { \
66 ASSERT(value != kLinearInitValue); \
67 ASSERT_EQUAL(name##_, kLinearInitValue); \
68 name##_ = value; \
69 }
70
71#define DEFINE_LINEAR_FIELD(name) intptr_t name##_ = kLinearInitValue;
72
73class BitsContainer;
74class Segment;
75
76static constexpr intptr_t kDefaultAlignment = -1;
77// Align note sections and segments to 4 byte boundries.
78static constexpr intptr_t kNoteAlignment = 4;
79
80class Section : public ZoneAllocated {
81 public:
82 Section(elf::SectionHeaderType t,
83 bool allocate,
84 bool executable,
85 bool writable,
86 intptr_t align = kDefaultAlignment)
87 : type(t),
88 flags(EncodeFlags(allocate, executable, writable)),
89 alignment(align == kDefaultAlignment ? DefaultAlignment(t) : align),
90 // Non-segments will never have a memory offset, here represented by 0.
91 memory_offset_(allocate ? kLinearInitValue : 0) {
92 // Only sections with type SHT_NULL are allowed to have an alignment of 0.
93 ASSERT(type == elf::SectionHeaderType::SHT_NULL || alignment > 0);
94 // Non-zero alignments must be a power of 2.
95 ASSERT(alignment == 0 || Utils::IsPowerOfTwo(alignment));
96 }
97
98 virtual ~Section() {}
99
100 // Linker view.
101 const elf::SectionHeaderType type;
102 const intptr_t flags;
103 const intptr_t alignment;
104
105 // These are fields that only are not set for most kinds of sections and so we
106 // set them to a reasonable default.
107 intptr_t link = elf::SHN_UNDEF;
108 intptr_t info = 0;
109 intptr_t entry_size = 0;
110
111 // Stores the name for the symbol that should be created in the dynamic (and
112 // static, if unstripped) tables for this section.
113 const char* symbol_name = nullptr;
114
115#define FOR_EACH_SECTION_LINEAR_FIELD(M) \
116 M(name) \
117 M(index) \
118 M(file_offset)
119
120 FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
121
122 virtual intptr_t FileSize() const = 0;
123
124 // Loader view.
125#define FOR_EACH_SEGMENT_LINEAR_FIELD(M) M(memory_offset)
126
127 FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
128
129 // Each section belongs to at most one PT_LOAD segment.
130 const Segment* load_segment = nullptr;
131
132 virtual intptr_t MemorySize() const = 0;
133
134 // Other methods.
135
136 bool IsAllocated() const {
137 return (flags & elf::SHF_ALLOC) == elf::SHF_ALLOC;
138 }
139 bool IsExecutable() const {
140 return (flags & elf::SHF_EXECINSTR) == elf::SHF_EXECINSTR;
141 }
142 bool IsWritable() const { return (flags & elf::SHF_WRITE) == elf::SHF_WRITE; }
143
144 // Returns whether new content can be added to a section.
145 bool HasBeenFinalized() const {
146 if (IsAllocated()) {
147 // The contents of a section that is allocated (part of a segment) must
148 // not change after the section is added.
149 return memory_offset_is_set();
150 } else {
151 // Unallocated sections can have new content added until we calculate
152 // file offsets.
153 return file_offset_is_set();
154 }
155 }
156
157 virtual const BitsContainer* AsBitsContainer() const { return nullptr; }
158
159 // Writes the file contents of the section.
160 virtual void Write(ElfWriteStream* stream) = 0;
161
162 virtual void WriteSectionHeader(ElfWriteStream* stream) {
163#if defined(TARGET_ARCH_IS_32_BIT)
164 stream->WriteWord(name());
165 stream->WriteWord(static_cast<uint32_t>(type));
166 stream->WriteWord(flags);
167 stream->WriteAddr(memory_offset());
168 stream->WriteOff(file_offset());
169 stream->WriteWord(FileSize()); // Has different meaning for BSS.
170 stream->WriteWord(link);
171 stream->WriteWord(info);
172 stream->WriteWord(alignment);
173 stream->WriteWord(entry_size);
174#else
175 stream->WriteWord(name());
176 stream->WriteWord(static_cast<uint32_t>(type));
177 stream->WriteXWord(flags);
178 stream->WriteAddr(memory_offset());
179 stream->WriteOff(file_offset());
180 stream->WriteXWord(FileSize()); // Has different meaning for BSS.
181 stream->WriteWord(link);
182 stream->WriteWord(info);
183 stream->WriteXWord(alignment);
184 stream->WriteXWord(entry_size);
185#endif
186 }
187
188 private:
189 static intptr_t EncodeFlags(bool allocate, bool executable, bool writable) {
190 if (!allocate) return 0;
191 intptr_t flags = elf::SHF_ALLOC;
192 if (executable) flags |= elf::SHF_EXECINSTR;
193 if (writable) flags |= elf::SHF_WRITE;
194 return flags;
195 }
196
197 static intptr_t DefaultAlignment(elf::SectionHeaderType type) {
198 switch (type) {
199 case elf::SectionHeaderType::SHT_SYMTAB:
200 case elf::SectionHeaderType::SHT_DYNSYM:
201 case elf::SectionHeaderType::SHT_HASH:
202 case elf::SectionHeaderType::SHT_DYNAMIC:
203 return compiler::target::kWordSize;
204 default:
205 return 1;
206 }
207 }
208
209 FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
210 FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
211
212#undef FOR_EACH_SECTION_LINEAR_FIELD
213#undef FOR_EACH_SEGMENT_LINEAR_FIELD
214};
215
216#undef DEFINE_LINEAR_FIELD
217#undef DEFINE_LINEAR_FIELD_METHODS
218
219class Segment : public ZoneAllocated {
220 public:
221 Segment(Zone* zone,
222 Section* initial_section,
223 elf::ProgramHeaderType segment_type)
224 : type(segment_type),
225 // Flags for the segment are the same as the initial section.
226 flags(EncodeFlags(ASSERT_NOTNULL(initial_section)->IsExecutable(),
227 ASSERT_NOTNULL(initial_section)->IsWritable())),
228 sections_(zone, 0) {
229 // Unlike sections, we don't have a reserved segment with the null type,
230 // so we never should pass this value.
231 ASSERT(segment_type != elf::ProgramHeaderType::PT_NULL);
232 // All segments should have at least one section. The first one is added
233 // during initialization. Unlike others added later, it should already have
234 // a memory offset since we use it to determine the segment memory offset.
235 ASSERT(initial_section->IsAllocated());
236 ASSERT(initial_section->memory_offset_is_set());
237 sections_.Add(initial_section);
238 if (type == elf::ProgramHeaderType::PT_LOAD) {
239 ASSERT(initial_section->load_segment == nullptr);
240 initial_section->load_segment = this;
241 }
242 }
243
244 virtual ~Segment() {}
245
246 static intptr_t Alignment(elf::ProgramHeaderType segment_type) {
247 switch (segment_type) {
248 case elf::ProgramHeaderType::PT_DYNAMIC:
249 return compiler::target::kWordSize;
250 case elf::ProgramHeaderType::PT_NOTE:
251 return kNoteAlignment;
252 default:
253 return Elf::kPageSize;
254 }
255 }
256
257 bool IsExecutable() const { return (flags & elf::PF_X) == elf::PF_X; }
258 bool IsWritable() const { return (flags & elf::PF_W) == elf::PF_W; }
259
260 void WriteProgramHeader(ElfWriteStream* stream) {
261#if defined(TARGET_ARCH_IS_32_BIT)
262 stream->WriteWord(static_cast<uint32_t>(type));
263 stream->WriteOff(FileOffset());
264 stream->WriteAddr(MemoryOffset()); // Virtual address.
265 stream->WriteAddr(MemoryOffset()); // Physical address, not used.
266 stream->WriteWord(FileSize());
267 stream->WriteWord(MemorySize());
268 stream->WriteWord(flags);
269 stream->WriteWord(Alignment(type));
270#else
271 stream->WriteWord(static_cast<uint32_t>(type));
272 stream->WriteWord(flags);
273 stream->WriteOff(FileOffset());
274 stream->WriteAddr(MemoryOffset()); // Virtual address.
275 stream->WriteAddr(MemoryOffset()); // Physical address, not used.
276 stream->WriteXWord(FileSize());
277 stream->WriteXWord(MemorySize());
278 stream->WriteXWord(Alignment(type));
279#endif
280 }
281
282 // Adds the given section to this segment.
283 //
284 // Returns whether the Section could be added to the segment. If not, a
285 // new segment will need to be created for this section.
286 //
287 // Sets the memory offset of the section if added.
288 bool Add(Section* section) {
289 // We only add additional sections to load segments.
290 ASSERT(type == elf::ProgramHeaderType::PT_LOAD);
291 ASSERT(section != nullptr);
292 // Only sections with the allocate flag set should be added to segments,
293 // and sections with already-set memory offsets cannot be added.
294 ASSERT(section->IsAllocated());
295 ASSERT(!section->memory_offset_is_set());
296 ASSERT(section->load_segment == nullptr);
297 switch (sections_.Last()->type) {
298 // We only use SHT_NULL sections as pseudo sections that will not appear
299 // in the final ELF file. Don't pack sections into these segments, as we
300 // may remove/replace the segments during finalization.
301 case elf::SectionHeaderType::SHT_NULL:
302 // If the last section in the segments is NOBITS, then we don't add it,
303 // as otherwise we'll be guaranteed the file offset and memory offset
304 // won't be page aligned without padding.
305 case elf::SectionHeaderType::SHT_NOBITS:
306 return false;
307 default:
308 break;
309 }
310 // We don't add if the W or X bits don't match.
311 if (IsExecutable() != section->IsExecutable() ||
312 IsWritable() != section->IsWritable()) {
313 return false;
314 }
315 auto const start_address = Utils::RoundUp(MemoryEnd(), section->alignment);
316 section->set_memory_offset(start_address);
317 sections_.Add(section);
318 section->load_segment = this;
319 return true;
320 }
321
322 intptr_t FileOffset() const { return sections_[0]->file_offset(); }
323
324 intptr_t FileSize() const {
325 auto const last = sections_.Last();
326 const intptr_t end = last->file_offset() + last->FileSize();
327 return end - FileOffset();
328 }
329
330 intptr_t MemoryOffset() const { return sections_[0]->memory_offset(); }
331
332 intptr_t MemorySize() const {
333 auto const last = sections_.Last();
334 const intptr_t end = last->memory_offset() + last->MemorySize();
335 return end - MemoryOffset();
336 }
337
338 intptr_t MemoryEnd() const { return MemoryOffset() + MemorySize(); }
339
340 private:
341 static constexpr intptr_t kInitValue = -1;
342 static_assert(kInitValue < 0, "init value must be negative");
343
344 static intptr_t EncodeFlags(bool executable, bool writable) {
345 intptr_t flags = elf::PF_R;
346 if (executable) flags |= elf::PF_X;
347 if (writable) flags |= elf::PF_W;
348 return flags;
349 }
350
351 public:
352 const elf::ProgramHeaderType type;
353 const intptr_t flags;
354
355 private:
356 GrowableArray<const Section*> sections_;
357};
358
359// Represents the first entry in the section table, which should only contain
360// zero values and does not correspond to a memory segment.
361class ReservedSection : public Section {
362 public:
363 ReservedSection()
364 : Section(elf::SectionHeaderType::SHT_NULL,
365 /*allocate=*/false,
366 /*executable=*/false,
367 /*writable=*/false,
368 /*alignment=*/0) {
369 set_name(0);
370 set_index(0);
371 set_file_offset(0);
372 }
373
374 intptr_t FileSize() const { return 0; }
375 intptr_t MemorySize() const { return 0; }
376 void Write(ElfWriteStream* stream) {}
377};
378
379// Represents portions of the file/memory space which do not correspond to
380// actual sections. Should never be added to sections_.
381class PseudoSection : public Section {
382 public:
383 PseudoSection(bool executable,
384 bool writable,
385 intptr_t file_offset,
386 intptr_t file_size,
387 intptr_t memory_offset,
388 intptr_t memory_size)
389 : Section(elf::SectionHeaderType::SHT_NULL,
390 /*allocate=*/true,
391 executable,
392 writable,
393 /*alignment=*/0),
394 file_size_(file_size),
395 memory_size_(memory_size) {
396 set_file_offset(file_offset);
397 set_memory_offset(memory_offset);
398 }
399
400 intptr_t FileSize() const { return file_size_; }
401 intptr_t MemorySize() const { return memory_size_; }
402 void WriteSectionHeader(ElfWriteStream* stream) { UNREACHABLE(); }
403 void Write(ElfWriteStream* stream) { UNREACHABLE(); }
404
405 private:
406 const intptr_t file_size_;
407 const intptr_t memory_size_;
408};
409
410// A segment for representing the program header table self-reference in the
411// program header table.
412class ProgramTableSelfSegment : public Segment {
413 public:
414 ProgramTableSelfSegment(Zone* zone, intptr_t offset, intptr_t size)
415 : Segment(zone,
416 new (zone) PseudoSection(/*executable=*/false,
417 /*writable=*/false,
418 offset,
419 size,
420 offset,
421 size),
422 elf::ProgramHeaderType::PT_PHDR) {}
423};
424
425// A segment for representing the program header table load segment in the
426// program header table.
427class ProgramTableLoadSegment : public Segment {
428 public:
429 // The Android dynamic linker in Jelly Bean incorrectly assumes that all
430 // non-writable segments are continguous. Since the BSS segment comes directly
431 // after the program header segment, we must make this segment writable so
432 // later non-writable segments does not cause the BSS to be also marked as
433 // read-only.
434 //
435 // The bug is here:
436 // https://github.com/aosp-mirror/platform_bionic/blob/94963af28e445384e19775a838a29e6a71708179/linker/linker.c#L1991-L2001
437 explicit ProgramTableLoadSegment(Zone* zone, intptr_t size)
438 : Segment(zone,
439 // This segment should always start at address 0.
440 new (zone) PseudoSection(/*executable=*/false,
441 /*writable=*/true,
442 0,
443 size,
444 0,
445 size),
446 elf::ProgramHeaderType::PT_LOAD) {}
447};
448
449class BitsContainer : public Section {
450 public:
451 // Fully specified BitsContainer information.
452 BitsContainer(elf::SectionHeaderType type,
453 bool allocate,
454 bool executable,
455 bool writable,
456 intptr_t size,
457 const uint8_t* bytes,
458 int alignment = kDefaultAlignment)
459 : Section(type, allocate, executable, writable, alignment),
460 file_size_(type == elf::SectionHeaderType::SHT_NOBITS ? 0 : size),
461 memory_size_(allocate ? size : 0),
462 bytes_(bytes) {
463 ASSERT(type == elf::SectionHeaderType::SHT_NOBITS || bytes != nullptr);
464 }
465
466 // For BitsContainers used only as sections.
467 BitsContainer(elf::SectionHeaderType type,
468 intptr_t size,
469 const uint8_t* bytes,
470 intptr_t alignment = kDefaultAlignment)
471 : BitsContainer(type,
472 /*allocate=*/false,
473 /*executable=*/false,
474 /*writable=*/false,
475 size,
476 bytes,
477 alignment) {}
478
479 // For BitsContainers used as segments whose type differ on the type of the
480 // ELF file. Creates an elf::SHT_NOBITS section if type is DebugInfo,
481 // otherwise creates an elf::SHT_PROGBITS section.
482 BitsContainer(Elf::Type t,
483 bool executable,
484 bool writable,
485 intptr_t size,
486 const uint8_t* bytes,
487 intptr_t alignment = kDefaultAlignment)
488 : BitsContainer(t == Elf::Type::DebugInfo
489 ? elf::SectionHeaderType::SHT_NOBITS
490 : elf::SectionHeaderType::SHT_PROGBITS,
491 /*allocate=*/true,
492 executable,
493 writable,
494 size,
495 bytes,
496 alignment) {}
497
498 const BitsContainer* AsBitsContainer() const { return this; }
499
500 void Write(ElfWriteStream* stream) {
501 if (type != elf::SectionHeaderType::SHT_NOBITS) {
502 stream->WriteBytes(bytes_, FileSize());
503 }
504 }
505
506 intptr_t FileSize() const { return file_size_; }
507 intptr_t MemorySize() const { return memory_size_; }
508 const uint8_t* bytes() const { return bytes_; }
509
510 private:
511 const intptr_t file_size_;
512 const intptr_t memory_size_;
513 const uint8_t* const bytes_;
514};
515
516class StringTable : public Section {
517 public:
518 explicit StringTable(Zone* zone, bool allocate)
519 : Section(elf::SectionHeaderType::SHT_STRTAB,
520 allocate,
521 /*executable=*/false,
522 /*writable=*/false),
523 dynamic_(allocate),
524 text_(zone, 128),
525 text_indices_(zone) {
526 text_.AddChar('\0');
527 text_indices_.Insert({"", 1});
528 }
529
530 intptr_t FileSize() const { return text_.length(); }
531 intptr_t MemorySize() const { return dynamic_ ? FileSize() : 0; }
532
533 void Write(ElfWriteStream* stream) {
534 stream->WriteBytes(reinterpret_cast<const uint8_t*>(text_.buffer()),
535 text_.length());
536 }
537
538 intptr_t AddString(const char* str) {
539 if (auto const kv = text_indices_.Lookup(str)) return kv->value - 1;
540 intptr_t offset = text_.length();
541 text_.AddString(str);
542 text_.AddChar('\0');
543 text_indices_.Insert({str, offset + 1});
544 return offset;
545 }
546
547 const char* At(intptr_t index) {
548 ASSERT(index < text_.length());
549 return text_.buffer() + index;
550 }
551 intptr_t Lookup(const char* str) const {
552 return text_indices_.LookupValue(str) - 1;
553 }
554
555 const bool dynamic_;
556 ZoneTextBuffer text_;
557 // To avoid kNoValue for intptr_t (0), we store an index n as n + 1.
558 CStringMap<intptr_t> text_indices_;
559};
560
561class Symbol : public ZoneAllocated {
562 public:
563 Symbol(const char* cstr,
564 intptr_t name,
565 intptr_t info,
566 intptr_t section,
567 intptr_t offset,
568 intptr_t size)
569 : name_index(name),
570 info(info),
571 section_index(section),
572 offset(offset),
573 size(size),
574 cstr_(cstr) {}
575
576 void Write(ElfWriteStream* stream) const {
577 const intptr_t start = stream->position();
578 stream->WriteWord(name_index);
579#if defined(TARGET_ARCH_IS_32_BIT)
580 stream->WriteAddr(offset);
581 stream->WriteWord(size);
582 stream->WriteByte(info);
583 stream->WriteByte(0);
584 stream->WriteHalf(section_index);
585#else
586 stream->WriteByte(info);
587 stream->WriteByte(0);
588 stream->WriteHalf(section_index);
589 stream->WriteAddr(offset);
590 stream->WriteXWord(size);
591#endif
592 ASSERT_EQUAL(stream->position() - start, sizeof(elf::Symbol));
593 }
594
595 const intptr_t name_index;
596 const intptr_t info;
597 const intptr_t section_index;
598 const intptr_t offset;
599 const intptr_t size;
600
601 private:
602 friend class SymbolHashTable; // For cstr_ access.
603
604 const char* const cstr_;
605};
606
607class SymbolTable : public Section {
608 public:
609 SymbolTable(Zone* zone, bool dynamic)
610 : Section(dynamic ? elf::SectionHeaderType::SHT_DYNSYM
611 : elf::SectionHeaderType::SHT_SYMTAB,
612 dynamic,
613 /*executable=*/false,
614 /*writable=*/false),
615 dynamic_(dynamic),
616 reserved_("", 0, 0, 0, 0, 0),
617 symbols_(zone, 1) {
618 entry_size = sizeof(elf::Symbol);
619 // The first symbol table entry is reserved and must be all zeros.
620 symbols_.Add(&reserved_);
621 info = 1; // One "local" symbol, the reserved first entry.
622 }
623
624 intptr_t FileSize() const { return Length() * entry_size; }
625 intptr_t MemorySize() const { return dynamic_ ? FileSize() : 0; }
626
627 void Write(ElfWriteStream* stream) {
628 for (intptr_t i = 0; i < Length(); i++) {
629 auto const symbol = At(i);
630 const intptr_t start = stream->position();
631 symbol->Write(stream);
632 ASSERT_EQUAL(stream->position() - start, entry_size);
633 }
634 }
635
636 void AddSymbol(const Symbol* symbol) { symbols_.Add(symbol); }
637 intptr_t Length() const { return symbols_.length(); }
638 const Symbol* At(intptr_t i) const { return symbols_[i]; }
639
640 const Symbol* FindSymbolWithNameIndex(intptr_t name_index) const {
641 for (intptr_t i = 0; i < Length(); i++) {
642 auto const symbol = At(i);
643 if (symbol->name_index == name_index) return symbol;
644 }
645 return nullptr;
646 }
647
648 private:
649 const bool dynamic_;
650 const Symbol reserved_;
651 GrowableArray<const Symbol*> symbols_;
652};
653
654static uint32_t ElfHash(const unsigned char* name) {
655 uint32_t h = 0;
656 while (*name != '\0') {
657 h = (h << 4) + *name++;
658 uint32_t g = h & 0xf0000000;
659 h ^= g;
660 h ^= g >> 24;
661 }
662 return h;
663}
664
665class SymbolHashTable : public Section {
666 public:
667 SymbolHashTable(Zone* zone, StringTable* strtab, SymbolTable* symtab)
668 : Section(elf::SectionHeaderType::SHT_HASH,
669 /*allocate=*/true,
670 /*executable=*/false,
671 /*writable=*/false) {
672 link = symtab->index();
673 entry_size = sizeof(int32_t);
674
675 nchain_ = symtab->Length();
676 nbucket_ = symtab->Length();
677
678 bucket_ = zone->Alloc<int32_t>(nbucket_);
679 for (intptr_t i = 0; i < nbucket_; i++) {
680 bucket_[i] = elf::STN_UNDEF;
681 }
682
683 chain_ = zone->Alloc<int32_t>(nchain_);
684 for (intptr_t i = 0; i < nchain_; i++) {
685 chain_[i] = elf::STN_UNDEF;
686 }
687
688 for (intptr_t i = 1; i < symtab->Length(); i++) {
689 auto const symbol = symtab->At(i);
690 uint32_t hash = ElfHash((const unsigned char*)symbol->cstr_);
691 uint32_t probe = hash % nbucket_;
692 chain_[i] = bucket_[probe]; // next = head
693 bucket_[probe] = i; // head = symbol
694 }
695 }
696
697 intptr_t FileSize() const { return entry_size * (nbucket_ + nchain_ + 2); }
698 intptr_t MemorySize() const { return FileSize(); }
699
700 void Write(ElfWriteStream* stream) {
701 stream->WriteWord(nbucket_);
702 stream->WriteWord(nchain_);
703 for (intptr_t i = 0; i < nbucket_; i++) {
704 stream->WriteWord(bucket_[i]);
705 }
706 for (intptr_t i = 0; i < nchain_; i++) {
707 stream->WriteWord(chain_[i]);
708 }
709 }
710
711 private:
712 int32_t nbucket_;
713 int32_t nchain_;
714 int32_t* bucket_; // "Head"
715 int32_t* chain_; // "Next"
716};
717
718class DynamicTable : public Section {
719 public:
720 DynamicTable(Zone* zone,
721 StringTable* strtab,
722 SymbolTable* symtab,
723 SymbolHashTable* hash)
724 : Section(elf::SectionHeaderType::SHT_DYNAMIC,
725 /*allocate=*/true,
726 /*executable=*/false,
727 /*writable=*/true) {
728 link = strtab->index();
729 entry_size = sizeof(elf::DynamicEntry);
730
731 AddEntry(zone, elf::DynamicEntryType::DT_HASH, hash->memory_offset());
732 AddEntry(zone, elf::DynamicEntryType::DT_STRTAB, strtab->memory_offset());
733 AddEntry(zone, elf::DynamicEntryType::DT_STRSZ, strtab->MemorySize());
734 AddEntry(zone, elf::DynamicEntryType::DT_SYMTAB, symtab->memory_offset());
735 AddEntry(zone, elf::DynamicEntryType::DT_SYMENT, sizeof(elf::Symbol));
736 AddEntry(zone, elf::DynamicEntryType::DT_NULL, 0);
737 }
738
739 intptr_t FileSize() const { return entries_.length() * entry_size; }
740 intptr_t MemorySize() const { return FileSize(); }
741
742 void Write(ElfWriteStream* stream) {
743 for (intptr_t i = 0; i < entries_.length(); i++) {
744 entries_[i]->Write(stream);
745 }
746 }
747
748 struct Entry : public ZoneAllocated {
749 Entry(elf::DynamicEntryType tag, intptr_t value) : tag(tag), value(value) {}
750
751 void Write(ElfWriteStream* stream) {
752 const intptr_t start = stream->position();
753#if defined(TARGET_ARCH_IS_32_BIT)
754 stream->WriteWord(static_cast<uint32_t>(tag));
755 stream->WriteAddr(value);
756#else
757 stream->WriteXWord(static_cast<uint64_t>(tag));
758 stream->WriteAddr(value);
759#endif
760 ASSERT_EQUAL(stream->position() - start, sizeof(elf::DynamicEntry));
761 }
762
763 elf::DynamicEntryType tag;
764 intptr_t value;
765 };
766
767 void AddEntry(Zone* zone, elf::DynamicEntryType tag, intptr_t value) {
768 auto const entry = new (zone) Entry(tag, value);
769 entries_.Add(entry);
770 }
771
772 private:
773 GrowableArray<Entry*> entries_;
774};
775
776// A segment for representing the dynamic table segment in the program header
777// table. There is no corresponding section for this segment.
778class DynamicSegment : public Segment {
779 public:
780 explicit DynamicSegment(Zone* zone, DynamicTable* dynamic)
781 : Segment(zone, dynamic, elf::ProgramHeaderType::PT_DYNAMIC) {}
782};
783
784// A segment for representing the dynamic table segment in the program header
785// table. There is no corresponding section for this segment.
786class NoteSegment : public Segment {
787 public:
788 NoteSegment(Zone* zone, Section* note)
789 : Segment(zone, note, elf::ProgramHeaderType::PT_NOTE) {
790 ASSERT_EQUAL(static_cast<uint32_t>(note->type),
791 static_cast<uint32_t>(elf::SectionHeaderType::SHT_NOTE));
792 }
793};
794
795static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
796
797// Here, both VM and isolate will be compiled into a single snapshot.
798// In assembly generation, each serialized text section gets a separate
799// pointer into the BSS segment and BSS slots are created for each, since
800// we may not serialize both VM and isolate. Here, we always serialize both,
801// so make a BSS segment large enough for both, with the VM entries coming
802// first.
803static constexpr const char* kSnapshotBssAsmSymbol = "_kDartBSSData";
804static const intptr_t kBssIsolateOffset =
805 BSS::kVmEntryCount * compiler::target::kWordSize;
806static const intptr_t kBssSize =
807 kBssIsolateOffset + BSS::kIsolateEntryCount * compiler::target::kWordSize;
808
809Elf::Elf(Zone* zone, StreamingWriteStream* stream, Type type, Dwarf* dwarf)
810 : zone_(zone),
811 unwrapped_stream_(stream),
812 type_(type),
813 dwarf_(dwarf),
814 bss_(CreateBSS(zone, type, kBssSize)),
815 shstrtab_(new (zone) StringTable(zone, /*allocate=*/false)),
816 dynstrtab_(new (zone) StringTable(zone, /*allocate=*/true)),
817 dynsym_(new (zone) SymbolTable(zone, /*dynamic=*/true)) {
818 // Separate debugging information should always have a Dwarf object.
819 ASSERT(type_ == Type::Snapshot || dwarf_ != nullptr);
820 // Assumed by various offset logic in this file.
821 ASSERT_EQUAL(unwrapped_stream_->position(), 0);
822 // The first section in the section header table is always a reserved
823 // entry containing only 0 values.
824 sections_.Add(new (zone_) ReservedSection());
825 if (!IsStripped()) {
826 // Not a stripped ELF file, so allocate static string and symbol tables.
827 strtab_ = new (zone_) StringTable(zone_, /* allocate= */ false);
828 symtab_ = new (zone_) SymbolTable(zone, /*dynamic=*/false);
829 }
830 // We add an initial segment to represent reserved space for the program
831 // header, and so we can always assume there's at least one segment in the
832 // segments_ array. We later remove this and replace it with appropriately
833 // calculated segments in Elf::FinalizeProgramTable().
834 auto const start_segment =
835 new (zone_) ProgramTableLoadSegment(zone_, kProgramTableSegmentSize);
836 segments_.Add(start_segment);
837 // Note that the BSS segment must be the first user-defined segment because
838 // it cannot be placed in between any two non-writable segments, due to a bug
839 // in Jelly Bean's ELF loader. See also Elf::WriteProgramTable().
840 //
841 // We add it in all cases, even to the separate debugging information ELF,
842 // to ensure that relocated addresses are consistent between ELF snapshots
843 // and ELF separate debugging information.
844 AddSection(bss_, ".bss", kSnapshotBssAsmSymbol);
845}
846
847intptr_t Elf::NextMemoryOffset() const {
848 return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), Elf::kPageSize);
849}
850
851uword Elf::BssStart(bool vm) const {
852 return bss_->memory_offset() + (vm ? 0 : kBssIsolateOffset);
853}
854
855intptr_t Elf::AddSection(Section* section,
856 const char* name,
857 const char* symbol_name) {
858 ASSERT(section_table_file_size_ < 0);
859 ASSERT(!shstrtab_->HasBeenFinalized());
860 section->set_name(shstrtab_->AddString(name));
861 section->set_index(sections_.length());
862 sections_.Add(section);
863
864 // No memory offset, so just return -1.
865 if (!section->IsAllocated()) return -1;
866
867 ASSERT(program_table_file_size_ < 0);
868 auto const last_load = LastLoadSegment();
869 if (!last_load->Add(section)) {
870 // We can't add this section to the last load segment, so create a new one.
871 // The new segment starts at the next aligned address.
872 auto const type = elf::ProgramHeaderType::PT_LOAD;
873 auto const start_address =
874 Utils::RoundUp(last_load->MemoryEnd(), Segment::Alignment(type));
875 section->set_memory_offset(start_address);
876 auto const segment = new (zone_) Segment(zone_, section, type);
877 segments_.Add(segment);
878 }
879 if (symbol_name != nullptr) {
880 section->symbol_name = symbol_name;
881 }
882 return section->memory_offset();
883}
884
885intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
886 // When making a separate debugging info file for assembly, we don't have
887 // the binary text segment contents.
888 ASSERT(type_ == Type::DebugInfo || bytes != nullptr);
889 auto const image = new (zone_)
890 BitsContainer(type_, /*executable=*/true,
891 /*writable=*/false, size, bytes, Elf::kPageSize);
892 return AddSection(image, ".text", name);
893}
894
895Section* Elf::CreateBSS(Zone* zone, Type type, intptr_t size) {
896 uint8_t* bytes = nullptr;
897 if (type != Type::DebugInfo) {
898 // Ideally the BSS segment would take no space in the object, but Android's
899 // "strip" utility truncates the memory-size of our segments to their
900 // file-size.
901 //
902 // Therefore we must insert zero-filled pages for the BSS.
903 bytes = zone->Alloc<uint8_t>(size);
904 memset(bytes, 0, size);
905 }
906 return new (zone) BitsContainer(type, /*executable=*/false, /*writable=*/true,
907 kBssSize, bytes, Image::kBssAlignment);
908}
909
910intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
911 ASSERT(bytes != nullptr);
912 auto const image = new (zone_)
913 BitsContainer(type_, /*executable=*/false,
914 /*writable=*/false, size, bytes, kMaxObjectAlignment);
915 return AddSection(image, ".rodata", name);
916}
917
918void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) {
919 ASSERT(!IsStripped());
920 ASSERT(bytes != nullptr);
921 auto const image = new (zone_)
922 BitsContainer(elf::SectionHeaderType::SHT_PROGBITS, size, bytes);
923 AddSection(image, name);
924}
925
926void Elf::AddDynamicSymbol(const char* name,
927 intptr_t info,
928 intptr_t section_index,
929 intptr_t address,
930 intptr_t size) {
931 ASSERT(!dynstrtab_->HasBeenFinalized() && !dynsym_->HasBeenFinalized());
932 auto const name_index = dynstrtab_->AddString(name);
933 auto const symbol =
934 new (zone_) Symbol(name, name_index, info, section_index, address, size);
935 dynsym_->AddSymbol(symbol);
936
937 // Some tools assume the static symbol table is a superset of the dynamic
938 // symbol table when it exists (see dartbug.com/41783).
939 AddStaticSymbol(name, info, section_index, address, size);
940}
941
942void Elf::AddStaticSymbol(const char* name,
943 intptr_t info,
944 intptr_t section_index,
945 intptr_t address,
946 intptr_t size) {
947 if (IsStripped()) return; // No static info kept in stripped ELF files.
948 ASSERT(!symtab_->HasBeenFinalized() && !strtab_->HasBeenFinalized());
949 auto const name_index = strtab_->AddString(name);
950 auto const symbol =
951 new (zone_) Symbol(name, name_index, info, section_index, address, size);
952 symtab_->AddSymbol(symbol);
953}
954
955#if defined(DART_PRECOMPILER)
956class DwarfElfStream : public DwarfWriteStream {
957 public:
958 explicit DwarfElfStream(Zone* zone,
959 WriteStream* stream,
960 const CStringMap<intptr_t>& address_map)
961 : zone_(zone),
962 stream_(ASSERT_NOTNULL(stream)),
963 address_map_(address_map) {}
964
965 void sleb128(intptr_t value) {
966 bool is_last_part = false;
967 while (!is_last_part) {
968 uint8_t part = value & 0x7F;
969 value >>= 7;
970 if ((value == 0 && (part & 0x40) == 0) ||
971 (value == static_cast<intptr_t>(-1) && (part & 0x40) != 0)) {
972 is_last_part = true;
973 } else {
974 part |= 0x80;
975 }
976 stream_->WriteFixed(part);
977 }
978 }
979
980 void uleb128(uintptr_t value) {
981 bool is_last_part = false;
982 while (!is_last_part) {
983 uint8_t part = value & 0x7F;
984 value >>= 7;
985 if (value == 0) {
986 is_last_part = true;
987 } else {
988 part |= 0x80;
989 }
990 stream_->WriteFixed(part);
991 }
992 }
993
994 void u1(uint8_t value) { stream_->WriteFixed(value); }
995 // Can't use WriteFixed for these, as we may not be at aligned positions.
996 void u2(uint16_t value) { stream_->WriteBytes(&value, sizeof(value)); }
997 void u4(uint32_t value) { stream_->WriteBytes(&value, sizeof(value)); }
998 void u8(uint64_t value) { stream_->WriteBytes(&value, sizeof(value)); }
999 void string(const char* cstr) { // NOLINT
1000 stream_->WriteBytes(reinterpret_cast<const uint8_t*>(cstr),
1001 strlen(cstr) + 1);
1002 }
1003 intptr_t position() { return stream_->Position(); }
1004 intptr_t ReserveSize(const char* prefix, intptr_t* start) {
1005 ASSERT(start != nullptr);
1006 intptr_t fixup = position();
1007 // We assume DWARF v2, so all sizes are 32-bit.
1008 u4(0);
1009 // All sizes for DWARF sections measure the size of the section data _after_
1010 // the size value.
1011 *start = position();
1012 return fixup;
1013 }
1014 void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
1015 const uint32_t value = position() - start;
1016 memmove(stream_->buffer() + fixup, &value, sizeof(value));
1017 }
1018 void OffsetFromSymbol(const char* symbol, intptr_t offset) {
1019 auto const address = address_map_.LookupValue(symbol);
1020 ASSERT(address != 0);
1021 addr(address + offset);
1022 }
1023 void DistanceBetweenSymbolOffsets(const char* symbol1,
1024 intptr_t offset1,
1025 const char* symbol2,
1026 intptr_t offset2) {
1027 auto const address1 = address_map_.LookupValue(symbol1);
1028 ASSERT(address1 != 0);
1029 auto const address2 = address_map_.LookupValue(symbol2);
1030 ASSERT(address2 != 0);
1031 auto const delta = (address1 + offset1) - (address2 + offset2);
1032 RELEASE_ASSERT(delta >= 0);
1033 uleb128(delta);
1034 }
1035 void InitializeAbstractOrigins(intptr_t size) {
1036 abstract_origins_size_ = size;
1037 abstract_origins_ = zone_->Alloc<uint32_t>(abstract_origins_size_);
1038 }
1039 void RegisterAbstractOrigin(intptr_t index) {
1040 ASSERT(abstract_origins_ != nullptr);
1041 ASSERT(index < abstract_origins_size_);
1042 abstract_origins_[index] = position();
1043 }
1044 void AbstractOrigin(intptr_t index) { u4(abstract_origins_[index]); }
1045
1046 private:
1047 void addr(uword value) {
1048#if defined(TARGET_ARCH_IS_32_BIT)
1049 u4(value);
1050#else
1051 u8(value);
1052#endif
1053 }
1054
1055 Zone* const zone_;
1056 WriteStream* const stream_;
1057 const CStringMap<intptr_t>& address_map_;
1058 uint32_t* abstract_origins_ = nullptr;
1059 intptr_t abstract_origins_size_ = -1;
1060
1061 DISALLOW_COPY_AND_ASSIGN(DwarfElfStream);
1062};
1063
1064static constexpr intptr_t kInitialDwarfBufferSize = 64 * KB;
1065#endif
1066
1067static uint8_t* ZoneReallocate(uint8_t* ptr, intptr_t len, intptr_t new_len) {
1068 return Thread::Current()->zone()->Realloc<uint8_t>(ptr, len, new_len);
1069}
1070
1071Segment* Elf::LastLoadSegment() const {
1072 for (intptr_t i = segments_.length() - 1; i >= 0; i--) {
1073 auto const segment = segments_.At(i);
1074 if (segment->type == elf::ProgramHeaderType::PT_LOAD) {
1075 return segment;
1076 }
1077 }
1078 // There should always be a load segment, since one is added in construction.
1079 UNREACHABLE();
1080}
1081
1082const Section* Elf::FindSectionForAddress(intptr_t address) const {
1083 for (auto const section : sections_) {
1084 if (!section->IsAllocated()) continue;
1085 auto const start = section->memory_offset();
1086 auto const end = start + section->MemorySize();
1087 if (address >= start && address < end) {
1088 return section;
1089 }
1090 }
1091 return nullptr;
1092}
1093
1094void Elf::AddSectionSymbols() {
1095 for (auto const section : sections_) {
1096 if (section->symbol_name == nullptr) continue;
1097 ASSERT(section->memory_offset_is_set());
1098 // While elf::STT_SECTION might seem more appropriate, those symbols are
1099 // usually local and dlsym won't return them.
1100 auto const info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
1101 AddDynamicSymbol(section->symbol_name, info, section->index(),
1102 section->memory_offset(), section->MemorySize());
1103 }
1104}
1105
1106void Elf::FinalizeDwarfSections() {
1107 if (dwarf_ == nullptr) return;
1108#if defined(DART_PRECOMPILER)
1109 // Add all the static symbols for Code objects. We'll keep a table of
1110 // symbol names to relocated addresses for use in the DwarfElfStream.
1111 // The default kNoValue of 0 is okay here, as no symbols are defined for
1112 // relocated address 0.
1113 CStringMap<intptr_t> symbol_to_address_map;
1114 // Prime the map with any existing static symbols.
1115 if (symtab_ != nullptr) {
1116 ASSERT(strtab_ != nullptr);
1117 // Skip the initial reserved entry in the symbol table.
1118 for (intptr_t i = 1; i < symtab_->Length(); i++) {
1119 auto const symbol = symtab_->At(i);
1120 auto const name = strtab_->At(symbol->name_index);
1121 symbol_to_address_map.Insert({name, symbol->offset});
1122 }
1123 }
1124
1125 // Need these to turn offsets into relocated addresses.
1126 auto const vm_start =
1127 symbol_to_address_map.LookupValue(kVmSnapshotInstructionsAsmSymbol);
1128 // vm_start is absent in deferred loading peices.
1129 auto const isolate_start =
1130 symbol_to_address_map.LookupValue(kIsolateSnapshotInstructionsAsmSymbol);
1131 ASSERT(isolate_start > 0);
1132 auto const vm_text = FindSectionForAddress(vm_start);
1133 // vm_text is absent in deferred loading peices.
1134 auto const isolate_text = FindSectionForAddress(isolate_start);
1135 ASSERT(isolate_text != nullptr);
1136
1137 SnapshotTextObjectNamer namer(zone_);
1138 const auto& codes = dwarf_->codes();
1139 if (codes.length() == 0) {
1140 return;
1141 }
1142 for (intptr_t i = 0; i < codes.length(); i++) {
1143 const auto& code = *codes[i];
1144 auto const name = namer.SnapshotNameFor(i, code);
1145 const auto& pair = dwarf_->CodeAddress(code);
1146 ASSERT(pair.offset > 0);
1147 auto const section = pair.vm ? vm_text : isolate_text;
1148 const intptr_t address = section->memory_offset() + pair.offset;
1149 auto const info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
1150 AddStaticSymbol(name, info, section->index(), address, code.Size());
1151 symbol_to_address_map.Insert({name, address});
1152 }
1153
1154 // TODO(rmacnak): Generate .debug_frame / .eh_frame / .arm.exidx to
1155 // provide unwinding information.
1156
1157 {
1158 uint8_t* buffer = nullptr;
1159 WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
1160 DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
1161 dwarf_->WriteAbbreviations(&dwarf_stream);
1162 AddDebug(".debug_abbrev", buffer, stream.bytes_written());
1163 }
1164
1165 {
1166 uint8_t* buffer = nullptr;
1167 WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
1168 DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
1169 dwarf_->WriteDebugInfo(&dwarf_stream);
1170 AddDebug(".debug_info", buffer, stream.bytes_written());
1171 }
1172
1173 {
1174 uint8_t* buffer = nullptr;
1175 WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
1176 DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
1177 dwarf_->WriteLineNumberProgram(&dwarf_stream);
1178 AddDebug(".debug_line", buffer, stream.bytes_written());
1179 }
1180#endif
1181}
1182
1183void Elf::Finalize() {
1184 AddSectionSymbols();
1185
1186 // The Build ID depends on the symbols being in place, so must be run after
1187 // AddSectionSymbols(). Unfortunately, it currently depends on the contents
1188 // of the .text and .rodata sections, so it can't come earlier in the file
1189 // without changing how we add the .text and .rodata sections (since we
1190 // determine memory offsets for those sections when we add them, and the
1191 // text sections must have the memory offsets to do BSS relocations).
1192 if (auto const build_id = GenerateBuildId()) {
1193 AddSection(build_id, ".note.gnu.build-id", kSnapshotBuildIdAsmSymbol);
1194
1195 // Add a PT_NOTE segment for the build ID.
1196 segments_.Add(new (zone_) NoteSegment(zone_, build_id));
1197 }
1198
1199 // Adding the dynamic symbol table and associated sections.
1200 AddSection(dynstrtab_, ".dynstr");
1201 AddSection(dynsym_, ".dynsym");
1202 dynsym_->link = dynstrtab_->index();
1203
1204 auto const hash = new (zone_) SymbolHashTable(zone_, dynstrtab_, dynsym_);
1205 AddSection(hash, ".hash");
1206
1207 auto const dynamic =
1208 new (zone_) DynamicTable(zone_, dynstrtab_, dynsym_, hash);
1209 AddSection(dynamic, ".dynamic");
1210
1211 // Add a PT_DYNAMIC segment for the dynamic symbol table.
1212 segments_.Add(new (zone_) DynamicSegment(zone_, dynamic));
1213
1214 // Currently, we add all (non-reserved) unallocated sections after all
1215 // allocated sections. If we put unallocated sections between allocated
1216 // sections, they would affect the file offset but not the memory offset
1217 // of the later allocated sections.
1218 //
1219 // However, memory offsets must be page-aligned to the file offset for the
1220 // ELF file to be successfully loaded. This means we'd either have to add
1221 // extra padding _or_ determine file offsets before memory offsets. The
1222 // latter would require us to handle BSS relocations during ELF finalization,
1223 // instead of while writing the .text section content.
1224 FinalizeDwarfSections();
1225 if (!IsStripped()) {
1226 AddSection(strtab_, ".strtab");
1227 AddSection(symtab_, ".symtab");
1228 symtab_->link = strtab_->index();
1229 }
1230 AddSection(shstrtab_, ".shstrtab");
1231
1232 // At this point, all non-programmatically calculated sections and segments
1233 // have been added. Add any programatically calculated sections and segments
1234 // and then calculate file offsets.
1235 FinalizeProgramTable();
1236 ComputeFileOffsets();
1237
1238 // Finally, write the ELF file contents.
1239 ElfWriteStream wrapped(unwrapped_stream_);
1240 WriteHeader(&wrapped);
1241 WriteProgramTable(&wrapped);
1242 WriteSections(&wrapped);
1243 WriteSectionTable(&wrapped);
1244}
1245
1246// Need to include the final \0 terminator in both byte count and byte output.
1247static const uint32_t kBuildIdNameLength = strlen(elf::ELF_NOTE_GNU) + 1;
1248// We generate a 128-bit hash, where each 32 bits is a hash of the contents of
1249// the following segments in order:
1250//
1251// .text(VM) | .text(Isolate) | .rodata(VM) | .rodata(Isolate)
1252static constexpr intptr_t kBuildIdSegmentNamesLength = 4;
1253static constexpr const char* kBuildIdSegmentNames[kBuildIdSegmentNamesLength]{
1254 kVmSnapshotInstructionsAsmSymbol,
1255 kIsolateSnapshotInstructionsAsmSymbol,
1256 kVmSnapshotDataAsmSymbol,
1257 kIsolateSnapshotDataAsmSymbol,
1258};
1259static constexpr uint32_t kBuildIdDescriptionLength =
1260 kBuildIdSegmentNamesLength * sizeof(uint32_t);
1261static const intptr_t kBuildIdDescriptionOffset =
1262 sizeof(elf::Note) + kBuildIdNameLength;
1263static const intptr_t kBuildIdSize =
1264 kBuildIdDescriptionOffset + kBuildIdDescriptionLength;
1265
1266static const Symbol* LookupSymbol(StringTable* strings,
1267 SymbolTable* symbols,
1268 const char* name) {
1269 ASSERT(strings != nullptr);
1270 ASSERT(symbols != nullptr);
1271 auto const name_index = strings->Lookup(name);
1272 if (name_index < 0) return nullptr;
1273 return symbols->FindSymbolWithNameIndex(name_index);
1274}
1275
1276static uint32_t HashBitsContainer(const BitsContainer* bits) {
1277 uint32_t hash = 0;
1278 auto const size = bits->MemorySize();
1279 auto const end = bits->bytes() + size;
1280 auto const non_word_size = size % kWordSize;
1281 auto const end_of_words =
1282 reinterpret_cast<const uword*>(bits->bytes() + (size - non_word_size));
1283 for (auto cursor = reinterpret_cast<const uword*>(bits->bytes());
1284 cursor < end_of_words; cursor++) {
1285 hash = CombineHashes(hash, *cursor);
1286 }
1287 for (auto cursor = reinterpret_cast<const uint8_t*>(end_of_words);
1288 cursor < end; cursor++) {
1289 hash = CombineHashes(hash, *cursor);
1290 }
1291 return FinalizeHash(hash, 32);
1292}
1293
1294Section* Elf::GenerateBuildId() {
1295 uint8_t* notes_buffer = nullptr;
1296 WriteStream stream(&notes_buffer, ZoneReallocate, kBuildIdSize);
1297 stream.WriteFixed(kBuildIdNameLength);
1298 stream.WriteFixed(kBuildIdDescriptionLength);
1299 stream.WriteFixed(static_cast<uint32_t>(elf::NoteType::NT_GNU_BUILD_ID));
1300 stream.WriteBytes(elf::ELF_NOTE_GNU, kBuildIdNameLength);
1301 const intptr_t description_start = stream.bytes_written();
1302 for (intptr_t i = 0; i < kBuildIdSegmentNamesLength; i++) {
1303 auto const name = kBuildIdSegmentNames[i];
1304 auto const symbol = LookupSymbol(dynstrtab_, dynsym_, name);
1305 if (symbol == nullptr) {
1306 stream.WriteFixed(static_cast<uint32_t>(0));
1307 continue;
1308 }
1309 auto const bits = sections_[symbol->section_index]->AsBitsContainer();
1310 if (bits == nullptr) {
1311 FATAL1("Section for symbol %s is not a BitsContainer", name);
1312 }
1313 ASSERT_EQUAL(bits->MemorySize(), symbol->size);
1314 // We don't actually have the bytes (i.e., this is a separate debugging
1315 // info file for an assembly snapshot), so we can't calculate the build ID.
1316 if (bits->bytes() == nullptr) return nullptr;
1317
1318 stream.WriteFixed(HashBitsContainer(bits));
1319 }
1320 ASSERT_EQUAL(stream.bytes_written() - description_start,
1321 kBuildIdDescriptionLength);
1322 return new (zone_) BitsContainer(
1323 elf::SectionHeaderType::SHT_NOTE, /*allocate=*/true, /*executable=*/false,
1324 /*writable=*/false, stream.bytes_written(), notes_buffer, kNoteAlignment);
1325}
1326
1327void Elf::FinalizeProgramTable() {
1328 ASSERT(program_table_file_size_ < 0);
1329
1330 program_table_file_offset_ = sizeof(elf::ElfHeader);
1331
1332 // There are two segments we need the size of the program table to create, so
1333 // calculate it as if those two segments were already in place.
1334 program_table_file_size_ =
1335 (2 + segments_.length()) * sizeof(elf::ProgramHeader);
1336
1337 // We pre-allocated the virtual memory space for the program table itself.
1338 // Check that we didn't generate too many segments. Currently we generate a
1339 // fixed num of segments based on the four pieces of a snapshot, but if we
1340 // use more in the future we'll likely need to do something more compilated
1341 // to generate DWARF without knowing a piece's virtual address in advance.
1342 auto const program_table_segment_size =
1343 program_table_file_offset_ + program_table_file_size_;
1344 RELEASE_ASSERT(program_table_segment_size < kProgramTableSegmentSize);
1345
1346 // Remove the original stand-in segment we added in the constructor.
1347 segments_.EraseAt(0);
1348
1349 // Self-reference to program header table. Required by Android but not by
1350 // Linux. Must appear before any PT_LOAD entries.
1351 segments_.InsertAt(
1352 0, new (zone_) ProgramTableSelfSegment(zone_, program_table_file_offset_,
1353 program_table_file_size_));
1354
1355 // Segment for loading the initial part of the ELF file, including the
1356 // program header table. Required by Android but not by Linux.
1357 segments_.InsertAt(1, new (zone_) ProgramTableLoadSegment(
1358 zone_, program_table_segment_size));
1359}
1360
1361static const intptr_t kElfSectionTableAlignment = compiler::target::kWordSize;
1362
1363void Elf::ComputeFileOffsets() {
1364 // We calculate the size and offset of the program header table during
1365 // finalization.
1366 ASSERT(program_table_file_offset_ > 0 && program_table_file_size_ > 0);
1367 intptr_t file_offset = program_table_file_offset_ + program_table_file_size_;
1368 // When calculating file offsets for sections, we'll need to know if we've
1369 // changed segments. Start with the one for the program table.
1370 const auto* current_segment = segments_[1];
1371
1372 // The non-reserved sections are output to the file in order after the program
1373 // header table. If we're entering a new segment, then we need to align
1374 // according to the PT_LOAD segment alignment as well to keep the file offsets
1375 // aligned with the memory addresses.
1376 auto const load_align = Segment::Alignment(elf::ProgramHeaderType::PT_LOAD);
1377 for (intptr_t i = 1; i < sections_.length(); i++) {
1378 auto const section = sections_[i];
1379 file_offset = Utils::RoundUp(file_offset, section->alignment);
1380 if (section->IsAllocated() && section->load_segment != current_segment) {
1381 file_offset = Utils::RoundUp(file_offset, load_align);
1382 current_segment = section->load_segment;
1383 }
1384 section->set_file_offset(file_offset);
1385#if defined(DEBUG)
1386 if (section->IsAllocated()) {
1387 // For files that will be dynamically loaded, make sure the file offsets
1388 // of allocated sections are page aligned to the memory offsets.
1389 ASSERT_EQUAL(section->file_offset() % load_align,
1390 section->memory_offset() % load_align);
1391 }
1392#endif
1393 file_offset += section->FileSize();
1394 }
1395
1396 file_offset = Utils::RoundUp(file_offset, kElfSectionTableAlignment);
1397 section_table_file_offset_ = file_offset;
1398 section_table_file_size_ = sections_.length() * sizeof(elf::SectionHeader);
1399 file_offset += section_table_file_size_;
1400}
1401
1402void Elf::WriteHeader(ElfWriteStream* stream) {
1403#if defined(TARGET_ARCH_IS_32_BIT)
1404 uint8_t size = elf::ELFCLASS32;
1405#else
1406 uint8_t size = elf::ELFCLASS64;
1407#endif
1408 uint8_t e_ident[16] = {0x7f,
1409 'E',
1410 'L',
1411 'F',
1412 size,
1413 elf::ELFDATA2LSB,
1414 elf::EV_CURRENT,
1415 elf::ELFOSABI_SYSV,
1416 0,
1417 0,
1418 0,
1419 0,
1420 0,
1421 0,
1422 0,
1423 0};
1424 stream->WriteBytes(e_ident, 16);
1425
1426 stream->WriteHalf(elf::ET_DYN); // Shared library.
1427
1428#if defined(TARGET_ARCH_IA32)
1429 stream->WriteHalf(elf::EM_386);
1430#elif defined(TARGET_ARCH_X64)
1431 stream->WriteHalf(elf::EM_X86_64);
1432#elif defined(TARGET_ARCH_ARM)
1433 stream->WriteHalf(elf::EM_ARM);
1434#elif defined(TARGET_ARCH_ARM64)
1435 stream->WriteHalf(elf::EM_AARCH64);
1436#else
1437 FATAL("Unknown ELF architecture");
1438#endif
1439
1440 stream->WriteWord(elf::EV_CURRENT); // Version
1441 stream->WriteAddr(0); // "Entry point"
1442 stream->WriteOff(program_table_file_offset_);
1443 stream->WriteOff(section_table_file_offset_);
1444
1445#if defined(TARGET_ARCH_ARM)
1446 uword flags = elf::EF_ARM_ABI | (TargetCPUFeatures::hardfp_supported()
1447 ? elf::EF_ARM_ABI_FLOAT_HARD
1448 : elf::EF_ARM_ABI_FLOAT_SOFT);
1449#else
1450 uword flags = 0;
1451#endif
1452 stream->WriteWord(flags);
1453
1454 stream->WriteHalf(sizeof(elf::ElfHeader));
1455 stream->WriteHalf(sizeof(elf::ProgramHeader));
1456 stream->WriteHalf(segments_.length());
1457 stream->WriteHalf(sizeof(elf::SectionHeader));
1458 stream->WriteHalf(sections_.length());
1459 stream->WriteHalf(shstrtab_->index());
1460
1461 ASSERT_EQUAL(stream->position(), sizeof(elf::ElfHeader));
1462}
1463
1464void Elf::WriteProgramTable(ElfWriteStream* stream) {
1465 ASSERT(program_table_file_size_ >= 0); // Check for finalization.
1466 ASSERT(stream->position() == program_table_file_offset_);
1467#if defined(DEBUG)
1468 // Here, we count the number of times that a PT_LOAD writable segment is
1469 // followed by a non-writable segment. We initialize last_writable to true so
1470 // that we catch the case where the first segment is non-writable.
1471 bool last_writable = true;
1472 int non_writable_groups = 0;
1473#endif
1474 for (auto const segment : segments_) {
1475#if defined(DEBUG)
1476 if (segment->type == elf::ProgramHeaderType::PT_LOAD) {
1477 if (last_writable && !segment->IsWritable()) {
1478 non_writable_groups++;
1479 }
1480 last_writable = segment->IsWritable();
1481 }
1482#endif
1483 const intptr_t start = stream->position();
1484 segment->WriteProgramHeader(stream);
1485 const intptr_t end = stream->position();
1486 ASSERT_EQUAL(end - start, sizeof(elf::ProgramHeader));
1487 }
1488#if defined(DEBUG)
1489 // All PT_LOAD non-writable segments must be contiguous. If not, some older
1490 // Android dynamic linkers fail to handle writable segments between
1491 // non-writable ones. See https://github.com/flutter/flutter/issues/43259.
1492 ASSERT(non_writable_groups <= 1);
1493#endif
1494}
1495
1496void Elf::WriteSectionTable(ElfWriteStream* stream) {
1497 ASSERT(section_table_file_size_ >= 0); // Check for finalization.
1498 stream->Align(kElfSectionTableAlignment);
1499 ASSERT_EQUAL(stream->position(), section_table_file_offset_);
1500
1501 for (auto const section : sections_) {
1502 const intptr_t start = stream->position();
1503 section->WriteSectionHeader(stream);
1504 const intptr_t end = stream->position();
1505 ASSERT_EQUAL(end - start, sizeof(elf::SectionHeader));
1506 }
1507}
1508
1509void Elf::WriteSections(ElfWriteStream* stream) {
1510 ASSERT(section_table_file_size_ >= 0); // Check for finalization.
1511
1512 // Skip the reserved first section, as its alignment is 0 (which will cause
1513 // stream->Align() to fail) and it never contains file contents anyway.
1514 ASSERT_EQUAL(static_cast<uint32_t>(sections_[0]->type),
1515 static_cast<uint32_t>(elf::SectionHeaderType::SHT_NULL));
1516 ASSERT_EQUAL(sections_[0]->alignment, 0);
1517 auto const load_align = Segment::Alignment(elf::ProgramHeaderType::PT_LOAD);
1518 const Segment* current_segment = segments_[1];
1519 for (intptr_t i = 1; i < sections_.length(); i++) {
1520 Section* section = sections_[i];
1521 stream->Align(section->alignment);
1522 if (section->IsAllocated() && section->load_segment != current_segment) {
1523 // Changing segments, so align accordingly.
1524 stream->Align(load_align);
1525 current_segment = section->load_segment;
1526 }
1527 ASSERT_EQUAL(stream->position(), section->file_offset());
1528 section->Write(stream);
1529 ASSERT_EQUAL(stream->position(),
1530 section->file_offset() + section->FileSize());
1531 }
1532}
1533
1534} // namespace dart
1535