Skip to content

Commit e160698

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
[vm/aot] Delay relocated address calculation for static symbols.
Since we no longer add the symbol for a given code object to the Elf object when writing the contents of the text segment, we don't need to calculate the relocated address that early. Instead, just store which text segment the instructions payload belongs to as well as its offset into the segment contents and let Elf::Finalize() calculate the relocated address when creating the symbol. This removes one need for knowing the segment base address when writing the segment contents. The remaining needs are related to BSS usage: * Calculating the BSS offset from the text segment for the Image header. * Fixing up BSS relocations in instructions payloads. Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try Change-Id: I8be860a7a7111721e6f546154a0814f4d16ac634 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150929 Commit-Queue: Tess Strickland <[email protected]> Reviewed-by: Clement Skau <[email protected]>
1 parent 6544c69 commit e160698

File tree

4 files changed

+99
-60
lines changed

4 files changed

+99
-60
lines changed

runtime/vm/dwarf.cc

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,36 +101,53 @@ Dwarf::Dwarf(Zone* zone)
101101
script_to_index_(zone),
102102
temp_(0) {}
103103

104-
intptr_t Dwarf::AddCode(const Code& non_zone_code, intptr_t relocated_address) {
105-
ASSERT(!non_zone_code.IsNull());
106-
ASSERT(relocated_address == kNoCodeAddress || relocated_address > 0);
107-
const auto& code = Code::ZoneHandle(zone_, non_zone_code.raw());
104+
SegmentRelativeOffset Dwarf::CodeAddress(const Code& code) const {
105+
const auto& pair = code_to_address_.LookupValue(&code);
106+
// This is only used by Elf::Finalize(), and the image writers always give a
107+
// text offset when calling AddCode() for an Elf object's Dwarf object. Thus,
108+
// we should have known code offsets for each code object in the map.
109+
ASSERT(pair.offset != SegmentRelativeOffset::kUnknownOffset);
110+
return pair;
111+
}
112+
113+
intptr_t Dwarf::AddCode(const Code& orig_code,
114+
const SegmentRelativeOffset& offset) {
115+
ASSERT(!orig_code.IsNull());
116+
// We should never get the no-argument constructed version here.
117+
ASSERT(offset.offset != SegmentRelativeOffset::kInvalidOffset);
118+
// Generate an appropriately zoned ZoneHandle for storing.
119+
const auto& code = Code::ZoneHandle(zone_, orig_code.raw());
108120

109121
// For now, we assume one of two flows for a given code object:
110-
// ELF: Calls to AddCode(code, address), address is the same over all calls.
111-
// Assembly: An initial call to AddCode(code) (assembly), possibly
112-
// followed by a later call to AddCode(code, address)
122+
// ELF: Calls to AddCode(code, vm, offset), vm and offset are the same over
123+
// all calls.
124+
// Assembly: An initial call to AddCode(code, vm) (assembly), possibly
125+
// followed by a later call to AddCode(code, vm, offset)
113126
// (separate debugging info ELF)
114-
if (relocated_address == kNoCodeAddress) {
127+
if (offset.offset == SegmentRelativeOffset::kUnknownOffset) {
115128
// A call without an address should always come before any calls with
116129
// addresses.
117130
ASSERT(code_to_address_.Lookup(&code) == nullptr);
118131
// Insert a marker so on later calls, we know we've already added to codes_.
119-
code_to_address_.Insert(CodeAddressPair(&code, kNoCodeAddress));
132+
code_to_address_.Insert(CodeAddressPair(&code, offset));
120133
} else {
121-
auto const old_value = code_to_address_.LookupValue(&code);
134+
const auto& old_value = code_to_address_.LookupValue(&code);
122135
// ELF does not need to know the index. If we've already added this Code
123136
// object to codes_ in a previous call, don't bother scanning codes_ to find
124137
// the corresponding index, just return -1 instead.
125-
switch (old_value) {
126-
case CodeAddressPair::kNoValue:
127-
code_to_address_.Insert(CodeAddressPair(&code, relocated_address));
138+
switch (old_value.offset) {
139+
case SegmentRelativeOffset::kInvalidOffset:
140+
code_to_address_.Insert(CodeAddressPair(&code, offset));
128141
break; // Still need to add to codes_.
129-
case kNoCodeAddress:
130-
code_to_address_.Update(CodeAddressPair(&code, relocated_address));
142+
case SegmentRelativeOffset::kUnknownOffset:
143+
// Code objects should only be associated with either the VM or isolate.
144+
ASSERT_EQUAL(old_value.vm, offset.vm);
145+
code_to_address_.Update(CodeAddressPair(&code, offset));
131146
return -1;
132147
default:
133-
ASSERT_EQUAL(old_value, relocated_address);
148+
// The information for the code object shouldn't have changed since the
149+
// previous update.
150+
ASSERT(old_value == offset);
134151
return -1;
135152
}
136153
}

runtime/vm/dwarf.h

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -82,41 +82,61 @@ struct FunctionIndexPair {
8282

8383
typedef DirectChainedHashMap<FunctionIndexPair> FunctionIndexMap;
8484

85+
struct SegmentRelativeOffset {
86+
// Used for the empty constructor (for hash map usage).
87+
static constexpr intptr_t kInvalidOffset = -2;
88+
// Used for cases where we know which segment, but don't know the offset.
89+
static constexpr intptr_t kUnknownOffset = -1;
90+
91+
SegmentRelativeOffset(bool vm, intptr_t offset) : vm(vm), offset(offset) {
92+
ASSERT(offset >= 0);
93+
}
94+
explicit SegmentRelativeOffset(bool vm) : vm(vm), offset(kUnknownOffset) {}
95+
SegmentRelativeOffset() : vm(false), offset(kInvalidOffset) {}
96+
97+
bool operator==(const SegmentRelativeOffset& b) const {
98+
return vm == b.vm && offset == b.offset;
99+
}
100+
bool operator==(const SegmentRelativeOffset& b) {
101+
return *const_cast<const SegmentRelativeOffset*>(this) == b;
102+
}
103+
bool operator!=(const SegmentRelativeOffset& b) { return !(*this == b); }
104+
105+
// Whether or not this is an offset into the VM text segment.
106+
bool vm;
107+
// The byte offset into the segment contents.
108+
intptr_t offset;
109+
};
110+
85111
struct CodeAddressPair {
86112
// Typedefs needed for the DirectChainedHashMap template.
87113
typedef const Code* Key;
88-
typedef intptr_t Value;
114+
typedef SegmentRelativeOffset Value;
89115
typedef CodeAddressPair Pair;
90116

91-
static constexpr intptr_t kNoValue = -1;
92-
static_assert(kNoValue < 0, "non-negative value used for kNoValue");
117+
static Key KeyOf(Pair kv) { return kv.code; }
93118

94-
static Key KeyOf(Pair kv) { return kv.code_; }
95-
96-
static Value ValueOf(Pair kv) { return kv.address_; }
119+
static Value ValueOf(Pair kv) { return kv.segment_offset; }
97120

98121
static inline intptr_t Hashcode(Key key) {
99122
// Code objects are always allocated in old space, so they don't move.
100123
return key->PayloadStart();
101124
}
102125

103126
static inline bool IsKeyEqual(Pair pair, Key key) {
104-
return pair.code_->raw() == key->raw();
127+
return pair.code->raw() == key->raw();
105128
}
106129

107-
CodeAddressPair(const Code* c, intptr_t address)
108-
: code_(c), address_(address) {
130+
CodeAddressPair(const Code* c, const SegmentRelativeOffset& o)
131+
: code(c), segment_offset(o) {
109132
ASSERT(!c->IsNull());
110133
ASSERT(c->IsNotTemporaryScopedHandle());
111-
ASSERT(address >= 0);
134+
ASSERT(o.offset == SegmentRelativeOffset::kUnknownOffset || o.offset >= 0);
112135
}
136+
CodeAddressPair() : code(nullptr), segment_offset() {}
113137

114-
CodeAddressPair() : code_(NULL), address_(kNoValue) {}
115-
116-
void Print() const;
117-
118-
const Code* code_;
119-
intptr_t address_;
138+
const Code* code;
139+
SegmentRelativeOffset segment_offset;
120140
};
121141

122142
typedef DirectChainedHashMap<CodeAddressPair> CodeAddressMap;
@@ -235,26 +255,16 @@ class Dwarf : public ZoneAllocated {
235255

236256
const ZoneGrowableArray<const Code*>& codes() const { return codes_; }
237257

238-
// Assumes that no code objects can be at a relocated address of 0 (true
239-
// for ELF, since the program header is at address 0).
240-
static constexpr intptr_t kNoCodeAddress = 0;
241-
242258
// Stores the code object for later creating the line number program.
243259
//
244-
// [relocated_address] is passed when the relocated address of the
245-
// instructions payload is known at snapshot generation time. For example,
246-
// it is provided when generating ELF snapshots.
247-
//
248260
// Returns the stored index of the code object when the relocated address
249-
// is not known at snapshot generation time (kNoCodeAddress).
250-
intptr_t AddCode(const Code& code,
251-
intptr_t relocated_address = kNoCodeAddress);
252-
253-
// Returns the stored relocated address for the given Code object. If no
254-
// address is stored, returns CodeAddressPair::kNoValue.
255-
intptr_t CodeAddress(const Code& code) const {
256-
return code_to_address_.LookupValue(&code);
257-
}
261+
// is not known at snapshot generation time (that is, when offset.offset is
262+
// SegmentRelativeOffset::kUnknownOffset).
263+
intptr_t AddCode(const Code& code, const SegmentRelativeOffset& offset);
264+
265+
// Returns the stored segment offset for the given Code object. If no
266+
// address is stored, the second element will be kNoCodeAddressPairOffset.
267+
SegmentRelativeOffset CodeAddress(const Code& code) const;
258268

259269
intptr_t AddFunction(const Function& function);
260270
intptr_t AddScript(const Script& script);

runtime/vm/elf.cc

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,8 @@ void Elf::FinalizeDwarfSections() {
974974
#if defined(DART_PRECOMPILER)
975975
// Add all the static symbols for Code objects. We'll keep a table of
976976
// symbol names to relocated addresses for use in the DwarfElfStream.
977+
// The default kNoValue of 0 is okay here, as no symbols are defined for
978+
// relocated address 0.
977979
CStringMap<intptr_t> symbol_to_address_map;
978980
// Prime the map with any existing static symbols.
979981
if (symtab_ != nullptr) {
@@ -986,15 +988,27 @@ void Elf::FinalizeDwarfSections() {
986988
}
987989
}
988990

991+
// Need these to turn offsets into relocated addresses.
992+
auto const vm_start =
993+
symbol_to_address_map.LookupValue(kVmSnapshotInstructionsAsmSymbol);
994+
ASSERT(vm_start > 0);
995+
auto const isolate_start =
996+
symbol_to_address_map.LookupValue(kIsolateSnapshotInstructionsAsmSymbol);
997+
ASSERT(isolate_start > 0);
998+
auto const vm_text = FindSegmentForAddress(vm_start);
999+
ASSERT(vm_text != nullptr);
1000+
auto const isolate_text = FindSegmentForAddress(isolate_start);
1001+
ASSERT(isolate_text != nullptr);
1002+
9891003
SnapshotTextObjectNamer namer(zone_);
9901004
const auto& codes = dwarf_->codes();
9911005
for (intptr_t i = 0; i < codes.length(); i++) {
9921006
const auto& code = *codes[i];
9931007
auto const name = namer.SnapshotNameFor(i, code);
994-
auto const address = dwarf_->CodeAddress(code);
995-
ASSERT(address != CodeAddressPair::kNoValue);
996-
auto const segment = FindSegmentForAddress(address);
997-
ASSERT(segment != nullptr);
1008+
const auto& pair = dwarf_->CodeAddress(code);
1009+
ASSERT(pair.offset > 0);
1010+
auto const segment = pair.vm ? vm_text : isolate_text;
1011+
const intptr_t address = segment->memory_offset() + pair.offset;
9981012
auto const info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
9991013
AddStaticSymbol(name, info, segment->section_index(), address, code.Size());
10001014
symbol_to_address_map.Insert({name, address});

runtime/vm/image_snapshot.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
858858
intptr_t dwarf_index = i;
859859
#if defined(DART_PRECOMPILER)
860860
if (!is_trampoline && assembly_dwarf_ != nullptr) {
861-
dwarf_index = assembly_dwarf_->AddCode(*data.code_);
861+
dwarf_index =
862+
assembly_dwarf_->AddCode(*data.code_, SegmentRelativeOffset(vm));
862863
}
863864
#endif
864865

@@ -937,8 +938,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
937938

938939
#if defined(DART_PRECOMPILER)
939940
if (debug_elf_ != nullptr) {
940-
auto const relocated_address = debug_segment_base + text_offset;
941-
debug_elf_->dwarf()->AddCode(code, relocated_address);
941+
debug_elf_->dwarf()->AddCode(code, {vm, text_offset});
942942
}
943943
#endif
944944
// 2. Write a label at the entry point.
@@ -1415,12 +1415,10 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
14151415
#if defined(DART_PRECOMPILER)
14161416
const auto& code = *data.code_;
14171417
if (elf_ != nullptr && elf_->dwarf() != nullptr) {
1418-
auto const relocated_address = segment_base + payload_offset;
1419-
elf_->dwarf()->AddCode(code, relocated_address);
1418+
elf_->dwarf()->AddCode(code, {vm, payload_offset});
14201419
}
14211420
if (debug_elf_ != nullptr) {
1422-
auto const relocated_address = debug_segment_base + payload_offset;
1423-
debug_elf_->dwarf()->AddCode(code, relocated_address);
1421+
debug_elf_->dwarf()->AddCode(code, {vm, payload_offset});
14241422
}
14251423

14261424
// Don't patch the relocation if we're not generating ELF. The regular blobs

0 commit comments

Comments
 (0)