[DTrace-devel] [PATCH 2/2] usdt: remove relocations rather than changing their type to R_*_NONE

Nick Alcock nick.alcock at oracle.com
Wed Oct 25 11:53:27 UTC 2023


On 25 Oct 2023, Kris Van Hees via DTrace-devel outgrape:

> The original DTrace code used to depend on STV_ELIMINATE and XXX
> to have the linker clean up USDT probe related relocations.  This
> does not work on Linux, so DTrace on Linux changed the type of those
> relocations to be R_*_NONE since those relocations get ignored.
>
> Binutils no longer allows that for PIC objects when a locally referenced
> symbol is involved.
>
> DTrace will now remove those relocations since they are no longer needed
> anyway.
>
> A test is included to ensure that PIC objects can be linked successfully
> when USDT probes are used.

Looks good modulo the nits below!

Reviewed-by: Nick Alcock <nick.alcock at oracle.com>

> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> @@ -1338,8 +1347,25 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
>  
>  			s = (char *)data_str->d_buf + rsym.st_name;
>  
> -			if (strncmp(s, dt_prefix, sizeof(dt_prefix) - 1) != 0)
> +			if (strncmp(s, dt_prefix, sizeof(dt_prefix) - 1) != 0) {
> +				/*
> +				 * If there was an earlier relocation that was
> +				 * to be removed, we need to copy this one to
> +				 * an earlier slot.
> +				 */
> +				if (j < i) {
> +					mod = 1;
> +					elf_flagdata(data_rel, ELF_C_SET, ELF_F_DIRTY);
> +
> +					if (shdr_rel.sh_type == SHT_RELA)
> +						gelf_update_rela(data_rel, j, &rela);
> +					else
> +						gelf_update_rel(data_rel, j,&rel);
> +				}
> +
> +				j++;
>  				continue;
> +			}

... this is compacting backwards, nicely done at the same time as the
main loop. There's a space missing before the &rel, but that's the only
"problem" I can see here.

> +		/*
> +		 * If some relocations were removed, shrink the relocation
> +		 * table.
> +		 */
> +		if (nrel > 0) {
> +			size_t	sz = data_rel->d_size -
> +				     nrel * shdr_rel.sh_entsize;
> +
> +			/* If we do not have a link set yet, allocate one. */
> +			if (set == NULL) {
> +				set = dt_zalloc(dtp, sizeof(*set));
> +				if (set == NULL)
> +					goto err;
>  			}

I was wondering how this could even be possible, but of course if the
relocs we added are all at the end, we would never have had to move any.

> diff --git a/test/unittest/usdt/tst.pie.r b/test/unittest/usdt/tst.pie.r
> new file mode 100644
> index 00000000..0cd43db7
> --- /dev/null
> +++ b/test/unittest/usdt/tst.pie.r
> @@ -0,0 +1,2 @@
> +test:func:go
> +
> diff --git a/test/unittest/usdt/tst.pie.sh b/test/unittest/usdt/tst.pie.sh
> new file mode 100755
> index 00000000..5a5e695c
> --- /dev/null
> +++ b/test/unittest/usdt/tst.pie.sh
> @@ -0,0 +1,79 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 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="-pie"
> +
> +DIRNAME="$tmpdir/usdt-enabled.$$.$RANDOM"

It's usdt-pie now I'd say.

> +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"
> +
> +static void
> +func(void)
> +{
> +	TEST_PROV_GO();
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> +	func();
> +}
> +EOF
> +
> +${CC} ${CFLAGS} -c test.c

Probably best to add an explicit -fno-inline here, or a -O0, or
something: otherwise func() might be inlined into main() and the test
becomes useless.

-- 
NULL && (void)



More information about the DTrace-devel mailing list