mirror of
https://github.com/dart-lang/sdk
synced 2024-07-08 12:06:26 +00:00
[vm/aot] Add a custom ELF loader in dart_precompiled_runtime.
Also switch some CQ bots using blobs to ELF. Once all embedders have migrated, we will remove blobs support entirely. Change-Id: Ie5e8c1187ad6c1af362b5715daafd3641bc8cc0e Cq-Include-Trybots:luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-bare-linux-release-simarm-try,vm-kernel-precomp-mac-debug-simarm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-precomp-android-release-arm-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/116620 Commit-Queue: Samir Jindel <sjindel@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
c195896c84
commit
362ef8e67c
|
@ -117,6 +117,23 @@ static_library("crashpad") {
|
|||
}
|
||||
}
|
||||
|
||||
static_library("elf_loader") {
|
||||
configs += [
|
||||
"..:dart_arch_config",
|
||||
"..:dart_config",
|
||||
"..:dart_product_config",
|
||||
"..:dart_os_fuchsia_config",
|
||||
]
|
||||
include_dirs = [ ".." ]
|
||||
sources = [
|
||||
"elf_loader.cc",
|
||||
"elf_loader.h",
|
||||
]
|
||||
deps = [
|
||||
":libdart_builtin",
|
||||
]
|
||||
}
|
||||
|
||||
template("build_gen_snapshot") {
|
||||
extra_configs = []
|
||||
if (defined(invoker.extra_configs)) {
|
||||
|
@ -841,6 +858,9 @@ dart_executable("dart_precompiled_runtime") {
|
|||
"main.cc",
|
||||
"snapshot_empty.cc",
|
||||
]
|
||||
|
||||
extra_deps += [ ":elf_loader" ]
|
||||
|
||||
if (dart_runtime_mode == "release") {
|
||||
extra_sources += [ "observatory_assets_empty.cc" ]
|
||||
}
|
||||
|
@ -862,6 +882,8 @@ dart_executable("dartaotruntime") {
|
|||
"observatory_assets_empty.cc",
|
||||
"snapshot_empty.cc",
|
||||
]
|
||||
|
||||
extra_deps += [ ":elf_loader" ]
|
||||
}
|
||||
|
||||
executable("process_test") {
|
||||
|
|
394
runtime/bin/elf_loader.cc
Normal file
394
runtime/bin/elf_loader.cc
Normal file
|
@ -0,0 +1,394 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
|
||||
#include <bin/elf_loader.h>
|
||||
#include <bin/file.h>
|
||||
#include <platform/elf.h>
|
||||
#include <platform/globals.h>
|
||||
#include <vm/cpu.h>
|
||||
#include <vm/virtual_memory.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
namespace elf {
|
||||
|
||||
/// A loader for a subset of ELF which may be used to load objects produced by
|
||||
/// Dart_CreateAppAOTSnapshotAsElf.
|
||||
class LoadedElf {
|
||||
public:
|
||||
explicit LoadedElf(const char* filename)
|
||||
: filename_(strdup(filename), std::free) {}
|
||||
~LoadedElf();
|
||||
|
||||
/// Loads the ELF object into memory. Returns whether the load was successful.
|
||||
/// On failure, the error may be retrieved by 'error()'.
|
||||
bool Load();
|
||||
|
||||
/// Reads Dart-specific symbols from the loaded ELF.
|
||||
///
|
||||
/// Stores the address of the corresponding symbol in each non-null output
|
||||
/// parameter.
|
||||
///
|
||||
/// Fails if any output parameter is non-null but points to null and the
|
||||
/// corresponding symbol was not found, or if the dynamic symbol table could
|
||||
/// not be decoded.
|
||||
///
|
||||
/// On failure, the error may be retrieved by 'error()'.
|
||||
bool ResolveSymbols(const uint8_t** vm_data,
|
||||
const uint8_t** vm_instrs,
|
||||
const uint8_t** isolate_data,
|
||||
const uint8_t** isolate_instrs);
|
||||
|
||||
const char* error() { return error_; }
|
||||
|
||||
private:
|
||||
bool ReadHeader();
|
||||
bool ReadProgramTable();
|
||||
bool LoadSegments();
|
||||
bool ReadSectionTable();
|
||||
bool ReadSectionStringTable();
|
||||
bool ReadSections();
|
||||
|
||||
static uword PageSize();
|
||||
|
||||
// Unlike File::Map, allows non-aligned 'start' and 'length'.
|
||||
MappedMemory* MapFilePiece(uword start,
|
||||
uword length,
|
||||
const void** mapping_start);
|
||||
|
||||
std::unique_ptr<char, decltype(std::free)*> filename_;
|
||||
|
||||
// Initialized on a successful Load().
|
||||
File* file_;
|
||||
|
||||
// Initialized on error.
|
||||
const char* error_ = nullptr;
|
||||
|
||||
// Initialized by ReadHeader().
|
||||
dart::elf::ElfHeader header_;
|
||||
|
||||
// Initialized by ReadProgramTable().
|
||||
std::unique_ptr<MappedMemory> program_table_mapping_;
|
||||
const dart::elf::ProgramHeader* program_table_ = nullptr;
|
||||
|
||||
// Initialized by LoadSegments().
|
||||
std::unique_ptr<VirtualMemory> base_;
|
||||
|
||||
// Initialized by ReadSectionTable().
|
||||
std::unique_ptr<MappedMemory> section_table_mapping_;
|
||||
const dart::elf::SectionHeader* section_table_ = nullptr;
|
||||
|
||||
// Initialized by ReadSectionStringTable().
|
||||
std::unique_ptr<MappedMemory> section_string_table_mapping_;
|
||||
const char* section_string_table_ = nullptr;
|
||||
|
||||
// Initialized by ReadSections().
|
||||
const char* dynamic_string_table_ = nullptr;
|
||||
const dart::elf::Symbol* dynamic_symbol_table_ = nullptr;
|
||||
uword dynamic_symbol_count_ = 0;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LoadedElf);
|
||||
};
|
||||
|
||||
#define CHECK(value) \
|
||||
if (!(value)) { \
|
||||
ASSERT(error_ != nullptr); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define ERROR(message) \
|
||||
{ \
|
||||
error_ = (message); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define CHECK_ERROR(value, message) \
|
||||
if (!(value)) { \
|
||||
error_ = (message); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
uword LoadedElf::PageSize() {
|
||||
static uword page_size_ = VirtualMemory::CalculatePageSize();
|
||||
return page_size_;
|
||||
}
|
||||
|
||||
bool LoadedElf::Load() {
|
||||
if (error_ != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file_ = File::Open(/*namespc=*/nullptr, filename_.get(),
|
||||
bin::File::FileOpenMode::kRead);
|
||||
CHECK_ERROR(file_ != nullptr, "Cannot open ELF object file.");
|
||||
|
||||
CHECK(ReadHeader());
|
||||
CHECK(ReadProgramTable());
|
||||
CHECK(LoadSegments());
|
||||
CHECK(ReadSectionTable());
|
||||
CHECK(ReadSectionStringTable());
|
||||
CHECK(ReadSections());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LoadedElf::~LoadedElf() {
|
||||
// Unmap the image.
|
||||
base_.reset();
|
||||
|
||||
// Explicitly destroy all the mappings before closing the file.
|
||||
program_table_mapping_.reset();
|
||||
section_table_mapping_.reset();
|
||||
section_string_table_mapping_.reset();
|
||||
|
||||
if (file_ != nullptr) {
|
||||
file_->Close();
|
||||
file_->Release();
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadedElf::ReadHeader() {
|
||||
CHECK_ERROR(file_->ReadFully(&header_, sizeof(dart::elf::ElfHeader)),
|
||||
"Could not read ELF file.");
|
||||
|
||||
CHECK_ERROR(header_.ident[dart::elf::EI_DATA] == dart::elf::ELFDATA2LSB,
|
||||
"Expected little-endian ELF object.");
|
||||
|
||||
CHECK_ERROR(header_.type == dart::elf::ET_DYN,
|
||||
"Can only load dynamic libraries.");
|
||||
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
CHECK_ERROR(header_.machine == dart::elf::EM_386, "Architecture mismatch.");
|
||||
#elif defined(TARGET_ARCH_X64)
|
||||
CHECK_ERROR(header_.machine == dart::elf::EM_X86_64,
|
||||
"Architecture mismatch.");
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
CHECK_ERROR(header_.machine == dart::elf::EM_ARM, "Architecture mismatch.");
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
CHECK_ERROR(header_.machine == dart::elf::EM_AARCH64,
|
||||
"Architecture mismatch.");
|
||||
#else
|
||||
#error Unsupported architecture architecture.
|
||||
#endif
|
||||
|
||||
CHECK_ERROR(header_.version == dart::elf::EV_CURRENT,
|
||||
"Unexpected ELF version.");
|
||||
CHECK_ERROR(header_.header_size == sizeof(dart::elf::ElfHeader),
|
||||
"Unexpected header size.");
|
||||
CHECK_ERROR(
|
||||
header_.program_table_entry_size == sizeof(dart::elf::ProgramHeader),
|
||||
"Unexpected program header size.");
|
||||
CHECK_ERROR(
|
||||
header_.section_table_entry_size == sizeof(dart::elf::SectionHeader),
|
||||
"Unexpected section header size.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadedElf::ReadProgramTable() {
|
||||
const uword file_start = header_.program_table_offset;
|
||||
const uword file_length =
|
||||
header_.num_program_headers * sizeof(dart::elf::ProgramHeader);
|
||||
program_table_mapping_.reset(
|
||||
MapFilePiece(file_start, file_length,
|
||||
reinterpret_cast<const void**>(&program_table_)));
|
||||
CHECK_ERROR(program_table_mapping_ != nullptr,
|
||||
"Could not mmap the program table.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadedElf::ReadSectionTable() {
|
||||
const uword file_start = header_.section_table_offset;
|
||||
const uword file_length =
|
||||
header_.num_section_headers * sizeof(dart::elf::SectionHeader);
|
||||
section_table_mapping_.reset(
|
||||
MapFilePiece(file_start, file_length,
|
||||
reinterpret_cast<const void**>(§ion_table_)));
|
||||
CHECK_ERROR(section_table_mapping_ != nullptr,
|
||||
"Could not mmap the section table.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadedElf::ReadSectionStringTable() {
|
||||
const dart::elf::SectionHeader header =
|
||||
section_table_[header_.shstrtab_section_index];
|
||||
section_string_table_mapping_.reset(
|
||||
MapFilePiece(header.file_offset, header.file_size,
|
||||
reinterpret_cast<const void**>(§ion_string_table_)));
|
||||
CHECK_ERROR(section_string_table_mapping_ != nullptr,
|
||||
"Could not mmap the section string table.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadedElf::LoadSegments() {
|
||||
// Calculate the total amount of virtual memory needed.
|
||||
uword total_memory = 0;
|
||||
for (uword i = 0; i < header_.num_program_headers; ++i) {
|
||||
const dart::elf::ProgramHeader header = program_table_[i];
|
||||
|
||||
// Only PT_LOAD segments need to be loaded.
|
||||
if (header.type != dart::elf::ProgramHeaderType::PT_LOAD) continue;
|
||||
|
||||
total_memory = Utils::Maximum(
|
||||
static_cast<uword>(header.memory_offset + header.memory_size),
|
||||
total_memory);
|
||||
CHECK_ERROR(Utils::IsPowerOfTwo(header.alignment),
|
||||
"Alignment must be a power of two.");
|
||||
CHECK_ERROR(header.alignment <= PageSize(),
|
||||
"Cannot align greater than page size.")
|
||||
}
|
||||
total_memory = Utils::RoundUp(total_memory, PageSize());
|
||||
|
||||
base_.reset(VirtualMemory::AllocateAligned(
|
||||
total_memory, /*alignment=*/PageSize(),
|
||||
/*is_executable=*/false, /*mapping name=*/filename_.get()));
|
||||
CHECK_ERROR(base_ != nullptr, "Could not reserve virtual memory.");
|
||||
|
||||
for (uword i = 0; i < header_.num_program_headers; ++i) {
|
||||
const dart::elf::ProgramHeader header = program_table_[i];
|
||||
|
||||
// Only PT_LOAD segments need to be loaded.
|
||||
if (header.type != dart::elf::ProgramHeaderType::PT_LOAD) continue;
|
||||
|
||||
const uword memory_offset = header.memory_offset,
|
||||
file_offset = header.file_offset;
|
||||
CHECK_ERROR(
|
||||
(memory_offset % PageSize()) == (file_offset % PageSize()),
|
||||
"Difference between file and memory offset must be page-aligned.");
|
||||
|
||||
const intptr_t adjustment = header.memory_offset % PageSize();
|
||||
|
||||
void* const memory_start =
|
||||
static_cast<char*>(base_->address()) + memory_offset - adjustment;
|
||||
const uword file_start = file_offset - adjustment;
|
||||
const uword length = header.memory_size + adjustment;
|
||||
|
||||
File::MapType map_type = File::kReadOnly;
|
||||
if (header.flags == (dart::elf::PF_R | dart::elf::PF_W)) {
|
||||
map_type = File::kReadWrite;
|
||||
} else if (header.flags == (dart::elf::PF_R | dart::elf::PF_X)) {
|
||||
map_type = File::kReadExecute;
|
||||
} else if (header.flags == dart::elf::PF_R) {
|
||||
map_type = File::kReadOnly;
|
||||
} else {
|
||||
ERROR("Unsupported segment flag set.");
|
||||
}
|
||||
|
||||
std::unique_ptr<MappedMemory> memory(
|
||||
file_->Map(map_type, file_start, length, memory_start));
|
||||
CHECK_ERROR(memory != nullptr, "Could not map segment.");
|
||||
CHECK_ERROR(memory->address() == memory_start,
|
||||
"Mapping not at requested address.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadedElf::ReadSections() {
|
||||
for (uword i = 0; i < header_.num_section_headers; ++i) {
|
||||
const dart::elf::SectionHeader header = section_table_[i];
|
||||
const char* const name = section_string_table_ + header.name;
|
||||
if (strcmp(name, ".dynstr") == 0) {
|
||||
CHECK_ERROR(header.memory_offset != 0, ".dynstr must be loaded.");
|
||||
dynamic_string_table_ =
|
||||
static_cast<const char*>(base_->address()) + header.memory_offset;
|
||||
} else if (strcmp(name, ".dynsym") == 0) {
|
||||
CHECK_ERROR(header.memory_offset != 0, ".dynsym must be loaded.");
|
||||
dynamic_symbol_table_ = reinterpret_cast<const dart::elf::Symbol*>(
|
||||
base_->start() + header.memory_offset);
|
||||
dynamic_symbol_count_ = header.file_size / sizeof(dart::elf::Symbol);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_ERROR(dynamic_string_table_ != nullptr, "Couldn't find .dynstr.");
|
||||
CHECK_ERROR(dynamic_symbol_table_ != nullptr, "Couldn't find .dynsym.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadedElf::ResolveSymbols(const uint8_t** vm_data,
|
||||
const uint8_t** vm_instrs,
|
||||
const uint8_t** isolate_data,
|
||||
const uint8_t** isolate_instrs) {
|
||||
if (error_ != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The first entry of the symbol table is reserved.
|
||||
for (uword i = 1; i < dynamic_symbol_count_; ++i) {
|
||||
const dart::elf::Symbol sym = dynamic_symbol_table_[i];
|
||||
const char* name = dynamic_string_table_ + sym.name;
|
||||
const uint8_t** output = nullptr;
|
||||
|
||||
if (strcmp(name, kVmSnapshotDataSymbolName) == 0) {
|
||||
output = vm_data;
|
||||
} else if (strcmp(name, kVmSnapshotInstructionsSymbolName) == 0) {
|
||||
output = vm_instrs;
|
||||
} else if (strcmp(name, kIsolateSnapshotDataSymbolName) == 0) {
|
||||
output = isolate_data;
|
||||
} else if (strcmp(name, kIsolateSnapshotInstructionsSymbolName) == 0) {
|
||||
output = isolate_instrs;
|
||||
}
|
||||
|
||||
if (output != nullptr) {
|
||||
*output = reinterpret_cast<const uint8_t*>(base_->start() + sym.value);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_ERROR(vm_data == nullptr || *vm_data != nullptr,
|
||||
"Could not find VM snapshot data.");
|
||||
CHECK_ERROR(vm_instrs == nullptr || *vm_instrs != nullptr,
|
||||
"Could not find VM snapshot instructions.");
|
||||
CHECK_ERROR(isolate_data == nullptr || *isolate_data != nullptr,
|
||||
"Could not find isolate snapshot data.");
|
||||
CHECK_ERROR(isolate_instrs == nullptr || *isolate_instrs != nullptr,
|
||||
"Could not find isolate instructions.");
|
||||
return true;
|
||||
}
|
||||
|
||||
MappedMemory* LoadedElf::MapFilePiece(uword file_start,
|
||||
uword file_length,
|
||||
const void** mem_start) {
|
||||
const uword mapping_offset = Utils::RoundDown(file_start, PageSize());
|
||||
const uword mapping_length =
|
||||
Utils::RoundUp(file_length + file_start % PageSize(), PageSize());
|
||||
MappedMemory* const mapping =
|
||||
file_->Map(bin::File::kReadOnly, mapping_offset, mapping_length);
|
||||
|
||||
if (mapping != nullptr) {
|
||||
*mem_start = reinterpret_cast<uint8_t*>(mapping->start() +
|
||||
(file_start % PageSize()));
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
} // namespace elf
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
DART_EXPORT void* Dart_LoadELF(const char* filename,
|
||||
const char** error,
|
||||
const uint8_t** vm_snapshot_data,
|
||||
const uint8_t** vm_snapshot_instrs,
|
||||
const uint8_t** vm_isolate_data,
|
||||
const uint8_t** vm_isolate_instrs) {
|
||||
std::unique_ptr<dart::bin::elf::LoadedElf> elf(
|
||||
new dart::bin::elf::LoadedElf(filename));
|
||||
|
||||
if (!elf->Load() ||
|
||||
!elf->ResolveSymbols(vm_snapshot_data, vm_snapshot_instrs,
|
||||
vm_isolate_data, vm_isolate_instrs)) {
|
||||
*error = elf->error();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return elf.release();
|
||||
}
|
||||
|
||||
DART_EXPORT void Dart_UnloadELF(void* loaded) {
|
||||
delete reinterpret_cast<dart::bin::elf::LoadedElf*>(loaded);
|
||||
}
|
30
runtime/bin/elf_loader.h
Normal file
30
runtime/bin/elf_loader.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2019, 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_BIN_ELF_LOADER_H_
|
||||
#define RUNTIME_BIN_ELF_LOADER_H_
|
||||
|
||||
#include <include/dart_api.h>
|
||||
|
||||
typedef void* LoadedElfLibrary;
|
||||
|
||||
/// Loads an ELF object in 'filename'.
|
||||
///
|
||||
/// On success, returns a handle to the library which may be used to close it
|
||||
/// in Dart_UnloadELF. On error, returns 'nullptr' and sets 'error'. The error
|
||||
/// string should not be 'free'-d.
|
||||
///
|
||||
/// Looks up the Dart snapshot symbols "_kVmSnapshotData",
|
||||
/// "_kVmSnapshotInstructions", "_kVmIsoalteData" and "_kVmIsolateInstructions"
|
||||
/// into the respectively named out-parameters.
|
||||
DART_EXPORT LoadedElfLibrary Dart_LoadELF(const char* filename,
|
||||
const char** error,
|
||||
const uint8_t** vm_snapshot_data,
|
||||
const uint8_t** vm_snapshot_instrs,
|
||||
const uint8_t** vm_isolate_data,
|
||||
const uint8_t** vm_isolate_instrs);
|
||||
|
||||
DART_EXPORT void Dart_UnloadELF(LoadedElfLibrary loaded);
|
||||
|
||||
#endif // RUNTIME_BIN_ELF_LOADER_H_
|
|
@ -13,12 +13,6 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
const char* kVmSnapshotDataSymbolName = "_kDartVmSnapshotData";
|
||||
const char* kVmSnapshotInstructionsSymbolName = "_kDartVmSnapshotInstructions";
|
||||
const char* kIsolateSnapshotDataSymbolName = "_kDartIsolateSnapshotData";
|
||||
const char* kIsolateSnapshotInstructionsSymbolName =
|
||||
"_kDartIsolateSnapshotInstructions";
|
||||
|
||||
void* Extensions::LoadExtensionLibrary(const char* library_file) {
|
||||
return dlopen(library_file, RTLD_LAZY);
|
||||
}
|
||||
|
|
|
@ -17,12 +17,6 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
const char* kVmSnapshotDataSymbolName = "_kDartVmSnapshotData";
|
||||
const char* kVmSnapshotInstructionsSymbolName = "_kDartVmSnapshotInstructions";
|
||||
const char* kIsolateSnapshotDataSymbolName = "_kDartIsolateSnapshotData";
|
||||
const char* kIsolateSnapshotInstructionsSymbolName =
|
||||
"_kDartIsolateSnapshotInstructions";
|
||||
|
||||
void* Extensions::LoadExtensionLibrary(const char* library_file) {
|
||||
return dlopen(library_file, RTLD_LAZY);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
const char* kVmSnapshotDataSymbolName = "_kDartVmSnapshotData";
|
||||
const char* kVmSnapshotInstructionsSymbolName = "_kDartVmSnapshotInstructions";
|
||||
const char* kIsolateSnapshotDataSymbolName = "_kDartIsolateSnapshotData";
|
||||
const char* kIsolateSnapshotInstructionsSymbolName =
|
||||
"_kDartIsolateSnapshotInstructions";
|
||||
|
||||
void* Extensions::LoadExtensionLibrary(const char* library_file) {
|
||||
return dlopen(library_file, RTLD_LAZY);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
const char* kVmSnapshotDataSymbolName = "kDartVmSnapshotData";
|
||||
const char* kVmSnapshotInstructionsSymbolName = "kDartVmSnapshotInstructions";
|
||||
const char* kIsolateSnapshotDataSymbolName = "kDartIsolateSnapshotData";
|
||||
const char* kIsolateSnapshotInstructionsSymbolName =
|
||||
"kDartIsolateSnapshotInstructions";
|
||||
|
||||
void* Extensions::LoadExtensionLibrary(const char* library_file) {
|
||||
return dlopen(library_file, RTLD_LAZY);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
const char* kVmSnapshotDataSymbolName = "_kDartVmSnapshotData";
|
||||
const char* kVmSnapshotInstructionsSymbolName = "_kDartVmSnapshotInstructions";
|
||||
const char* kIsolateSnapshotDataSymbolName = "_kDartIsolateSnapshotData";
|
||||
const char* kIsolateSnapshotInstructionsSymbolName =
|
||||
"_kDartIsolateSnapshotInstructions";
|
||||
|
||||
void* Extensions::LoadExtensionLibrary(const char* library_file) {
|
||||
SetLastError(0);
|
||||
|
||||
|
|
|
@ -24,15 +24,23 @@ class FileHandle;
|
|||
|
||||
class MappedMemory {
|
||||
public:
|
||||
MappedMemory(void* address, intptr_t size) : address_(address), size_(size) {}
|
||||
~MappedMemory() { Unmap(); }
|
||||
MappedMemory(void* address, intptr_t size, bool should_unmap = true)
|
||||
: should_unmap_(should_unmap), address_(address), size_(size) {}
|
||||
~MappedMemory() {
|
||||
if (should_unmap_) Unmap();
|
||||
}
|
||||
|
||||
void* address() const { return address_; }
|
||||
intptr_t size() const { return size_; }
|
||||
uword start() const { return reinterpret_cast<uword>(address()); }
|
||||
|
||||
private:
|
||||
void Unmap();
|
||||
|
||||
// False for mappings which reside inside another, and will be removed when
|
||||
// the outer mapping is removed.
|
||||
bool should_unmap_;
|
||||
|
||||
void* address_;
|
||||
intptr_t size_;
|
||||
|
||||
|
@ -100,8 +108,30 @@ class File : public ReferenceCounted<File> {
|
|||
enum MapType {
|
||||
kReadOnly = 0,
|
||||
kReadExecute = 1,
|
||||
kReadWrite = 2,
|
||||
};
|
||||
MappedMemory* Map(MapType type, int64_t position, int64_t length);
|
||||
|
||||
/// Maps or copies the file into memory.
|
||||
///
|
||||
/// 'position' and 'length' should be page-aligned.
|
||||
///
|
||||
/// If 'start' is zero, allocates virtual memory for the mapping. When the
|
||||
/// returned 'MappedMemory' is destroyed, the mapping is removed.
|
||||
///
|
||||
/// If 'start' is non-zero, it must point within a suitably sized existing
|
||||
/// mapping. The returned 'MappedMemory' will not remove the mapping when it
|
||||
/// is destroyed; rather, the mapping will be removed when the enclosing
|
||||
/// mapping is removed. This mode is not supported on Fuchsia.
|
||||
///
|
||||
/// If 'type' is 'kReadWrite', writes to the mapping are *not* copied back to
|
||||
/// the file.
|
||||
///
|
||||
/// 'position' + 'length' may be larger than the file size. In this case, the
|
||||
/// extra memory is zero-filled.
|
||||
MappedMemory* Map(MapType type,
|
||||
int64_t position,
|
||||
int64_t length,
|
||||
void* start = nullptr);
|
||||
|
||||
// Read/Write attempt to transfer num_bytes to/from buffer. It returns
|
||||
// the number of bytes read/written.
|
||||
|
@ -172,7 +202,7 @@ class File : public ReferenceCounted<File> {
|
|||
// reading. If mode contains kWrite the file is opened for both
|
||||
// reading and writing. If mode contains kWrite and the file does
|
||||
// not exist the file is created. The file is truncated to length 0 if
|
||||
// mode contains kTruncate. Assumes we are in an API scope.
|
||||
// mode contains kTruncate.
|
||||
static File* Open(Namespace* namespc, const char* path, FileOpenMode mode);
|
||||
|
||||
// Same as [File::Open], but attempts to convert uri to path before opening
|
||||
|
|
|
@ -76,7 +76,10 @@ bool File::IsClosed() {
|
|||
return handle_->fd() == kClosedFd;
|
||||
}
|
||||
|
||||
MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
||||
MappedMemory* File::Map(MapType type,
|
||||
int64_t position,
|
||||
int64_t length,
|
||||
void* start) {
|
||||
ASSERT(handle_->fd() >= 0);
|
||||
ASSERT(length > 0);
|
||||
int prot = PROT_NONE;
|
||||
|
@ -87,14 +90,16 @@ MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
|||
case kReadExecute:
|
||||
prot = PROT_READ | PROT_EXEC;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
case kReadWrite:
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position);
|
||||
const int flags = MAP_PRIVATE | (start != nullptr ? MAP_FIXED : 0);
|
||||
void* addr = mmap(start, length, prot, flags, handle_->fd(), position);
|
||||
if (addr == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
return new MappedMemory(addr, length);
|
||||
return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
|
||||
}
|
||||
|
||||
void MappedMemory::Unmap() {
|
||||
|
|
|
@ -75,7 +75,10 @@ bool File::IsClosed() {
|
|||
return handle_->fd() == kClosedFd;
|
||||
}
|
||||
|
||||
MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
||||
MappedMemory* File::Map(MapType type,
|
||||
int64_t position,
|
||||
int64_t length,
|
||||
void* start) {
|
||||
ASSERT(handle_->fd() >= 0);
|
||||
ASSERT(length > 0);
|
||||
int prot = PROT_NONE;
|
||||
|
@ -86,14 +89,16 @@ MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
|||
case kReadExecute:
|
||||
prot = PROT_READ | PROT_EXEC;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
case kReadWrite:
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position);
|
||||
const int flags = MAP_PRIVATE | (start != nullptr ? MAP_FIXED : 0);
|
||||
void* addr = mmap(start, length, prot, flags, handle_->fd(), position);
|
||||
if (addr == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
return new MappedMemory(addr, length);
|
||||
return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
|
||||
}
|
||||
|
||||
void MappedMemory::Unmap() {
|
||||
|
|
|
@ -75,7 +75,10 @@ bool File::IsClosed() {
|
|||
return handle_->fd() == kClosedFd;
|
||||
}
|
||||
|
||||
MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
||||
MappedMemory* File::Map(MapType type,
|
||||
int64_t position,
|
||||
int64_t length,
|
||||
void* start) {
|
||||
ASSERT(handle_->fd() >= 0);
|
||||
ASSERT(length > 0);
|
||||
int prot = PROT_NONE;
|
||||
|
@ -86,14 +89,16 @@ MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
|||
case kReadExecute:
|
||||
prot = PROT_READ | PROT_EXEC;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
case kReadWrite:
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position);
|
||||
const int flags = MAP_PRIVATE | (start != nullptr ? MAP_FIXED : 0);
|
||||
void* addr = mmap(start, length, prot, flags, handle_->fd(), position);
|
||||
if (addr == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
return new MappedMemory(addr, length);
|
||||
return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
|
||||
}
|
||||
|
||||
void MappedMemory::Unmap() {
|
||||
|
|
|
@ -76,7 +76,10 @@ bool File::IsClosed() {
|
|||
return handle_->fd() == kClosedFd;
|
||||
}
|
||||
|
||||
MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
||||
MappedMemory* File::Map(MapType type,
|
||||
int64_t position,
|
||||
int64_t length,
|
||||
void* start) {
|
||||
ASSERT(handle_->fd() >= 0);
|
||||
ASSERT(length > 0);
|
||||
int prot = PROT_NONE;
|
||||
|
@ -91,34 +94,58 @@ MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
|
|||
map_flags |= (MAP_JIT | MAP_ANONYMOUS);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
case kReadWrite:
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
void* addr = NULL;
|
||||
if (start != nullptr) {
|
||||
map_flags |= MAP_FIXED;
|
||||
}
|
||||
void* addr = start;
|
||||
if ((type == kReadExecute) && IsAtLeastOS10_14()) {
|
||||
addr = mmap(NULL, length, (PROT_READ | PROT_WRITE), map_flags, -1, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
Syslog::PrintErr("mmap failed %s\n", strerror(errno));
|
||||
return NULL;
|
||||
// Due to codesigning restrictions, we cannot map the file as executable
|
||||
// directly. We must first copy it into an anonymous mapping and then mark
|
||||
// the mapping as executable.
|
||||
if (addr == nullptr) {
|
||||
addr = mmap(nullptr, length, (PROT_READ | PROT_WRITE), map_flags, -1, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
Syslog::PrintErr("mmap failed %s\n", strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const int64_t remaining_length = Length() - position;
|
||||
SetPosition(position);
|
||||
if (!ReadFully(addr, length)) {
|
||||
if (!ReadFully(addr, Utils::Minimum(length, remaining_length))) {
|
||||
Syslog::PrintErr("ReadFully failed\n");
|
||||
munmap(addr, length);
|
||||
return NULL;
|
||||
if (start == nullptr) {
|
||||
munmap(addr, length);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the requested mapping is larger than the file size, we should fill the
|
||||
// extra memory with zeros.
|
||||
if (length > remaining_length) {
|
||||
memset(reinterpret_cast<uint8_t*>(addr) + remaining_length, 0,
|
||||
length - remaining_length);
|
||||
}
|
||||
|
||||
if (mprotect(addr, length, prot) != 0) {
|
||||
Syslog::PrintErr("mprotect failed %s\n", strerror(errno));
|
||||
munmap(addr, length);
|
||||
return NULL;
|
||||
if (start == nullptr) {
|
||||
munmap(addr, length);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
addr = mmap(NULL, length, prot, map_flags, handle_->fd(), position);
|
||||
addr = mmap(addr, length, prot, map_flags, handle_->fd(), position);
|
||||
if (addr == MAP_FAILED) {
|
||||
Syslog::PrintErr("mmap failed %s\n", strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (addr == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
return new MappedMemory(addr, length);
|
||||
return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
|
||||
}
|
||||
|
||||
void MappedMemory::Unmap() {
|
||||
|
|
|
@ -73,7 +73,10 @@ bool File::IsClosed() {
|
|||
return handle_->fd() == kClosedFd;
|
||||
}
|
||||
|
||||
MappedMemory* File::Map(File::MapType type, int64_t position, int64_t length) {
|
||||
MappedMemory* File::Map(File::MapType type,
|
||||
int64_t position,
|
||||
int64_t length,
|
||||
void* start) {
|
||||
DWORD prot_alloc;
|
||||
DWORD prot_final;
|
||||
switch (type) {
|
||||
|
@ -85,31 +88,48 @@ MappedMemory* File::Map(File::MapType type, int64_t position, int64_t length) {
|
|||
prot_alloc = PAGE_EXECUTE_READWRITE;
|
||||
prot_final = PAGE_EXECUTE_READ;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
case File::kReadWrite:
|
||||
prot_alloc = PAGE_READWRITE;
|
||||
prot_final = PAGE_READWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
void* addr = VirtualAlloc(NULL, length, MEM_COMMIT | MEM_RESERVE, prot_alloc);
|
||||
if (addr == NULL) {
|
||||
Syslog::PrintErr("VirtualAlloc failed %d\n", GetLastError());
|
||||
return NULL;
|
||||
void* addr = start;
|
||||
if (addr == nullptr) {
|
||||
addr = VirtualAlloc(nullptr, length, MEM_COMMIT | MEM_RESERVE, prot_alloc);
|
||||
if (addr == nullptr) {
|
||||
Syslog::PrintErr("VirtualAlloc failed %d\n", GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const int64_t remaining_length = Length() - position;
|
||||
SetPosition(position);
|
||||
if (!ReadFully(addr, length)) {
|
||||
if (!ReadFully(addr, Utils::Minimum(length, remaining_length))) {
|
||||
Syslog::PrintErr("ReadFully failed %d\n", GetLastError());
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
return NULL;
|
||||
if (start == nullptr) {
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the requested mapping is larger than the file size, we should fill the
|
||||
// extra memory with zeros.
|
||||
if (length > remaining_length) {
|
||||
memset(reinterpret_cast<uint8_t*>(addr) + remaining_length, 0,
|
||||
length - remaining_length);
|
||||
}
|
||||
|
||||
DWORD old_prot;
|
||||
bool result = VirtualProtect(addr, length, prot_final, &old_prot);
|
||||
if (!result) {
|
||||
Syslog::PrintErr("VirtualProtect failed %d\n", GetLastError());
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
return NULL;
|
||||
if (start == nullptr) {
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return new MappedMemory(addr, length);
|
||||
return new MappedMemory(addr, length, /*should_unmap=*/start == nullptr);
|
||||
}
|
||||
|
||||
void MappedMemory::Unmap() {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/dfe.h"
|
||||
#include "bin/elf_loader.h"
|
||||
#include "bin/error_exit.h"
|
||||
#include "bin/extensions.h"
|
||||
#include "bin/file.h"
|
||||
|
@ -20,11 +21,6 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
extern const char* kVmSnapshotDataSymbolName;
|
||||
extern const char* kVmSnapshotInstructionsSymbolName;
|
||||
extern const char* kIsolateSnapshotDataSymbolName;
|
||||
extern const char* kIsolateSnapshotInstructionsSymbolName;
|
||||
|
||||
static const int64_t kAppSnapshotHeaderSize = 5 * kInt64Size;
|
||||
static const int64_t kAppSnapshotPageSize = 4 * KB;
|
||||
|
||||
|
@ -192,6 +188,42 @@ AppSnapshot* Snapshot::TryReadAppendedAppSnapshotBlobs(
|
|||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if defined(TARGET_OS_WINDOWS) || defined(USING_SIMULATOR)
|
||||
class ElfAppSnapshot : public AppSnapshot {
|
||||
public:
|
||||
ElfAppSnapshot(LoadedElfLibrary elf,
|
||||
const uint8_t* vm_snapshot_data,
|
||||
const uint8_t* vm_snapshot_instructions,
|
||||
const uint8_t* isolate_snapshot_data,
|
||||
const uint8_t* isolate_snapshot_instructions)
|
||||
: elf_(elf),
|
||||
vm_snapshot_data_(vm_snapshot_data),
|
||||
vm_snapshot_instructions_(vm_snapshot_instructions),
|
||||
isolate_snapshot_data_(isolate_snapshot_data),
|
||||
isolate_snapshot_instructions_(isolate_snapshot_instructions) {}
|
||||
|
||||
virtual ~ElfAppSnapshot() { Dart_UnloadELF(elf_); }
|
||||
|
||||
void SetBuffers(const uint8_t** vm_data_buffer,
|
||||
const uint8_t** vm_instructions_buffer,
|
||||
const uint8_t** isolate_data_buffer,
|
||||
const uint8_t** isolate_instructions_buffer) {
|
||||
*vm_data_buffer = vm_snapshot_data_;
|
||||
*vm_instructions_buffer = vm_snapshot_instructions_;
|
||||
*isolate_data_buffer = isolate_snapshot_data_;
|
||||
*isolate_instructions_buffer = isolate_snapshot_instructions_;
|
||||
}
|
||||
|
||||
private:
|
||||
LoadedElfLibrary elf_;
|
||||
const uint8_t* vm_snapshot_data_;
|
||||
const uint8_t* vm_snapshot_instructions_;
|
||||
const uint8_t* isolate_snapshot_data_;
|
||||
const uint8_t* isolate_snapshot_instructions_;
|
||||
};
|
||||
#endif // defined(TARGET_OS_WINDOWS) || defined(USING_SIMULATOR)
|
||||
|
||||
class DylibAppSnapshot : public AppSnapshot {
|
||||
public:
|
||||
DylibAppSnapshot(void* library,
|
||||
|
@ -261,17 +293,37 @@ static AppSnapshot* TryReadAppSnapshotDynamicLibrary(const char* script_name) {
|
|||
return new DylibAppSnapshot(library, vm_data_buffer, vm_instructions_buffer,
|
||||
isolate_data_buffer, isolate_instructions_buffer);
|
||||
}
|
||||
|
||||
static AppSnapshot* TryReadAppSnapshotElf(const char* script_name) {
|
||||
#if defined(TARGET_OS_WINDOWS) || defined(USING_SIMULATOR)
|
||||
const char* error = nullptr;
|
||||
const uint8_t *vm_data_buffer = nullptr, *vm_instructions_buffer = nullptr,
|
||||
*isolate_data_buffer = nullptr,
|
||||
*isolate_instructions_buffer = nullptr;
|
||||
void* handle = Dart_LoadELF(script_name, &error, &vm_data_buffer,
|
||||
&vm_instructions_buffer, &isolate_data_buffer,
|
||||
&isolate_instructions_buffer);
|
||||
if (handle == nullptr) {
|
||||
Syslog::PrintErr("Loading failed: %s\n", error);
|
||||
return nullptr;
|
||||
}
|
||||
return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
|
||||
isolate_data_buffer, isolate_instructions_buffer);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_name) {
|
||||
if (File::GetType(NULL, script_name, true) != File::kIsFile) {
|
||||
if (File::GetType(nullptr, script_name, true) != File::kIsFile) {
|
||||
// If 'script_name' refers to a pipe, don't read to check for an app
|
||||
// snapshot since we cannot rewind if it isn't (and couldn't mmap it in
|
||||
// anyway if it was).
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
AppSnapshot* snapshot = TryReadAppSnapshotBlobs(script_name);
|
||||
if (snapshot != NULL) {
|
||||
if (snapshot != nullptr) {
|
||||
return snapshot;
|
||||
}
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
@ -287,12 +339,16 @@ AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_name) {
|
|||
#endif
|
||||
|
||||
snapshot = TryReadAppSnapshotDynamicLibrary(script_name);
|
||||
if (snapshot != nullptr) {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
if (snapshot != NULL) {
|
||||
snapshot = TryReadAppSnapshotElf(script_name);
|
||||
if (snapshot != nullptr) {
|
||||
return snapshot;
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
|
||||
|
|
|
@ -3283,8 +3283,7 @@ DART_EXPORT Dart_Port Dart_ServiceWaitForLoadPort();
|
|||
* \return Returns true if the profile is successfully written and false
|
||||
* otherwise.
|
||||
*/
|
||||
DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port,
|
||||
char** error);
|
||||
DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error);
|
||||
|
||||
/*
|
||||
* ====================
|
||||
|
@ -3360,16 +3359,30 @@ typedef void (*Dart_StreamingWriteCallback)(void* callback_data,
|
|||
const uint8_t* buffer,
|
||||
intptr_t size);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define kVmSnapshotDataSymbolName "kDartVmSnapshotData"
|
||||
#define kVmSnapshotInstructionsSymbolName "kDartVmSnapshotInstructions"
|
||||
#define kIsolateSnapshotDataSymbolName "kDartIsolateSnapshotData"
|
||||
#define kIsolateSnapshotInstructionsSymbolName \
|
||||
"kDartIsolateSnapshotInstructions"
|
||||
#else
|
||||
#define kVmSnapshotDataSymbolName "_kDartVmSnapshotData"
|
||||
#define kVmSnapshotInstructionsSymbolName "_kDartVmSnapshotInstructions"
|
||||
#define kIsolateSnapshotDataSymbolName "_kDartIsolateSnapshotData"
|
||||
#define kIsolateSnapshotInstructionsSymbolName \
|
||||
"_kDartIsolateSnapshotInstructions"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a precompiled snapshot.
|
||||
* - A root library must have been loaded.
|
||||
* - Dart_Precompile must have been called.
|
||||
*
|
||||
* Outputs an assembly file defining the symbols
|
||||
* - kDartVmSnapshotData
|
||||
* - kDartVmSnapshotInstructions
|
||||
* - kDartIsolateSnapshotData
|
||||
* - kDartIsolateSnapshotInstructions
|
||||
* - _kDartVmSnapshotData
|
||||
* - _kDartVmSnapshotInstructions
|
||||
* - _kDartIsolateSnapshotData
|
||||
* - _kDartIsolateSnapshotInstructions
|
||||
*
|
||||
* The assembly should be compiled as a static or shared library and linked or
|
||||
* loaded by the embedder.
|
||||
|
@ -3392,10 +3405,10 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
|
|||
* - Dart_Precompile must have been called.
|
||||
*
|
||||
* Outputs an ELF shared library defining the symbols
|
||||
* - kDartVmSnapshotData
|
||||
* - kDartVmSnapshotInstructions
|
||||
* - kDartIsolateSnapshotData
|
||||
* - kDartIsolateSnapshotInstructions
|
||||
* - _kDartVmSnapshotData
|
||||
* - _kDartVmSnapshotInstructions
|
||||
* - _kDartIsolateSnapshotData
|
||||
* - _kDartIsolateSnapshotInstructions
|
||||
*
|
||||
* The shared library should be dynamically loaded by the embedder.
|
||||
* Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT.
|
||||
|
|
170
runtime/platform/elf.h
Normal file
170
runtime/platform/elf.h
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright (c) 2019, 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_PLATFORM_ELF_H_
|
||||
#define RUNTIME_PLATFORM_ELF_H_
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
namespace elf {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct ElfHeader {
|
||||
uint8_t ident[16];
|
||||
uint16_t type;
|
||||
uint16_t machine;
|
||||
uint32_t version;
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
uint32_t entry_point;
|
||||
uint32_t program_table_offset;
|
||||
uint32_t section_table_offset;
|
||||
#else
|
||||
uint64_t entry_point;
|
||||
uint64_t program_table_offset;
|
||||
uint64_t section_table_offset;
|
||||
#endif
|
||||
uint32_t flags;
|
||||
uint16_t header_size;
|
||||
uint16_t program_table_entry_size;
|
||||
uint16_t num_program_headers;
|
||||
uint16_t section_table_entry_size;
|
||||
uint16_t num_section_headers;
|
||||
uint16_t shstrtab_section_index;
|
||||
};
|
||||
|
||||
enum class ProgramHeaderType : uint32_t {
|
||||
PT_LOAD = 1,
|
||||
PT_DYNAMIC = 2,
|
||||
PT_PHDR = 6,
|
||||
};
|
||||
|
||||
struct ProgramHeader {
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
ProgramHeaderType type;
|
||||
uint32_t file_offset;
|
||||
uint32_t memory_offset;
|
||||
uint32_t physical_memory_offset;
|
||||
uint32_t file_size;
|
||||
uint32_t memory_size;
|
||||
uint32_t flags;
|
||||
uint32_t alignment;
|
||||
#else
|
||||
ProgramHeaderType type;
|
||||
uint32_t flags;
|
||||
uint64_t file_offset;
|
||||
uint64_t memory_offset;
|
||||
uint64_t physical_memory_offset;
|
||||
uint64_t file_size;
|
||||
uint64_t memory_size;
|
||||
uint64_t alignment;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SectionHeader {
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
uint32_t name;
|
||||
uint32_t type;
|
||||
uint32_t flags;
|
||||
uint32_t memory_offset;
|
||||
uint32_t file_offset;
|
||||
uint32_t file_size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uint32_t alignment;
|
||||
uint32_t entry_size;
|
||||
#else
|
||||
uint32_t name;
|
||||
uint32_t type;
|
||||
uint64_t flags;
|
||||
uint64_t memory_offset;
|
||||
uint64_t file_offset;
|
||||
uint64_t file_size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uint64_t alignment;
|
||||
uint64_t entry_size;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
uint32_t name;
|
||||
uint32_t value;
|
||||
uint32_t size;
|
||||
uint8_t info;
|
||||
uint8_t other; // Reserved by ELF.
|
||||
uint16_t section;
|
||||
#else
|
||||
uint32_t name;
|
||||
uint8_t info;
|
||||
uint8_t other; // Reserved by ELF.
|
||||
uint16_t section;
|
||||
uint64_t value;
|
||||
uint64_t size;
|
||||
#endif
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static constexpr intptr_t ELFCLASS32 = 1;
|
||||
static constexpr intptr_t ELFCLASS64 = 2;
|
||||
|
||||
static const intptr_t EI_DATA = 5;
|
||||
static const intptr_t ELFDATA2LSB = 1;
|
||||
|
||||
static const intptr_t ELFOSABI_SYSV = 0;
|
||||
|
||||
static const intptr_t ET_DYN = 3;
|
||||
|
||||
static constexpr intptr_t EF_ARM_ABI_FLOAT_HARD = 0x00000400;
|
||||
static constexpr intptr_t EF_ARM_ABI_FLOAT_SOFT = 0x00000200;
|
||||
static constexpr intptr_t EF_ARM_ABI = 0x05000000;
|
||||
|
||||
static constexpr intptr_t EM_386 = 3;
|
||||
static constexpr intptr_t EM_ARM = 40;
|
||||
static constexpr intptr_t EM_X86_64 = 62;
|
||||
static constexpr intptr_t EM_AARCH64 = 183;
|
||||
|
||||
static const intptr_t EV_CURRENT = 1;
|
||||
|
||||
static const intptr_t PF_X = 1;
|
||||
static const intptr_t PF_W = 2;
|
||||
static const intptr_t PF_R = 4;
|
||||
|
||||
static const intptr_t SHT_PROGBITS = 1;
|
||||
static const intptr_t SHT_STRTAB = 3;
|
||||
static const intptr_t SHT_HASH = 5;
|
||||
static const intptr_t SHT_DYNSYM = 11;
|
||||
static const intptr_t SHT_DYNAMIC = 6;
|
||||
|
||||
static const intptr_t SHF_WRITE = 0x1;
|
||||
static const intptr_t SHF_ALLOC = 0x2;
|
||||
static const intptr_t SHF_EXECINSTR = 0x4;
|
||||
|
||||
static const intptr_t SHN_UNDEF = 0;
|
||||
|
||||
static const intptr_t STN_UNDEF = 0;
|
||||
|
||||
static const intptr_t PT_LOAD = 1;
|
||||
static const intptr_t PT_DYNAMIC = 2;
|
||||
static const intptr_t PT_PHDR = 6;
|
||||
|
||||
static const intptr_t STB_GLOBAL = 1;
|
||||
|
||||
static const intptr_t STT_OBJECT = 1; // I.e., data.
|
||||
static const intptr_t STT_FUNC = 2;
|
||||
|
||||
static const intptr_t DT_NULL = 0;
|
||||
static const intptr_t DT_HASH = 4;
|
||||
static const intptr_t DT_STRTAB = 5;
|
||||
static const intptr_t DT_SYMTAB = 6;
|
||||
static const intptr_t DT_STRSZ = 10;
|
||||
static const intptr_t DT_SYMENT = 11;
|
||||
|
||||
} // namespace elf
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_PLATFORM_ELF_H_
|
|
@ -6182,10 +6182,6 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
|
|||
return Api::NewError("AOT compilation is not supported on IA32.");
|
||||
#elif defined(TARGET_ARCH_DBC)
|
||||
return Api::NewError("AOT compilation is not supported on DBC.");
|
||||
#elif defined(TARGET_OS_WINDOWS)
|
||||
return Api::NewError("Windows cannot load ELF.");
|
||||
#elif defined(TARGET_OS_MACOS)
|
||||
return Api::NewError("macOS/iOS cannot load ELF.");
|
||||
#elif !defined(DART_PRECOMPILER)
|
||||
return Api::NewError(
|
||||
"This VM was built without support for AOT compilation.");
|
||||
|
|
|
@ -4,66 +4,13 @@
|
|||
|
||||
#include "vm/elf.h"
|
||||
|
||||
#include "platform/elf.h"
|
||||
#include "platform/text_buffer.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/thread.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
|
||||
static const intptr_t ELFDATA2LSB = 1;
|
||||
|
||||
static const intptr_t ELFOSABI_SYSV = 0;
|
||||
|
||||
#define EF_ARM_ABI_FLOAT_HARD 0x00000400
|
||||
#define EF_ARM_ABI_FLOAT_SOFT 0x00000200
|
||||
#define EF_ARM_ABI 0x05000000
|
||||
|
||||
static const intptr_t ET_DYN = 3;
|
||||
|
||||
#define EM_386 3
|
||||
#define EM_ARM 40
|
||||
#define EM_X86_64 62
|
||||
#define EM_AARCH64 183
|
||||
|
||||
static const intptr_t EV_CURRENT = 1;
|
||||
|
||||
static const intptr_t SHT_PROGBITS = 1;
|
||||
static const intptr_t SHT_STRTAB = 3;
|
||||
static const intptr_t SHT_HASH = 5;
|
||||
static const intptr_t SHT_DYNSYM = 11;
|
||||
static const intptr_t SHT_DYNAMIC = 6;
|
||||
|
||||
static const intptr_t SHF_WRITE = 0x1;
|
||||
static const intptr_t SHF_ALLOC = 0x2;
|
||||
static const intptr_t SHF_EXECINSTR = 0x4;
|
||||
|
||||
static const intptr_t SHN_UNDEF = 0;
|
||||
|
||||
static const intptr_t STN_UNDEF = 0;
|
||||
|
||||
static const intptr_t PT_LOAD = 1;
|
||||
static const intptr_t PT_DYNAMIC = 2;
|
||||
static const intptr_t PT_PHDR = 6;
|
||||
|
||||
static const intptr_t PF_X = 1;
|
||||
static const intptr_t PF_W = 2;
|
||||
static const intptr_t PF_R = 4;
|
||||
|
||||
static const intptr_t STB_GLOBAL = 1;
|
||||
|
||||
static const intptr_t STT_OBJECT = 1; // I.e., data.
|
||||
static const intptr_t STT_FUNC = 2;
|
||||
|
||||
static const intptr_t DT_NULL = 0;
|
||||
static const intptr_t DT_HASH = 4;
|
||||
static const intptr_t DT_STRTAB = 5;
|
||||
static const intptr_t DT_SYMTAB = 6;
|
||||
static const intptr_t DT_STRSZ = 10;
|
||||
static const intptr_t DT_SYMENT = 11;
|
||||
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
static const intptr_t kElfHeaderSize = 52;
|
||||
static const intptr_t kElfSectionTableAlignment = 4;
|
||||
|
@ -94,7 +41,7 @@ class Section : public ZoneAllocated {
|
|||
intptr_t section_type = 0;
|
||||
intptr_t section_flags = 0;
|
||||
intptr_t section_index = -1;
|
||||
intptr_t section_link = SHN_UNDEF;
|
||||
intptr_t section_link = elf::SHN_UNDEF;
|
||||
intptr_t section_info = 0;
|
||||
intptr_t section_entry_size = 0;
|
||||
intptr_t file_size = 0;
|
||||
|
@ -119,16 +66,16 @@ class ProgramBits : public Section {
|
|||
intptr_t memsz = -1) {
|
||||
if (memsz == -1) memsz = filesz;
|
||||
|
||||
section_type = SHT_PROGBITS;
|
||||
section_type = elf::SHT_PROGBITS;
|
||||
if (allocate) {
|
||||
section_flags = SHF_ALLOC;
|
||||
if (executable) section_flags |= SHF_EXECINSTR;
|
||||
if (writable) section_flags |= SHF_WRITE;
|
||||
section_flags = elf::SHF_ALLOC;
|
||||
if (executable) section_flags |= elf::SHF_EXECINSTR;
|
||||
if (writable) section_flags |= elf::SHF_WRITE;
|
||||
|
||||
segment_type = PT_LOAD;
|
||||
segment_flags = PF_R;
|
||||
if (executable) segment_flags |= PF_X;
|
||||
if (writable) segment_flags |= PF_W;
|
||||
segment_type = elf::PT_LOAD;
|
||||
segment_flags = elf::PF_R;
|
||||
if (executable) segment_flags |= elf::PF_X;
|
||||
if (writable) segment_flags |= elf::PF_W;
|
||||
}
|
||||
|
||||
bytes_ = bytes;
|
||||
|
@ -148,10 +95,10 @@ class ProgramBits : public Section {
|
|||
class StringTable : public Section {
|
||||
public:
|
||||
explicit StringTable(bool allocate) : text_(128) {
|
||||
section_type = SHT_STRTAB;
|
||||
section_flags = allocate ? SHF_ALLOC : 0;
|
||||
segment_type = PT_LOAD;
|
||||
segment_flags = PF_R;
|
||||
section_type = elf::SHT_STRTAB;
|
||||
section_flags = allocate ? elf::SHF_ALLOC : 0;
|
||||
segment_type = elf::PT_LOAD;
|
||||
segment_flags = elf::PF_R;
|
||||
|
||||
text_.AddChar('\0');
|
||||
memory_size = file_size = text_.length();
|
||||
|
@ -186,10 +133,10 @@ class Symbol : public ZoneAllocated {
|
|||
class SymbolTable : public Section {
|
||||
public:
|
||||
SymbolTable() {
|
||||
section_type = SHT_DYNSYM;
|
||||
section_flags = SHF_ALLOC;
|
||||
segment_type = PT_LOAD;
|
||||
segment_flags = PF_R;
|
||||
section_type = elf::SHT_DYNSYM;
|
||||
section_flags = elf::SHF_ALLOC;
|
||||
segment_type = elf::PT_LOAD;
|
||||
segment_flags = elf::PF_R;
|
||||
|
||||
section_entry_size = kElfSymbolTableEntrySize;
|
||||
AddSymbol(NULL);
|
||||
|
@ -268,24 +215,24 @@ static uint32_t ElfHash(const unsigned char* name) {
|
|||
class SymbolHashTable : public Section {
|
||||
public:
|
||||
SymbolHashTable(StringTable* strtab, SymbolTable* symtab) {
|
||||
section_type = SHT_HASH;
|
||||
section_flags = SHF_ALLOC;
|
||||
section_type = elf::SHT_HASH;
|
||||
section_flags = elf::SHF_ALLOC;
|
||||
section_link = symtab->section_index;
|
||||
section_entry_size = kElfSymbolHashTableEntrySize;
|
||||
segment_type = PT_LOAD;
|
||||
segment_flags = PF_R;
|
||||
segment_type = elf::PT_LOAD;
|
||||
segment_flags = elf::PF_R;
|
||||
|
||||
nchain_ = symtab->length();
|
||||
nbucket_ = symtab->length();
|
||||
|
||||
bucket_ = Thread::Current()->zone()->Alloc<int32_t>(nbucket_);
|
||||
for (intptr_t i = 0; i < nbucket_; i++) {
|
||||
bucket_[i] = STN_UNDEF;
|
||||
bucket_[i] = elf::STN_UNDEF;
|
||||
}
|
||||
|
||||
chain_ = Thread::Current()->zone()->Alloc<int32_t>(nchain_);
|
||||
for (intptr_t i = 0; i < nchain_; i++) {
|
||||
chain_[i] = STN_UNDEF;
|
||||
chain_[i] = elf::STN_UNDEF;
|
||||
}
|
||||
|
||||
for (intptr_t i = 1; i < symtab->length(); i++) {
|
||||
|
@ -322,20 +269,20 @@ class DynamicTable : public Section {
|
|||
DynamicTable(StringTable* strtab,
|
||||
SymbolTable* symtab,
|
||||
SymbolHashTable* hash) {
|
||||
section_type = SHT_DYNAMIC;
|
||||
section_type = elf::SHT_DYNAMIC;
|
||||
section_link = strtab->section_index;
|
||||
section_flags = SHF_ALLOC | SHF_WRITE;
|
||||
section_flags = elf::SHF_ALLOC | elf::SHF_WRITE;
|
||||
section_entry_size = kElfDynamicTableEntrySize;
|
||||
|
||||
segment_type = PT_LOAD;
|
||||
segment_flags = PF_R | PF_W;
|
||||
segment_type = elf::PT_LOAD;
|
||||
segment_flags = elf::PF_R | elf::PF_W;
|
||||
|
||||
AddEntry(DT_HASH, hash->memory_offset);
|
||||
AddEntry(DT_STRTAB, strtab->memory_offset);
|
||||
AddEntry(DT_STRSZ, strtab->memory_size);
|
||||
AddEntry(DT_SYMTAB, symtab->memory_offset);
|
||||
AddEntry(DT_SYMENT, kElfSymbolTableEntrySize);
|
||||
AddEntry(DT_NULL, 0);
|
||||
AddEntry(elf::DT_HASH, hash->memory_offset);
|
||||
AddEntry(elf::DT_STRTAB, strtab->memory_offset);
|
||||
AddEntry(elf::DT_STRSZ, strtab->memory_size);
|
||||
AddEntry(elf::DT_SYMTAB, symtab->memory_offset);
|
||||
AddEntry(elf::DT_SYMENT, kElfSymbolTableEntrySize);
|
||||
AddEntry(elf::DT_NULL, 0);
|
||||
}
|
||||
|
||||
void Write(Elf* stream) {
|
||||
|
@ -432,7 +379,7 @@ intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
|
|||
Symbol* symbol = new (zone_) Symbol();
|
||||
symbol->cstr = name;
|
||||
symbol->name = symstrtab_->AddString(name);
|
||||
symbol->info = (STB_GLOBAL << 4) | STT_FUNC;
|
||||
symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_FUNC;
|
||||
symbol->section = image->section_index;
|
||||
// For shared libraries, this is the offset from the DSO base. For static
|
||||
// libraries, this is section relative.
|
||||
|
@ -453,7 +400,7 @@ intptr_t Elf::AddBSSData(const char* name, intptr_t size) {
|
|||
Symbol* symbol = new (zone_) Symbol();
|
||||
symbol->cstr = name;
|
||||
symbol->name = symstrtab_->AddString(name);
|
||||
symbol->info = (STB_GLOBAL << 4) | STT_OBJECT;
|
||||
symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_OBJECT;
|
||||
symbol->section = image->section_index;
|
||||
// For shared libraries, this is the offset from the DSO base. For static
|
||||
// libraries, this is section relative.
|
||||
|
@ -473,7 +420,7 @@ intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
|
|||
Symbol* symbol = new (zone_) Symbol();
|
||||
symbol->cstr = name;
|
||||
symbol->name = symstrtab_->AddString(name);
|
||||
symbol->info = (STB_GLOBAL << 4) | STT_OBJECT;
|
||||
symbol->info = (elf::STB_GLOBAL << 4) | elf::STT_OBJECT;
|
||||
symbol->section = image->section_index;
|
||||
// For shared libraries, this is the offset from the DSO base. For static
|
||||
// libraries, this is section relative.
|
||||
|
@ -550,39 +497,52 @@ void Elf::ComputeFileOffsets() {
|
|||
|
||||
void Elf::WriteHeader() {
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
uint8_t size = ELFCLASS32;
|
||||
uint8_t size = elf::ELFCLASS32;
|
||||
#else
|
||||
uint8_t size = ELFCLASS64;
|
||||
uint8_t size = elf::ELFCLASS64;
|
||||
#endif
|
||||
uint8_t e_ident[16] = {
|
||||
0x7f, 'E', 'L', 'F', size, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV,
|
||||
0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t e_ident[16] = {0x7f,
|
||||
'E',
|
||||
'L',
|
||||
'F',
|
||||
size,
|
||||
elf::ELFDATA2LSB,
|
||||
elf::EV_CURRENT,
|
||||
elf::ELFOSABI_SYSV,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
stream_->WriteBytes(e_ident, 16);
|
||||
|
||||
WriteHalf(ET_DYN); // Shared library.
|
||||
WriteHalf(elf::ET_DYN); // Shared library.
|
||||
|
||||
#if defined(TARGET_ARCH_IA32)
|
||||
WriteHalf(EM_386);
|
||||
WriteHalf(elf::EM_386);
|
||||
#elif defined(TARGET_ARCH_X64)
|
||||
WriteHalf(EM_X86_64);
|
||||
WriteHalf(elf::EM_X86_64);
|
||||
#elif defined(TARGET_ARCH_ARM)
|
||||
WriteHalf(EM_ARM);
|
||||
WriteHalf(elf::EM_ARM);
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
WriteHalf(EM_AARCH64);
|
||||
WriteHalf(elf::EM_AARCH64);
|
||||
#else
|
||||
// E.g., DBC.
|
||||
FATAL("Unknown ELF architecture");
|
||||
#endif
|
||||
|
||||
WriteWord(EV_CURRENT); // Version
|
||||
WriteWord(elf::EV_CURRENT); // Version
|
||||
WriteAddr(0); // "Entry point"
|
||||
WriteOff(program_table_file_offset_);
|
||||
WriteOff(section_table_file_offset_);
|
||||
|
||||
#if defined(TARGET_ARCH_ARM)
|
||||
uword flags = EF_ARM_ABI |
|
||||
(TargetCPUFeatures::hardfp_supported() ? EF_ARM_ABI_FLOAT_HARD
|
||||
: EF_ARM_ABI_FLOAT_SOFT);
|
||||
uword flags = elf::EF_ARM_ABI | (TargetCPUFeatures::hardfp_supported()
|
||||
? elf::EF_ARM_ABI_FLOAT_HARD
|
||||
: elf::EF_ARM_ABI_FLOAT_SOFT);
|
||||
#else
|
||||
uword flags = 0;
|
||||
#endif
|
||||
|
@ -607,17 +567,17 @@ void Elf::WriteProgramTable() {
|
|||
ASSERT(kNumImplicitSegments == 3);
|
||||
const intptr_t start = stream_->position();
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
WriteWord(PT_PHDR);
|
||||
WriteWord(elf::PT_PHDR);
|
||||
WriteOff(program_table_file_offset_); // File offset.
|
||||
WriteAddr(program_table_file_offset_); // Virtual address.
|
||||
WriteAddr(program_table_file_offset_); // Physical address, not used.
|
||||
WriteWord(program_table_file_size_);
|
||||
WriteWord(program_table_file_size_);
|
||||
WriteWord(PF_R);
|
||||
WriteWord(elf::PF_R);
|
||||
WriteWord(kPageSize);
|
||||
#else
|
||||
WriteWord(PT_PHDR);
|
||||
WriteWord(PF_R);
|
||||
WriteWord(elf::PT_PHDR);
|
||||
WriteWord(elf::PF_R);
|
||||
WriteOff(program_table_file_offset_); // File offset.
|
||||
WriteAddr(program_table_file_offset_); // Virtual address.
|
||||
WriteAddr(program_table_file_offset_); // Physical address, not used.
|
||||
|
@ -642,17 +602,17 @@ void Elf::WriteProgramTable() {
|
|||
ASSERT(kNumImplicitSegments == 3);
|
||||
const intptr_t start = stream_->position();
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
WriteWord(PT_LOAD);
|
||||
WriteWord(elf::PT_LOAD);
|
||||
WriteOff(0); // File offset.
|
||||
WriteAddr(0); // Virtual address.
|
||||
WriteAddr(0); // Physical address, not used.
|
||||
WriteWord(program_table_file_offset_ + program_table_file_size_);
|
||||
WriteWord(program_table_file_offset_ + program_table_file_size_);
|
||||
WriteWord(PF_R);
|
||||
WriteWord(elf::PF_R);
|
||||
WriteWord(kPageSize);
|
||||
#else
|
||||
WriteWord(PT_LOAD);
|
||||
WriteWord(PF_R);
|
||||
WriteWord(elf::PT_LOAD);
|
||||
WriteWord(elf::PF_R);
|
||||
WriteOff(0); // File offset.
|
||||
WriteAddr(0); // Virtual address.
|
||||
WriteAddr(0); // Physical address, not used.
|
||||
|
@ -696,7 +656,7 @@ void Elf::WriteProgramTable() {
|
|||
ASSERT(kNumImplicitSegments == 3);
|
||||
const intptr_t start = stream_->position();
|
||||
#if defined(TARGET_ARCH_IS_32_BIT)
|
||||
WriteWord(PT_DYNAMIC);
|
||||
WriteWord(elf::PT_DYNAMIC);
|
||||
WriteOff(dynamic_->file_offset);
|
||||
WriteAddr(dynamic_->memory_offset); // Virtual address.
|
||||
WriteAddr(dynamic_->memory_offset); // Physical address, not used.
|
||||
|
@ -705,7 +665,7 @@ void Elf::WriteProgramTable() {
|
|||
WriteWord(dynamic_->segment_flags);
|
||||
WriteWord(dynamic_->alignment);
|
||||
#else
|
||||
WriteWord(PT_DYNAMIC);
|
||||
WriteWord(elf::PT_DYNAMIC);
|
||||
WriteWord(dynamic_->segment_flags);
|
||||
WriteOff(dynamic_->file_offset);
|
||||
WriteAddr(dynamic_->memory_offset); // Virtual address.
|
||||
|
|
|
@ -57,12 +57,15 @@ class VirtualMemory {
|
|||
bool is_executable,
|
||||
const char* name);
|
||||
|
||||
// Returns the cached page size. Use only if Init() has been called.
|
||||
static intptr_t PageSize() {
|
||||
ASSERT(page_size_ != 0);
|
||||
ASSERT(Utils::IsPowerOfTwo(page_size_));
|
||||
return page_size_;
|
||||
}
|
||||
|
||||
// Use only if Init() might not have been called.
|
||||
static intptr_t CalculatePageSize();
|
||||
|
||||
static bool InSamePage(uword address0, uword address1);
|
||||
|
||||
// Truncate this virtual memory segment.
|
||||
|
|
|
@ -40,8 +40,15 @@ DECLARE_FLAG(bool, write_protect_code);
|
|||
|
||||
uword VirtualMemory::page_size_ = 0;
|
||||
|
||||
intptr_t VirtualMemory::CalculatePageSize() {
|
||||
const intptr_t page_size = getpagesize();
|
||||
ASSERT(page_size != 0);
|
||||
ASSERT(Utils::IsPowerOfTwo(page_size));
|
||||
return page_size;
|
||||
}
|
||||
|
||||
void VirtualMemory::Init() {
|
||||
page_size_ = getpagesize();
|
||||
page_size_ = CalculatePageSize();
|
||||
}
|
||||
|
||||
static void Unmap(zx_handle_t vmar, uword start, uword end) {
|
||||
|
|
|
@ -42,8 +42,15 @@ DECLARE_FLAG(bool, generate_perf_jitdump);
|
|||
|
||||
uword VirtualMemory::page_size_ = 0;
|
||||
|
||||
intptr_t VirtualMemory::CalculatePageSize() {
|
||||
const intptr_t page_size = getpagesize();
|
||||
ASSERT(page_size != 0);
|
||||
ASSERT(Utils::IsPowerOfTwo(page_size));
|
||||
return page_size;
|
||||
}
|
||||
|
||||
void VirtualMemory::Init() {
|
||||
page_size_ = getpagesize();
|
||||
page_size_ = CalculatePageSize();
|
||||
|
||||
#if defined(DUAL_MAPPING_SUPPORTED)
|
||||
// Perf is Linux-specific and the flags aren't defined in Product.
|
||||
|
@ -62,7 +69,7 @@ void VirtualMemory::Init() {
|
|||
// such as on docker containers, and disable dual mapping in this case.
|
||||
// Also detect for missing support of memfd_create syscall.
|
||||
if (FLAG_dual_map_code) {
|
||||
intptr_t size = page_size_;
|
||||
intptr_t size = PageSize();
|
||||
intptr_t alignment = 256 * 1024; // e.g. heap page size.
|
||||
VirtualMemory* vm = AllocateAligned(size, alignment, true, NULL);
|
||||
if (vm == NULL) {
|
||||
|
@ -167,10 +174,10 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
|
|||
//
|
||||
// If FLAG_dual_map_code is active, the executable mapping will be mapped RX
|
||||
// immediately and never changes protection until it is eventually unmapped.
|
||||
ASSERT(Utils::IsAligned(size, page_size_));
|
||||
ASSERT(Utils::IsAligned(size, PageSize()));
|
||||
ASSERT(Utils::IsPowerOfTwo(alignment));
|
||||
ASSERT(Utils::IsAligned(alignment, page_size_));
|
||||
const intptr_t allocated_size = size + alignment - page_size_;
|
||||
ASSERT(Utils::IsAligned(alignment, PageSize()));
|
||||
const intptr_t allocated_size = size + alignment - PageSize();
|
||||
#if defined(DUAL_MAPPING_SUPPORTED)
|
||||
int fd = -1;
|
||||
const bool dual_mapping =
|
||||
|
|
|
@ -18,10 +18,17 @@ DECLARE_FLAG(bool, write_protect_code);
|
|||
|
||||
uword VirtualMemory::page_size_ = 0;
|
||||
|
||||
void VirtualMemory::Init() {
|
||||
intptr_t VirtualMemory::CalculatePageSize() {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
page_size_ = info.dwPageSize;
|
||||
const intptr_t page_size = info.dwPageSize;
|
||||
ASSERT(page_size != 0);
|
||||
ASSERT(Utils::IsPowerOfTwo(page_size));
|
||||
return page_size;
|
||||
}
|
||||
|
||||
void VirtualMemory::Init() {
|
||||
page_size_ = CalculatePageSize();
|
||||
}
|
||||
|
||||
bool VirtualMemory::DualMappingEnabled() {
|
||||
|
@ -35,10 +42,10 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
|
|||
// When FLAG_write_protect_code is active, code memory (indicated by
|
||||
// is_executable = true) is allocated as non-executable and later
|
||||
// changed to executable via VirtualMemory::Protect.
|
||||
ASSERT(Utils::IsAligned(size, page_size_));
|
||||
ASSERT(Utils::IsAligned(size, PageSize()));
|
||||
ASSERT(Utils::IsPowerOfTwo(alignment));
|
||||
ASSERT(Utils::IsAligned(alignment, page_size_));
|
||||
intptr_t reserved_size = size + alignment - page_size_;
|
||||
ASSERT(Utils::IsAligned(alignment, PageSize()));
|
||||
intptr_t reserved_size = size + alignment - PageSize();
|
||||
int prot = (is_executable && !FLAG_write_protect_code)
|
||||
? PAGE_EXECUTE_READWRITE
|
||||
: PAGE_READWRITE;
|
||||
|
|
|
@ -5,15 +5,6 @@
|
|||
[ $arch == simdbc || $arch == simdbc64 ]
|
||||
*: Skip # SIMDBC will be deleted soon.
|
||||
|
||||
# Issue 37295, not yet supported in blobs snapshots at present.
|
||||
[ $compiler == dartkp && $system == windows ]
|
||||
function_callbacks_test: Skip
|
||||
regress_37511_callbacks_test: Skip
|
||||
stacktrace_regress_37910_test: Skip
|
||||
|
||||
[ $compiler != dartkp || $system != windows ]
|
||||
function_callbacks_unsupported_test: SkipByDesign # See above
|
||||
|
||||
[ $builder_tag == asan ]
|
||||
data_not_asan_test: SkipByDesign # This test tries to allocate too much memory on purpose.
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
//
|
||||
// Dart test program for testing that FFI callbacks report an appropriate
|
||||
// runtime error for unsupported snapshot formats.
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
bool checkError(UnsupportedError err) {
|
||||
return "$err".contains("callbacks are not yet supported in blobs");
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.throws<UnsupportedError>(
|
||||
() => Pointer.fromFunction<Void Function()>(main), checkError);
|
||||
}
|
|
@ -66,7 +66,7 @@ main() {
|
|||
throw "'file' failed";
|
||||
return;
|
||||
}
|
||||
if (!result.stdout.contains("shared object")) {
|
||||
if (!result.stdout.contains("Mach-O")) {
|
||||
print("Skipping test because we are not running from a dylib");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -341,11 +341,7 @@
|
|||
"use-elf": true
|
||||
}},
|
||||
"dartk-android-(debug|product|release)-(arm|arm64)": {},
|
||||
"dartkp-linux-(debug|product|release)-(simarm|simarm64)": {
|
||||
"options": {
|
||||
"use-blobs": true
|
||||
}},
|
||||
"dartkp-(win|mac)-(debug|product|release)-(simarm|simarm64)": {
|
||||
"dartkp-(linux|win|mac)-(debug|product|release)-(simarm|simarm64)": {
|
||||
"options": {
|
||||
"use-blobs": true
|
||||
}},
|
||||
|
@ -356,11 +352,11 @@
|
|||
}},
|
||||
"dartkp-win-(product|release)-x64": {
|
||||
"options": {
|
||||
"use-blobs": true
|
||||
"use-elf": true
|
||||
}},
|
||||
"dartkp-win-debug-x64": {
|
||||
"options": {
|
||||
"use-blobs": true,
|
||||
"use-elf": true,
|
||||
"vm-options": ["--no-enable-malloc-hooks"]
|
||||
}},
|
||||
"dartkp-(linux|mac)-(product|release)-x64": { },
|
||||
|
@ -380,7 +376,7 @@
|
|||
"dartkp-no-bare-(linux|mac|win)-(debug|product|release)-(simarm|simarm64)": {
|
||||
"options": {
|
||||
"vm-options": ["--no-enable-malloc-hooks", "--no-use-bare-instructions"],
|
||||
"use-blobs": true
|
||||
"use-elf": true
|
||||
}},
|
||||
"dartk-(linux|mac|win)-(debug|product|release)-(ia32|x64)": { },
|
||||
"dartk-checked-(linux|mac|win)-(debug|product|release)-(ia32|x64)": {
|
||||
|
|
Loading…
Reference in New Issue
Block a user