blob: b2d9c43a4abfdbda81f2c63924e3ff0d07b0b406 [file] [log] [blame] [edit]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_SO_WRITER_H_
#define RUNTIME_VM_SO_WRITER_H_
#include "platform/globals.h"
#if defined(DART_PRECOMPILER)
#include "vm/allocation.h"
#include "vm/compiler/runtime_api.h"
#include "vm/datastream.h"
#include "vm/growable_array.h"
#include "vm/zone.h"
namespace dart {
class Dwarf;
class ElfWriter;
class MachOWriter;
class SharedObjectWriter : public ZoneAllocated {
public:
enum class Type {
// A snapshot that should include segment contents.
Snapshot,
// Separately compiled debugging information that should not include
// most segment contents.
DebugInfo,
};
enum class Output {
Elf,
MachO,
};
SharedObjectWriter(Zone* zone,
BaseWriteStream* stream,
Type type,
Dwarf* dwarf = nullptr)
: zone_(zone), unwrapped_stream_(stream), type_(type), dwarf_(dwarf) {
// Separate debugging information should always have a Dwarf object.
ASSERT(type == Type::Snapshot || dwarf != nullptr);
// Assumed by various offset logic in the subclasses.
ASSERT_EQUAL(stream->Position(), 0);
}
virtual ~SharedObjectWriter() {}
virtual intptr_t page_size() const = 0;
virtual Output output() const = 0;
static bool IsStripped(Dwarf* dwarf) { return dwarf == nullptr; }
bool IsStripped() const { return IsStripped(dwarf_); }
Zone* zone() const { return zone_; }
Dwarf* dwarf() { return dwarf_; }
// Stores the information needed to appropriately generate a
// relocation from the target to the source at the given section offset.
struct Relocation {
size_t size_in_bytes;
intptr_t section_offset;
intptr_t source_label;
intptr_t source_offset;
intptr_t target_label;
intptr_t target_offset;
// Used when the corresponding offset is relative from the location of the
// relocation itself.
static constexpr intptr_t kSelfRelative = -1;
// Used when the corresponding offset is relative to the start of the
// snapshot.
static constexpr intptr_t kSnapshotRelative = -2;
Relocation(size_t size_in_bytes,
intptr_t section_offset,
intptr_t source_label,
intptr_t source_offset,
intptr_t target_label,
intptr_t target_offset)
: size_in_bytes(size_in_bytes),
section_offset(section_offset),
source_label(source_label),
source_offset(source_offset),
target_label(target_label),
target_offset(target_offset) {
// Other than special values, all labels should be positive.
ASSERT(source_label > 0 || source_label == kSelfRelative ||
source_label == kSnapshotRelative);
ASSERT(target_label > 0 || target_label == kSelfRelative ||
target_label == kSnapshotRelative);
}
};
using RelocationArray = ZoneGrowableArray<Relocation>;
// Stores the information needed to appropriately generate a symbol
// during finalization.
struct SymbolData {
enum class Type {
Section,
Function,
Object,
};
const char* name;
Type type;
intptr_t offset;
size_t size;
// A positive unique ID only used internally in the Dart VM, not part of
// the shared object output.
intptr_t label;
SymbolData(const char* name,
Type type,
intptr_t offset,
size_t size,
intptr_t label)
: name(name), type(type), offset(offset), size(size), label(label) {
ASSERT(label > 0);
}
};
using SymbolDataArray = ZoneGrowableArray<SymbolData>;
struct WriteStream : public AbstractWriteStream {
WriteStream() {}
void WriteBytesWithRelocations(const uint8_t* bytes,
intptr_t size,
intptr_t start_address,
const RelocationArray& relocations);
virtual bool HasValueForLabel(intptr_t label, intptr_t* value) const = 0;
intptr_t FindValueForLabel(intptr_t label) const {
intptr_t value = -1;
const bool valid = HasValueForLabel(label, &value);
if (!valid) {
FATAL("Expected symbol for label: %" Pd "", label);
}
return value;
}
private:
DISALLOW_COPY_AND_ASSIGN(WriteStream);
};
class DelegatingWriteStream : public WriteStream {
public:
DelegatingWriteStream(BaseWriteStream* stream,
const SharedObjectWriter& writer)
: WriteStream(),
stream_(ASSERT_NOTNULL(stream)),
start_(stream->Position()),
page_size_(writer.page_size()) {
// So that we can use the underlying stream's Align, as all alignments
// will be less than or equal to this alignment.
ASSERT(Utils::IsAligned(start_, page_size_));
}
// We return positions in terms of the local content that has been written,
// ignoring any previous content on the stream.
intptr_t Position() const override { return stream_->Position() - start_; }
void WriteBytes(const void* b, intptr_t size) override {
stream_->WriteBytes(b, size);
}
void WriteByte(uint8_t value) override { stream_->WriteByte(value); }
intptr_t Align(intptr_t alignment, intptr_t offset = 0) override {
ASSERT(Utils::IsPowerOfTwo(alignment));
ASSERT(alignment <= page_size_);
return stream_->Align(alignment, offset);
}
protected:
BaseWriteStream* const stream_;
private:
const intptr_t start_;
const intptr_t page_size_;
DISALLOW_COPY_AND_ASSIGN(DelegatingWriteStream);
};
// Must be the same value as the values returned by ImageWriter::SectionLabel
// for the appropriate section and vm values.
static constexpr intptr_t kVmBssLabel = 5;
static constexpr intptr_t kIsolateBssLabel = 6;
static constexpr intptr_t kBuildIdLabel = 7;
virtual void AddText(const char* name,
intptr_t label,
const uint8_t* bytes,
intptr_t size,
const RelocationArray* relocations,
const SymbolDataArray* symbols) = 0;
virtual void AddROData(const char* name,
intptr_t label,
const uint8_t* bytes,
intptr_t size,
const RelocationArray* relocations,
const SymbolDataArray* symbols) = 0;
virtual void Finalize() = 0;
virtual void AssertConsistency(const SharedObjectWriter* debug) const = 0;
virtual const ElfWriter* AsElfWriter() const { return nullptr; }
virtual const MachOWriter* AsMachOWriter() const { return nullptr; }
protected:
Zone* const zone_;
BaseWriteStream* const unwrapped_stream_;
const Type type_;
// If nullptr, then the shared object file should be stripped of static
// information like the static symbol table.
Dwarf* const dwarf_;
};
} // namespace dart
#endif // DART_PRECOMPILER
#endif // RUNTIME_VM_SO_WRITER_H_