diff --git a/tools/hotplug/Linux/launch-xenstore.in b/tools/hotplug/Linux/launch-xenstore.in
index 991dec8d25..a6f2254030 100644
--- a/tools/hotplug/Linux/launch-xenstore.in
+++ b/tools/hotplug/Linux/launch-xenstore.in
@@ -62,7 +62,7 @@ test -f @CONFIG_DIR@/@CONFIG_LEAF_DIR@/xencommons && . @CONFIG_DIR@/@CONFIG_LEAF
 	}
 
 	echo -n Starting $XENSTORED...
-	$XENSTORED --pid-file @XEN_RUN_DIR@/xenstored.pid $XENSTORED_ARGS
+	$XENSTORED --pid-file @XEN_RUN_DIR@/xenstored.pid --buildid-file @XEN_RUN_DIR@/xenstored.buildid $XENSTORED_ARGS
 
 	systemd-notify --booted 2>/dev/null || timeout_xenstore $XENSTORED || exit 1
 
diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 9a0f0d012d..c63350980b 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -66,6 +66,10 @@ $(XENSTORED_OBJS): CFLAGS += $(SYSTEMD_CFLAGS)
 xenstored: LDFLAGS += $(SYSTEMD_LIBS)
 endif
 
+# xenstored: enforce creation of a buildID section and use a linker
+# script to add additional symbols around that section
+xenstored: LDFLAGS +=  -Wl,--build-id=sha1 -Wl,-T,buildid_symbols.ld
+
 $(XENSTORED_OBJS): CFLAGS += $(CFLAGS_libxengnttab)
 
 xenstored: $(XENSTORED_OBJS)
diff --git a/tools/xenstore/buildid_symbols.ld b/tools/xenstore/buildid_symbols.ld
new file mode 100644
index 0000000000..d74024c4e9
--- /dev/null
+++ b/tools/xenstore/buildid_symbols.ld
@@ -0,0 +1,10 @@
+SECTIONS
+{
+       __buildid_note_section = . ;
+       .note.gnu.build-id :
+       {
+               *(.note.gnu.build-id)
+       }
+       __buildid_end = . ;
+}
+INSERT AFTER .data
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index b4be374d3f..c6f107bdd9 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1844,6 +1844,7 @@ static void usage(void)
 
 
 static struct option options[] = {
+	{ "buildid-file", 1, NULL, 'B' },
 	{ "no-domain-init", 0, NULL, 'D' },
 	{ "entry-nb", 1, NULL, 'E' },
 	{ "pid-file", 1, NULL, 'F' },
@@ -1875,12 +1876,16 @@ int main(int argc, char *argv[])
 	bool outputpid = false;
 	bool no_domain_init = false;
 	const char *pidfile = NULL;
+	const char *buildid_file = NULL;
 	int timeout;
 
 
 	while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:T:RVW:", options,
 				  NULL)) != -1) {
 		switch (opt) {
+		case 'B':
+			buildid_file = optarg;
+			break;
 		case 'D':
 			no_domain_init = true;
 			break;
@@ -1948,6 +1953,9 @@ int main(int argc, char *argv[])
 	if (pidfile)
 		write_pidfile(pidfile);
 
+	if (buildid_file)
+		write_buildid_file(buildid_file);
+
 	/* Talloc leak reports go to stderr, which is closed if we fork. */
 	if (!dofork)
 		talloc_enable_leak_report_full();
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 1df6ad94ab..712280626c 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -193,6 +193,9 @@ void xenbus_notify_running(void);
 /* Write out the pidfile */
 void write_pidfile(const char *pidfile);
 
+/* Write the buildid file */
+void write_buildid_file(const char *buildidfile);
+
 /* Fork but do not close terminal FDs */
 void daemonize(void);
 /* Close stdin/stdout/stderr to complete daemonize */
diff --git a/tools/xenstore/xenstored_minios.c b/tools/xenstore/xenstored_minios.c
index c94493e52a..ef1151aee4 100644
--- a/tools/xenstore/xenstored_minios.c
+++ b/tools/xenstore/xenstored_minios.c
@@ -24,6 +24,10 @@ void write_pidfile(const char *pidfile)
 {
 }
 
+void write_buildid_file(const char *buildid_file)
+{
+}
+
 void daemonize(void)
 {
 }
diff --git a/tools/xenstore/xenstored_posix.c b/tools/xenstore/xenstored_posix.c
index 1f9603fea2..ec017611d6 100644
--- a/tools/xenstore/xenstored_posix.c
+++ b/tools/xenstore/xenstored_posix.c
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 
@@ -48,6 +49,57 @@ void write_pidfile(const char *pidfile)
 	close(fd);
 }
 
+/*
+ * We don't have a working elf.h available here, so let's define our very own
+ * data structs and accessor macros for ELF notes.
+ *
+ * https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html:
+ * For 64–bit objects and 32–bit objects, each entry is an array of 4-byte
+ * words in the format of the target processor.
+ */
+typedef struct
+{
+	uint32_t namesz;
+	uint32_t descsz;
+	uint32_t type;
+} elf_note_hdr;
+
+/* ELF Note accessors, copied from Xen's elf.h */
+#define ELFNOTE_ALIGN(_n_) (((_n_)+3)&~3)
+#define ELFNOTE_NAME(_n_) ((char*)(_n_) + sizeof(*(_n_)))
+#define ELFNOTE_DESC(_n_) (ELFNOTE_NAME(_n_) + ELFNOTE_ALIGN((_n_)->namesz))
+/* GNU LD: type == note (NT_GNU_BUILD_ID as in
+ * https://sourceware.org/ml/binutils/2007-07/msg00012.html)*/
+#define NT_GNU_BUILD_ID 3
+
+
+void write_buildid_file(const char *buildid_file)
+{
+	unsigned int i = 0;
+	FILE *fdesc;
+	extern elf_note_hdr __buildid_note_section;
+	unsigned int id_length = __buildid_note_section.descsz;
+	char* desc = ELFNOTE_DESC(&__buildid_note_section);
+
+	if (__buildid_note_section.type != NT_GNU_BUILD_ID)
+		barf("Expected GNU_BUILDID note, but found type '%d'",
+		     __buildid_note_section.type);
+
+	fdesc = fopen(buildid_file, "w+");
+	if (!fdesc)
+		barf_perror("Error opening buildid file %s", buildid_file);
+
+	/* We exit silently if daemon already running. */
+	if (lockf(fileno(fdesc), F_TLOCK, 0) == -1)
+		exit(0);
+
+	for (i = 0; i < id_length; ++i)
+		fprintf(fdesc, "%02x", (unsigned char)desc[i]);
+	fprintf(fdesc, "\n");
+
+	fclose(fdesc);
+}
+
 /* Stevens. */
 void daemonize(void)
 {
