diff --git a/meta-arm/recipes-devtools/fvp/fvp-base-a-aem_11.28.23.bb b/meta-arm/recipes-devtools/fvp/fvp-base-a-aem_11.28.23.bb
index f411276b..45fd21fe 100644
--- a/meta-arm/recipes-devtools/fvp/fvp-base-a-aem_11.28.23.bb
+++ b/meta-arm/recipes-devtools/fvp/fvp-base-a-aem_11.28.23.bb
@@ -17,3 +17,6 @@ UPSTREAM_VERSION_UNKNOWN = "1"
 MODEL_CODE = "FVP_Base_RevC-2xAEMvA"
 
 COMPATIBLE_HOST = "(aarch64|x86_64).*-linux"
+
+require remove-execstack.inc
+REMOVE_EXECSTACKS:x86-64 = "${FVPDIR}/models/${FVP_ARCH_DIR}*/libarmctmodel.so"
diff --git a/meta-arm/recipes-devtools/fvp/remove-execstack.inc b/meta-arm/recipes-devtools/fvp/remove-execstack.inc
new file mode 100644
index 00000000..7f02b502
--- /dev/null
+++ b/meta-arm/recipes-devtools/fvp/remove-execstack.inc
@@ -0,0 +1,26 @@
+# Clear the executable stack flag on named shared libraries. This are typically
+# not needed, and glibc 2.41 will refuse to dlopen() a library that expects
+# an executable stack.
+#
+# The stack permissions can be checked with readelf -lW <.so> | grep GNU_STACK.
+# RW is read/write, RWE is read/write/execute.
+
+DEPENDS += "execstack-native"
+
+REMOVE_EXECSTACKS ?= ""
+
+do_install:append() {
+    for SO in ${REMOVE_EXECSTACKS}; do
+        NAME=$(basename $SO)
+        SO=${D}$SO
+
+        test -f $SO || bbfatal remove-execstack: cannot find $SO
+
+        if execstack --query $SO | grep -q ^X; then
+            bbnote "Stripping executable stack bit on $NAME"
+            execstack --clear-execstack $SO
+        else
+            bbwarn "Executable stack stripping no longer required for $NAME, remove"
+        fi
+    done
+}
