Skip to content

Commit

Permalink
link: do not modify the input object files unless changed
Browse files Browse the repository at this point in the history
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@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
Steven Sistare authored and kvanhees committed May 25, 2023
1 parent cddcc07 commit 15e89bc
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 12 deletions.
27 changes: 15 additions & 12 deletions libdtrace/dt_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -1431,9 +1431,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
Expand All @@ -1442,6 +1439,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);
}
Expand All @@ -1453,15 +1452,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);
}
}
}
}
Expand Down
66 changes: 66 additions & 0 deletions test/unittest/usdt/tst.link-idempotence.sh
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 15e89bc

Please sign in to comment.