Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@

#include <fstream>

#if defined(TARGET_UNIX)
#include <dlfcn.h>
#endif

#if defined(TARGET_WINDOWS)
#include <windows.h>
#endif

using char_t = pal::char_t;
using string_t = pal::string_t;

Expand Down Expand Up @@ -81,6 +89,9 @@ namespace envvar
// - Not set: same as PROPERTY
// - The TPA list as a platform delimited list of paths. The same format as the system's PATH env var.
const char_t* appAssemblies = W("APP_ASSEMBLIES");

// Variable indicating if a callback to support platform-native R2R should be provided to the runtime
const char_t* platformNativeR2R = W("PLATFORM_NATIVE_R2R");
}

static void wait_for_debugger()
Expand Down Expand Up @@ -273,6 +284,58 @@ size_t HOST_CONTRACT_CALLTYPE get_runtime_property(
static char* s_core_libs_path = nullptr;
static char* s_core_root_path = nullptr;

static bool HOST_CONTRACT_CALLTYPE get_native_code_data(
const host_runtime_contract_native_code_context* context,
host_runtime_contract_native_code_data* data)
{
#if !defined(TARGET_WINDOWS) && !defined(TARGET_OSX)
// Platform-native R2R is only supported on Windows and macOS
return false;
#else
if (context == nullptr || data == nullptr)
return false;

const char* assembly_path = context->assembly_path;
const char* owner_name = context->owner_composite_name;

if (assembly_path == nullptr || owner_name == nullptr)
return false;

// Look for native library next to the assembly
pal::string_t native_image_path;
{
pal::string_t file;
pal::split_path_to_dir_filename(pal::convert_from_utf8(assembly_path), native_image_path, file);
pal::ensure_trailing_delimiter(native_image_path);
}
native_image_path.append(pal::convert_from_utf8(owner_name));

pal::mod_t native_image;
if (!pal::try_load_library(native_image_path, native_image))
return false;

// Get the R2R header export
void* header_ptr = pal::get_module_symbol(native_image, "RTR_HEADER");
if (header_ptr == nullptr)
return false;

// Get module information (base address and size)
void* base_address = pal::get_image_base(native_image, header_ptr);
if (base_address == nullptr)
return false;

size_t image_size = pal::get_image_size(base_address);
if (image_size == 0)
return false;

data->size = sizeof(host_runtime_contract_native_code_data);
data->r2r_header_ptr = header_ptr;
data->image_size = image_size;
data->image_base = base_address;
return true;
#endif // TARGET_WINDOWS || TARGET_OSX
}

static bool HOST_CONTRACT_CALLTYPE external_assembly_probe(
const char* path,
void** data_start,
Expand Down Expand Up @@ -464,7 +527,8 @@ static int run(const configuration& config)
&get_runtime_property,
nullptr,
nullptr,
use_external_assembly_probe ? &external_assembly_probe : nullptr };
use_external_assembly_probe ? &external_assembly_probe : nullptr,
pal::getenv(envvar::platformNativeR2R) == W("1") ? &get_native_code_data : nullptr };
propertyKeys.push_back(HOST_PROPERTY_RUNTIME_CONTRACT);
std::stringstream ss;
ss << "0x" << std::hex << (size_t)(&host_contract);
Expand Down
127 changes: 127 additions & 0 deletions src/coreclr/hosts/corerun/corerun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,39 @@ namespace pal
return { buffer.get() };
}

inline string_t convert_from_utf8(const char* str)
{
int wchar_req = ::MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);

malloc_ptr<wchar_t> buffer{ (wchar_t*)::malloc(wchar_req * sizeof(wchar_t)) };
assert(buffer != nullptr);

int written = ::MultiByteToWideChar(CP_UTF8, 0, str, -1, buffer.get(), wchar_req);
assert(wchar_req == written);

return { buffer.get() };
}

inline void* get_image_base(mod_t m, void* sym)
{
// On Windows, the HMODULE is the base address
return (void*)m;
}

inline size_t get_image_size(void* base_address)
{
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)base_address;
if (dos_header->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS*)((BYTE*)base_address + dos_header->e_lfanew);
if (nt_headers->Signature == IMAGE_NT_SIGNATURE)
{
return nt_headers->OptionalHeader.SizeOfImage;
}
}
return 0;
}

inline bool try_load_hostpolicy(pal::string_t mock_hostpolicy_value)
{
const char_t* hostpolicyName = W("hostpolicy.dll");
Expand Down Expand Up @@ -333,6 +366,7 @@ class platform_specific_actions final
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstddef>

// Needed for detecting the debugger attach scenario
#if defined(__APPLE__)
Expand All @@ -342,6 +376,16 @@ class platform_specific_actions final
#include <ctype.h>
#endif // !__APPLE__

// For getting image size
#if defined(TARGET_APPLE)
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#elif !defined(TARGET_WASM)
#include <link.h>
#include <elf.h>
#include <cstring>
#endif

// CMake generated
#include <config.h>
#include <minipal/getexepath.h>
Expand Down Expand Up @@ -568,6 +612,89 @@ namespace pal
return { str };
}

inline string_t convert_from_utf8(const char* str)
{
return { str };
}

inline void* get_image_base(mod_t m, void* sym)
{
#ifndef TARGET_WASM
Dl_info info;
if (dladdr(sym, &info) != 0)
{
return info.dli_fbase;
}
#endif
return nullptr;
}

inline size_t get_image_size(void* base_address)
{
if (base_address == nullptr)
return 0;

#if defined(TARGET_APPLE)
uint32_t image_count = _dyld_image_count();
for (uint32_t i = 0; i < image_count; ++i)
{
const struct mach_header_64* header =
reinterpret_cast<const struct mach_header_64*>(_dyld_get_image_header(i));
if (reinterpret_cast<const void*>(header) != base_address)
continue;

const struct load_command* cmd =
reinterpret_cast<const struct load_command*>(
reinterpret_cast<const char*>(header) + sizeof(struct mach_header_64));

size_t image_size = 0;
for (uint32_t j = 0; j < header->ncmds; ++j)
{
if (cmd->cmd == LC_SEGMENT_64)
{
const struct segment_command_64* seg =
reinterpret_cast<const struct segment_command_64*>(cmd);
size_t end_addr = static_cast<size_t>(seg->vmaddr + seg->vmsize);
if (end_addr > image_size)
image_size = end_addr;
}

cmd = reinterpret_cast<const struct load_command*>(
reinterpret_cast<const char*>(cmd) + cmd->cmdsize);
}

return image_size;
}
#elif !defined(TARGET_WASM)
ElfW(Ehdr)* ehdr = reinterpret_cast<ElfW(Ehdr)*>(base_address);
if (std::memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
return 0;

ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(
reinterpret_cast<char*>(base_address) + ehdr->e_phoff);

size_t max_addr = 0;
size_t min_addr = static_cast<size_t>(-1);

for (int i = 0; i < ehdr->e_phnum; ++i)
{
if (phdr[i].p_type == PT_LOAD)
{
size_t seg_start = phdr[i].p_vaddr;
size_t seg_end = phdr[i].p_vaddr + phdr[i].p_memsz;
if (seg_start < min_addr)
min_addr = seg_start;
if (seg_end > max_addr)
max_addr = seg_end;
}
}

if (max_addr > min_addr)
return max_addr - min_addr;
#endif
return 0;
}

inline bool try_load_hostpolicy(pal::string_t mock_hostpolicy_value)
{
#ifndef TARGET_WASM
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/inc/hostinformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class HostInformation

static bool HasExternalProbe();
static bool ExternalAssemblyProbe(_In_ const SString& path, _Out_ void** data, _Out_ int64_t* size);

static bool GetNativeCodeData(_In_ const SString& assemblyPath, _In_z_ const char* ownerCompositeName, _Out_ void** header, _Out_ size_t* image_size, _Out_ void** image_base);
};

#endif // _HOSTINFORMATION_H_
1 change: 1 addition & 0 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum ReadyToRunFlag
READYTORUN_FLAG_COMPONENT = 0x00000020, // This is the header describing a component assembly of composite R2R
READYTORUN_FLAG_MULTIMODULE_VERSION_BUBBLE = 0x00000040, // This R2R module has multiple modules within its version bubble (For versions before version 6.2, all modules are assumed to possibly have this characteristic)
READYTORUN_FLAG_UNRELATED_R2R_CODE = 0x00000080, // This R2R module has code in it that would not be naturally encoded into this module
READYTORUN_FLAG_PLATFORM_NATIVE_IMAGE = 0x00000100, // The owning composite executable is in the platform native format
};

enum class ReadyToRunSectionType : uint32_t
Expand Down
5 changes: 2 additions & 3 deletions src/coreclr/vm/assemblybinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@ HRESULT AssemblyBinder::BindAssemblyByName(AssemblyNameData* pAssemblyNameData,
}


NativeImage* AssemblyBinder::LoadNativeImage(Module* componentModule, LPCUTF8 nativeImageName)
NativeImage* AssemblyBinder::LoadNativeImage(Module* componentModule, LPCUTF8 nativeImageName, bool isPlatformNative)
{
STANDARD_VM_CONTRACT;

AppDomain::LoadLockHolder lock(AppDomain::GetCurrentDomain());
AssemblyBinder* binder = componentModule->GetPEAssembly()->GetAssemblyBinder();
PTR_LoaderAllocator moduleLoaderAllocator = componentModule->GetLoaderAllocator();

bool isNewNativeImage;
NativeImage* nativeImage = NativeImage::Open(componentModule, nativeImageName, binder, moduleLoaderAllocator, &isNewNativeImage);
NativeImage* nativeImage = NativeImage::Open(componentModule->GetPath(), nativeImageName, this, moduleLoaderAllocator, isPlatformNative, &isNewNativeImage);

return nativeImage;
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/assemblybinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class AssemblyBinder
m_ptrAssemblyLoadContext = ptrManagedDefaultBinderInstance;
}

NativeImage* LoadNativeImage(Module* componentModule, LPCUTF8 nativeImageName);
NativeImage* LoadNativeImage(Module* componentModule, LPCUTF8 nativeImageName, bool isPlatformNative);
void AddLoadedAssembly(Assembly* loadedAssembly);

void GetNameForDiagnostics(/*out*/ SString& alcName);
Expand Down
32 changes: 32 additions & 0 deletions src/coreclr/vm/hostinformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,35 @@ bool HostInformation::ExternalAssemblyProbe(_In_ const SString& path, _Out_ void
utf8Path.SetAndConvertToUTF8(path.GetUnicode());
return s_hostContract.external_assembly_probe(utf8Path.GetUTF8(), data, size);
}

bool HostInformation::GetNativeCodeData(_In_ const SString& assemblyPath, _In_z_ const char* ownerCompositeName, _Out_ void** header, _Out_ size_t* image_size, _Out_ void** image_base)
{
_ASSERT(header != nullptr);
_ASSERT(image_base != nullptr);
_ASSERT(image_size != nullptr);

size_t requiredSize = offsetof(host_runtime_contract, get_native_code_data) + sizeof(s_hostContract.get_native_code_data);
if (s_hostContract.size < requiredSize || s_hostContract.get_native_code_data == nullptr)
return false;

StackSString utf8Path;
utf8Path.SetAndConvertToUTF8(assemblyPath.GetUnicode());
host_runtime_contract_native_code_context context
{
sizeof(host_runtime_contract_native_code_context),
utf8Path.GetUTF8(),
ownerCompositeName
};
host_runtime_contract_native_code_data data = { sizeof(host_runtime_contract_native_code_data) };
if (!s_hostContract.get_native_code_data(&context, &data))
return false;

if (data.r2r_header_ptr == nullptr || data.image_size == 0 || data.image_base == nullptr)
return false;

_ASSERT(data.size >= offsetof(host_runtime_contract_native_code_data, image_base) + sizeof(data.image_base));
*header = data.r2r_header_ptr;
*image_size = data.image_size;
*image_base = data.image_base;
return true;
}
Loading
Loading