diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index 3ceddbda19c..1b7a1f7f8ac 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -1023,6 +1023,7 @@ enum
 {
   GNU_PROPERTY_STACK_SIZE = 1,
   GNU_PROPERTY_NO_COPY_ON_PROTECTED = 2,
+  GNU_PROPERTY_MEMORY_SEAL = 3,
   GNU_PROPERTY_LOPROC = 0xc0000000,
   GNU_PROPERTY_X86_COMPAT_ISA_1_USED = 0xc0000000,
   GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED = 0xc0000001,
diff --git a/gold/NEWS b/gold/NEWS
index c0f4842e617..7fca7603476 100644
--- a/gold/NEWS
+++ b/gold/NEWS
@@ -5,6 +5,9 @@
 
 * Remove support for -z bndplt (MPX prefix instructions).
 
+* Add -z memory-seal/-z nomemory-seal options to ELF linker to mark the
+  object to memory sealed.
+
 Changes in 1.16:
 
 * Improve warning messages for relocations that refer to discarded sections.
diff --git a/gold/layout.cc b/gold/layout.cc
index f690c67618e..8adace07676 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -3277,6 +3277,10 @@ Layout::create_gnu_properties_note()
 {
   parameters->target().finalize_gnu_properties(this);
 
+  if (parameters->options().memory_seal())
+    this->add_gnu_property(elfcpp::NT_GNU_PROPERTY_TYPE_0,
+			   elfcpp::GNU_PROPERTY_MEMORY_SEAL, 0, 0);
+
   if (this->gnu_properties_.empty())
     return;
 
diff --git a/gold/options.h b/gold/options.h
index 4eb3678e9ec..441ba98acd7 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -1546,6 +1546,9 @@ class General_options
 	      N_("Keep .text.hot, .text.startup, .text.exit and .text.unlikely "
 		 "as separate sections in the final binary."),
 	      N_("Merge all .text.* prefix sections."));
+  DEFINE_bool(memory_seal, options::DASH_Z, '\0', false,
+	      N_("Mark object be memory sealed"),
+	      N_("Don't mark oject to be memory sealed"));
 
 
  public:
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 8f158ba20cc..0de31e287aa 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -4384,6 +4384,30 @@ MOSTLYCLEANFILES += split_s390_z1 split_s390_z2 split_s390_z3 \
 
 endif DEFAULT_TARGET_S390
 
+check_SCRIPTS += memory_seal_test.sh
+check_DATA += memory_seal_test_1.stdout memory_seal_test_2.stdout \
+	      memory_seal_test_3.stdout memory_seal_test_4.stdout
+MOSTLYCLEANFILES += memory_seal_test
+memory_seal_test_1.stdout: memory_seal_main_1
+	$(TEST_READELF) -n $< >$@
+memory_seal_test_2.stdout: memory_seal_shared_1.so
+	$(TEST_READELF) -n $< >$@
+memory_seal_test_3.stdout: memory_seal_main_2
+	$(TEST_READELF) -n $< >$@
+memory_seal_test_4.stdout: memory_seal_shared_2.so
+	$(TEST_READELF) -n $< >$@
+memory_seal_main_1: gcctestdir/ld memory_seal_main.o property_seal_1.o
+	gcctestdir/ld -o $@ memory_seal_main.o
+memory_seal_main_2: gcctestdir/ld memory_seal_main.o property_seal_1.o
+	gcctestdir/ld -z memory-seal -o $@ memory_seal_main.o property_seal_1.o
+memory_seal_shared_1.so: gcctestdir/ld memory_seal_shared.o property_seal_1.o
+	gcctestdir/ld -shared -o $@ memory_seal_shared.o
+memory_seal_shared_2.so: gcctestdir/ld memory_seal_shared.o property_seal_1.o
+	gcctestdir/ld -zmemory-seal -shared -o $@ memory_seal_shared.o property_seal_1.o
+property_seal_1.o: property_seal_1.S
+	$(COMPILE) -c -o $@ $<
+
+
 endif NATIVE_OR_CROSS_LINKER
 
 # Tests for the dwp tool.
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 357dec0d4f9..1eeab03b411 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -1138,11 +1138,16 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_z1_ns split_s390x_z2_ns split_s390x_z3_ns \
 @DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_z4_ns split_s390x_n1_ns split_s390x_n2_ns split_s390x_r
 
-@DEFAULT_TARGET_X86_64_TRUE@am__append_121 = *.dwo *.dwp pr26936a \
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_121 = memory_seal_test.sh
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_122 = memory_seal_test_1.stdout memory_seal_test_2.stdout \
+@NATIVE_OR_CROSS_LINKER_TRUE@	      memory_seal_test_3.stdout memory_seal_test_4.stdout
+
+@NATIVE_OR_CROSS_LINKER_TRUE@am__append_123 = memory_seal_test
+@DEFAULT_TARGET_X86_64_TRUE@am__append_124 = *.dwo *.dwp pr26936a \
 @DEFAULT_TARGET_X86_64_TRUE@	pr26936b retain_1 retain_2
-@DEFAULT_TARGET_X86_64_TRUE@am__append_122 = dwp_test_1.sh \
+@DEFAULT_TARGET_X86_64_TRUE@am__append_125 = dwp_test_1.sh \
 @DEFAULT_TARGET_X86_64_TRUE@	dwp_test_2.sh pr26936.sh retain.sh
-@DEFAULT_TARGET_X86_64_TRUE@am__append_123 = dwp_test_1.stdout \
+@DEFAULT_TARGET_X86_64_TRUE@am__append_126 = dwp_test_1.stdout \
 @DEFAULT_TARGET_X86_64_TRUE@	dwp_test_2.stdout pr26936a.stdout \
 @DEFAULT_TARGET_X86_64_TRUE@	pr26936b.stdout retain_1.out \
 @DEFAULT_TARGET_X86_64_TRUE@	retain_2.out
@@ -2888,7 +2893,7 @@ MOSTLYCLEANFILES = *.so *.syms *.stdout *.stderr $(am__append_4) \
 	$(am__append_88) $(am__append_91) $(am__append_93) \
 	$(am__append_102) $(am__append_105) $(am__append_108) \
 	$(am__append_111) $(am__append_114) $(am__append_117) \
-	$(am__append_120) $(am__append_121)
+	$(am__append_120) $(am__append_123) $(am__append_124)
 
 # We will add to these later, for each individual test.  Note
 # that we add each test under check_SCRIPTS or check_PROGRAMS;
@@ -2901,7 +2906,7 @@ check_SCRIPTS = $(am__append_2) $(am__append_21) $(am__append_25) \
 	$(am__append_89) $(am__append_96) $(am__append_100) \
 	$(am__append_103) $(am__append_106) $(am__append_109) \
 	$(am__append_112) $(am__append_115) $(am__append_118) \
-	$(am__append_122)
+	$(am__append_121) $(am__append_125)
 check_DATA = $(am__append_3) $(am__append_22) $(am__append_26) \
 	$(am__append_32) $(am__append_38) $(am__append_45) \
 	$(am__append_50) $(am__append_54) $(am__append_58) \
@@ -2910,7 +2915,7 @@ check_DATA = $(am__append_3) $(am__append_22) $(am__append_26) \
 	$(am__append_90) $(am__append_97) $(am__append_101) \
 	$(am__append_104) $(am__append_107) $(am__append_110) \
 	$(am__append_113) $(am__append_116) $(am__append_119) \
-	$(am__append_123)
+	$(am__append_122) $(am__append_126)
 BUILT_SOURCES = $(am__append_42)
 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
 
@@ -6496,6 +6501,13 @@ split_s390.sh.log: split_s390.sh
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+memory_seal_test.sh.log: memory_seal_test.sh
+	@p='memory_seal_test.sh'; \
+	b='memory_seal_test.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 dwp_test_1.sh.log: dwp_test_1.sh
 	@p='dwp_test_1.sh'; \
 	b='dwp_test_1.sh'; \
@@ -10454,6 +10466,24 @@ uninstall-am:
 @DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
 @DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_r.stdout: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
 @DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new -r split_s390x_1_z1.o split_s390x_2_ns.o -o split_s390x_r > $@ 2>&1 || exit 0
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_test_1.stdout: memory_seal_main_1
+@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_READELF) -n $< >$@
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_test_2.stdout: memory_seal_shared_1.so
+@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_READELF) -n $< >$@
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_test_3.stdout: memory_seal_main_2
+@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_READELF) -n $< >$@
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_test_4.stdout: memory_seal_shared_2.so
+@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_READELF) -n $< >$@
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_main_1: gcctestdir/ld memory_seal_main.o property_seal_1.o
+@NATIVE_OR_CROSS_LINKER_TRUE@	gcctestdir/ld -o $@ memory_seal_main.o
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_main_2: gcctestdir/ld memory_seal_main.o property_seal_1.o
+@NATIVE_OR_CROSS_LINKER_TRUE@	gcctestdir/ld -z memory-seal -o $@ memory_seal_main.o property_seal_1.o
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_shared_1.so: gcctestdir/ld memory_seal_shared.o property_seal_1.o
+@NATIVE_OR_CROSS_LINKER_TRUE@	gcctestdir/ld -shared -o $@ memory_seal_shared.o
+@NATIVE_OR_CROSS_LINKER_TRUE@memory_seal_shared_2.so: gcctestdir/ld memory_seal_shared.o property_seal_1.o
+@NATIVE_OR_CROSS_LINKER_TRUE@	gcctestdir/ld -zmemory-seal -shared -o $@ memory_seal_shared.o property_seal_1.o
+@NATIVE_OR_CROSS_LINKER_TRUE@property_seal_1.o: property_seal_1.S
+@NATIVE_OR_CROSS_LINKER_TRUE@	$(COMPILE) -c -o $@ $<
 
 # Tests for the dwp tool.
 # We don't want to rely yet on GCC support for -gsplit-dwarf,
diff --git a/gold/testsuite/memory_seal_main.c b/gold/testsuite/memory_seal_main.c
new file mode 100644
index 00000000000..77bc677e8eb
--- /dev/null
+++ b/gold/testsuite/memory_seal_main.c
@@ -0,0 +1,5 @@
+int
+main(void)
+{
+  return 0;
+}
diff --git a/gold/testsuite/memory_seal_shared.c b/gold/testsuite/memory_seal_shared.c
new file mode 100644
index 00000000000..8cf7b6143da
--- /dev/null
+++ b/gold/testsuite/memory_seal_shared.c
@@ -0,0 +1,7 @@
+int foo (void);
+
+int
+foo(void)
+{
+  return 0;
+}
diff --git a/gold/testsuite/memory_seal_test.sh b/gold/testsuite/memory_seal_test.sh
new file mode 100755
index 00000000000..91aa2abf9b4
--- /dev/null
+++ b/gold/testsuite/memory_seal_test.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+# memory_seal_test.sh -- test GNU_PROPERTY_MEMORY_SEAL gnu property
+
+# Copyright (C) 2018-2024 Free Software Foundation, Inc.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This script checks that after linking the three object files
+# gnu_property_[abc].S, each of which contains a .note.gnu.property
+# section, the resulting output has only a single such note section,
+# and that the properties have been correctly combined.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+	echo "Did not find expected output in $1:"
+	echo "   $2"
+	echo ""
+	echo "Actual output below:"
+	cat "$1"
+	exit 1
+    fi
+}
+
+check_not()
+{
+    if grep -q "$2" "$1"
+    then
+        echo "Found unexpected output in $1:"
+        echo "   $2"
+        echo ""
+        echo "Actual output below:"
+        cat "$1"
+        exit 1
+    fi
+}
+
+check_not memory_seal_test_1.stdout "memory seal"
+check_not memory_seal_test_2.stdout "memory seal"
+check     memory_seal_test_3.stdout "memory seal"
+check     memory_seal_test_4.stdout "memory seal"
+
+exit 0
diff --git a/gold/testsuite/property_seal_1.S b/gold/testsuite/property_seal_1.S
new file mode 100644
index 00000000000..346f734edd2
--- /dev/null
+++ b/gold/testsuite/property_seal_1.S
@@ -0,0 +1,22 @@
+#define GNU_PROPERTY_MEMORY_SEAL 3
+
+#define NT_GNU_PROPERTY_TYPE_0 5
+
+#if __SIZEOF_PTRDIFF_T__  == 8
+# define ALIGN 3
+#elif __SIZEOF_PTRDIFF_T__  == 4
+# define ALIGN 2
+#endif
+
+	.section ".note.gnu.property", "a"
+	.p2align ALIGN
+
+	.long 1f - 0f			/* name length */
+	.long 3f - 2f			/* data length */
+	.long NT_GNU_PROPERTY_TYPE_0	/* note type */
+0:	.asciz "GNU"			/* vendor name */
+1:
+	.p2align ALIGN
+2:	.long GNU_PROPERTY_MEMORY_SEAL	/* pr_type.  */
+	.long 0				/* pr_datasz.  */
+3:
