mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
Reland "[vm] Allow BaseWriteStream::WriteFixed to be used at unaligned positions."
Fixes errors introduced by adding PRINTF_ATTRIBUTE to BaseWriteStream::Printf due to attempting to print a compiler::target::uword using the format for uword. Original description: For snapshot writing, we generally only have aligned writes so the old methods worked well, but in some formats (like DWARF) we're not guaranteed to have aligned writes and so had to use WriteBytes. Instead, have WriteFixed call WriteBytes and replace any other uses of WriteBytes(&value, sizeof(value)) with WriteFixed(value) instead. Also makes the following additional changes: * Expose WriteByte(value), instead of forcing use of WriteFixed<uint8_t> or Raw<1,T>::Write to get the same behavior. * Rename Print/VPrint to Printf/VPrintf, so methods taking format strings are named consistently with others in the codebase. * Add format string checking to Printf when supported. * Add AddString() for non-formatted string writing. Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-mac-release-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try Change-Id: Ib70ccaa752dbf9ead5ea57e386a67725723bac84 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/164324 Commit-Queue: Tess Strickland <sstrickl@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
a10b728aa2
commit
a36d17730a
5 changed files with 135 additions and 147 deletions
|
@ -280,6 +280,9 @@ static constexpr int kWordSizeLog2 = 3;
|
|||
#endif
|
||||
static constexpr int kWordSize = 1 << kWordSizeLog2;
|
||||
static_assert(kWordSize == sizeof(word), "kWordSize should match sizeof(word)");
|
||||
// Our compiler code currently assumes this, so formally check it.
|
||||
static_assert(dart::kWordSize >= kWordSize,
|
||||
"Host word size smaller than target word size");
|
||||
|
||||
static constexpr word kBitsPerWordLog2 = kWordSizeLog2 + kBitsPerByteLog2;
|
||||
static constexpr word kBitsPerWord = 1 << kBitsPerWordLog2;
|
||||
|
|
|
@ -332,7 +332,7 @@ class BaseWriteStream : public ValueObject {
|
|||
class Raw<1, T> {
|
||||
public:
|
||||
static void Write(BaseWriteStream* st, T value) {
|
||||
st->WriteByte(bit_cast<int8_t>(value));
|
||||
st->WriteByte(bit_cast<uint8_t>(value));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -390,33 +390,25 @@ class BaseWriteStream : public ValueObject {
|
|||
current_ += len;
|
||||
}
|
||||
|
||||
void WriteWord(uword value) {
|
||||
const intptr_t len = sizeof(uword);
|
||||
EnsureSpace(len);
|
||||
*reinterpret_cast<uword*>(current_) = value;
|
||||
current_ += len;
|
||||
}
|
||||
void WriteWord(uword value) { WriteFixed(value); }
|
||||
|
||||
void WriteTargetWord(uword value) {
|
||||
#if defined(IS_SIMARM_X64)
|
||||
RELEASE_ASSERT(Utils::IsInt(32, static_cast<word>(value)));
|
||||
const intptr_t len = sizeof(uint32_t);
|
||||
EnsureSpace(len);
|
||||
*reinterpret_cast<uint32_t*>(current_) = static_cast<uint32_t>(value);
|
||||
current_ += len;
|
||||
#else // defined(IS_SIMARM_X64)
|
||||
WriteWord(value);
|
||||
#endif // defined(IS_SIMARM_X64)
|
||||
WriteFixed(static_cast<uint32_t>(value));
|
||||
#else
|
||||
WriteFixed(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Print(const char* format, ...) {
|
||||
void Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
VPrint(format, args);
|
||||
VPrintf(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void VPrint(const char* format, va_list args) {
|
||||
void VPrintf(const char* format, va_list args) {
|
||||
// Measure.
|
||||
va_list measure_args;
|
||||
va_copy(measure_args, args);
|
||||
|
@ -447,18 +439,17 @@ class BaseWriteStream : public ValueObject {
|
|||
|
||||
template <typename T>
|
||||
void WriteFixed(T value) {
|
||||
const intptr_t len = sizeof(T);
|
||||
EnsureSpace(len);
|
||||
*reinterpret_cast<T*>(current_) = static_cast<T>(value);
|
||||
current_ += len;
|
||||
WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
|
||||
protected:
|
||||
DART_FORCE_INLINE void WriteByte(uint8_t value) {
|
||||
EnsureSpace(1);
|
||||
*current_++ = value;
|
||||
}
|
||||
|
||||
void WriteString(const char* cstr) { WriteBytes(cstr, strlen(cstr)); }
|
||||
|
||||
protected:
|
||||
void EnsureSpace(intptr_t size_needed) {
|
||||
if (Remaining() >= size_needed) return;
|
||||
intptr_t increment_size = capacity_;
|
||||
|
|
|
@ -21,7 +21,7 @@ class ElfWriteStream : public ValueObject {
|
|||
explicit ElfWriteStream(BaseWriteStream* stream)
|
||||
: stream_(ASSERT_NOTNULL(stream)) {}
|
||||
|
||||
intptr_t position() const { return stream_->Position(); }
|
||||
intptr_t Position() const { return stream_->Position(); }
|
||||
void Align(const intptr_t alignment) {
|
||||
ASSERT(Utils::IsPowerOfTwo(alignment));
|
||||
stream_->Align(alignment);
|
||||
|
@ -29,25 +29,13 @@ class ElfWriteStream : public ValueObject {
|
|||
void WriteBytes(const uint8_t* b, intptr_t size) {
|
||||
stream_->WriteBytes(b, size);
|
||||
}
|
||||
void WriteByte(uint8_t value) {
|
||||
stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
void WriteHalf(uint16_t value) {
|
||||
stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
void WriteWord(uint32_t value) {
|
||||
stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
void WriteAddr(compiler::target::uword value) {
|
||||
stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
void WriteOff(compiler::target::uword value) {
|
||||
stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
void WriteByte(uint8_t value) { stream_->WriteByte(value); }
|
||||
void WriteHalf(uint16_t value) { stream_->WriteFixed(value); }
|
||||
void WriteWord(uint32_t value) { stream_->WriteFixed(value); }
|
||||
void WriteAddr(compiler::target::uword value) { stream_->WriteFixed(value); }
|
||||
void WriteOff(compiler::target::uword value) { stream_->WriteFixed(value); }
|
||||
#if defined(TARGET_ARCH_IS_64_BIT)
|
||||
void WriteXWord(uint64_t value) {
|
||||
stream_->WriteBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
void WriteXWord(uint64_t value) { stream_->WriteFixed(value); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -602,7 +590,7 @@ class Symbol : public ZoneAllocated {
|
|||
cstr_(cstr) {}
|
||||
|
||||
void Write(ElfWriteStream* stream) const {
|
||||
const intptr_t start = stream->position();
|
||||
const intptr_t start = stream->Position();
|
||||
stream->WriteWord(name_index);
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
stream->WriteAddr(offset);
|
||||
|
@ -617,7 +605,7 @@ class Symbol : public ZoneAllocated {
|
|||
stream->WriteAddr(offset);
|
||||
stream->WriteXWord(size);
|
||||
#endif
|
||||
ASSERT_EQUAL(stream->position() - start, sizeof(elf::Symbol));
|
||||
ASSERT_EQUAL(stream->Position() - start, sizeof(elf::Symbol));
|
||||
}
|
||||
|
||||
const intptr_t name_index;
|
||||
|
@ -655,9 +643,9 @@ class SymbolTable : public Section {
|
|||
void Write(ElfWriteStream* stream) {
|
||||
for (intptr_t i = 0; i < Length(); i++) {
|
||||
auto const symbol = At(i);
|
||||
const intptr_t start = stream->position();
|
||||
const intptr_t start = stream->Position();
|
||||
symbol->Write(stream);
|
||||
ASSERT_EQUAL(stream->position() - start, entry_size);
|
||||
ASSERT_EQUAL(stream->Position() - start, entry_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,7 +765,7 @@ class DynamicTable : public Section {
|
|||
Entry(elf::DynamicEntryType tag, intptr_t value) : tag(tag), value(value) {}
|
||||
|
||||
void Write(ElfWriteStream* stream) {
|
||||
const intptr_t start = stream->position();
|
||||
const intptr_t start = stream->Position();
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
stream->WriteWord(static_cast<uint32_t>(tag));
|
||||
stream->WriteAddr(value);
|
||||
|
@ -785,7 +773,7 @@ class DynamicTable : public Section {
|
|||
stream->WriteXWord(static_cast<uint64_t>(tag));
|
||||
stream->WriteAddr(value);
|
||||
#endif
|
||||
ASSERT_EQUAL(stream->position() - start, sizeof(elf::DynamicEntry));
|
||||
ASSERT_EQUAL(stream->Position() - start, sizeof(elf::DynamicEntry));
|
||||
}
|
||||
|
||||
elf::DynamicEntryType tag;
|
||||
|
@ -1039,7 +1027,7 @@ class DwarfElfStream : public DwarfWriteStream {
|
|||
} else {
|
||||
part |= 0x80;
|
||||
}
|
||||
stream_->WriteFixed(part);
|
||||
stream_->WriteByte(part);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1053,35 +1041,32 @@ class DwarfElfStream : public DwarfWriteStream {
|
|||
} else {
|
||||
part |= 0x80;
|
||||
}
|
||||
stream_->WriteFixed(part);
|
||||
stream_->WriteByte(part);
|
||||
}
|
||||
}
|
||||
|
||||
void u1(uint8_t value) { stream_->WriteFixed(value); }
|
||||
// Can't use WriteFixed for these, as we may not be at aligned positions.
|
||||
void u2(uint16_t value) { stream_->WriteBytes(&value, sizeof(value)); }
|
||||
void u4(uint32_t value) { stream_->WriteBytes(&value, sizeof(value)); }
|
||||
void u8(uint64_t value) { stream_->WriteBytes(&value, sizeof(value)); }
|
||||
void u1(uint8_t value) { stream_->WriteByte(value); }
|
||||
void u2(uint16_t value) { stream_->WriteFixed(value); }
|
||||
void u4(uint32_t value) { stream_->WriteFixed(value); }
|
||||
void u8(uint64_t value) { stream_->WriteFixed(value); }
|
||||
void string(const char* cstr) { // NOLINT
|
||||
stream_->WriteBytes(reinterpret_cast<const uint8_t*>(cstr),
|
||||
strlen(cstr) + 1);
|
||||
// Unlike stream_->WriteString(), we want the null terminator written.
|
||||
stream_->WriteBytes(cstr, strlen(cstr) + 1);
|
||||
}
|
||||
intptr_t position() { return stream_->Position(); }
|
||||
intptr_t ReserveSize(const char* prefix, intptr_t* start) {
|
||||
ASSERT(start != nullptr);
|
||||
intptr_t fixup = position();
|
||||
intptr_t fixup = stream_->Position();
|
||||
// We assume DWARF v2, so all sizes are 32-bit.
|
||||
u4(0);
|
||||
// All sizes for DWARF sections measure the size of the section data _after_
|
||||
// the size value.
|
||||
*start = position();
|
||||
*start = stream_->Position();
|
||||
return fixup;
|
||||
}
|
||||
void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
|
||||
const intptr_t old_position = position();
|
||||
const intptr_t old_position = stream_->Position();
|
||||
stream_->SetPosition(fixup);
|
||||
const uint32_t value = old_position - start;
|
||||
stream_->WriteBytes(&value, sizeof(value));
|
||||
stream_->WriteFixed(static_cast<uint32_t>(old_position - start));
|
||||
stream_->SetPosition(old_position);
|
||||
}
|
||||
void OffsetFromSymbol(const char* symbol, intptr_t offset) {
|
||||
|
@ -1108,7 +1093,7 @@ class DwarfElfStream : public DwarfWriteStream {
|
|||
void RegisterAbstractOrigin(intptr_t index) {
|
||||
ASSERT(abstract_origins_ != nullptr);
|
||||
ASSERT(index < abstract_origins_size_);
|
||||
abstract_origins_[index] = position();
|
||||
abstract_origins_[index] = stream_->Position();
|
||||
}
|
||||
void AbstractOrigin(intptr_t index) { u4(abstract_origins_[index]); }
|
||||
|
||||
|
@ -1532,12 +1517,12 @@ void Elf::WriteHeader(ElfWriteStream* stream) {
|
|||
stream->WriteHalf(sections_.length());
|
||||
stream->WriteHalf(shstrtab_->index());
|
||||
|
||||
ASSERT_EQUAL(stream->position(), sizeof(elf::ElfHeader));
|
||||
ASSERT_EQUAL(stream->Position(), sizeof(elf::ElfHeader));
|
||||
}
|
||||
|
||||
void Elf::WriteProgramTable(ElfWriteStream* stream) {
|
||||
ASSERT(program_table_file_size_ >= 0); // Check for finalization.
|
||||
ASSERT(stream->position() == program_table_file_offset_);
|
||||
ASSERT(stream->Position() == program_table_file_offset_);
|
||||
#if defined(DEBUG)
|
||||
// Here, we count the number of times that a PT_LOAD writable segment is
|
||||
// followed by a non-writable segment. We initialize last_writable to true so
|
||||
|
@ -1554,9 +1539,9 @@ void Elf::WriteProgramTable(ElfWriteStream* stream) {
|
|||
last_writable = segment->IsWritable();
|
||||
}
|
||||
#endif
|
||||
const intptr_t start = stream->position();
|
||||
const intptr_t start = stream->Position();
|
||||
segment->WriteProgramHeader(stream);
|
||||
const intptr_t end = stream->position();
|
||||
const intptr_t end = stream->Position();
|
||||
ASSERT_EQUAL(end - start, sizeof(elf::ProgramHeader));
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
|
@ -1570,12 +1555,12 @@ void Elf::WriteProgramTable(ElfWriteStream* stream) {
|
|||
void Elf::WriteSectionTable(ElfWriteStream* stream) {
|
||||
ASSERT(section_table_file_size_ >= 0); // Check for finalization.
|
||||
stream->Align(kElfSectionTableAlignment);
|
||||
ASSERT_EQUAL(stream->position(), section_table_file_offset_);
|
||||
ASSERT_EQUAL(stream->Position(), section_table_file_offset_);
|
||||
|
||||
for (auto const section : sections_) {
|
||||
const intptr_t start = stream->position();
|
||||
const intptr_t start = stream->Position();
|
||||
section->WriteSectionHeader(stream);
|
||||
const intptr_t end = stream->position();
|
||||
const intptr_t end = stream->Position();
|
||||
ASSERT_EQUAL(end - start, sizeof(elf::SectionHeader));
|
||||
}
|
||||
}
|
||||
|
@ -1598,9 +1583,9 @@ void Elf::WriteSections(ElfWriteStream* stream) {
|
|||
stream->Align(load_align);
|
||||
current_segment = section->load_segment;
|
||||
}
|
||||
ASSERT_EQUAL(stream->position(), section->file_offset());
|
||||
ASSERT_EQUAL(stream->Position(), section->file_offset());
|
||||
section->Write(stream);
|
||||
ASSERT_EQUAL(stream->position(),
|
||||
ASSERT_EQUAL(stream->Position(),
|
||||
section->file_offset() + section->FileSize());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -622,27 +622,30 @@ class DwarfAssemblyStream : public DwarfWriteStream {
|
|||
explicit DwarfAssemblyStream(BaseWriteStream* stream)
|
||||
: stream_(ASSERT_NOTNULL(stream)) {}
|
||||
|
||||
void sleb128(intptr_t value) { Print(".sleb128 %" Pd "\n", value); }
|
||||
void uleb128(uintptr_t value) { Print(".uleb128 %" Pd "\n", value); }
|
||||
void u1(uint8_t value) { Print(".byte %u\n", value); }
|
||||
void u2(uint16_t value) { Print(".2byte %u\n", value); }
|
||||
void u4(uint32_t value) { Print(".4byte %" Pu32 "\n", value); }
|
||||
void u8(uint64_t value) { Print(".8byte %" Pu64 "\n", value); }
|
||||
void sleb128(intptr_t value) { stream_->Printf(".sleb128 %" Pd "\n", value); }
|
||||
void uleb128(uintptr_t value) {
|
||||
stream_->Printf(".uleb128 %" Pd "\n", value);
|
||||
}
|
||||
void u1(uint8_t value) { stream_->Printf(".byte %u\n", value); }
|
||||
void u2(uint16_t value) { stream_->Printf(".2byte %u\n", value); }
|
||||
void u4(uint32_t value) { stream_->Printf(".4byte %" Pu32 "\n", value); }
|
||||
void u8(uint64_t value) { stream_->Printf(".8byte %" Pu64 "\n", value); }
|
||||
void string(const char* cstr) { // NOLINT
|
||||
Print(".string \"%s\"\n", cstr); // NOLINT
|
||||
stream_->Printf(".string \"%s\"\n", cstr); // NOLINT
|
||||
}
|
||||
// Uses labels, so doesn't output to start or return a useful fixup position.
|
||||
intptr_t ReserveSize(const char* prefix, intptr_t* start) {
|
||||
// Assignment to temp works around buggy Mac assembler.
|
||||
Print("L%s_size = .L%s_end - .L%s_start\n", prefix, prefix, prefix);
|
||||
Print(".4byte L%s_size\n", prefix);
|
||||
Print(".L%s_start:\n", prefix);
|
||||
stream_->Printf("L%s_size = .L%s_end - .L%s_start\n", prefix, prefix,
|
||||
prefix);
|
||||
stream_->Printf(".4byte L%s_size\n", prefix);
|
||||
stream_->Printf(".L%s_start:\n", prefix);
|
||||
return -1;
|
||||
}
|
||||
// Just need to label the end so the assembler can calculate the size, so
|
||||
// start and the fixup position is unused.
|
||||
void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
|
||||
Print(".L%s_end:\n", prefix);
|
||||
stream_->Printf(".L%s_end:\n", prefix);
|
||||
}
|
||||
void OffsetFromSymbol(const char* symbol, intptr_t offset) {
|
||||
if (offset == 0) {
|
||||
|
@ -655,51 +658,53 @@ class DwarfAssemblyStream : public DwarfWriteStream {
|
|||
intptr_t offset1,
|
||||
const char* symbol2,
|
||||
intptr_t offset2) {
|
||||
Print(".uleb128 %s - %s + %" Pd "\n", symbol1, symbol2, offset1 - offset2);
|
||||
stream_->Printf(".uleb128 %s - %s + %" Pd "\n", symbol1, symbol2,
|
||||
offset1 - offset2);
|
||||
}
|
||||
|
||||
// No-op, we'll be using labels.
|
||||
void InitializeAbstractOrigins(intptr_t size) {}
|
||||
void RegisterAbstractOrigin(intptr_t index) {
|
||||
// Label for DW_AT_abstract_origin references
|
||||
Print(".Lfunc%" Pd ":\n", index);
|
||||
stream_->Printf(".Lfunc%" Pd ":\n", index);
|
||||
}
|
||||
void AbstractOrigin(intptr_t index) {
|
||||
// Assignment to temp works around buggy Mac assembler.
|
||||
Print("Ltemp%" Pd " = .Lfunc%" Pd " - %s\n", temp_, index, kDebugInfoLabel);
|
||||
Print(".4byte Ltemp%" Pd "\n", temp_);
|
||||
stream_->Printf("Ltemp%" Pd " = .Lfunc%" Pd " - %s\n", temp_, index,
|
||||
kDebugInfoLabel);
|
||||
stream_->Printf(".4byte Ltemp%" Pd "\n", temp_);
|
||||
temp_++;
|
||||
}
|
||||
|
||||
// Methods for writing the assembly prologues for various DWARF sections.
|
||||
void AbbreviationsPrologue() {
|
||||
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
Print(".section __DWARF,__debug_abbrev,regular,debug\n");
|
||||
stream_->WriteString(".section __DWARF,__debug_abbrev,regular,debug\n");
|
||||
#elif defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
|
||||
defined(TARGET_OS_FUCHSIA)
|
||||
Print(".section .debug_abbrev,\"\"\n");
|
||||
stream_->WriteString(".section .debug_abbrev,\"\"\n");
|
||||
#else
|
||||
UNIMPLEMENTED();
|
||||
#endif
|
||||
}
|
||||
void DebugInfoPrologue() {
|
||||
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
Print(".section __DWARF,__debug_info,regular,debug\n");
|
||||
stream_->WriteString(".section __DWARF,__debug_info,regular,debug\n");
|
||||
#elif defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
|
||||
defined(TARGET_OS_FUCHSIA)
|
||||
Print(".section .debug_info,\"\"\n");
|
||||
stream_->WriteString(".section .debug_info,\"\"\n");
|
||||
#else
|
||||
UNIMPLEMENTED();
|
||||
#endif
|
||||
// Used to calculate abstract origin values.
|
||||
Print("%s:\n", kDebugInfoLabel);
|
||||
stream_->Printf("%s:\n", kDebugInfoLabel);
|
||||
}
|
||||
void LineNumberProgramPrologue() {
|
||||
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
Print(".section __DWARF,__debug_line,regular,debug\n");
|
||||
stream_->WriteString(".section __DWARF,__debug_line,regular,debug\n");
|
||||
#elif defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
|
||||
defined(TARGET_OS_FUCHSIA)
|
||||
Print(".section .debug_line,\"\"\n");
|
||||
stream_->WriteString(".section .debug_line,\"\"\n");
|
||||
#else
|
||||
UNIMPLEMENTED();
|
||||
#endif
|
||||
|
@ -708,22 +713,17 @@ class DwarfAssemblyStream : public DwarfWriteStream {
|
|||
private:
|
||||
static constexpr const char* kDebugInfoLabel = ".Ldebug_info";
|
||||
|
||||
void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
stream_->VPrint(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
#define FORM_ADDR ".4byte"
|
||||
#elif defined(TARGET_ARCH_IS_64_BIT)
|
||||
#define FORM_ADDR ".8byte"
|
||||
#endif
|
||||
|
||||
void PrintNamedAddress(const char* name) { Print(FORM_ADDR " %s\n", name); }
|
||||
void PrintNamedAddress(const char* name) {
|
||||
stream_->Printf(FORM_ADDR " %s\n", name);
|
||||
}
|
||||
void PrintNamedAddressWithOffset(const char* name, intptr_t offset) {
|
||||
Print(FORM_ADDR " %s + %" Pd "\n", name, offset);
|
||||
stream_->Printf(FORM_ADDR " %s + %" Pd "\n", name, offset);
|
||||
}
|
||||
|
||||
#undef FORM_ADDR
|
||||
|
@ -840,10 +840,10 @@ void AssemblyImageWriter::WriteBss(bool vm) {
|
|||
#if defined(DART_PRECOMPILER)
|
||||
auto const bss_symbol =
|
||||
vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
|
||||
assembly_stream_->Print(".bss\n");
|
||||
assembly_stream_->WriteString(".bss\n");
|
||||
// Align the BSS contents as expected by the Image class.
|
||||
Align(ImageWriter::kBssAlignment);
|
||||
assembly_stream_->Print("%s:\n", bss_symbol);
|
||||
assembly_stream_->Printf("%s:\n", bss_symbol);
|
||||
|
||||
auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
|
||||
for (intptr_t i = 0; i < entry_count; i++) {
|
||||
|
@ -860,18 +860,18 @@ void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
|
|||
#else
|
||||
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
|
||||
defined(TARGET_OS_FUCHSIA)
|
||||
assembly_stream_->Print(".section .rodata\n");
|
||||
assembly_stream_->WriteString(".section .rodata\n");
|
||||
#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
assembly_stream_->Print(".const\n");
|
||||
assembly_stream_->WriteString(".const\n");
|
||||
#else
|
||||
UNIMPLEMENTED();
|
||||
#endif
|
||||
|
||||
const char* data_symbol =
|
||||
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
|
||||
assembly_stream_->Print(".globl %s\n", data_symbol);
|
||||
assembly_stream_->Printf(".globl %s\n", data_symbol);
|
||||
Align(ImageWriter::kRODataAlignment);
|
||||
assembly_stream_->Print("%s:\n", data_symbol);
|
||||
assembly_stream_->Printf("%s:\n", data_symbol);
|
||||
const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
|
||||
const intptr_t length = clustered_stream->bytes_written();
|
||||
WriteByteSequence(buffer, buffer + length);
|
||||
|
@ -895,13 +895,13 @@ void AssemblyImageWriter::WriteText(bool vm) {
|
|||
|
||||
const char* instructions_symbol = vm ? kVmSnapshotInstructionsAsmSymbol
|
||||
: kIsolateSnapshotInstructionsAsmSymbol;
|
||||
assembly_stream_->Print(".text\n");
|
||||
assembly_stream_->Print(".globl %s\n", instructions_symbol);
|
||||
assembly_stream_->WriteString(".text\n");
|
||||
assembly_stream_->Printf(".globl %s\n", instructions_symbol);
|
||||
|
||||
// Start snapshot at page boundary.
|
||||
ASSERT(ImageWriter::kTextAlignment >= VirtualMemory::PageSize());
|
||||
Align(ImageWriter::kTextAlignment);
|
||||
assembly_stream_->Print("%s:\n", instructions_symbol);
|
||||
assembly_stream_->Printf("%s:\n", instructions_symbol);
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
auto const bss_symbol =
|
||||
|
@ -976,8 +976,8 @@ void AssemblyImageWriter::WriteText(bool vm) {
|
|||
|
||||
// An ImageHeader has four fields:
|
||||
// 1) The BSS offset from this section.
|
||||
assembly_stream_->Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
|
||||
instructions_symbol);
|
||||
assembly_stream_->Printf("%s %s - %s\n", kLiteralPrefix, bss_symbol,
|
||||
instructions_symbol);
|
||||
text_offset += compiler::target::kWordSize;
|
||||
// 2) The relocated address of the instructions.
|
||||
//
|
||||
|
@ -1133,7 +1133,7 @@ void AssemblyImageWriter::WriteText(bool vm) {
|
|||
#endif
|
||||
// 2. Write a label at the entry point.
|
||||
// Linux's perf uses these labels.
|
||||
assembly_stream_->Print("%s:\n", object_name);
|
||||
assembly_stream_->Printf("%s:\n", object_name);
|
||||
|
||||
{
|
||||
// 3. Write from the payload start to payload end. For AOT snapshots
|
||||
|
@ -1160,11 +1160,10 @@ void AssemblyImageWriter::WriteText(bool vm) {
|
|||
Utils::RoundDown(payload_end, sizeof(compiler::target::uword));
|
||||
for (uword cursor = payload_start; cursor < possible_relocations_end;
|
||||
cursor += sizeof(compiler::target::uword)) {
|
||||
compiler::target::uword data =
|
||||
*reinterpret_cast<compiler::target::uword*>(cursor);
|
||||
uword data = *reinterpret_cast<compiler::target::uword*>(cursor);
|
||||
if ((cursor - payload_start) == next_reloc_offset) {
|
||||
assembly_stream_->Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
|
||||
bss_symbol, /*addend=*/data);
|
||||
assembly_stream_->Printf("%s %s - (.) + %" Pu "\n", kLiteralPrefix,
|
||||
bss_symbol, /*addend=*/data);
|
||||
text_offset += compiler::target::kWordSize;
|
||||
next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
|
||||
} else {
|
||||
|
@ -1243,12 +1242,14 @@ void AssemblyImageWriter::FrameUnwindPrologue() {
|
|||
// Creates DWARF's .debug_frame
|
||||
// CFI = Call frame information
|
||||
// CFA = Canonical frame address
|
||||
assembly_stream_->Print(".cfi_startproc\n");
|
||||
assembly_stream_->WriteString(".cfi_startproc\n");
|
||||
|
||||
#if defined(TARGET_ARCH_X64)
|
||||
assembly_stream_->Print(".cfi_def_cfa rbp, 0\n"); // CFA is fp+0
|
||||
assembly_stream_->Print(".cfi_offset rbp, 0\n"); // saved fp is *(CFA+0)
|
||||
assembly_stream_->Print(".cfi_offset rip, 8\n"); // saved pc is *(CFA+8)
|
||||
assembly_stream_->WriteString(".cfi_def_cfa rbp, 0\n"); // CFA is fp+0
|
||||
assembly_stream_->WriteString(
|
||||
".cfi_offset rbp, 0\n"); // saved fp is *(CFA+0)
|
||||
assembly_stream_->WriteString(
|
||||
".cfi_offset rip, 8\n"); // saved pc is *(CFA+8)
|
||||
// saved sp is CFA+16
|
||||
// Should be ".cfi_value_offset rsp, 16", but requires gcc newer than late
|
||||
// 2016 and not supported by Android's libunwind.
|
||||
|
@ -1257,14 +1258,16 @@ void AssemblyImageWriter::FrameUnwindPrologue() {
|
|||
// uleb128 size of operation 2
|
||||
// DW_OP_plus_uconst 0x23
|
||||
// uleb128 addend 16
|
||||
assembly_stream_->Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
|
||||
assembly_stream_->WriteString(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
|
||||
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
COMPILE_ASSERT(FP == R29);
|
||||
COMPILE_ASSERT(LR == R30);
|
||||
assembly_stream_->Print(".cfi_def_cfa x29, 0\n"); // CFA is fp+0
|
||||
assembly_stream_->Print(".cfi_offset x29, 0\n"); // saved fp is *(CFA+0)
|
||||
assembly_stream_->Print(".cfi_offset x30, 8\n"); // saved pc is *(CFA+8)
|
||||
assembly_stream_->WriteString(".cfi_def_cfa x29, 0\n"); // CFA is fp+0
|
||||
assembly_stream_->WriteString(
|
||||
".cfi_offset x29, 0\n"); // saved fp is *(CFA+0)
|
||||
assembly_stream_->WriteString(
|
||||
".cfi_offset x30, 8\n"); // saved pc is *(CFA+8)
|
||||
// saved sp is CFA+16
|
||||
// Should be ".cfi_value_offset sp, 16", but requires gcc newer than late
|
||||
// 2016 and not supported by Android's libunwind.
|
||||
|
@ -1273,19 +1276,20 @@ void AssemblyImageWriter::FrameUnwindPrologue() {
|
|||
// uleb128 size of operation 2
|
||||
// DW_OP_plus_uconst 0x23
|
||||
// uleb128 addend 16
|
||||
assembly_stream_->Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
|
||||
assembly_stream_->WriteString(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
|
||||
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
COMPILE_ASSERT(FP == R7);
|
||||
assembly_stream_->Print(".cfi_def_cfa r7, 0\n"); // CFA is fp+j0
|
||||
assembly_stream_->Print(".cfi_offset r7, 0\n"); // saved fp is *(CFA+0)
|
||||
assembly_stream_->WriteString(".cfi_def_cfa r7, 0\n"); // CFA is fp+j0
|
||||
assembly_stream_->WriteString(".cfi_offset r7, 0\n"); // saved fp is *(CFA+0)
|
||||
#else
|
||||
COMPILE_ASSERT(FP == R11);
|
||||
assembly_stream_->Print(".cfi_def_cfa r11, 0\n"); // CFA is fp+0
|
||||
assembly_stream_->Print(".cfi_offset r11, 0\n"); // saved fp is *(CFA+0)
|
||||
assembly_stream_->WriteString(".cfi_def_cfa r11, 0\n"); // CFA is fp+0
|
||||
assembly_stream_->WriteString(
|
||||
".cfi_offset r11, 0\n"); // saved fp is *(CFA+0)
|
||||
#endif
|
||||
assembly_stream_->Print(".cfi_offset lr, 4\n"); // saved pc is *(CFA+4)
|
||||
assembly_stream_->WriteString(".cfi_offset lr, 4\n"); // saved pc is *(CFA+4)
|
||||
// saved sp is CFA+8
|
||||
// Should be ".cfi_value_offset sp, 8", but requires gcc newer than late
|
||||
// 2016 and not supported by Android's libunwind.
|
||||
|
@ -1294,14 +1298,14 @@ void AssemblyImageWriter::FrameUnwindPrologue() {
|
|||
// uleb128 size of operation 2
|
||||
// DW_OP_plus_uconst 0x23
|
||||
// uleb128 addend 8
|
||||
assembly_stream_->Print(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
|
||||
assembly_stream_->WriteString(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
|
||||
|
||||
// libunwind on ARM may use .ARM.exidx instead of .debug_frame
|
||||
#if !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_MACOS_IOS)
|
||||
COMPILE_ASSERT(FP == R11);
|
||||
assembly_stream_->Print(".fnstart\n");
|
||||
assembly_stream_->Print(".save {r11, lr}\n");
|
||||
assembly_stream_->Print(".setfp r11, sp, #0\n");
|
||||
assembly_stream_->WriteString(".fnstart\n");
|
||||
assembly_stream_->WriteString(".save {r11, lr}\n");
|
||||
assembly_stream_->WriteString(".setfp r11, sp, #0\n");
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1310,10 +1314,10 @@ void AssemblyImageWriter::FrameUnwindPrologue() {
|
|||
void AssemblyImageWriter::FrameUnwindEpilogue() {
|
||||
#if defined(TARGET_ARCH_ARM)
|
||||
#if !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_MACOS_IOS)
|
||||
assembly_stream_->Print(".fnend\n");
|
||||
assembly_stream_->WriteString(".fnend\n");
|
||||
#endif
|
||||
#endif
|
||||
assembly_stream_->Print(".cfi_endproc\n");
|
||||
assembly_stream_->WriteString(".cfi_endproc\n");
|
||||
}
|
||||
|
||||
intptr_t AssemblyImageWriter::WriteByteSequence(uword start, uword end) {
|
||||
|
@ -1327,20 +1331,22 @@ intptr_t AssemblyImageWriter::WriteByteSequence(uword start, uword end) {
|
|||
}
|
||||
if (end != end_of_words) {
|
||||
auto start_of_rest = reinterpret_cast<const uint8_t*>(end_of_words);
|
||||
assembly_stream_->Print(".byte ");
|
||||
assembly_stream_->WriteString(".byte ");
|
||||
for (auto cursor = start_of_rest;
|
||||
cursor < reinterpret_cast<const uint8_t*>(end); cursor++) {
|
||||
if (cursor != start_of_rest) assembly_stream_->Print(", ");
|
||||
assembly_stream_->Print("0x%0.2" Px "", *cursor);
|
||||
if (cursor != start_of_rest) {
|
||||
assembly_stream_->WriteString(", ");
|
||||
}
|
||||
assembly_stream_->Printf("0x%0.2x", *cursor);
|
||||
}
|
||||
assembly_stream_->Print("\n");
|
||||
assembly_stream_->WriteString("\n");
|
||||
}
|
||||
return end - start;
|
||||
}
|
||||
|
||||
intptr_t AssemblyImageWriter::Align(intptr_t alignment, uword position) {
|
||||
const uword next_position = Utils::RoundUp(position, alignment);
|
||||
assembly_stream_->Print(".balign %" Pd ", 0\n", alignment);
|
||||
assembly_stream_->Printf(".balign %" Pd ", 0\n", alignment);
|
||||
return next_position - position;
|
||||
}
|
||||
|
||||
|
|
|
@ -484,12 +484,15 @@ class AssemblyImageWriter : public ImageWriter {
|
|||
const char* kLiteralPrefix = ".long";
|
||||
#endif
|
||||
|
||||
intptr_t WriteWordLiteralText(compiler::target::uword value) {
|
||||
intptr_t WriteWordLiteralText(uword value) {
|
||||
#if defined(IS_SIMARM_X64)
|
||||
ASSERT(value <= kMaxUint32);
|
||||
#endif
|
||||
// Padding is helpful for comparing the .S with --disassemble.
|
||||
#if defined(TARGET_ARCH_IS_64_BIT)
|
||||
assembly_stream_->Print(".quad 0x%0.16" Px "\n", value);
|
||||
assembly_stream_->Printf(".quad 0x%0.16" Px "\n", value);
|
||||
#else
|
||||
assembly_stream_->Print(".long 0x%0.8" Px "\n", value);
|
||||
assembly_stream_->Printf(".long 0x%0.8" Px "\n", value);
|
||||
#endif
|
||||
return compiler::target::kWordSize;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue