20#if defined(DART_PRECOMPILER)
24class ElfWriteStream :
public ValueObject {
26 explicit ElfWriteStream(BaseWriteStream* stream,
const Elf& elf)
29 start_(stream_->Position()) {
32 ASSERT(Utils::IsAligned(start_, Elf::kPageSize));
37 const Elf& elf()
const {
return elf_; }
41 intptr_t Position()
const {
return stream_->Position() - start_; }
42 void Align(
const intptr_t alignment) {
43 ASSERT(Utils::IsPowerOfTwo(alignment));
44 ASSERT(alignment <= Elf::kPageSize);
45 stream_->Align(alignment);
47 void WriteBytes(
const uint8_t*
b, intptr_t size) {
48 stream_->WriteBytes(
b, size);
50 void WriteByte(uint8_t value) { stream_->WriteByte(value); }
51 void WriteHalf(uint16_t value) { stream_->WriteFixed(value); }
52 void WriteWord(uint32_t value) { stream_->WriteFixed(value); }
53 void WriteAddr(compiler::target::uword value) { stream_->WriteFixed(value); }
54 void WriteOff(compiler::target::uword value) { stream_->WriteFixed(value); }
55#if defined(TARGET_ARCH_IS_64_BIT)
56 void WriteXWord(uint64_t value) { stream_->WriteFixed(value); }
60 BaseWriteStream*
const stream_;
62 const intptr_t start_;
65static constexpr intptr_t kLinearInitValue = -1;
67#define DEFINE_LINEAR_FIELD_METHODS(name) \
68 intptr_t name() const { \
69 ASSERT(name##_ != kLinearInitValue); \
72 bool name##_is_set() const { \
73 return name##_ != kLinearInitValue; \
75 void set_##name(intptr_t value) { \
76 ASSERT(value != kLinearInitValue); \
77 ASSERT_EQUAL(name##_, kLinearInitValue); \
81#define DEFINE_LINEAR_FIELD(name) intptr_t name##_ = kLinearInitValue;
85#define FOR_EACH_SECTION_TYPE(V) \
90 V(TextSection) V(DataSection) V(BssSection) V(PseudoSection) V(SectionTable)
91#define DEFINE_TYPE_CHECK_FOR(Type) \
92 bool Is##Type() const { \
96#define DECLARE_SECTION_TYPE_CLASS(Type) class Type;
97FOR_EACH_SECTION_TYPE(DECLARE_SECTION_TYPE_CLASS)
98#undef DECLARE_SECTION_TYPE_CLASS
104static constexpr intptr_t kNoteAlignment = 4;
106class Section :
public ZoneAllocated {
108 Section(elf::SectionHeaderType t,
112 intptr_t align = compiler::target::kWordSize)
114 flags(EncodeFlags(allocate, executable, writable)),
117 memory_offset_(allocate ? kLinearInitValue : 0) {
121 ASSERT(alignment > 0 ||
type == elf::SectionHeaderType::SHT_NULL);
123 ASSERT(alignment == 0 || Utils::IsPowerOfTwo(alignment));
126 virtual ~Section() {}
130 const elf::SectionHeaderType
type;
131 const intptr_t
flags;
132 const intptr_t alignment;
136 intptr_t
link = elf::SHN_UNDEF;
138 intptr_t entry_size = 0;
141 intptr_t index = elf::SHN_UNDEF;
143#define FOR_EACH_SECTION_LINEAR_FIELD(M) \
147 FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
151 virtual intptr_t FileSize()
const {
152 if (!IsAllocated()) {
160#define FOR_EACH_SEGMENT_LINEAR_FIELD(M) M(memory_offset)
162 FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
165 virtual intptr_t MemorySize()
const {
174 bool IsAllocated()
const {
175 return (
flags & elf::SHF_ALLOC) == elf::SHF_ALLOC;
177 bool IsExecutable()
const {
178 return (
flags & elf::SHF_EXECINSTR) == elf::SHF_EXECINSTR;
180 bool IsWritable()
const {
return (
flags & elf::SHF_WRITE) == elf::SHF_WRITE; }
182 bool HasBits()
const {
return type != elf::SectionHeaderType::SHT_NOBITS; }
185 bool HasBeenFinalized()
const {
188 return file_offset_is_set();
191#define DEFINE_BASE_TYPE_CHECKS(Type) \
193 return Is##Type() ? reinterpret_cast<Type*>(this) : nullptr; \
195 const Type* As##Type() const { \
196 return const_cast<Type*>(const_cast<Section*>(this)->As##Type()); \
198 virtual bool Is##Type() const { return false; }
200 FOR_EACH_SECTION_TYPE(DEFINE_BASE_TYPE_CHECKS)
201#undef DEFINE_BASE_TYPE_CHECKS
204 virtual bool CanMergeWith(
const Section& other)
const {
return false; }
205 virtual void Merge(
const Section& other) {
UNREACHABLE(); }
208 virtual void Write(ElfWriteStream* stream)
const {
UNREACHABLE(); }
210 virtual void WriteSectionHeader(ElfWriteStream* stream)
const {
211#if defined(TARGET_ARCH_IS_32_BIT)
213 stream->WriteWord(
static_cast<uint32_t
>(
type));
215 stream->WriteAddr(memory_offset());
216 stream->WriteOff(file_offset());
217 stream->WriteWord(FileSize());
220 stream->WriteWord(alignment);
221 stream->WriteWord(entry_size);
224 stream->WriteWord(
static_cast<uint32_t
>(
type));
226 stream->WriteAddr(memory_offset());
227 stream->WriteOff(file_offset());
228 stream->WriteXWord(FileSize());
231 stream->WriteXWord(alignment);
232 stream->WriteXWord(entry_size);
237 static intptr_t EncodeFlags(
bool allocate,
bool executable,
bool writable) {
239 ASSERT(!executable || !writable);
241 if (allocate)
flags |= elf::SHF_ALLOC;
242 if (executable)
flags |= elf::SHF_EXECINSTR;
243 if (writable)
flags |= elf::SHF_WRITE;
247 FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
248 FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
250#undef FOR_EACH_SECTION_LINEAR_FIELD
251#undef FOR_EACH_SEGMENT_LINEAR_FIELD
254#undef DEFINE_LINEAR_FIELD
255#undef DEFINE_LINEAR_FIELD_METHODS
257class Segment :
public ZoneAllocated {
260 Section* initial_section,
261 elf::ProgramHeaderType segment_type)
262 :
type(segment_type),
269 ASSERT(segment_type != elf::ProgramHeaderType::PT_NULL);
271 ASSERT(initial_section !=
nullptr);
272 sections_.Add(initial_section);
275 virtual ~Segment() {}
277 const GrowableArray<Section*>& sections()
const {
return sections_; }
279 intptr_t Alignment()
const {
281 case elf::ProgramHeaderType::PT_LOAD:
282 return Elf::kPageSize;
283 case elf::ProgramHeaderType::PT_PHDR:
284 case elf::ProgramHeaderType::PT_DYNAMIC:
285 return compiler::target::kWordSize;
286 case elf::ProgramHeaderType::PT_NOTE:
287 return kNoteAlignment;
288 case elf::ProgramHeaderType::PT_GNU_STACK:
296 bool IsExecutable()
const {
return (
flags & elf::PF_X) == elf::PF_X; }
297 bool IsWritable()
const {
return (
flags & elf::PF_W) == elf::PF_W; }
299 void WriteProgramHeader(ElfWriteStream* stream)
const {
300#if defined(TARGET_ARCH_IS_32_BIT)
301 stream->WriteWord(
static_cast<uint32_t
>(
type));
302 stream->WriteOff(FileOffset());
303 stream->WriteAddr(MemoryOffset());
304 stream->WriteAddr(MemoryOffset());
305 stream->WriteWord(FileSize());
306 stream->WriteWord(MemorySize());
308 stream->WriteWord(Alignment());
310 stream->WriteWord(
static_cast<uint32_t
>(
type));
312 stream->WriteOff(FileOffset());
313 stream->WriteAddr(MemoryOffset());
314 stream->WriteAddr(MemoryOffset());
315 stream->WriteXWord(FileSize());
316 stream->WriteXWord(MemorySize());
317 stream->WriteXWord(Alignment());
323 bool Add(Section* section) {
324 ASSERT(section !=
nullptr);
326 ASSERT(!section->memory_offset_is_set());
328 ASSERT(
type == elf::ProgramHeaderType::PT_LOAD);
330 if (IsExecutable() != section->IsExecutable() ||
331 IsWritable() != section->IsWritable()) {
334 sections_.Add(section);
338 intptr_t FileOffset()
const {
return sections_[0]->file_offset(); }
340 intptr_t FileSize()
const {
341 auto const last = sections_.Last();
342 const intptr_t
end = last->file_offset() + last->FileSize();
343 return end - FileOffset();
346 intptr_t MemoryOffset()
const {
return sections_[0]->memory_offset(); }
348 intptr_t MemorySize()
const {
349 auto const last = sections_.Last();
350 const intptr_t
end = last->memory_offset() + last->MemorySize();
351 return end - MemoryOffset();
354 intptr_t MemoryEnd()
const {
return MemoryOffset() + MemorySize(); }
356 const elf::ProgramHeaderType
type;
357 const intptr_t
flags;
360 static intptr_t EncodeFlags(
bool executable,
bool writable) {
361 intptr_t
flags = elf::PF_R;
362 if (executable)
flags |= elf::PF_X;
363 if (writable)
flags |= elf::PF_W;
367 GrowableArray<Section*> sections_;
372class ReservedSection :
public Section {
383 DEFINE_TYPE_CHECK_FOR(ReservedSection);
384 intptr_t FileSize()
const {
return 0; }
389class GnuStackSection :
public Section {
399 intptr_t FileSize()
const {
return 0; }
402class StringTable :
public Section {
404 explicit StringTable(Zone* zone,
bool allocate)
411 text_indices_(zone) {
415 intptr_t FileSize()
const {
return text_.length(); }
416 intptr_t MemorySize()
const {
return dynamic_ ? FileSize() : 0; }
418 void Write(ElfWriteStream* stream)
const {
419 stream->WriteBytes(
reinterpret_cast<const uint8_t*
>(text_.buffer()),
423 intptr_t Add(
const char* str) {
425 if (
auto const kv = text_indices_.Lookup(str)) {
428 intptr_t
offset = text_.length();
429 text_.AddString(str);
431 text_indices_.Insert({str,
offset});
435 const char* At(intptr_t index)
const {
436 if (index >= text_.length())
return nullptr;
437 return text_.buffer() + index;
440 static constexpr intptr_t kNotIndexed = CStringIntMapKeyValueTrait::kNoValue;
444 intptr_t Lookup(
const char* str)
const {
445 return text_indices_.LookupValue(str);
449 ZoneTextBuffer text_;
450 CStringIntMap text_indices_;
453class SymbolTable :
public Section {
455 SymbolTable(Zone* zone, StringTable*
table,
bool dynamic)
465 by_label_index_(zone) {
466 link = table_->index;
467 entry_size =
sizeof(elf::Symbol);
471 symbols_.Add({0, elf::STB_LOCAL, elf::STT_NOTYPE, 0,
472 elf::SHN_UNDEF, 0, 0});
479 DEFINE_TYPE_CHECK_FOR(SymbolTable)
480 const StringTable& strtab()
const {
return *table_; }
481 intptr_t FileSize()
const {
return symbols_.length() * entry_size; }
482 intptr_t MemorySize()
const {
return dynamic_ ? FileSize() : 0; }
485 void Write(ElfWriteStream* stream)
const {
488 stream->WriteWord(name_index);
489#if defined(TARGET_ARCH_IS_32_BIT)
492 stream->WriteByte(elf::SymbolInfo(binding,
type));
494 stream->WriteHalf(section_index);
496 stream->WriteByte(elf::SymbolInfo(binding,
type));
498 stream->WriteHalf(section_index);
510 intptr_t section_index;
522 const GrowableArray<Symbol>&
symbols()
const {
return symbols_; }
524 void Initialize(
const GrowableArray<Section*>& sections);
526 void Write(ElfWriteStream* stream)
const {
527 for (
const auto& symbol : symbols_) {
529 symbol.Write(stream);
534 void AddSymbol(
const char*
name,
542 ASSERT(!table_->HasBeenFinalized());
543 auto const name_index = table_->Add(
name);
545 const intptr_t new_index = symbols_.length();
546 symbols_.Add({name_index, binding,
type,
size, index,
offset, label});
547 by_label_index_.Insert(label, new_index);
551 if (binding == elf::STB_LOCAL) {
552 if (
info != new_index) {
557 ASSERT(symbols_[
info].binding != elf::STB_LOCAL);
558 symbols_.Swap(
info, new_index);
560 by_label_index_.Update({symbols_[
info].label,
info});
561 by_label_index_.Update({symbols_[new_index].label, new_index});
567 void UpdateSectionIndices(
const GrowableArray<intptr_t>& index_map) {
569 const intptr_t map_size = index_map.length();
573 for (intptr_t i = 1; i < map_size; i++) {
574 ASSERT(index_map[i] != 0);
575 ASSERT(index_map[i] < map_size);
578 for (
auto& symbol : symbols_) {
580 symbol.section_index = index_map[symbol.section_index];
584 void Finalize(
const GrowableArray<intptr_t>& address_map) {
586 const intptr_t map_size = address_map.length();
590 for (intptr_t i = 1; i < map_size; i++) {
592 ASSERT(address_map[i] != 0);
595 for (
auto& symbol : symbols_) {
597 symbol.offset += address_map[symbol.section_index];
601 const Symbol* FindUid(intptr_t label)
const {
603 const intptr_t symbols_index = by_label_index_.Lookup(label);
604 if (symbols_index == 0)
return nullptr;
605 return &symbols_[symbols_index];
610 StringTable*
const table_;
612 GrowableArray<Symbol> symbols_;
615 IntMap<intptr_t> by_label_index_;
618class SymbolHashTable :
public Section {
620 SymbolHashTable(Zone* zone, SymbolTable* symtab)
627 link = symtab->index;
628 entry_size =
sizeof(int32_t);
630 const auto&
symbols = symtab->symbols();
631 const intptr_t num_symbols =
symbols.length();
632 buckets_.FillWith(elf::STN_UNDEF, 0, num_symbols);
633 chains_.FillWith(elf::STN_UNDEF, 0, num_symbols);
635 for (intptr_t i = 1; i < num_symbols; i++) {
636 const auto& symbol =
symbols[i];
637 uint32_t
hash = HashSymbolName(symtab->strtab().At(symbol.name_index));
638 uint32_t probe =
hash % num_symbols;
639 chains_[i] = buckets_[probe];
644 intptr_t MemorySize()
const {
645 return entry_size * (buckets_.length() + chains_.length() + 2);
648 void Write(ElfWriteStream* stream)
const {
649 stream->WriteWord(buckets_.length());
650 stream->WriteWord(chains_.length());
651 for (
const int32_t bucket : buckets_) {
652 stream->WriteWord(bucket);
654 for (
const int32_t chain : chains_) {
659 static uint32_t HashSymbolName(
const void* p) {
660 auto*
name =
reinterpret_cast<const uint8_t*
>(
p);
662 while (*
name !=
'\0') {
664 uint32_t g =
h & 0xf0000000;
672 GrowableArray<int32_t> buckets_;
673 GrowableArray<int32_t> chains_;
676class DynamicTable :
public Section {
681 DynamicTable(Zone* zone, SymbolTable* symtab, SymbolHashTable*
hash)
688 link = strtab().index;
689 entry_size =
sizeof(elf::DynamicEntry);
691 AddEntry(zone, elf::DynamicEntryType::DT_HASH, kInvalidEntry);
692 AddEntry(zone, elf::DynamicEntryType::DT_STRTAB, kInvalidEntry);
693 AddEntry(zone, elf::DynamicEntryType::DT_STRSZ, kInvalidEntry);
694 AddEntry(zone, elf::DynamicEntryType::DT_SYMTAB, kInvalidEntry);
695 AddEntry(zone, elf::DynamicEntryType::DT_SYMENT,
sizeof(elf::Symbol));
696 AddEntry(zone, elf::DynamicEntryType::DT_NULL, 0);
699 static constexpr intptr_t kInvalidEntry = -1;
701 DEFINE_TYPE_CHECK_FOR(DynamicTable)
702 const SymbolHashTable&
hash()
const {
return *hash_; }
703 const SymbolTable& symtab()
const {
return *symtab_; }
704 const StringTable& strtab()
const {
return symtab().strtab(); }
705 intptr_t MemorySize()
const {
return entries_.length() * entry_size; }
707 void Write(ElfWriteStream* stream)
const {
708 for (intptr_t i = 0; i < entries_.length(); i++) {
709 entries_[i]->Write(stream);
714 FinalizeEntry(elf::DynamicEntryType::DT_HASH,
hash().memory_offset());
715 FinalizeEntry(elf::DynamicEntryType::DT_STRTAB, strtab().memory_offset());
716 FinalizeEntry(elf::DynamicEntryType::DT_STRSZ, strtab().MemorySize());
717 FinalizeEntry(elf::DynamicEntryType::DT_SYMTAB, symtab().memory_offset());
721 struct Entry :
public ZoneAllocated {
722 Entry(elf::DynamicEntryType tag, intptr_t value) : tag(tag),
value(
value) {}
724 void Write(ElfWriteStream* stream)
const {
725 ASSERT(value != kInvalidEntry);
727#if defined(TARGET_ARCH_IS_32_BIT)
728 stream->WriteWord(
static_cast<uint32_t
>(tag));
731 stream->WriteXWord(
static_cast<uint64_t
>(tag));
737 elf::DynamicEntryType tag;
741 void AddEntry(Zone* zone, elf::DynamicEntryType tag, intptr_t value) {
742 auto const entry =
new (zone)
Entry(tag, value);
746 void FinalizeEntry(elf::DynamicEntryType tag, intptr_t value) {
747 for (
auto* entry : entries_) {
748 if (entry->tag == tag) {
749 entry->value =
value;
755 SymbolTable*
const symtab_;
756 SymbolHashTable*
const hash_;
757 GrowableArray<Entry*> entries_;
760class BitsContainer :
public Section {
764 BitsContainer(elf::SectionHeaderType
type,
769 :
Section(
type, allocate, executable, writable, alignment) {}
772 explicit BitsContainer(elf::SectionHeaderType
type, intptr_t alignment = 1)
773 : BitsContainer(
type,
782 BitsContainer(Elf::Type t,
785 intptr_t alignment = 1)
786 : BitsContainer(t == Elf::
Type::Snapshot
794 DEFINE_TYPE_CHECK_FOR(BitsContainer)
796 bool IsNoBits()
const {
return type == elf::SectionHeaderType::SHT_NOBITS; }
797 bool HasBytes()
const {
798 return portions_.length() != 0 && portions_[0].bytes !=
nullptr;
802 void Write(ElfWriteStream* stream, intptr_t section_start)
const {
804 if (relocations ==
nullptr) {
805 stream->WriteBytes(bytes, size);
808 const SymbolTable& symtab =
stream->elf().symtab();
810 intptr_t current_pos = 0;
811 for (
const auto& reloc : *relocations) {
814 ASSERT(current_pos <= reloc.section_offset);
815 if (current_pos < reloc.section_offset) {
816 stream->WriteBytes(bytes + current_pos,
817 reloc.section_offset - current_pos);
819 intptr_t source_address = reloc.source_offset;
820 if (reloc.source_label > 0) {
821 auto*
const source_symbol = symtab.FindUid(reloc.source_label);
822 ASSERT(source_symbol !=
nullptr);
823 source_address += source_symbol->offset;
824 }
else if (reloc.source_label == Elf::Relocation::kSelfRelative) {
825 source_address += section_start +
offset + reloc.section_offset;
827 ASSERT_EQUAL(reloc.source_label, Elf::Relocation::kSnapshotRelative);
830 ASSERT(reloc.size_in_bytes <= kWordSize);
831 word to_write = reloc.target_offset - source_address;
832 if (reloc.target_label > 0) {
833 if (
auto*
const target_symbol = symtab.FindUid(reloc.target_label)) {
834 to_write += target_symbol->offset;
839 ASSERT_EQUAL(reloc.size_in_bytes, compiler::target::kWordSize);
843 to_write = Image::kNoRelocatedAddress;
845 }
else if (reloc.target_label == Elf::Relocation::kSelfRelative) {
846 to_write += section_start +
offset + reloc.section_offset;
848 ASSERT_EQUAL(reloc.target_label, Elf::Relocation::kSnapshotRelative);
851 ASSERT(Utils::IsInt(reloc.size_in_bytes * kBitsPerByte, to_write));
852 stream->WriteBytes(
reinterpret_cast<const uint8_t*
>(&to_write),
853 reloc.size_in_bytes);
854 current_pos = reloc.section_offset + reloc.size_in_bytes;
856 stream->WriteBytes(bytes + current_pos, size - current_pos);
860 const char* symbol_name;
862 const uint8_t* bytes;
864 const ZoneGrowableArray<Elf::Relocation>* relocations;
865 const ZoneGrowableArray<Elf::SymbolData>*
symbols;
871 const GrowableArray<Portion>& portions()
const {
return portions_; }
873 const Portion& AddPortion(
874 const uint8_t* bytes,
876 const ZoneGrowableArray<Elf::Relocation>* relocations =
nullptr,
877 const ZoneGrowableArray<Elf::SymbolData>* symbols =
nullptr,
878 const char* symbol_name =
nullptr,
879 intptr_t label = 0) {
881 ASSERT(symbol_name ==
nullptr || label > 0);
882 ASSERT(IsNoBits() || bytes !=
nullptr);
883 ASSERT(bytes !=
nullptr || relocations ==
nullptr);
885 ASSERT(portions_.is_empty() || HasBytes() == (bytes !=
nullptr));
886 const intptr_t
offset = Utils::RoundUp(total_size_, alignment);
889 const Portion& portion = portions_.Last();
894 void Write(ElfWriteStream* stream)
const {
895 if (
type == elf::SectionHeaderType::SHT_NOBITS)
return;
896 intptr_t start_position =
stream->Position();
897 for (
const auto& portion : portions_) {
900 portion.Write(stream, memory_offset());
907 uint32_t Hash(
const char* symbol_name)
const {
908 for (
const auto& portion : portions_) {
909 if (strcmp(symbol_name, portion.symbol_name) == 0) {
910 if (portion.bytes ==
nullptr)
return 0;
911 const uint32_t
hash = Utils::StringHash(portion.bytes, portion.size);
919 intptr_t FileSize()
const {
return IsNoBits() ? 0 : total_size_; }
920 intptr_t MemorySize()
const {
return IsAllocated() ? total_size_ : 0; }
923 GrowableArray<Portion> portions_;
924 intptr_t total_size_ = 0;
927class NoteSection :
public BitsContainer {
939class ConcatenableBitsContainer :
public BitsContainer {
941 ConcatenableBitsContainer(Elf::Type
type,
945 : BitsContainer(
type, executable, writable, alignment) {}
947 virtual bool CanMergeWith(
const Section& other)
const = 0;
948 virtual void Merge(
const Section& other) {
949 ASSERT(other.IsBitsContainer());
950 ASSERT(CanMergeWith(other));
951 for (
const auto& portion : other.AsBitsContainer()->portions()) {
952 AddPortion(portion.bytes, portion.size, portion.relocations,
953 portion.symbols, portion.symbol_name, portion.label);
958class TextSection :
public ConcatenableBitsContainer {
960 explicit TextSection(Elf::Type t)
961 : ConcatenableBitsContainer(t,
964 ImageWriter::kTextAlignment) {}
966 DEFINE_TYPE_CHECK_FOR(TextSection);
968 virtual bool CanMergeWith(
const Section& other)
const {
969 return other.IsTextSection();
973class DataSection :
public ConcatenableBitsContainer {
975 explicit DataSection(Elf::Type t)
976 : ConcatenableBitsContainer(t,
979 ImageWriter::kRODataAlignment) {}
981 DEFINE_TYPE_CHECK_FOR(DataSection);
983 virtual bool CanMergeWith(
const Section& other)
const {
984 return other.IsDataSection();
988class BssSection :
public ConcatenableBitsContainer {
990 explicit BssSection(Elf::Type t)
991 : ConcatenableBitsContainer(t,
994 ImageWriter::kBssAlignment) {}
996 DEFINE_TYPE_CHECK_FOR(BssSection);
998 virtual bool CanMergeWith(
const Section& other)
const {
999 return other.IsBssSection();
1006class PseudoSection :
public Section {
1009 static constexpr intptr_t kAlignment = compiler::target::kWordSize;
1011 PseudoSection(
bool allocate,
bool executable,
bool writable)
1018 DEFINE_TYPE_CHECK_FOR(PseudoSection)
1020 void Write(ElfWriteStream* stream)
const = 0;
1023class ProgramTable :
public PseudoSection {
1025 explicit ProgramTable(Zone* zone)
1026 : PseudoSection(
true,
1029 segments_(zone, 0) {
1030 entry_size =
sizeof(elf::ProgramHeader);
1033 const GrowableArray<Segment*>& segments()
const {
return segments_; }
1034 intptr_t SegmentCount()
const {
return segments_.length(); }
1035 intptr_t MemorySize()
const {
1036 return segments_.length() *
sizeof(elf::ProgramHeader);
1039 void Add(Segment* segment) {
1040 ASSERT(segment !=
nullptr);
1041 segments_.Add(segment);
1044 void Write(ElfWriteStream* stream)
const;
1047 GrowableArray<Segment*> segments_;
1052class SectionTable :
public PseudoSection {
1054 explicit SectionTable(Zone* zone)
1055 : PseudoSection(
false,
1059 sections_(zone_, 2),
1060 shstrtab_(zone_,
false) {
1061 entry_size =
sizeof(elf::SectionHeader);
1064 Add(
new (zone_) ReservedSection(),
"");
1065 Add(&shstrtab_,
".shstrtab");
1068 const GrowableArray<Section*>& sections()
const {
return sections_; }
1069 intptr_t SectionCount()
const {
return sections_.length(); }
1070 intptr_t StringTableIndex()
const {
return shstrtab_.index; }
1072 bool HasSectionNamed(
const char*
name) {
1073 return shstrtab_.Lookup(
name) != StringTable::kNotIndexed;
1076 void Add(Section* section,
const char*
name =
nullptr) {
1077 ASSERT(!section->IsPseudoSection());
1078 ASSERT(
name !=
nullptr || section->name_is_set());
1079 if (
name !=
nullptr) {
1081 if (
auto*
const old_section = Find(
name)) {
1082 ASSERT(old_section->CanMergeWith(*section));
1083 old_section->Merge(*section);
1087 const intptr_t name_index = shstrtab_.Add(
name);
1088 section->set_name(name_index);
1090 section->index = sections_.length();
1091 sections_.Add(section);
1095 const intptr_t name_index = shstrtab_.Lookup(
name);
1096 if (name_index == StringTable::kNotIndexed) {
1102 for (Section*
const section : sections_) {
1103 if (section->name() == name_index) {
1115 intptr_t FileSize()
const {
1116 return sections_.length() *
sizeof(elf::SectionHeader);
1119 void Write(ElfWriteStream* stream)
const;
1126 ProgramTable* CreateProgramTable(SymbolTable* symtab);
1130 GrowableArray<Section*> sections_;
1131 StringTable shstrtab_;
1134class ElfHeader :
public PseudoSection {
1136 ElfHeader(
const ProgramTable& program_table,
1137 const SectionTable& section_table)
1138 : PseudoSection(
true,
1141 program_table_(program_table),
1142 section_table_(section_table) {}
1144 intptr_t MemorySize()
const {
return sizeof(elf::ElfHeader); }
1146 void Write(ElfWriteStream* stream)
const;
1149 const ProgramTable& program_table_;
1150 const SectionTable& section_table_;
1153#undef DEFINE_TYPE_CHECK_FOR
1154#undef FOR_EACH_SECTION_TYPE
1156Elf::Elf(Zone* zone, BaseWriteStream* stream,
Type type, Dwarf* dwarf)
1158 unwrapped_stream_(
stream),
1161 section_table_(new(zone) SectionTable(zone)) {
1163 ASSERT(type_ == Type::Snapshot || dwarf_ !=
nullptr);
1168void Elf::AddText(
const char*
name,
1170 const uint8_t* bytes,
1172 const ZoneGrowableArray<Relocation>* relocations,
1173 const ZoneGrowableArray<SymbolData>* symbols) {
1174 auto*
const container =
new (zone_) TextSection(type_);
1175 container->AddPortion(bytes, size, relocations, symbols,
name, label);
1176 section_table_->Add(container, kTextName);
1179void Elf::CreateBSS() {
1181 ASSERT(section_table_->Find(kBssName) ==
nullptr);
1183 auto*
const text_section = section_table_->Find(kTextName);
1184 if (text_section ==
nullptr)
return;
1185 ASSERT(text_section->IsTextSection());
1187 auto*
const bss_container =
new (zone_) BssSection(type_);
1188 for (
const auto& portion : text_section->AsBitsContainer()->portions()) {
1190 const char* symbol_name;
1194 size = BSS::kVmEntryCount * compiler::target::kWordSize;
1196 label = kVmBssLabel;
1197 }
else if (strcmp(portion.symbol_name,
1199 size = BSS::kIsolateGroupEntryCount * compiler::target::kWordSize;
1201 label = kIsolateBssLabel;
1208 uint8_t* bytes =
nullptr;
1209 if (type_ == Type::Snapshot) {
1215 bytes = zone_->Alloc<uint8_t>(
size);
1216 memset(bytes, 0, size);
1221 auto*
symbols =
new (zone_) ZoneGrowableArray<Elf::SymbolData>();
1222 symbols->Add({symbol_name, elf::STT_SECTION, 0,
size, label});
1223 bss_container->AddPortion(bytes, size,
nullptr, symbols);
1226 section_table_->Add(bss_container, kBssName);
1229void Elf::AddROData(
const char*
name,
1231 const uint8_t* bytes,
1233 const ZoneGrowableArray<Relocation>* relocations,
1234 const ZoneGrowableArray<SymbolData>* symbols) {
1235 auto*
const container =
new (zone_) DataSection(type_);
1236 container->AddPortion(bytes, size, relocations, symbols,
name, label);
1237 section_table_->Add(container, kDataName);
1240#if defined(DART_PRECOMPILER)
1241class DwarfElfStream :
public DwarfWriteStream {
1243 DwarfElfStream(Zone* zone, NonStreamingWriteStream* stream)
1246 relocations_(new(zone) ZoneGrowableArray<Elf::Relocation>()) {}
1248 const uint8_t*
buffer()
const {
return stream_->buffer(); }
1249 intptr_t bytes_written()
const {
return stream_->bytes_written(); }
1250 intptr_t Position()
const {
return stream_->Position(); }
1252 void sleb128(intptr_t value) { stream_->WriteSLEB128(value); }
1253 void uleb128(uintptr_t value) { stream_->WriteLEB128(value); }
1254 void u1(uint8_t value) { stream_->WriteByte(value); }
1255 void u2(uint16_t value) { stream_->WriteFixed(value); }
1256 void u4(uint32_t value) { stream_->WriteFixed(value); }
1257 void u8(uint64_t value) { stream_->WriteFixed(value); }
1258 void string(
const char* cstr) {
1260 stream_->WriteBytes(cstr, strlen(cstr) + 1);
1263 void WritePrefixedLength(
const char*
unused, std::function<
void()> body) {
1264 const intptr_t fixup = stream_->Position();
1269 const intptr_t
start = stream_->Position();
1271 const intptr_t
end = stream_->Position();
1272 stream_->SetPosition(fixup);
1274 stream_->SetPosition(
end);
1277 void WritePrefixedLength(std::function<
void()> body) {
1278 WritePrefixedLength(
nullptr, body);
1281 void OffsetFromSymbol(intptr_t label, intptr_t
offset) {
1282 relocations_->Add({kAddressSize, stream_->Position(),
1283 Elf::Relocation::kSnapshotRelative, 0, label,
offset});
1286 template <
typename T>
1287 void RelativeSymbolOffset(intptr_t label) {
1288 relocations_->Add({
sizeof(
T), stream_->Position(),
1289 Elf::Relocation::kSelfRelative, 0, label, 0});
1290 stream_->WriteFixed<
T>(0);
1292 void InitializeAbstractOrigins(intptr_t size) {
1293 abstract_origins_size_ =
size;
1294 abstract_origins_ = zone_->Alloc<uint32_t>(abstract_origins_size_);
1296 void RegisterAbstractOrigin(intptr_t index) {
1297 ASSERT(abstract_origins_ !=
nullptr);
1298 ASSERT(index < abstract_origins_size_);
1299 abstract_origins_[index] = stream_->Position();
1301 void AbstractOrigin(intptr_t index) { u4(abstract_origins_[index]); }
1303 const ZoneGrowableArray<Elf::Relocation>* relocations()
const {
1304 return relocations_;
1308#if defined(TARGET_ARCH_IS_32_BIT)
1309 static constexpr intptr_t kAddressSize =
kInt32Size;
1311 static constexpr intptr_t kAddressSize =
kInt64Size;
1314 void addr(uword value) {
1315#if defined(TARGET_ARCH_IS_32_BIT)
1323 NonStreamingWriteStream*
const stream_;
1324 ZoneGrowableArray<Elf::Relocation>* relocations_ =
nullptr;
1325 uint32_t* abstract_origins_ =
nullptr;
1326 intptr_t abstract_origins_size_ = -1;
1332static constexpr intptr_t kInitialDwarfBufferSize = 64 *
KB;
1335void SymbolTable::Initialize(
const GrowableArray<Section*>& sections) {
1336 for (
auto*
const section : sections) {
1338 if (!section->IsAllocated())
continue;
1339 if (
auto*
const bits = section->AsBitsContainer()) {
1340 for (
const auto& portion : section->AsBitsContainer()->portions()) {
1341 if (portion.symbol_name !=
nullptr) {
1344 const intptr_t binding = elf::STB_GLOBAL;
1345 const intptr_t
type = elf::STT_OBJECT;
1349 AddSymbol(portion.symbol_name, binding,
type, portion.size,
1350 section->index, portion.offset, portion.label);
1352 if (!dynamic_ && portion.symbols !=
nullptr) {
1353 for (
const auto& symbol_data : *portion.
symbols) {
1355 AddSymbol(symbol_data.name, elf::STB_LOCAL, symbol_data.type,
1356 symbol_data.size, section->index,
1357 portion.offset + symbol_data.offset, symbol_data.label);
1365void Elf::InitializeSymbolTables() {
1367 ASSERT(symtab_ ==
nullptr);
1370 auto*
const dynstrtab =
new (zone_) StringTable(zone_,
true);
1371 section_table_->Add(dynstrtab,
".dynstr");
1372 auto*
const dynsym =
1373 new (zone_) SymbolTable(zone_, dynstrtab,
true);
1374 section_table_->Add(dynsym,
".dynsym");
1375 dynsym->Initialize(section_table_->sections());
1378 auto*
const hash =
new (zone_) SymbolHashTable(zone_, dynsym);
1379 section_table_->Add(
hash,
".hash");
1380 auto*
const dynamic =
new (zone_) DynamicTable(zone_, dynsym,
hash);
1381 section_table_->Add(dynamic, kDynamicTableName);
1386 auto*
const strtab =
new (zone_) StringTable(zone_,
false);
1387 if (!IsStripped()) {
1388 section_table_->Add(strtab,
".strtab");
1390 symtab_ =
new (zone_) SymbolTable(zone_, strtab,
false);
1391 if (!IsStripped()) {
1392 section_table_->Add(symtab_,
".symtab");
1394 symtab_->Initialize(section_table_->sections());
1397void Elf::FinalizeEhFrame() {
1398#if !defined(TARGET_ARCH_IA32)
1399#if defined(TARGET_ARCH_X64)
1402 const intptr_t DWARF_RA = 16;
1403 const intptr_t DWARF_FP = 6;
1406 const intptr_t DWARF_FP =
FP;
1410 TextSection* text_section =
nullptr;
1411 if (
auto*
const section = section_table_->Find(kTextName)) {
1412 text_section = section->AsTextSection();
1413 ASSERT(text_section !=
nullptr);
1416 if (text_section ==
nullptr)
return;
1418#if defined(DART_TARGET_OS_WINDOWS) && \
1419 (defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64))
1422 auto*
const unwinding_instructions_frame =
new (zone_) TextSection(type_);
1425 UnwindingRecordsPlatform::SizeInBytes());
1426 uint8_t* unwinding_instructions =
1427 zone()->Alloc<uint8_t>(UnwindingRecordsPlatform::SizeInBytes());
1429 intptr_t start_offset =
1430 Utils::RoundUp(text_section->FileSize(), text_section->alignment);
1431 stream.WriteBytes(UnwindingRecords::GenerateRecordsInto(
1432 start_offset, unwinding_instructions),
1433 UnwindingRecordsPlatform::SizeInBytes());
1435 unwinding_instructions_frame->AddPortion(
stream.buffer(),
1437 section_table_->Add(unwinding_instructions_frame, kTextName);
1443 const intptr_t kDataAlignment = -compiler::target::kWordSize;
1445 static constexpr uint8_t DW_EH_PE_pcrel = 0x10;
1446 static constexpr uint8_t DW_EH_PE_sdata4 = 0x0b;
1448 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1449 DwarfElfStream dwarf_stream(zone_, &stream);
1454 const intptr_t cie_start = dwarf_stream.Position();
1455 dwarf_stream.WritePrefixedLength([&] {
1459 dwarf_stream.string(
"zR");
1460 dwarf_stream.uleb128(1);
1461 dwarf_stream.sleb128(kDataAlignment);
1462 dwarf_stream.u1(DWARF_RA);
1463 dwarf_stream.uleb128(1);
1464 dwarf_stream.u1(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
1466 dwarf_stream.u1(Dwarf::DW_CFA_def_cfa);
1467 dwarf_stream.uleb128(DWARF_FP);
1468 dwarf_stream.uleb128(kCallerSpSlotFromFp * compiler::target::kWordSize);
1472 const auto cfa_offset = [&](intptr_t reg, intptr_t
offset) {
1473 const intptr_t scaled_offset =
offset / kDataAlignment;
1475 dwarf_stream.u1(Dwarf::DW_CFA_offset | reg);
1476 dwarf_stream.uleb128(scaled_offset);
1480 for (
const auto& portion : text_section->portions()) {
1481#if defined(DART_TARGET_OS_WINDOWS) && \
1482 (defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64))
1483 if (portion.label == 0) {
1488 ASSERT(portion.label != 0);
1489 dwarf_stream.WritePrefixedLength([&]() {
1492 dwarf_stream.u4(
stream.Position() - cie_start);
1494 dwarf_stream.RelativeSymbolOffset<int32_t>(portion.label);
1495 dwarf_stream.u4(portion.size);
1500 COMPILE_ASSERT((kSavedCallerFpSlotFromFp - kCallerSpSlotFromFp) <= 0);
1501 cfa_offset(DWARF_FP, (kSavedCallerFpSlotFromFp - kCallerSpSlotFromFp) *
1502 compiler::target::kWordSize);
1506 COMPILE_ASSERT((kSavedCallerPcSlotFromFp - kCallerSpSlotFromFp) <= 0);
1507 cfa_offset(DWARF_RA, (kSavedCallerPcSlotFromFp - kCallerSpSlotFromFp) *
1508 compiler::target::kWordSize);
1514 auto*
const eh_frame =
new (zone_)
1515 BitsContainer(type_,
false,
false);
1516 eh_frame->AddPortion(dwarf_stream.buffer(), dwarf_stream.bytes_written(),
1517 dwarf_stream.relocations());
1518 section_table_->Add(eh_frame,
".eh_frame");
1522void Elf::FinalizeDwarfSections() {
1523 if (dwarf_ ==
nullptr)
return;
1526 ASSERT(section_table_->HasSectionNamed(kTextName));
1528 auto add_debug = [&](
const char*
name,
const DwarfElfStream&
stream) {
1529 auto const container =
1530 new (zone_) BitsContainer(elf::SectionHeaderType::SHT_PROGBITS);
1531 container->AddPortion(
stream.buffer(),
stream.bytes_written(),
1533 section_table_->Add(container,
name);
1536 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1537 DwarfElfStream dwarf_stream(zone_, &stream);
1538 dwarf_->WriteAbbreviations(&dwarf_stream);
1539 add_debug(
".debug_abbrev", dwarf_stream);
1543 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1544 DwarfElfStream dwarf_stream(zone_, &stream);
1545 dwarf_->WriteDebugInfo(&dwarf_stream);
1546 add_debug(
".debug_info", dwarf_stream);
1550 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1551 DwarfElfStream dwarf_stream(zone_, &stream);
1552 dwarf_->WriteLineNumberProgram(&dwarf_stream);
1553 add_debug(
".debug_line", dwarf_stream);
1557ProgramTable* SectionTable::CreateProgramTable(SymbolTable* symtab) {
1558 const intptr_t num_sections = sections_.length();
1560 ASSERT(!sections_.is_empty());
1565 auto*
const program_table =
new (zone_) ProgramTable(zone_);
1567 GrowableArray<Section*> reordered_sections(zone_, num_sections);
1569 GrowableArray<intptr_t> index_map(zone_, num_sections);
1570 index_map.FillWith(0, 0, num_sections);
1572 Segment* current_segment =
nullptr;
1575 auto add_to_reordered_sections = [&](
Section* section) {
1576 intptr_t new_index = reordered_sections.length();
1577 index_map[section->index] = new_index;
1578 section->index = new_index;
1579 reordered_sections.Add(section);
1580 if (section->IsAllocated()) {
1581 ASSERT(current_segment !=
nullptr);
1582 if (!current_segment->Add(section)) {
1585 current_segment =
new (zone_)
1586 Segment(zone_, section, elf::ProgramHeaderType::PT_LOAD);
1587 program_table->Add(current_segment);
1594 add_to_reordered_sections(sections_[0]);
1619 auto*
const elf_header =
new (zone_) ElfHeader(*program_table, *
this);
1623 program_table->Add(
new (zone_) Segment(zone_, program_table,
1624 elf::ProgramHeaderType::PT_PHDR));
1629 new (zone_) Segment(zone_, elf_header, elf::ProgramHeaderType::PT_LOAD);
1630 program_table->Add(current_segment);
1631 current_segment->Add(program_table);
1636 auto add_sections_matching =
1637 [&](
const std::function<bool(Section*)>& should_add) {
1641 for (
auto*
const section : sections_) {
1642 if (!section->HasBits())
continue;
1643 if (should_add(section)) {
1644 add_to_reordered_sections(section);
1647 for (
auto*
const section : sections_) {
1648 if (section->HasBits())
continue;
1649 if (should_add(section)) {
1650 add_to_reordered_sections(section);
1657 auto*
const build_id = Find(Elf::kBuildIdNoteName);
1658 if (build_id !=
nullptr) {
1659 ASSERT(build_id->type == elf::SectionHeaderType::SHT_NOTE);
1660 add_to_reordered_sections(build_id);
1664 add_sections_matching([&](Section* section) ->
bool {
1665 if (section == build_id)
return false;
1666 return section->IsAllocated() && !section->IsWritable() &&
1667 !section->IsExecutable();
1671 add_sections_matching([](Section* section) ->
bool {
1672 return section->IsExecutable();
1676 add_sections_matching([](Section* section) ->
bool {
1677 return section->IsWritable();
1685 add_sections_matching([](Section* section) ->
bool {
1687 return !section->IsReservedSection() && !section->IsAllocated();
1691 ASSERT_EQUAL(sections_.length(), reordered_sections.length());
1694 sections_.AddArray(reordered_sections);
1697 ASSERT_EQUAL(index_map[elf::SHN_UNDEF], elf::SHN_UNDEF);
1701 for (
auto*
const section : sections_) {
1703 section->link = index_map[section->link];
1704 if (
auto*
const table = section->AsSymbolTable()) {
1705 table->UpdateSectionIndices(index_map);
1708 if (symtab->index == elf::SHN_UNDEF) {
1710 symtab->UpdateSectionIndices(index_map);
1714 if (build_id !=
nullptr) {
1717 new (zone_) Segment(zone_, build_id, elf::ProgramHeaderType::PT_NOTE));
1721 ASSERT(HasSectionNamed(Elf::kDynamicTableName));
1722 auto*
const dynamic = Find(Elf::kDynamicTableName)->AsDynamicTable();
1724 new (zone_) Segment(zone_, dynamic, elf::ProgramHeaderType::PT_DYNAMIC));
1728 auto*
const gnu_stack =
new (zone_) GnuStackSection();
1729 program_table->Add(
new (zone_) Segment(zone_, gnu_stack,
1730 elf::ProgramHeaderType::PT_GNU_STACK));
1732 return program_table;
1735void Elf::Finalize() {
1745 FinalizeDwarfSections();
1749 InitializeSymbolTables();
1754 program_table_ = section_table_->CreateProgramTable(symtab_);
1760 if (type_ == Type::Snapshot) {
1763 for (
auto*
const segment : program_table_->segments()) {
1764 for (
auto*
const section : segment->sections()) {
1766 section->memory_offset() % Elf::kPageSize);
1773 ElfWriteStream
wrapped(unwrapped_stream_, *
this);
1775 auto write_section = [&](
const Section* section) {
1776 wrapped.Align(section->alignment);
1780 section->file_offset() + section->FileSize());
1786 intptr_t section_index = 1;
1787 for (
auto*
const segment : program_table_->segments()) {
1788 if (segment->type != elf::ProgramHeaderType::PT_LOAD)
continue;
1789 wrapped.Align(segment->Alignment());
1790 for (
auto*
const section : segment->sections()) {
1791 ASSERT(section->IsAllocated());
1792 write_section(section);
1793 if (!section->IsPseudoSection()) {
1799 const auto& sections = section_table_->sections();
1800 for (; section_index < sections.length(); section_index++) {
1801 auto*
const section = sections[section_index];
1802 ASSERT(!section->IsAllocated());
1803 write_section(section);
1806 write_section(section_table_);
1813static constexpr const char* kBuildIdSegmentNames[]{
1819static constexpr intptr_t kBuildIdSegmentNamesLength =
1822static constexpr intptr_t kBuildIdHeaderSize =
1823 sizeof(elf::Note) +
sizeof(elf::ELF_NOTE_GNU);
1825void Elf::GenerateBuildId() {
1827 ASSERT(section_table_->Find(kBuildIdNoteName) ==
nullptr);
1828 uint32_t
hashes[kBuildIdSegmentNamesLength];
1834 auto*
const text_section = section_table_->Find(kTextName);
1835 if (text_section ==
nullptr)
return;
1836 ASSERT(text_section->IsTextSection());
1837 auto*
const text_bits = text_section->AsBitsContainer();
1838 auto*
const data_section = section_table_->Find(kDataName);
1839 ASSERT(data_section ==
nullptr || data_section->IsDataSection());
1845 bool has_any_text =
false;
1846 for (intptr_t i = 0; i < kBuildIdSegmentNamesLength; i++) {
1847 auto*
const name = kBuildIdSegmentNames[i];
1849 if (hashes[i] != 0) {
1850 has_any_text =
true;
1851 }
else if (data_section !=
nullptr) {
1852 hashes[i] = data_section->AsBitsContainer()->Hash(
name);
1857 if (!has_any_text)
return;
1858 auto const description_bytes =
reinterpret_cast<uint8_t*
>(
hashes);
1859 const size_t description_length =
sizeof(
hashes);
1861 ZoneWriteStream
stream(zone(), kBuildIdHeaderSize + description_length);
1862 stream.WriteFixed<
decltype(elf::Note::name_size)>(
sizeof(elf::ELF_NOTE_GNU));
1863 stream.WriteFixed<
decltype(elf::Note::description_size)>(description_length);
1864 stream.WriteFixed<
decltype(elf::Note::type)>(elf::NoteType::NT_GNU_BUILD_ID);
1866 stream.WriteBytes(elf::ELF_NOTE_GNU,
sizeof(elf::ELF_NOTE_GNU));
1868 stream.WriteBytes(description_bytes, description_length);
1869 auto*
const container =
new (zone_) NoteSection();
1870 container->AddPortion(
stream.buffer(),
stream.bytes_written(),
1873 section_table_->Add(container, kBuildIdNoteName);
1876void Elf::ComputeOffsets() {
1877 intptr_t file_offset = 0;
1878 intptr_t memory_offset = 0;
1881 const intptr_t num_sections = section_table_->SectionCount();
1882 GrowableArray<intptr_t> address_map(zone_, num_sections);
1885 auto calculate_section_offsets = [&](
Section* section) {
1886 file_offset = Utils::RoundUp(file_offset, section->alignment);
1887 section->set_file_offset(file_offset);
1888 file_offset += section->FileSize();
1889 if (section->IsAllocated()) {
1890 memory_offset = Utils::RoundUp(memory_offset, section->alignment);
1891 section->set_memory_offset(memory_offset);
1892 memory_offset += section->MemorySize();
1896 intptr_t section_index = 1;
1897 for (
auto*
const segment : program_table_->segments()) {
1898 if (segment->type != elf::ProgramHeaderType::PT_LOAD)
continue;
1900 file_offset = Utils::RoundUp(file_offset, segment->Alignment());
1901 memory_offset = Utils::RoundUp(memory_offset, segment->Alignment());
1902 for (
auto*
const section : segment->sections()) {
1903 ASSERT(section->IsAllocated());
1904 calculate_section_offsets(section);
1905 if (!section->IsPseudoSection()) {
1909 address_map.Add(section->memory_offset());
1916 const auto& sections = section_table_->sections();
1917 for (; section_index < sections.length(); section_index++) {
1918 auto*
const section = sections[section_index];
1919 ASSERT(!section->IsAllocated());
1920 calculate_section_offsets(section);
1926 calculate_section_offsets(section_table_);
1930 for (
auto*
const segment : program_table_->segments()) {
1931 ASSERT(Utils::IsAligned(segment->MemoryOffset(), segment->Alignment()));
1939 for (
auto*
const section : sections) {
1940 if (
auto*
const table = section->AsSymbolTable()) {
1941 table->Finalize(address_map);
1942 }
else if (
auto*
const dynamic = section->AsDynamicTable()) {
1943 dynamic->Finalize();
1949 symtab_->Finalize(address_map);
1953void ElfHeader::Write(ElfWriteStream* stream)
const {
1956#if defined(TARGET_ARCH_IS_32_BIT)
1957 uint8_t
size = elf::ELFCLASS32;
1959 uint8_t
size = elf::ELFCLASS64;
1961 uint8_t e_ident[16] = {0x7f,
1977 stream->WriteBytes(e_ident, 16);
1979 stream->WriteHalf(elf::ET_DYN);
1981#if defined(TARGET_ARCH_IA32)
1982 stream->WriteHalf(elf::EM_386);
1983#elif defined(TARGET_ARCH_X64)
1984 stream->WriteHalf(elf::EM_X86_64);
1985#elif defined(TARGET_ARCH_ARM)
1986 stream->WriteHalf(elf::EM_ARM);
1987#elif defined(TARGET_ARCH_ARM64)
1988 stream->WriteHalf(elf::EM_AARCH64);
1989#elif defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
1990 stream->WriteHalf(elf::EM_RISCV);
1992 FATAL(
"Unknown ELF architecture");
1995 stream->WriteWord(elf::EV_CURRENT);
1997 stream->WriteOff(program_table_.file_offset());
1998 stream->WriteOff(section_table_.file_offset());
2000#if defined(TARGET_ARCH_ARM)
2001 uword flags = elf::EF_ARM_ABI | (TargetCPUFeatures::hardfp_supported()
2002 ? elf::EF_ARM_ABI_FLOAT_HARD
2003 : elf::EF_ARM_ABI_FLOAT_SOFT);
2009 stream->WriteHalf(
sizeof(elf::ElfHeader));
2010 stream->WriteHalf(program_table_.entry_size);
2011 stream->WriteHalf(program_table_.SegmentCount());
2012 stream->WriteHalf(section_table_.entry_size);
2013 stream->WriteHalf(section_table_.SectionCount());
2014 stream->WriteHalf(
stream->elf().section_table().StringTableIndex());
2017void ProgramTable::Write(ElfWriteStream* stream)
const {
2018 ASSERT(segments_.length() > 0);
2021 ASSERT(segments_[0]->
type == elf::ProgramHeaderType::PT_PHDR);
2029 bool last_writable =
true;
2030 int non_writable_groups = 0;
2032 for (intptr_t i = 0; i < segments_.length(); i++) {
2033 const Segment*
const segment = segments_[i];
2034 ASSERT(segment->type != elf::ProgramHeaderType::PT_NULL);
2035 ASSERT_EQUAL(i == 0, segment->type == elf::ProgramHeaderType::PT_PHDR);
2037 if (segment->type == elf::ProgramHeaderType::PT_LOAD) {
2038 if (last_writable && !segment->IsWritable()) {
2039 non_writable_groups++;
2041 last_writable = segment->IsWritable();
2045 segment->WriteProgramHeader(stream);
2046 const intptr_t
end =
stream->Position();
2053 ASSERT(non_writable_groups <= 1);
2057void SectionTable::Write(ElfWriteStream* stream)
const {
2058 for (intptr_t i = 0; i < sections_.length(); i++) {
2059 const Section*
const section = sections_[i];
2062 ASSERT(section->link < sections_.length());
2064 section->WriteSectionHeader(stream);
2065 const intptr_t
end =
stream->Position();
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static sk_sp< GrTextureProxy > wrapped(skiatest::Reporter *reporter, GrRecordingContext *rContext, GrProxyProvider *proxyProvider, SkBackingFit fit)
#define DEBUG_ASSERT(cond)
#define ASSERT_EQUAL(expected, actual)
#define RELEASE_ASSERT(cond)
#define COMPILE_ASSERT(expr)
#define ASSERT_NOTNULL(ptr)
#define kIsolateSnapshotDataAsmSymbol
#define kIsolateSnapshotBssAsmSymbol
#define kIsolateSnapshotInstructionsAsmSymbol
#define kVmSnapshotBssAsmSymbol
#define kVmSnapshotDataAsmSymbol
#define kVmSnapshotInstructionsAsmSymbol
#define kSnapshotBuildIdAsmSymbol
FlutterSemanticsFlag flags
static const uint8_t buffer[]
constexpr intptr_t kInt64Size
Register ConcreteRegister(LinkRegister)
constexpr intptr_t kInt32Size
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
void Initialize(zx::channel directory_request, std::optional< zx::eventpair > view_ref)
Initializes Dart bindings for the Fuchsia application model.
#define ARRAY_SIZE(array)