diff --git a/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj b/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj
index cb112b3b3fa767..bf56a93391a174 100644
--- a/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj
+++ b/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj
@@ -14,6 +14,7 @@
 
   
     
+    
     
     
     
       
+      
+      
     
 
     
diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts
index 0bdfe5f0268a11..1e6dcf1daa5033 100644
--- a/src/mono/wasm/runtime/cwraps.ts
+++ b/src/mono/wasm/runtime/cwraps.ts
@@ -1,17 +1,19 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+import MonoWasmThreads from "consts:monoWasmThreads";
+import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
+
 import type {
     MonoArray, MonoAssembly, MonoClass,
     MonoMethod, MonoObject,
     MonoType, MonoObjectRef, MonoStringRef, JSMarshalerArguments
 } from "./types/internal";
 import type { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr, ManagedPointer } from "./types/emscripten";
-import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop";
-import { disableLegacyJsInterop, Module } from "./globals";
+import { linkerDisableLegacyJsInterop, linkerEnableAotProfiler, linkerEnableBrowserProfiler, Module } from "./globals";
 import { mono_log_error } from "./logging";
 
-type SigLine = [lazy: boolean, name: string, returnType: string | null, argTypes?: string[], opts?: any];
+type SigLine = [lazyOrSkip: boolean | (() => boolean), name: string, returnType: string | null, argTypes?: string[], opts?: any];
 
 const legacy_interop_cwraps: SigLine[] = WasmEnableLegacyJsInterop ? [
     [true, "mono_wasm_array_get_ref", "void", ["number", "number", "number"]],
@@ -29,6 +31,17 @@ const legacy_interop_cwraps: SigLine[] = WasmEnableLegacyJsInterop ? [
     [true, "mono_wasm_array_length_ref", "number", ["number"]],
 ] : [];
 
+const diagnostics_cwraps: SigLine[] = MonoWasmThreads ? [
+    // MONO.diagnostics
+    [true, "mono_wasm_event_pipe_enable", "bool", ["string", "number", "number", "string", "bool", "number"]],
+    [true, "mono_wasm_event_pipe_session_start_streaming", "bool", ["number"]],
+    [true, "mono_wasm_event_pipe_session_disable", "bool", ["number"]],
+    [true, "mono_wasm_diagnostic_server_create_thread", "bool", ["string", "number"]],
+    [true, "mono_wasm_diagnostic_server_thread_attach_to_runtime", "void", []],
+    [true, "mono_wasm_diagnostic_server_post_resume_runtime", "void", []],
+    [true, "mono_wasm_diagnostic_server_create_stream", "number", []],
+] : [];
+
 // when the method is assigned/cached at usage, instead of being invoked directly from cwraps, it can't be marked lazy, because it would be re-bound on each call
 const fn_signatures: SigLine[] = [
     // MONO
@@ -61,22 +74,14 @@ const fn_signatures: SigLine[] = [
     [true, "mono_wasm_assembly_get_entry_point", "number", ["number", "number"]],
     [true, "mono_wasm_class_get_type", "number", ["number"]],
 
-    // MONO.diagnostics
-    [true, "mono_wasm_event_pipe_enable", "bool", ["string", "number", "number", "string", "bool", "number"]],
-    [true, "mono_wasm_event_pipe_session_start_streaming", "bool", ["number"]],
-    [true, "mono_wasm_event_pipe_session_disable", "bool", ["number"]],
-    [true, "mono_wasm_diagnostic_server_create_thread", "bool", ["string", "number"]],
-    [true, "mono_wasm_diagnostic_server_thread_attach_to_runtime", "void", []],
-    [true, "mono_wasm_diagnostic_server_post_resume_runtime", "void", []],
-    [true, "mono_wasm_diagnostic_server_create_stream", "number", []],
-
     //INTERNAL
     [false, "mono_wasm_exit", "void", ["number"]],
     [true, "mono_wasm_getenv", "number", ["string"]],
     [true, "mono_wasm_set_main_args", "void", ["number", "number"]],
     [false, "mono_wasm_enable_on_demand_gc", "void", ["number"]],
     // These two need to be lazy because they may be missing
-    [true, "mono_wasm_profiler_init_aot", "void", ["string"]],
+    [() => !linkerEnableAotProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
+    [() => !linkerEnableBrowserProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
     [true, "mono_wasm_profiler_init_browser", "void", ["number"]],
     [false, "mono_wasm_exec_regression", "number", ["number", "string"]],
     [false, "mono_wasm_invoke_method_bound", "number", ["number", "number", "number"]],
@@ -132,6 +137,7 @@ const fn_signatures: SigLine[] = [
     [true, "mono_jiterp_get_opcode_info", "number", ["number", "number"]],
     [true, "mono_wasm_is_zero_page_reserved", "number", []],
     [true, "mono_jiterp_is_special_interface", "number", ["number"]],
+    ...diagnostics_cwraps,
     ...legacy_interop_cwraps
 ];
 
@@ -152,6 +158,22 @@ export interface t_LegacyCwraps {
     mono_wasm_array_length_ref(array: MonoObjectRef): number;
 }
 
+export interface t_DiagnosticsCwraps {
+    // MONO.diagnostics
+    mono_wasm_event_pipe_enable(outputPath: string | null, stream: VoidPtr, bufferSizeInMB: number, providers: string, rundownRequested: boolean, outSessionId: VoidPtr): boolean;
+    mono_wasm_event_pipe_session_start_streaming(sessionId: number): boolean;
+    mono_wasm_event_pipe_session_disable(sessionId: number): boolean;
+    mono_wasm_diagnostic_server_create_thread(websocketURL: string, threadIdOutPtr: VoidPtr): boolean;
+    mono_wasm_diagnostic_server_thread_attach_to_runtime(): void;
+    mono_wasm_diagnostic_server_post_resume_runtime(): void;
+    mono_wasm_diagnostic_server_create_stream(): VoidPtr;
+}
+
+export interface t_ProfilerCwraps {
+    mono_wasm_profiler_init_aot(desc: string): void;
+    mono_wasm_profiler_init_browser(desc: string): void;
+}
+
 export interface t_Cwraps {
     // MONO
     mono_wasm_register_root(start: VoidPtr, size: number, name: string): number;
@@ -182,23 +204,11 @@ export interface t_Cwraps {
     mono_wasm_assembly_get_entry_point(assembly: MonoAssembly, idx: number): MonoMethod;
     mono_wasm_intern_string_ref(strRef: MonoStringRef): void;
 
-
-    // MONO.diagnostics
-    mono_wasm_event_pipe_enable(outputPath: string | null, stream: VoidPtr, bufferSizeInMB: number, providers: string, rundownRequested: boolean, outSessionId: VoidPtr): boolean;
-    mono_wasm_event_pipe_session_start_streaming(sessionId: number): boolean;
-    mono_wasm_event_pipe_session_disable(sessionId: number): boolean;
-    mono_wasm_diagnostic_server_create_thread(websocketURL: string, threadIdOutPtr: VoidPtr): boolean;
-    mono_wasm_diagnostic_server_thread_attach_to_runtime(): void;
-    mono_wasm_diagnostic_server_post_resume_runtime(): void;
-    mono_wasm_diagnostic_server_create_stream(): VoidPtr;
-
     //INTERNAL
     mono_wasm_exit(exit_code: number): number;
     mono_wasm_getenv(name: string): CharPtr;
     mono_wasm_enable_on_demand_gc(enable: number): void;
     mono_wasm_set_main_args(argc: number, argv: VoidPtr): void;
-    mono_wasm_profiler_init_aot(desc: string): void;
-    mono_wasm_profiler_init_browser(desc: string): void;
     mono_wasm_exec_regression(verbose_level: number, image: string): number;
     mono_wasm_invoke_method_bound(method: MonoMethod, args: JSMarshalerArguments, fail: MonoStringRef): number;
     mono_wasm_write_managed_pointer_unsafe(destination: VoidPtr | MonoObjectRef, pointer: ManagedPointer): void;
@@ -265,6 +275,8 @@ const wrapped_c_functions: t_Cwraps = {};
 
 export default wrapped_c_functions;
 export const legacy_c_functions: t_LegacyCwraps & t_Cwraps = wrapped_c_functions as any;
+export const diagnostics_c_functions: t_DiagnosticsCwraps & t_Cwraps = wrapped_c_functions as any;
+export const profiler_c_functions: t_ProfilerCwraps & t_Cwraps = wrapped_c_functions as any;
 
 // see src/mono/wasm/driver.c I52_ERROR_xxx
 export const enum I52Error {
@@ -275,7 +287,7 @@ export const enum I52Error {
 
 const fastCwrapTypes = ["void", "number", null];
 
-function cwrap(name: string, returnType: string | null, argTypes: string[] | undefined, opts: any, throwOnError: boolean): Function {
+function cwrap(name: string, returnType: string | null, argTypes: string[] | undefined, opts: any): Function {
     // Attempt to bypass emscripten's generated wrapper if it is safe to do so
     let fce =
         // Special cwrap options disable the fast path
@@ -301,29 +313,29 @@ function cwrap(name: string, returnType: string | null, argTypes: string[] | und
 
     if (typeof (fce) !== "function") {
         const msg = `cwrap ${name} not found or not a function`;
-        if (throwOnError)
-            throw new Error(msg);
-        else
-            mono_log_error("" + msg);
+        throw new Error(msg);
     }
     return fce;
 }
 
 export function init_c_exports(): void {
-    const lfns = WasmEnableLegacyJsInterop && !disableLegacyJsInterop ? legacy_interop_cwraps : [];
+    const lfns = WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop ? legacy_interop_cwraps : [];
     const fns = [...fn_signatures, ...lfns];
     for (const sig of fns) {
         const wf: any = wrapped_c_functions;
-        const [lazy, name, returnType, argTypes, opts] = sig;
-        if (lazy) {
+        const [lazyOrSkip, name, returnType, argTypes, opts] = sig;
+        const maybeSkip = typeof lazyOrSkip === "function";
+        if (lazyOrSkip === true || maybeSkip) {
             // lazy init on first run
             wf[name] = function (...args: any[]) {
-                const fce = cwrap(name, returnType, argTypes, opts, true);
+                const isNotSkipped = !maybeSkip || !lazyOrSkip();
+                mono_assert(isNotSkipped, () => `cwrap ${name} should not be called when binding was skipped`);
+                const fce = cwrap(name, returnType, argTypes, opts);
                 wf[name] = fce;
                 return fce(...args);
             };
         } else {
-            const fce = cwrap(name, returnType, argTypes, opts, false);
+            const fce = cwrap(name, returnType, argTypes, opts);
             wf[name] = fce;
         }
     }
diff --git a/src/mono/wasm/runtime/diagnostics/browser/controller.ts b/src/mono/wasm/runtime/diagnostics/browser/controller.ts
index 3f3c9213c83621..91ea014ff8994c 100644
--- a/src/mono/wasm/runtime/diagnostics/browser/controller.ts
+++ b/src/mono/wasm/runtime/diagnostics/browser/controller.ts
@@ -1,7 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import cwraps from "../../cwraps";
+import MonoWasmThreads from "consts:monoWasmThreads";
+
+import { diagnostics_c_functions as cwraps } from "../../cwraps";
 import { INTERNAL } from "../../globals";
 import { mono_log_info, mono_log_debug, mono_log_warn } from "../../logging";
 import { withStackAlloc, getI32 } from "../../memory";
@@ -52,6 +54,7 @@ export function getController(): ServerController {
 }
 
 export async function startDiagnosticServer(websocket_url: string): Promise {
+    mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
     const sizeOfPthreadT = 4;
     mono_log_info(`starting the diagnostic server url: ${websocket_url}`);
     const result: number | undefined = withStackAlloc(sizeOfPthreadT, (pthreadIdPtr) => {
diff --git a/src/mono/wasm/runtime/diagnostics/index.ts b/src/mono/wasm/runtime/diagnostics/index.ts
index 0db99e66fee9b2..ee92751818b97d 100644
--- a/src/mono/wasm/runtime/diagnostics/index.ts
+++ b/src/mono/wasm/runtime/diagnostics/index.ts
@@ -41,23 +41,22 @@ export async function mono_wasm_init_diagnostics(): Promise {
     if (!MonoWasmThreads) {
         mono_log_warn("ignoring diagnostics options because this runtime does not support diagnostics");
         return;
-    } else {
-        const options = diagnostic_options_from_environment();
-        if (!options)
-            return;
-        diagnosticsInitialized = true;
-        if (!is_nullish(options?.server)) {
-            if (options.server.connectUrl === undefined || typeof (options.server.connectUrl) !== "string") {
-                throw new Error("server.connectUrl must be a string");
-            }
-            const url = options.server.connectUrl;
-            const suspend = boolsyOption(options.server.suspend);
-            const controller = await startDiagnosticServer(url);
-            if (controller) {
-                diagnosticsServerEnabled = true;
-                if (suspend) {
-                    suspendOnStartup = true;
-                }
+    }
+    const options = diagnostic_options_from_environment();
+    if (!options)
+        return;
+    diagnosticsInitialized = true;
+    if (!is_nullish(options?.server)) {
+        if (options.server.connectUrl === undefined || typeof (options.server.connectUrl) !== "string") {
+            throw new Error("server.connectUrl must be a string");
+        }
+        const url = options.server.connectUrl;
+        const suspend = boolsyOption(options.server.suspend);
+        const controller = await startDiagnosticServer(url);
+        if (controller) {
+            diagnosticsServerEnabled = true;
+            if (suspend) {
+                suspendOnStartup = true;
             }
         }
     }
@@ -144,6 +143,7 @@ function diagnostic_options_from_ports_spec(val: string): DiagnosticOptions | nu
 }
 
 export function mono_wasm_diagnostic_server_on_runtime_server_init(out_options: VoidPtr): void {
+    mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
     if (diagnosticsServerEnabled) {
         /* called on the main thread when the runtime is sufficiently initialized */
         const controller = getController();
diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts
index df5c92e8431c49..8bc87ea37633b0 100644
--- a/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts
+++ b/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 /// 
-
+import MonoWasmThreads from "consts:monoWasmThreads";
 import monoDiagnosticsMock from "consts:monoDiagnosticsMock";
+
 import { PromiseAndController, assertNever } from "../../types/internal";
 import { pthread_self } from "../../pthreads/worker";
 import { createPromiseController } from "../../globals";
-import cwraps from "../../cwraps";
+import { diagnostics_c_functions as cwraps } from "../../cwraps";
 import { EventPipeSessionIDImpl } from "../shared/types";
 import { CharPtr } from "../../types/emscripten";
 import {
@@ -284,6 +285,7 @@ function parseProtocolCommand(data: ArrayBuffer | BinaryProtocolCommand): ParseC
 
 /// Called by the runtime  to initialize the diagnostic server workers
 export function mono_wasm_diagnostic_server_on_server_thread_created(websocketUrlPtr: CharPtr): void {
+    mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
     const websocketUrl = utf8ToString(websocketUrlPtr);
     mono_log_debug(`mono_wasm_diagnostic_server_on_server_thread_created, url ${websocketUrl}`);
     let mock: PromiseAndController | undefined = undefined;
diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/streaming-session.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/streaming-session.ts
index 8d7209a98482c1..88fbc7d3913cd2 100644
--- a/src/mono/wasm/runtime/diagnostics/server_pthread/streaming-session.ts
+++ b/src/mono/wasm/runtime/diagnostics/server_pthread/streaming-session.ts
@@ -1,13 +1,13 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
-import {
-    EventPipeSessionIDImpl
-} from "../shared/types";
+import MonoWasmThreads from "consts:monoWasmThreads";
+
+import { EventPipeSessionIDImpl } from "../shared/types";
 import { EventPipeSocketConnection, takeOverSocket } from "./socket-connection";
 import { StreamQueue, allocateQueue } from "./stream-queue";
 import type { MockRemoteSocket } from "../mock";
 import type { VoidPtr } from "../../types/emscripten";
-import cwraps from "../../cwraps";
+import { diagnostics_c_functions as cwraps } from "../../cwraps";
 import {
     EventPipeCommandCollectTracing2,
     EventPipeCollectTracingCommandProvider,
@@ -24,6 +24,7 @@ export class EventPipeStreamingSession {
 }
 
 export async function makeEventPipeStreamingSession(ws: WebSocket | MockRemoteSocket, cmd: EventPipeCommandCollectTracing2): Promise {
+    mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
     // First, create the native IPC stream and get its queue.
     const ipcStreamAddr = cwraps.mono_wasm_diagnostic_server_create_stream(); // FIXME: this should be a wrapped in a JS object so we can free it when we're done.
     const queueAddr = getQueueAddrFromStreamAddr(ipcStreamAddr);
diff --git a/src/mono/wasm/runtime/diagnostics/shared/create-session.ts b/src/mono/wasm/runtime/diagnostics/shared/create-session.ts
index 820a094174ee1d..e6d80d2cb3a246 100644
--- a/src/mono/wasm/runtime/diagnostics/shared/create-session.ts
+++ b/src/mono/wasm/runtime/diagnostics/shared/create-session.ts
@@ -3,7 +3,7 @@
 
 import * as memory from "../../memory";
 import { VoidPtr } from "../../types/emscripten";
-import cwraps from "../../cwraps";
+import { diagnostics_c_functions as cwraps } from "../../cwraps";
 import type { EventPipeSessionIDImpl } from "./types";
 
 const sizeOfInt32 = 4;
diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
index 66477cc88d8deb..cea78ac93822af 100644
--- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
+++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
@@ -7,8 +7,10 @@
 
 // because we can't pass custom define symbols to acorn optimizer, we use environment variables to pass other build options
 const DISABLE_LEGACY_JS_INTEROP = process.env.DISABLE_LEGACY_JS_INTEROP === "1";
+const ENABLE_BROWSER_PROFILER = process.env.ENABLE_BROWSER_PROFILER === "1";
+const ENABLE_AOT_PROFILER = process.env.ENABLE_AOT_PROFILER === "1";
 
-function setup(disableLegacyJsInterop) {
+function setup(linkerSetup) {
     const pthreadReplacements = {};
     const dotnet_replacements = {
         fetch: globalThis.fetch,
@@ -29,8 +31,8 @@ function setup(disableLegacyJsInterop) {
 
     Module.__dotnet_runtime.passEmscriptenInternals({
         isPThread: ENVIRONMENT_IS_PTHREAD,
-        disableLegacyJsInterop,
-        quit_, ExitStatus
+        quit_, ExitStatus,
+        ...linkerSetup
     });
     Module.__dotnet_runtime.initializeReplacements(dotnet_replacements);
 
@@ -58,7 +60,11 @@ function setup(disableLegacyJsInterop) {
 }
 
 const postset = `
-    DOTNET.setup(${DISABLE_LEGACY_JS_INTEROP ? "true" : "false"});
+    DOTNET.setup({ `+
+    `linkerDisableLegacyJsInterop: ${DISABLE_LEGACY_JS_INTEROP ? "true" : "false"},` +
+    `linkerEnableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` +
+    `linkerEnableBrowserProfiler: ${ENABLE_BROWSER_PROFILER ? "true" : "false"}` +
+    `});
 `;
 
 const DotnetSupportLib = {
@@ -131,6 +137,22 @@ linked_functions = [...linked_functions,
     "mono_wasm_install_js_worker_interop",
     "mono_wasm_uninstall_js_worker_interop",
 ]
+
+if (ENABLE_AOT_PROFILER) {
+    linked_functions = [...linked_functions,
+        "mono_wasm_invoke_js_with_args_ref",
+        "mono_wasm_get_object_property_ref",
+        "mono_wasm_set_object_property_ref",
+        "mono_wasm_get_by_index_ref",
+        "mono_wasm_set_by_index_ref",
+        "mono_wasm_get_global_object_ref",
+        "mono_wasm_create_cs_owned_object_ref",
+        "mono_wasm_typed_array_to_array_ref",
+        "mono_wasm_typed_array_from_ref",
+        "mono_wasm_invoke_js_blazor",
+    ]
+}
+
 #endif
 if (!DISABLE_LEGACY_JS_INTEROP) {
     linked_functions = [...linked_functions,
diff --git a/src/mono/wasm/runtime/exports-internal.ts b/src/mono/wasm/runtime/exports-internal.ts
index 66540624866639..5653bec9bd6911 100644
--- a/src/mono/wasm/runtime/exports-internal.ts
+++ b/src/mono/wasm/runtime/exports-internal.ts
@@ -2,7 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import { mono_wasm_cancel_promise } from "./cancelable-promise";
-import cwraps from "./cwraps";
+import cwraps, { profiler_c_functions } from "./cwraps";
 import { mono_wasm_send_dbg_command_with_parms, mono_wasm_send_dbg_command, mono_wasm_get_dbg_command_info, mono_wasm_get_details, mono_wasm_release_object, mono_wasm_call_function_on, mono_wasm_debugger_resume, mono_wasm_detach_debugger, mono_wasm_raise_debug_event, mono_wasm_change_debugger_log_level, mono_wasm_debugger_attached } from "./debug";
 import { http_wasm_supports_streaming_response, http_wasm_create_abort_controler, http_wasm_abort_request, http_wasm_abort_response, http_wasm_fetch, http_wasm_fetch_bytes, http_wasm_get_response_header_names, http_wasm_get_response_header_values, http_wasm_get_response_bytes, http_wasm_get_response_length, http_wasm_get_streamed_response_bytes } from "./http";
 import { exportedRuntimeAPI, Module, runtimeHelpers } from "./globals";
@@ -18,10 +18,6 @@ export function export_internal(): any {
     return {
         // tests
         mono_wasm_exit: (exit_code: number) => { Module.err("early exit " + exit_code); },
-        mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
-        mono_wasm_profiler_init_aot: cwraps.mono_wasm_profiler_init_aot,
-        mono_wasm_profiler_init_browser: cwraps.mono_wasm_profiler_init_browser,
-        mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
 
         // with mono_wasm_debugger_log and mono_wasm_trace_logger
         logging: undefined,
@@ -89,8 +85,8 @@ export function cwraps_internal(internal: any): void {
     Object.assign(internal, {
         mono_wasm_exit: cwraps.mono_wasm_exit,
         mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
-        mono_wasm_profiler_init_aot: cwraps.mono_wasm_profiler_init_aot,
-        mono_wasm_profiler_init_browser: cwraps.mono_wasm_profiler_init_browser,
+        mono_wasm_profiler_init_aot: profiler_c_functions.mono_wasm_profiler_init_aot,
+        mono_wasm_profiler_init_browser: profiler_c_functions.mono_wasm_profiler_init_browser,
         mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
     });
 }
diff --git a/src/mono/wasm/runtime/exports-linker.ts b/src/mono/wasm/runtime/exports-linker.ts
index 857c62026adfdc..440fdda419fb13 100644
--- a/src/mono/wasm/runtime/exports-linker.ts
+++ b/src/mono/wasm/runtime/exports-linker.ts
@@ -2,7 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import MonoWasmThreads from "consts:monoWasmThreads";
-import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop";
+import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
+
 import { mono_wasm_debugger_log, mono_wasm_add_dbg_command_received, mono_wasm_set_entrypoint_breakpoint, mono_wasm_fire_debugger_agent_message_with_data, mono_wasm_fire_debugger_agent_message_with_data_to_pause } from "./debug";
 import { mono_wasm_release_cs_owned_object } from "./gc-handles";
 import { mono_wasm_bind_cs_function } from "./invoke-cs";
diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts
index 903f835a97a8d1..e3d1bdc544424f 100644
--- a/src/mono/wasm/runtime/exports.ts
+++ b/src/mono/wasm/runtime/exports.ts
@@ -4,10 +4,10 @@
 import ProductVersion from "consts:productVersion";
 import GitHash from "consts:gitHash";
 import BuildConfiguration from "consts:configuration";
-import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop";
+import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
 import type { RuntimeAPI } from "./types";
 
-import { Module, disableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals";
+import { Module, linkerDisableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals";
 import { GlobalObjects, is_nullish } from "./types/internal";
 import { configureEmscriptenStartup, configureWorkerStartup } from "./startup";
 
@@ -29,12 +29,12 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
     const globals = globalObjects;
     const globalThisAny = globalThis as any;
 
-    if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) {
+    if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
         initializeLegacyExports(globals);
     }
 
     // here we merge methods from the local objects into exported objects
-    if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) {
+    if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
         Object.assign(globals.mono, export_mono_api());
         Object.assign(globals.binding, export_binding_api());
         Object.assign(globals.internal, export_internal_api());
@@ -58,7 +58,7 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
         },
         ...API,
     });
-    if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) {
+    if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
         Object.assign(exportedRuntimeAPI, {
             MONO: globals.mono,
             BINDING: globals.binding,
@@ -72,7 +72,7 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
     if (!module.disableDotnet6Compatibility) {
         Object.assign(module, exportedRuntimeAPI);
 
-        if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) {
+        if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
             // backward compatibility
             // eslint-disable-next-line @typescript-eslint/ban-ts-comment
             // @ts-ignore
diff --git a/src/mono/wasm/runtime/globals.ts b/src/mono/wasm/runtime/globals.ts
index 91b4248b7ca4a1..22fef7474b2ae3 100644
--- a/src/mono/wasm/runtime/globals.ts
+++ b/src/mono/wasm/runtime/globals.ts
@@ -21,13 +21,17 @@ export let ENVIRONMENT_IS_PTHREAD: boolean;
 export let exportedRuntimeAPI: RuntimeAPI = null as any;
 export let runtimeHelpers: RuntimeHelpers = null as any;
 export let loaderHelpers: LoaderHelpers = null as any;
-// this is when we link with workload tools. The consts:WasmEnableLegacyJsInterop is when we compile with rollup.
-export let disableLegacyJsInterop = false;
+// this is when we link with workload tools. The consts:wasmEnableLegacyJsInterop is when we compile with rollup.
+export let linkerDisableLegacyJsInterop = false;
+export let linkerEnableAotProfiler = false;
+export let linkerEnableBrowserProfiler = false;
 export let _runtimeModuleLoaded = false; // please keep it in place also as rollup guard
 
 export function passEmscriptenInternals(internals: EmscriptenInternals): void {
     ENVIRONMENT_IS_PTHREAD = internals.isPThread;
-    disableLegacyJsInterop = internals.disableLegacyJsInterop;
+    linkerDisableLegacyJsInterop = internals.linkerDisableLegacyJsInterop;
+    linkerEnableAotProfiler = internals.linkerEnableAotProfiler;
+    linkerEnableBrowserProfiler = internals.linkerEnableBrowserProfiler;
     runtimeHelpers.quit = internals.quit_;
     runtimeHelpers.ExitStatus = internals.ExitStatus;
 }
diff --git a/src/mono/wasm/runtime/profiler.ts b/src/mono/wasm/runtime/profiler.ts
index da627b50ec4a45..a62d0c82792c07 100644
--- a/src/mono/wasm/runtime/profiler.ts
+++ b/src/mono/wasm/runtime/profiler.ts
@@ -1,9 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import { ENVIRONMENT_IS_WEB, runtimeHelpers } from "./globals";
+import { ENVIRONMENT_IS_WEB, linkerEnableAotProfiler, linkerEnableBrowserProfiler, runtimeHelpers } from "./globals";
 import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions } from "./types/internal";
-import cwraps from "./cwraps";
+import { profiler_c_functions as cwraps } from "./cwraps";
 import { utf8ToString } from "./strings";
 
 // Initialize the AOT profiler with OPTIONS.
@@ -15,6 +15,7 @@ import { utf8ToString } from "./strings";
 // DumpAotProfileData stores the data into INTERNAL.aotProfileData.
 //
 export function mono_wasm_init_aot_profiler(options: AOTProfilerOptions): void {
+    mono_assert(linkerEnableAotProfiler, "AOT profiler is not enabled, please use aot; in your project file.");
     if (options == null)
         options = {};
     if (!("writeAt" in options))
@@ -26,6 +27,7 @@ export function mono_wasm_init_aot_profiler(options: AOTProfilerOptions): void {
 }
 
 export function mono_wasm_init_browser_profiler(options: BrowserProfilerOptions): void {
+    mono_assert(linkerEnableBrowserProfiler, "Browser profiler is not enabled, please use browser; in your project file.");
     if (options == null)
         options = {};
     const arg = "browser:";
@@ -56,8 +58,6 @@ export type TimeStamp = {
     __brand: "TimeStamp"
 }
 
-
-
 export function startMeasure(): TimeStamp {
     if (runtimeHelpers.enablePerfMeasure) {
         return globalThis.performance.now() as any;
diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js
index b7181da2180b13..9d1074488e1cd6 100644
--- a/src/mono/wasm/runtime/rollup.config.js
+++ b/src/mono/wasm/runtime/rollup.config.js
@@ -16,7 +16,7 @@ const isDebug = configuration !== "Release";
 const productVersion = process.env.ProductVersion || "8.0.0-dev";
 const nativeBinDir = process.env.NativeBinDir ? process.env.NativeBinDir.replace(/"/g, "") : "bin";
 const monoWasmThreads = process.env.MonoWasmThreads === "true" ? true : false;
-const WasmEnableLegacyJsInterop = process.env.DISABLE_LEGACY_JS_INTEROP !== "1" ? true : false;
+const wasmEnableLegacyJsInterop = process.env.DISABLE_LEGACY_JS_INTEROP !== "1" ? true : false;
 const monoDiagnosticsMock = process.env.MonoDiagnosticsMock === "true" ? true : false;
 const terserConfig = {
     compress: {
@@ -71,6 +71,14 @@ try {
 } catch (e) {
     gitHash = "unknown";
 }
+const envConstants = {
+    productVersion,
+    configuration,
+    monoWasmThreads,
+    monoDiagnosticsMock,
+    gitHash,
+    wasmEnableLegacyJsInterop,
+};
 
 function consts(dict) {
     // implement rollup-plugin-const in terms of @rollup/plugin-virtual
@@ -94,7 +102,7 @@ const typescriptConfigOptions = {
     include: ["**/*.ts", "../../../../artifacts/bin/native/generated/**/*.ts"]
 };
 
-const outputCodePlugins = [consts({ productVersion, configuration, monoWasmThreads, monoDiagnosticsMock, gitHash, WasmEnableLegacyJsInterop }), typescript(typescriptConfigOptions)];
+const outputCodePlugins = [consts(envConstants), typescript(typescriptConfigOptions)];
 const externalDependencies = ["module"];
 
 const loaderConfig = {
diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts
index e9eee44f0de192..978bbb55025ece 100644
--- a/src/mono/wasm/runtime/startup.ts
+++ b/src/mono/wasm/runtime/startup.ts
@@ -2,10 +2,10 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import MonoWasmThreads from "consts:monoWasmThreads";
-import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop";
+import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
 
 import { DotnetModuleInternal, CharPtrNull } from "./types/internal";
-import { disableLegacyJsInterop, ENVIRONMENT_IS_PTHREAD, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers } from "./globals";
+import { linkerDisableLegacyJsInterop, ENVIRONMENT_IS_PTHREAD, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers } from "./globals";
 import cwraps, { init_c_exports } from "./cwraps";
 import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
 import { toBase64StringImpl } from "./base64";
@@ -327,7 +327,7 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void {
 
     init_c_exports();
     cwraps_internal(INTERNAL);
-    if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) {
+    if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
         cwraps_mono_api(MONO);
         cwraps_binding_api(BINDING);
     }
@@ -581,7 +581,7 @@ export function bindings_init(): void {
         const mark = startMeasure();
         strings_init();
         init_managed_exports();
-        if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop && !ENVIRONMENT_IS_PTHREAD) {
+        if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop && !ENVIRONMENT_IS_PTHREAD) {
             init_legacy_exports();
         }
         initialize_marshalers_to_js();
diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts
index f2dba23fe73892..992fea25a25705 100644
--- a/src/mono/wasm/runtime/types/internal.ts
+++ b/src/mono/wasm/runtime/types/internal.ts
@@ -245,7 +245,9 @@ export function is_nullish(value: T | null | undefined): value is null | unde
 
 export type EmscriptenInternals = {
     isPThread: boolean,
-    disableLegacyJsInterop: boolean,
+    linkerDisableLegacyJsInterop: boolean,
+    linkerEnableAotProfiler: boolean,
+    linkerEnableBrowserProfiler: boolean,
     quit_: Function,
     ExitStatus: ExitStatusError,
 };