Support CXX configuration options in Bazel
diff --git a/bazel/config/BUILD.bazel b/bazel/config/BUILD.bazel
index 96d96fd..9307b5e 100644
--- a/bazel/config/BUILD.bazel
+++ b/bazel/config/BUILD.bazel
@@ -27,6 +27,24 @@
     build_setting_default = "compile_time_choice",
 )
 
+# PICO_BAZEL_CONFIG: PICO_CXX_ENABLE_EXCEPTIONS, Enabled CXX exception handling, type=bool, default=0, group=pico_cxx_options
+bool_flag(
+    name = "PICO_CXX_ENABLE_EXCEPTIONS",
+    build_setting_default = False,
+)
+
+# PICO_BAZEL_CONFIG: PICO_CXX_ENABLE_RTTI, Enabled CXX rtti, type=bool, default=0, group=pico_cxx_options
+bool_flag(
+    name = "PICO_CXX_ENABLE_RTTI",
+    build_setting_default = False,
+)
+
+# PICO_BAZEL_CONFIG: PICO_CXX_ENABLE_CXA_ATEXIT, Enabled cxa-atexit, type=bool, default=0, group=pico_cxx_options
+bool_flag(
+    name = "PICO_CXX_ENABLE_CXA_ATEXIT",
+    build_setting_default = False,
+)
+
 # This should always point to a cc_library that provides
 # a "pico_config_extra_headers.h".
 label_flag(
diff --git a/bazel/constraint/BUILD.bazel b/bazel/constraint/BUILD.bazel
index 76fee88..837f7c8 100644
--- a/bazel/constraint/BUILD.bazel
+++ b/bazel/constraint/BUILD.bazel
@@ -40,6 +40,21 @@
     flag_values = {"//bazel/config:PICO_NO_GC_SECTIONS": "True"},
 )
 
+config_setting(
+    name = "pico_cxx_enable_exceptions_enabled",
+    flag_values = {"//bazel/config:PICO_CXX_ENABLE_EXCEPTIONS": "True"},
+)
+
+config_setting(
+    name = "pico_cxx_enable_rtti_enabled",
+    flag_values = {"//bazel/config:PICO_CXX_ENABLE_RTTI": "True"},
+)
+
+config_setting(
+    name = "pico_cxx_enable_cxa_atexit_enabled",
+    flag_values = {"//bazel/config:PICO_CXX_ENABLE_RTTI": "True"},
+)
+
 # This constraint setting guides Bazel's build file evaluation differences
 # across different stdio configurations (e.g. stdio_usb needs TinyUSB).
 constraint_setting(
diff --git a/bazel/toolchain/BUILD.bazel b/bazel/toolchain/BUILD.bazel
index b66f552..4c07e30 100644
--- a/bazel/toolchain/BUILD.bazel
+++ b/bazel/toolchain/BUILD.bazel
@@ -2,6 +2,7 @@
 load("@rules_cc//cc/toolchains:args_list.bzl", "cc_args_list")
 load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature")
 load("@rules_cc//cc/toolchains:toolchain.bzl", "cc_toolchain")
+load("configurable_feature.bzl", "configurable_toolchain_feature")
 
 cc_args(
     name = "cortex-m0",
@@ -44,37 +45,35 @@
     ],
 )
 
-cc_args(
-    name = "gc_sections_compile_args",
-    actions = ["@rules_cc//cc/toolchains/actions:compile_actions"],
-    args = [
+configurable_toolchain_feature(
+    name = "gc_sections",
+    copts = [
         "-ffunction-sections",
         "-fdata-sections",
     ],
+    linkopts = ["-Wl,--gc-sections"],
+    disable_if = "//bazel/constraint:pico_no_gc_sections_enabled",
 )
 
-cc_args(
-    name = "gc_sections_link_args",
-    actions = ["@rules_cc//cc/toolchains/actions:link_actions"],
-    args = ["-Wl,--gc-sections"],
-)
-
-cc_args_list(
-    name = "gc_sections_args",
-    args = [
-        ":gc_sections_compile_args",
-        ":gc_sections_link_args"
+configurable_toolchain_feature(
+    name = "cxx_no_exceptions",
+    cxxopts = [
+        "-fno-exceptions",
+        "-fno-unwind-tables",
     ],
+    disable_if = "//bazel/constraint:pico_cxx_enable_exceptions_enabled",
 )
 
-cc_feature(
-    name = "gc_sections",
-    feature_name = "gc_sections",
-    args = [":gc_sections_args"],
-    enabled = select({
-        "//bazel/constraint:pico_no_gc_sections_enabled": False,
-        "//conditions:default": True,
-    }),
+configurable_toolchain_feature(
+    name = "cxx_no_rtti",
+    cxxopts = ["-fno-rtti"],
+    disable_if = "//bazel/constraint:pico_cxx_enable_rtti_enabled",
+)
+
+configurable_toolchain_feature(
+    name = "cxx_no_cxa_atexit",
+    cxxopts = ["-fno-use-cxa-atexit"],
+    disable_if = "//bazel/constraint:pico_cxx_enable_cxa_atexit_enabled",
 )
 
 # TODO: Make this shim unnecessary.
@@ -168,6 +167,9 @@
         "@pico-sdk//bazel/toolchain:legacy_features",
         "@pico-sdk//bazel/toolchain:override_debug",
         "@pico-sdk//bazel/toolchain:gc_sections",
+        "@pico-sdk//bazel/toolchain:cxx_no_exceptions",
+        "@pico-sdk//bazel/toolchain:cxx_no_rtti",
+        "@pico-sdk//bazel/toolchain:cxx_no_cxa_atexit",
     ],
 ) for host_os, host_cpu in HOSTS]
 
diff --git a/bazel/toolchain/configurable_feature.bzl b/bazel/toolchain/configurable_feature.bzl
new file mode 100644
index 0000000..19e59a5
--- /dev/null
+++ b/bazel/toolchain/configurable_feature.bzl
@@ -0,0 +1,54 @@
+load("@rules_cc//cc/toolchains:args.bzl", "cc_args")
+load("@rules_cc//cc/toolchains:args_list.bzl", "cc_args_list")
+load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature")
+
+def configurable_toolchain_feature(name, copts = [], cxxopts = [], linkopts = [], enable_if=None, disable_if=None):
+    if enable_if != None and disable_if != None:
+        fail('Cannot specify both enable_if and disable_if')
+    if enable_if == None and disable_if == None:
+        fail('Must specify at least one of enable_if and disable_if')
+    if enable_if == None:
+        enable_if = "//conditions:default"
+    if disable_if == None:
+        disable_if = "//conditions:default"
+
+    all_args = []
+
+    if copts:
+        cc_args(
+            name = name + "_cc_args",
+            actions = ["@rules_cc//cc/toolchains/actions:compile_actions"],
+            args = copts,
+        )
+        all_args.append(name + "_cc_args")
+
+    if cxxopts:
+        cc_args(
+            name = name + "_cxx_args",
+            actions = ["@rules_cc//cc/toolchains/actions:cpp_compile_actions"],
+            args = cxxopts,
+        )
+        all_args.append(name + "_cxx_args")
+
+    if linkopts:
+        cc_args(
+            name = name + "_link_args",
+            actions = ["@rules_cc//cc/toolchains/actions:link_actions"],
+            args = linkopts,
+        )
+        all_args.append(name + "_link_args")
+
+    cc_args_list(
+        name = name + "_args",
+        args = all_args,
+    )
+
+    cc_feature(
+        name = name,
+        feature_name = name,
+        args = [":{}_args".format(name)],
+        enabled = select({
+            disable_if: False,
+            enable_if: True,
+        }),
+    )
diff --git a/bazel/util/sdk_define.bzl b/bazel/util/sdk_define.bzl
new file mode 100644
index 0000000..72ecdfe
--- /dev/null
+++ b/bazel/util/sdk_define.bzl
@@ -0,0 +1,25 @@
+load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
+
+def _pico_sdk_define_impl(ctx):
+    val = ctx.attr.from_flag[BuildSettingInfo].value
+
+    if type(val) == "string":
+        # Strings need quotes.
+        val = "\"{}\"".format(val)
+    elif type(val) == "bool":
+        # Convert bools to 0 or 1.
+        val = 1 if val else 0
+    cc_ctx = cc_common.create_compilation_context(
+        defines = depset(
+            ["{}={}".format(ctx.attr.define_name, val)]
+        )
+    )
+    return [CcInfo(compilation_context = cc_ctx)]
+
+pico_sdk_define = rule(
+    implementation = _pico_sdk_define_impl,
+    attrs = {
+        "define_name": attr.string(mandatory = True),
+        "from_flag": attr.label(mandatory = True),
+    }
+)
diff --git a/src/rp2_common/pico_standard_link/BUILD.bazel b/src/rp2_common/pico_standard_link/BUILD.bazel
index 46b94d9..0de9005 100644
--- a/src/rp2_common/pico_standard_link/BUILD.bazel
+++ b/src/rp2_common/pico_standard_link/BUILD.bazel
@@ -1,11 +1,20 @@
+load("//bazel/util:sdk_define.bzl", "pico_sdk_define")
+
 package(default_visibility = ["//visibility:public"])
 
+# PICO_BUILD_DEFINE: PICO_CXX_ENABLE_EXCEPTIONS, value of CMake var PICO_CXX_ENABLE_EXCEPTIONS, type=string, default=0, group=pico_cxx_options
+pico_sdk_define(
+    name = "PICO_CXX_ENABLE_EXCEPTIONS",
+    define_name = "PICO_CXX_ENABLE_EXCEPTIONS",
+    from_flag = "//bazel/config:PICO_CXX_ENABLE_EXCEPTIONS",
+)
+
 cc_library(
     name = "pico_standard_link",
     srcs = [
         "binary_info.c",
         "crt0.S",
-        # "new_delete.cpp",  # TODO: Doesn't build yet?
+        "new_delete.cpp",
     ],
     # TODO: Make this configurable.
     linkopts = [
@@ -16,6 +25,7 @@
         "//conditions:default": ["@platforms//:incompatible"],
     }),
     deps = [
+        ":PICO_CXX_ENABLE_EXCEPTIONS",
         "memmap_default.ld",
         "//src/common/pico_base:pico_base_interface",
         "//src/common/pico_binary_info",