1
0
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:
Samir Jindel 2019-09-24 15:03:19 +00:00 committed by commit-bot@chromium.org
parent c195896c84
commit 362ef8e67c
27 changed files with 962 additions and 267 deletions

View File

@ -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
View 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**>(&section_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**>(&section_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
View 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_

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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() {

View File

@ -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() {

View File

@ -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() {

View File

@ -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() {

View File

@ -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() {

View File

@ -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)

View File

@ -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
View 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_

View File

@ -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.");

View File

@ -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.

View File

@ -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.

View File

@ -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) {

View File

@ -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 =

View File

@ -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;

View File

@ -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.

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)": {