Skip to content
Merged
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
19 changes: 17 additions & 2 deletions src/coreclr/hosts/corerun/wasm/libCorerun.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,15 @@ function libCoreRunFactory() {
} catch (e) {
return false;
}
const wasmModule = new WebAssembly.Module(wasmBytes);
let wasmModule;
try {
wasmModule = new WebAssembly.Module(wasmBytes);
} catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e);
console.error("Failed to construct WebAssembly module for Webcil image:", {wasmPath, errorMessage});
return false;
}

const tableStartIndex = wasmTable.length;

var payloadSize = 0;
Expand All @@ -195,7 +203,14 @@ function libCoreRunFactory() {
console.error("Webcil payload size is 0; cannot load image");
return false;
}
wasmTable.grow(tableSize);

try {
wasmTable.grow(tableSize);
} catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e);
console.error("Failed to grow WebAssembly table for Webcil image:", {wasmPath, errorMessage});
return false;
}

var payloadPtr = 0;
var wasmInstance;
Expand Down
28 changes: 20 additions & 8 deletions src/coreclr/inc/webcildecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ class WebcilDecoder

WebcilDecoder();
void Init(void *flatBase, COUNT_T size);
void Reset();

// ------------------------------------------------------------
// COR header — public for CorDecoderHelpers access
Expand Down Expand Up @@ -197,15 +196,26 @@ class WebcilDecoder
void *GetNativeEntryPoint() const { return NULL; }

// ------------------------------------------------------------
// R2R — not supported for Webcil
// R2R
// ------------------------------------------------------------

BOOL HasReadyToRunHeader() const { return FALSE; }
BOOL HasReadyToRunHeader() const;
BOOL IsComponentAssembly() const { return FALSE; }
READYTORUN_HEADER *GetReadyToRunHeader() const { return NULL; }
BOOL IsNativeMachineFormat() const { return FALSE; }
PTR_CVOID GetNativeManifestMetadata(COUNT_T *pSize = NULL) const;
READYTORUN_HEADER *GetReadyToRunHeader() const;
BOOL IsNativeMachineFormat() const { return true; } // This can only be loaded on a Wasm runtime which matches the necessary load environment, which means these are always in the native machine format.
PTR_CVOID GetNativeManifestMetadata(COUNT_T *pSize) const;

CHECK CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const;
TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir) const;
SSIZE_T GetTableBaseOffset() const
{
if (m_pHeader == NULL)
return 0;
return m_pHeader->VersionMajor >= WEBCIL_VERSION_MAJOR_1 ? ((const WebcilHeader_1 *)m_pHeader)->TableBase : 0;
}
private:
READYTORUN_HEADER *FindReadyToRunHeader() const;
public:
// ------------------------------------------------------------
// RVA operations (remaining private)
// ------------------------------------------------------------
Expand Down Expand Up @@ -274,12 +284,14 @@ class WebcilDecoder
// Instance members
TADDR m_base;
COUNT_T m_size;
BOOL m_hasContents;
BOOL m_relocated = FALSE;
bool m_relocated = FALSE;
bool m_hasContents;
mutable bool m_hasNoReadyToRunHeader;
const WebcilHeader *m_pHeader;
const WebcilSectionHeader *m_sections;

mutable IMAGE_COR20_HEADER *m_pCorHeader;
mutable PTR_READYTORUN_HEADER m_pReadyToRunHeader;
};

#endif // FEATURE_WEBCIL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,19 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
symbol = method;
}

runtimeFunctionsBuilder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: frameInfo.StartOffset + _nodeFactory.Target.CodeDelta);
if (!relocsOnly && _nodeFactory.Target.Architecture == TargetArchitecture.X64)
if (_nodeFactory.Target.Architecture == TargetArchitecture.Wasm32)
{
// On Amd64, the 2nd word contains the EndOffset of the runtime function
Debug.Assert(frameInfo.StartOffset != frameInfo.EndOffset);
runtimeFunctionsBuilder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: frameInfo.EndOffset);
runtimeFunctionsBuilder.EmitReloc(symbol, RelocType.WASM_TABLE_INDEX_I32, frameIndex);
}
else
{
runtimeFunctionsBuilder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: frameInfo.StartOffset + _nodeFactory.Target.CodeDelta);
if (!relocsOnly && _nodeFactory.Target.Architecture == TargetArchitecture.X64)
{
// On Amd64, the 2nd word contains the EndOffset of the runtime function
Debug.Assert(frameInfo.StartOffset != frameInfo.EndOffset);
runtimeFunctionsBuilder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: frameInfo.EndOffset);
}
}
Comment thread
davidwrighton marked this conversation as resolved.
runtimeFunctionsBuilder.EmitReloc(factory.RuntimeFunctionsGCInfo, RelocType.IMAGE_REL_BASED_ADDR32NB, funcletOffsets[frameIndex]);
runtimeFunctionIndex++;
Expand Down
182 changes: 159 additions & 23 deletions src/coreclr/utilcode/webcildecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ bool WebcilDecoder::DetectWebcilFormat(const void* data, COUNT_T size)
WebcilDecoder::WebcilDecoder()
: m_base(0),
m_size(0),
m_hasContents(FALSE),
m_hasContents(false),
m_hasNoReadyToRunHeader(false),
m_pHeader(NULL),
m_sections(NULL),
m_pCorHeader(NULL)
m_pCorHeader(NULL),
m_pReadyToRunHeader(NULL)
{
Comment thread
davidwrighton marked this conversation as resolved.
LIMITED_METHOD_CONTRACT;
}
Expand Down Expand Up @@ -77,18 +79,6 @@ void WebcilDecoder::Init(void *flatBase, COUNT_T size)
m_relocated = FALSE;
}

void WebcilDecoder::Reset()
{
LIMITED_METHOD_CONTRACT;
m_base = 0;
m_size = 0;
m_hasContents = FALSE;
m_pHeader = NULL;
m_sections = NULL;
m_pCorHeader = NULL;
m_relocated = FALSE;
}

// ------------------------------------------------------------
// Basic properties
// ------------------------------------------------------------
Expand Down Expand Up @@ -470,14 +460,6 @@ ULONG WebcilDecoder::GetEntryPointToken() const
// R2R / native manifest metadata
// ------------------------------------------------------------

PTR_CVOID WebcilDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const
{
LIMITED_METHOD_CONTRACT;
if (pSize != NULL)
*pSize = 0;
return NULL;
}

// ------------------------------------------------------------
// RVA operations
// ------------------------------------------------------------
Expand Down Expand Up @@ -864,7 +846,7 @@ TADDR WebcilDecoder::GetDirectoryEntryData(int entry, COUNT_T *pSize) const
return (TADDR)0;
}

const WebcilSectionHeader *sections = (const WebcilSectionHeader *)(m_base + sizeof(WebcilHeader));
const WebcilSectionHeader *sections = m_sections;
const WebcilSectionHeader *relocSection = &sections[sectionIndex];

if (pSize != NULL)
Expand Down Expand Up @@ -916,6 +898,160 @@ CHECK WebcilDecoder::CheckILMethod(RVA rva)
return CorDecoderHelpers::CheckILMethod(*this, rva);
}

BOOL WebcilDecoder::HasReadyToRunHeader() const
{
CONTRACTL
{
INSTANCE_CHECK;
NOTHROW;
GC_NOTRIGGER;
CANNOT_TAKE_LOCK;
SUPPORTS_DAC;
}
CONTRACTL_END;

if (m_hasNoReadyToRunHeader)
return FALSE;

if (m_pReadyToRunHeader != NULL)
return TRUE;

return FindReadyToRunHeader() != NULL;
}

READYTORUN_HEADER * WebcilDecoder::GetReadyToRunHeader() const
{
CONTRACT(READYTORUN_HEADER *)
{
INSTANCE_CHECK;
PRECONDITION(CheckWebcilHeaders());
PRECONDITION(HasCorHeader());
PRECONDITION(HasReadyToRunHeader());
NOTHROW;
GC_NOTRIGGER;
Comment thread
davidwrighton marked this conversation as resolved.
POSTCONDITION(CheckPointer(RETVAL));
SUPPORTS_DAC;
CANNOT_TAKE_LOCK;
}
CONTRACT_END;

if (m_pReadyToRunHeader != NULL)
RETURN m_pReadyToRunHeader;

RETURN FindReadyToRunHeader();
}

PTR_CVOID WebcilDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const
{
CONTRACT(PTR_CVOID)
{
INSTANCE_CHECK;
PRECONDITION(HasReadyToRunHeader());
POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // TBD - may not store metadata for IJW
NOTHROW;
GC_NOTRIGGER;
}
CONTRACT_END;

IMAGE_DATA_DIRECTORY *pDir = NULL;
{
READYTORUN_HEADER * pHeader = GetReadyToRunHeader();

PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(pHeader) + sizeof(READYTORUN_HEADER));
for (DWORD i = 0; i < pHeader->CoreHeader.NumberOfSections; i++)
{
// Verify that section types are sorted
_ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type));

READYTORUN_SECTION * pSection = pSections + i;
if (pSection->Type == ReadyToRunSectionType::ManifestMetadata)
{
// Set pDir to the address of the manifest metadata section
pDir = &pSection->Section;
break;
}
}

// Handle the no ManifestMetadata case, which will happen in a ReadyToRun file without large version bubble support.
if (pDir == NULL)
{
if (pSize != NULL)
{
*pSize = 0;
}

RETURN NULL;
}
}

if (pSize != NULL)
*pSize = VAL32(pDir->Size);

RETURN dac_cast<PTR_VOID>(GetDirectoryData(pDir));
}

READYTORUN_HEADER * WebcilDecoder::FindReadyToRunHeader() const
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
SUPPORTS_DAC;
}
CONTRACTL_END;

IMAGE_DATA_DIRECTORY *pDir = &GetCorHeader()->ManagedNativeHeader;

if (VAL32(pDir->Size) >= sizeof(READYTORUN_HEADER) && CheckDirectory(pDir))
{
PTR_READYTORUN_HEADER pHeader = PTR_READYTORUN_HEADER((TADDR)GetDirectoryData(pDir));
if (pHeader->Signature == READYTORUN_SIGNATURE)
{
m_pReadyToRunHeader = pHeader;
return pHeader;
}
}

m_hasNoReadyToRunHeader = true;
return NULL;
}

TADDR WebcilDecoder::GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir) const
{
CONTRACT(TADDR)
{
INSTANCE_CHECK;
PRECONDITION(CheckWebcilHeaders());
PRECONDITION(CheckDirectory(pDir, 0, NULL_OK));
NOTHROW;
GC_NOTRIGGER;
SUPPORTS_DAC;
POSTCONDITION(CheckPointer((void *)RETVAL, NULL_OK));
CANNOT_TAKE_LOCK;
}
CONTRACT_END;

RETURN GetRvaData(VAL32(pDir->VirtualAddress));
}

CHECK WebcilDecoder::CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags, IsNullOK ok) const
{
CONTRACT_CHECK
{
INSTANCE_CHECK;
PRECONDITION(CheckWebcilHeaders());
PRECONDITION(CheckPointer(pDir));
NOTHROW;
Comment thread
davidwrighton marked this conversation as resolved.
GC_NOTRIGGER;
SUPPORTS_DAC;
}
CONTRACT_CHECK_END;

CHECK(CheckRva(VAL32(pDir->VirtualAddress), VAL32(pDir->Size), forbiddenFlags, ok));

CHECK_OK;
}

// ------------------------------------------------------------
// DAC support
// ------------------------------------------------------------
Expand Down
20 changes: 18 additions & 2 deletions src/coreclr/vm/peimagelayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ void PEImageLayout::InitDecoders(void* data, COUNT_T size)
{
m_format = FORMAT_WEBCIL;
m_webcilDecoder.Init(data, size);
if (HasBaseRelocations())
ApplyBaseRelocations(true);
m_peDecoder.Init(data, size); // Initialize base/size/flags for cDAC
}
else
Expand Down Expand Up @@ -245,7 +247,7 @@ void PEImageLayout::ApplyBaseRelocations(bool relocationMustWriteCopy)
SSIZE_T delta = (SIZE_T) GetBase() - (SIZE_T) GetPreferredBase();

#ifdef FEATURE_WEBCIL
SSIZE_T tableBaseDelta = m_tableBaseOffset;
SSIZE_T tableBaseDelta = GetTableBaseOffset();
#endif // FEATURE_WEBCIL

// Nothing to do - image is loaded at preferred base and no table base offset
Expand Down Expand Up @@ -275,12 +277,26 @@ void PEImageLayout::ApplyBaseRelocations(bool relocationMustWriteCopy)
const SIZE_T cbPageSize = 4096;

COUNT_T dirPos = 0;
#ifdef TARGET_WASM
// WASM will pad out the reloc size to the next 16 byte boundary, so we need to validate we can safely read the IMAGE_BASE_RELOCATION struct before processing each entry.
while (dirPos + sizeof(IMAGE_BASE_RELOCATION) <= dirSize)
#else
Comment thread
davidwrighton marked this conversation as resolved.
while (dirPos < dirSize)
#endif
Comment thread
davidwrighton marked this conversation as resolved.
{
PIMAGE_BASE_RELOCATION r = (PIMAGE_BASE_RELOCATION)(dir + dirPos);

COUNT_T fixupsSize = VAL32(r->SizeOfBlock);

#ifdef TARGET_WASM
if (fixupsSize == 0)
{
// Since WASM will pad the reloc block to the next 16 byte boundary with 0's we need to allow for a SizeOfBlock being zero.
// This can only happen for the last block in the relocation list, so we can break here instead of continue.
break;
}
#endif

Comment thread
davidwrighton marked this conversation as resolved.
USHORT *fixups = (USHORT *) (r + 1);

_ASSERTE(fixupsSize > sizeof(IMAGE_BASE_RELOCATION));
Expand Down Expand Up @@ -415,7 +431,7 @@ void PEImageLayout::ApplyBaseRelocations(bool relocationMustWriteCopy)

dirPos += fixupsSize;
}
_ASSERTE(dirSize == dirPos);
_ASSERTE(dirSize == dirPos || !IsPEFormat());

if (dwOldProtection != 0)
{
Expand Down
Loading
Loading