[DTrace-devel] [PATCH 2/2] link: do not modify the input object files unless changed

Nick Alcock nick.alcock at oracle.com
Mon May 22 22:24:22 UTC 2023


From: Steven Sistare <steven.sistare at oracle.com>

process_obj() and the various implementations of dt_modtext() go to
considerable lengths to not modify the input .o files unless they
actually need to change (dtrace -G differs from a linker in this,
since it modifies its input object files as well as creating an
output).

But if it finds probes, it unconditionally declares the file modified
and (eventually) calls elf_update() on it, even if all the modifications
were already done by a prior invocation of dtrace -G on the same inputs.
This leads to needless re-make(1)s and is entirely unnecessary.  (The
output is still modified regardless, of course.)

(nca: wrote test, commit log)

Orabug: 35417184
Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 libdtrace/dt_link.c                        | 27 +++++----
 test/unittest/usdt/tst.link-idempotence.sh | 66 ++++++++++++++++++++++
 2 files changed, 81 insertions(+), 12 deletions(-)
 create mode 100755 test/unittest/usdt/tst.link-idempotence.sh

diff --git a/libdtrace/dt_link.c b/libdtrace/dt_link.c
index e3646d92ad0ca..9986acb152331 100644
--- a/libdtrace/dt_link.c
+++ b/libdtrace/dt_link.c
@@ -1441,9 +1441,6 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp,
 					return dt_link_error(dtp, elf, fd, bufs,
 					    "failed to allocate space for probe");
 
-			mod = 1;
-			elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
-
 			/*
 			 * This symbol may already have been marked to
 			 * be ignored by another relocation referencing
@@ -1452,6 +1449,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp,
 			 * invocation.
 			 */
 			if (rsym.st_shndx != SHN_SUNW_IGNORE) {
+				mod = 1;
+				elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
 				rsym.st_shndx = SHN_SUNW_IGNORE;
 				gelf_update_sym(data_sym, ndx, &rsym);
 			}
@@ -1463,15 +1462,19 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp,
 			 * causes the linker to try to fill in an address on
 			 * top of the NOPs we so carefully planted.
 			 */
-			if (shdr_rel.sh_type == SHT_RELA) {
-				rela.r_info = GELF_R_INFO(ndx, 0);
-				gelf_update_rela(data_rel, i, &rela);
-			} else {
-				GElf_Rel rel;
-
-				rel.r_offset = rela.r_offset;
-				rel.r_info = GELF_R_INFO(ndx, 0);
-				gelf_update_rel(data_rel, i, &rel);
+			if (rela.r_info != GELF_R_INFO(ndx,0)) {
+				mod = 1;
+				elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
+				if (shdr_rel.sh_type == SHT_RELA) {
+					rela.r_info = GELF_R_INFO(ndx, 0);
+					gelf_update_rela(data_rel, i, &rela);
+				} else {
+					GElf_Rel rel;
+
+					rel.r_offset = rela.r_offset;
+					rel.r_info = GELF_R_INFO(ndx, 0);
+					gelf_update_rel(data_rel, i, &rel);
+				}
 			}
 		}
 	}
diff --git a/test/unittest/usdt/tst.link-idempotence.sh b/test/unittest/usdt/tst.link-idempotence.sh
new file mode 100755
index 0000000000000..5d54e19dca4c1
--- /dev/null
+++ b/test/unittest/usdt/tst.link-idempotence.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+if [ $# != 1 ]; then
+	echo expected one argument: '<'dtrace-path'>'
+	exit 2
+fi
+
+dtrace=$1
+CC=/usr/bin/gcc
+CFLAGS=
+
+DIRNAME="$tmpdir/usdt-link-idempotence.$$.$RANDOM"
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+cat > prov.d <<EOF
+provider test_prov {
+	probe go();
+};
+EOF
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+	echo "failed to generate header file" >& 2
+	exit 1
+fi
+
+cat > test.c <<EOF
+#include <sys/types.h>
+#include "prov.h"
+
+int
+main(int argc, char **argv)
+{
+	if (TEST_PROV_GO_ENABLED()) {
+		TEST_PROV_GO();
+	}
+}
+EOF
+
+${CC} ${CFLAGS} -c test.c
+if [ $? -ne 0 ]; then
+	echo "failed to compile test.c" >& 2
+	exit 1
+fi
+$dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+	echo "failed to create DOF" >& 2
+	exit 1
+fi
+${CC} ${CFLAGS} -o test test.o prov.o
+DTRACE_DEBUG=t $dtrace -G -s prov.d test.o
+if [ $? -ne 0 ]; then
+	echo "failed to regenerate DOF" >& 2
+	exit 1
+fi
+if [ test.o -nt test ]; then
+	exit 1
+fi
+
+exit 0
-- 
2.39.1.268.g9de2f9a303




More information about the DTrace-devel mailing list