Skip to content

Commit 2e939f2

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
[vm/aot] Move ELF section manipulation out of CreateAppAOTSnapshotAsElf.
Instead, we just always add a BSS section and we add the ROData sections for ELF snapshots in BlobImageWriter::WriteText() (similar to how AssemblyImageWriter::WriteText() handles it for assembly). Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try Change-Id: I87ce64037821ce10f2344964e7f379376c4538df Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150937 Reviewed-by: Martin Kustermann <[email protected]>
1 parent 261e283 commit 2e939f2

File tree

6 files changed

+110
-68
lines changed

6 files changed

+110
-68
lines changed

runtime/vm/dart_api_impl.cc

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6443,9 +6443,10 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
64436443
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
64446444
callback, debug_callback_data);
64456445

6446-
auto const elf = generate_debug ? new (Z)
6447-
Elf(Z, &debug_stream, new (Z) Dwarf(Z))
6448-
: nullptr;
6446+
auto const elf = generate_debug
6447+
? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo,
6448+
new (Z) Dwarf(Z))
6449+
: nullptr;
64496450

64506451
AssemblyImageWriter image_writer(T, callback, callback_data, strip, elf);
64516452
uint8_t* vm_snapshot_data_buffer = NULL;
@@ -6517,49 +6518,23 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
65176518
callback, debug_callback_data);
65186519

65196520
auto const dwarf = strip ? nullptr : new (Z) Dwarf(Z);
6520-
auto const elf = new (Z) Elf(Z, &elf_stream, dwarf);
6521-
// Re-use the same DWARF object if unstripped.
6521+
auto const elf = new (Z) Elf(Z, &elf_stream, Elf::Type::Snapshot, dwarf);
6522+
// Re-use the same DWARF object if the snapshot is unstripped.
65226523
auto const debug_elf =
6523-
generate_debug
6524-
? new (Z) Elf(Z, &debug_stream, strip ? new (Z) Dwarf(Z) : dwarf)
6525-
: nullptr;
6526-
6527-
// Here, both VM and isolate will be compiled into a single snapshot.
6528-
// In assembly generation, each serialized text section gets a separate
6529-
// pointer into the BSS segment and BSS slots are created for each, since
6530-
// we may not serialize both VM and isolate. Here, we always serialize both,
6531-
// so make a BSS segment large enough for both, with the VM entries coming
6532-
// first.
6533-
auto const isolate_offset = BSS::kVmEntryCount * compiler::target::kWordSize;
6534-
auto const bss_size =
6535-
isolate_offset + BSS::kIsolateEntryCount * compiler::target::kWordSize;
6536-
// Note that the BSS section must come first because it cannot be placed in
6537-
// between any two non-writable segments, due to a bug in Jelly Bean's ELF
6538-
// loader. See also Elf::WriteProgramTable().
6539-
const intptr_t vm_bss_base = elf->AddBSSData("_kDartBSSData", bss_size);
6540-
const intptr_t isolate_bss_base = vm_bss_base + isolate_offset;
6541-
// Add the BSS section to the separately saved debugging information, even
6542-
// though there will be no code in it to relocate, since it precedes the
6543-
// .text sections and thus affects their virtual addresses.
6544-
if (debug_elf != nullptr) {
6545-
debug_elf->AddBSSData("_kDartBSSData", bss_size);
6546-
}
6524+
generate_debug ? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo,
6525+
strip ? new (Z) Dwarf(Z) : dwarf)
6526+
: nullptr;
65476527

65486528
BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions_buffer,
6549-
ApiReallocate, kInitialSize, debug_elf,
6550-
vm_bss_base, elf);
6529+
ApiReallocate, kInitialSize, debug_elf, elf);
65516530
BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions_buffer,
65526531
ApiReallocate, kInitialSize, debug_elf,
6553-
isolate_bss_base, elf);
6532+
elf);
65546533
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
65556534
&isolate_snapshot_data_buffer, ApiReallocate,
65566535
&vm_image_writer, &isolate_image_writer);
65576536

65586537
writer.WriteFullSnapshot();
6559-
elf->AddROData(kVmSnapshotDataAsmSymbol, vm_snapshot_data_buffer,
6560-
writer.VmIsolateSnapshotSize());
6561-
elf->AddROData(kIsolateSnapshotDataAsmSymbol, isolate_snapshot_data_buffer,
6562-
writer.IsolateSnapshotSize());
65636538

65646539
elf->Finalize();
65656540
if (debug_elf != nullptr) {

runtime/vm/elf.cc

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -678,14 +678,29 @@ class DynamicSegment : public BlobSection {
678678

679679
static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
680680

681-
Elf::Elf(Zone* zone, StreamingWriteStream* stream, Dwarf* dwarf)
681+
// Here, both VM and isolate will be compiled into a single snapshot.
682+
// In assembly generation, each serialized text section gets a separate
683+
// pointer into the BSS segment and BSS slots are created for each, since
684+
// we may not serialize both VM and isolate. Here, we always serialize both,
685+
// so make a BSS segment large enough for both, with the VM entries coming
686+
// first.
687+
static const intptr_t kBssIsolateOffset =
688+
BSS::kVmEntryCount * compiler::target::kWordSize;
689+
static const intptr_t kBssSize =
690+
kBssIsolateOffset + BSS::kIsolateEntryCount * compiler::target::kWordSize;
691+
692+
Elf::Elf(Zone* zone, StreamingWriteStream* stream, Type type, Dwarf* dwarf)
682693
: zone_(zone),
683694
unwrapped_stream_(stream),
695+
type_(type),
684696
dwarf_(dwarf),
697+
bss_(CreateBSS(zone, type, kBssSize)),
685698
shstrtab_(new (zone) StringTable(/*allocate=*/false)),
686699
dynstrtab_(new (zone) StringTable(/*allocate=*/true)),
687700
dynsym_(new (zone) SymbolTable(/*dynamic=*/true)),
688701
memory_offset_(kProgramTableSegmentSize) {
702+
// Separate debugging information should always have a Dwarf object.
703+
ASSERT(type_ == Type::Snapshot || dwarf_ != nullptr);
689704
// Assumed by various offset logic in this file.
690705
ASSERT_EQUAL(unwrapped_stream_->position(), 0);
691706
// The first section in the section header table is always a reserved
@@ -702,6 +717,19 @@ Elf::Elf(Zone* zone, StreamingWriteStream* stream, Dwarf* dwarf)
702717
AddSection(symtab_, ".symtab");
703718
symtab_->section_link = strtab_->section_index();
704719
}
720+
// Note that the BSS segment must be the first user-defined segment because
721+
// it cannot be placed in between any two non-writable segments, due to a bug
722+
// in Jelly Bean's ELF loader. See also Elf::WriteProgramTable().
723+
//
724+
// We add it in all cases, even to the separate debugging information ELF,
725+
// to ensure that relocated addresses are consistent between ELF snapshots
726+
// and ELF separate debugging information.
727+
AddSection(bss_, ".bss");
728+
AddSegmentSymbol(bss_, "_kDartBSSData");
729+
}
730+
731+
uword Elf::BssStart(bool vm) const {
732+
return bss_->memory_offset() + (vm ? 0 : kBssIsolateOffset);
705733
}
706734

707735
void Elf::AddSection(Section* section, const char* name) {
@@ -734,11 +762,14 @@ intptr_t Elf::AddSegmentSymbol(const Section* section, const char* name) {
734762
}
735763

736764
intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
737-
Section* image = nullptr;
738-
if (bytes != nullptr) {
739-
image = new (zone_) ProgramBits(true, true, false, bytes, size);
740-
} else {
765+
// When making a separate debugging info file for assembly, we don't have
766+
// the binary text segment contents.
767+
ASSERT(type_ == Type::DebugInfo || bytes != nullptr);
768+
Section* image;
769+
if (type_ == Type::DebugInfo) {
741770
image = new (zone_) NoBits(true, true, false, size);
771+
} else {
772+
image = new (zone_) ProgramBits(true, true, false, bytes, size);
742773
}
743774
AddSection(image, ".text");
744775

@@ -776,28 +807,34 @@ bool Elf::FindStaticSymbol(const char* name,
776807
return FindSymbol(strtab_, symtab_, name, offset, size);
777808
}
778809

779-
intptr_t Elf::AddBSSData(const char* name, intptr_t size) {
780-
// Ideally the BSS segment would take no space in the object, but Android's
781-
// "strip" utility truncates the memory-size of our segments to their
782-
// file-size.
783-
//
784-
// Therefore we must insert zero-filled pages for the BSS.
785-
uint8_t* const bytes = zone_->Alloc<uint8_t>(size);
786-
memset(bytes, 0, size);
787-
788-
ProgramBits* const image =
789-
new (zone_) ProgramBits(true, false, true, bytes, size);
810+
Section* Elf::CreateBSS(Zone* zone, Type type, intptr_t size) {
811+
Section* image;
812+
if (type == Type::DebugInfo) {
813+
image = new (zone) NoBits(true, false, true, size);
814+
} else {
815+
// Ideally the BSS segment would take no space in the object, but Android's
816+
// "strip" utility truncates the memory-size of our segments to their
817+
// file-size.
818+
//
819+
// Therefore we must insert zero-filled pages for the BSS.
820+
uint8_t* const bytes = zone->Alloc<uint8_t>(size);
821+
memset(bytes, 0, size);
822+
image = new (zone) ProgramBits(true, false, true, bytes, size);
823+
}
790824
static_assert(Image::kBssAlignment <= kPageSize,
791825
"ELF .bss section is not aligned as expected by Image class");
792826
ASSERT_EQUAL(image->alignment, kPageSize);
793-
AddSection(image, ".bss");
794-
795-
return AddSegmentSymbol(image, name);
827+
return image;
796828
}
797829

798830
intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
799831
ASSERT(bytes != nullptr);
800-
ProgramBits* image = new (zone_) ProgramBits(true, false, false, bytes, size);
832+
Section* image;
833+
if (type_ == Type::DebugInfo) {
834+
image = new (zone_) NoBits(true, false, false, size);
835+
} else {
836+
image = new (zone_) ProgramBits(true, false, false, bytes, size);
837+
}
801838
AddSection(image, ".rodata");
802839

803840
return AddSegmentSymbol(image, name);

runtime/vm/elf.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,31 @@ class SymbolTable;
2424

2525
class Elf : public ZoneAllocated {
2626
public:
27-
Elf(Zone* zone, StreamingWriteStream* stream, Dwarf* dwarf = nullptr);
27+
enum class Type {
28+
// A snapshot that should include segment contents.
29+
Snapshot,
30+
// Separately compiled debugging information that should not include
31+
// most segment contents.
32+
DebugInfo,
33+
};
34+
35+
Elf(Zone* zone,
36+
StreamingWriteStream* stream,
37+
Type type,
38+
Dwarf* dwarf = nullptr);
2839

2940
static const intptr_t kPageSize = 4096;
3041

3142
Zone* zone() { return zone_; }
3243
const Dwarf* dwarf() const { return dwarf_; }
3344
Dwarf* dwarf() { return dwarf_; }
3445

46+
uword BssStart(bool vm) const;
47+
3548
intptr_t NextMemoryOffset() const { return memory_offset_; }
3649
intptr_t NextSectionIndex() const { return sections_.length(); }
3750
intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
3851
intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
39-
intptr_t AddBSSData(const char* name, intptr_t size);
4052
void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
4153

4254
// Returns whether the symbol was found. If found, sets the contents of
@@ -66,6 +78,8 @@ class Elf : public ZoneAllocated {
6678
intptr_t address,
6779
intptr_t size);
6880

81+
static Section* CreateBSS(Zone* zone, Type type, intptr_t size);
82+
6983
const Section* FindSegmentForAddress(intptr_t address) const;
7084

7185
void FinalizeDwarfSections();
@@ -79,10 +93,15 @@ class Elf : public ZoneAllocated {
7993

8094
Zone* const zone_;
8195
StreamingWriteStream* const unwrapped_stream_;
96+
const Type type_;
8297
// If nullptr, then the ELF file should be stripped of static information like
8398
// the static symbol table (and its corresponding string table).
8499
Dwarf* const dwarf_;
85100

101+
// We always create a BSS section for all Elf files, though it may be NOBITS
102+
// if this is separate debugging information.
103+
Section* const bss_;
104+
86105
// All our strings would fit in a single page. However, we use separate
87106
// .shstrtab and .dynstr to work around a bug in Android's strip utility.
88107
StringTable* const shstrtab_;

runtime/vm/image_snapshot.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,8 @@ void ImageWriter::Write(WriteStream* clustered_stream, bool vm) {
418418

419419
offset_space_ = vm ? V8SnapshotProfileWriter::kVmText
420420
: V8SnapshotProfileWriter::kIsolateText;
421+
// Needs to happen after WriteROData, because all image writers currently
422+
// add the clustered data information to their output in WriteText().
421423
WriteText(clustered_stream, vm);
422424
}
423425

@@ -1190,12 +1192,10 @@ BlobImageWriter::BlobImageWriter(Thread* thread,
11901192
ReAlloc alloc,
11911193
intptr_t initial_size,
11921194
Elf* debug_elf,
1193-
intptr_t bss_base,
11941195
Elf* elf)
11951196
: ImageWriter(thread),
11961197
instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
11971198
elf_(elf),
1198-
bss_base_(bss_base),
11991199
debug_elf_(debug_elf) {
12001200
#if defined(DART_PRECOMPILER)
12011201
ASSERT(debug_elf_ == nullptr || debug_elf_->dwarf() != nullptr);
@@ -1248,7 +1248,8 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
12481248
#if defined(DART_PRECOMPILER)
12491249
// Store the offset of the BSS section from the instructions section here.
12501250
// If not compiling to ELF (and thus no BSS segment), write 0.
1251-
const word bss_offset = elf_ != nullptr ? bss_base_ - segment_base : 0;
1251+
const word bss_offset =
1252+
elf_ != nullptr ? elf_->BssStart(vm) - segment_base : 0;
12521253
ASSERT_EQUAL(Utils::RoundDown(bss_offset, Image::kBssAlignment), bss_offset);
12531254
// Set the lowest bit if we are compiling to ELF.
12541255
const word compiled_to_elf = elf_ != nullptr ? 0x1 : 0x0;
@@ -1479,17 +1480,26 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
14791480
ASSERT_EQUAL(text_offset, image_size);
14801481

14811482
#ifdef DART_PRECOMPILER
1483+
auto const data_symbol =
1484+
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
14821485
if (elf_ != nullptr) {
14831486
auto const segment_base2 =
14841487
elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
14851488
instructions_blob_stream_.bytes_written());
14861489
ASSERT(segment_base == segment_base2);
1490+
// Write the .rodata section here like the AssemblyImageWriter.
1491+
elf_->AddROData(data_symbol, clustered_stream->buffer(),
1492+
clustered_stream->bytes_written());
14871493
}
14881494
if (debug_elf_ != nullptr) {
1489-
auto const debug_segment_base2 =
1490-
debug_elf_->AddText(instructions_symbol, nullptr,
1491-
instructions_blob_stream_.bytes_written());
1495+
// To keep memory addresses consistent, we need to add corresponding
1496+
// sections (though these will be NOBITS sections).
1497+
auto const debug_segment_base2 = debug_elf_->AddText(
1498+
instructions_symbol, instructions_blob_stream_.buffer(),
1499+
instructions_blob_stream_.bytes_written());
14921500
ASSERT(debug_segment_base == debug_segment_base2);
1501+
debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
1502+
clustered_stream->bytes_written());
14931503
}
14941504
#endif
14951505
}

runtime/vm/image_snapshot.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@ class BlobImageWriter : public ImageWriter {
429429
ReAlloc alloc,
430430
intptr_t initial_size,
431431
Elf* debug_elf = nullptr,
432-
intptr_t bss_base = 0,
433432
Elf* elf = nullptr);
434433

435434
virtual void WriteText(WriteStream* clustered_stream, bool vm);
@@ -443,7 +442,6 @@ class BlobImageWriter : public ImageWriter {
443442

444443
WriteStream instructions_blob_stream_;
445444
Elf* const elf_;
446-
const intptr_t bss_base_;
447445
Elf* const debug_elf_;
448446

449447
DISALLOW_COPY_AND_ASSIGN(BlobImageWriter);

tests/standalone_2/dwarf_stack_trace_test.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ Future<void> checkStackTrace(String rawStack, Dwarf dwarf,
7171
final absolutes = absoluteAddresses(rawLines);
7272
final relocatedAddresses = absolutes.map((a) => a - dsoBase);
7373
final explicits = explicitVirtualAddresses(rawLines);
74-
Expect.deepEquals(relocatedAddresses, virtualAddresses);
75-
// Explicits will be empty if not generating ELF snapshots directly.
74+
75+
// Explicits will be empty if not generating ELF snapshots directly, which
76+
// means we can't depend on virtual addresses in the snapshot lining up with
77+
// those in the separate debugging information.
7678
if (explicits.isNotEmpty) {
79+
Expect.deepEquals(relocatedAddresses, virtualAddresses);
7780
Expect.deepEquals(explicits, virtualAddresses);
7881
}
7982

0 commit comments

Comments
 (0)