ld: add --package-metadata
Generate a .note.package FDO package metadata ELF note, following the spec: https://systemd.io/ELF_PACKAGE_METADATA/ If the jansson library is available at build time (and it is explicitly enabled), link ld to it, and use it to validate that the input is correct JSON, to avoid writing garbage to the file. The configure option --enable-jansson has to be used to explicitly enable it (error out when not found). This allows bootstrappers (or others who are not interested) to seamlessly skip it without issues.
This commit is contained in:
parent
d1a24139ad
commit
9e2bb0cb5e
17 changed files with 545 additions and 12 deletions
|
@ -1918,6 +1918,14 @@ struct output_elf_obj_tdata
|
|||
asection *sec;
|
||||
} build_id;
|
||||
|
||||
/* FDO_PACKAGING_METADATA note type info. */
|
||||
struct
|
||||
{
|
||||
bool (*after_write_object_contents) (bfd *);
|
||||
const char *json;
|
||||
asection *sec;
|
||||
} package_metadata;
|
||||
|
||||
/* Records the result of `get_program_header_size'. */
|
||||
bfd_size_type program_header_size;
|
||||
|
||||
|
|
|
@ -6779,8 +6779,12 @@ _bfd_elf_write_object_contents (bfd *abfd)
|
|||
return false;
|
||||
|
||||
/* This is last since write_shdrs_and_ehdr can touch i_shdrp[0]. */
|
||||
if (t->o->build_id.after_write_object_contents != NULL)
|
||||
return (*t->o->build_id.after_write_object_contents) (abfd);
|
||||
if (t->o->build_id.after_write_object_contents != NULL
|
||||
&& !(*t->o->build_id.after_write_object_contents) (abfd))
|
||||
return false;
|
||||
if (t->o->package_metadata.after_write_object_contents != NULL
|
||||
&& !(*t->o->package_metadata.after_write_object_contents) (abfd))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ ELF_CLFAGS=-DELF_LIST_OPTIONS=@elf_list_options@ \
|
|||
-DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
|
||||
WARN_CFLAGS = @WARN_CFLAGS@
|
||||
NO_WERROR = @NO_WERROR@
|
||||
AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS)
|
||||
AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
|
||||
|
||||
# We put the scripts in the directory $(scriptdir)/ldscripts.
|
||||
# We can't put the scripts in $(datadir) because the SEARCH_DIR
|
||||
|
@ -964,8 +964,8 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
|
|||
ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c plugin.c \
|
||||
ldbuildid.c
|
||||
ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
|
||||
$(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP)
|
||||
ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB)
|
||||
$(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
|
||||
ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
|
||||
|
||||
# Dependency tracking for the generated emulation files.
|
||||
EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
|
||||
|
|
|
@ -122,6 +122,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
|
|||
$(top_srcdir)/../config/lead-dot.m4 \
|
||||
$(top_srcdir)/../config/nls.m4 \
|
||||
$(top_srcdir)/../config/override.m4 \
|
||||
$(top_srcdir)/../config/pkg.m4 \
|
||||
$(top_srcdir)/../config/plugins.m4 \
|
||||
$(top_srcdir)/../config/po.m4 \
|
||||
$(top_srcdir)/../config/progtest.m4 \
|
||||
|
@ -405,6 +406,8 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
|||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
INSTOBJEXT = @INSTOBJEXT@
|
||||
JANSSON_CFLAGS = @JANSSON_CFLAGS@
|
||||
JANSSON_LIBS = @JANSSON_LIBS@
|
||||
LARGEFILE_CPPFLAGS = @LARGEFILE_CPPFLAGS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
@ -450,6 +453,9 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
|||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
POSUB = @POSUB@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
|
@ -558,7 +564,7 @@ ELF_CLFAGS = -DELF_LIST_OPTIONS=@elf_list_options@ \
|
|||
-DELF_SHLIB_LIST_OPTIONS=@elf_shlib_list_options@ \
|
||||
-DELF_PLT_UNWIND_LIST_OPTIONS=@elf_plt_unwind_list_options@
|
||||
|
||||
AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS)
|
||||
AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS) $(JANSSON_CFLAGS)
|
||||
|
||||
# We put the scripts in the directory $(scriptdir)/ldscripts.
|
||||
# We can't put the scripts in $(datadir) because the SEARCH_DIR
|
||||
|
@ -1006,9 +1012,9 @@ ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmai
|
|||
ldbuildid.c
|
||||
|
||||
ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) \
|
||||
$(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP)
|
||||
$(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL_DEP) $(JANSSON_LIBS)
|
||||
|
||||
ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB)
|
||||
ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBCTF) $(LIBIBERTY) $(LIBINTL) $(ZLIB) $(JANSSON_LIBS)
|
||||
#
|
||||
#
|
||||
# Build a dummy plugin using libtool.
|
||||
|
|
6
ld/NEWS
6
ld/NEWS
|
@ -36,6 +36,12 @@
|
|||
* Remove (rudimentary) support for the x86-64 sub-architectures Intel L1OM and
|
||||
Intel K1OM.
|
||||
|
||||
* The ELF linker now supports a new --package-metadata option that allows
|
||||
embedding a JSON payload in accordance to the Package Metadata specification.
|
||||
If support for libjansson is enabled at build time, the linker will use it to
|
||||
validate the input. This can be enabled with --enable-jansson.
|
||||
For more details, see: https://systemd.io/ELF_PACKAGE_METADATA/
|
||||
|
||||
Changes in 2.38:
|
||||
|
||||
* Add -z pack-relative-relocs/-z no pack-relative-relocs to x86 ELF
|
||||
|
|
1
ld/aclocal.m4
vendored
1
ld/aclocal.m4
vendored
|
@ -1198,6 +1198,7 @@ m4_include([../config/lcmessage.m4])
|
|||
m4_include([../config/lead-dot.m4])
|
||||
m4_include([../config/nls.m4])
|
||||
m4_include([../config/override.m4])
|
||||
m4_include([../config/pkg.m4])
|
||||
m4_include([../config/plugins.m4])
|
||||
m4_include([../config/po.m4])
|
||||
m4_include([../config/progtest.m4])
|
||||
|
|
|
@ -100,6 +100,9 @@
|
|||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* The jansson library is to be used */
|
||||
#undef HAVE_JANSSON
|
||||
|
||||
/* Define if your <locale.h> file defines LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
|
||||
|
|
270
ld/configure
vendored
270
ld/configure
vendored
|
@ -677,6 +677,11 @@ WARN_WRITE_STRINGS
|
|||
NO_WERROR
|
||||
WARN_CFLAGS_FOR_BUILD
|
||||
WARN_CFLAGS
|
||||
JANSSON_LIBS
|
||||
JANSSON_CFLAGS
|
||||
PKG_CONFIG_LIBDIR
|
||||
PKG_CONFIG_PATH
|
||||
PKG_CONFIG
|
||||
enable_libctf
|
||||
ENABLE_LIBCTF_FALSE
|
||||
ENABLE_LIBCTF_TRUE
|
||||
|
@ -845,6 +850,7 @@ enable_error_handling_script
|
|||
enable_default_hash_style
|
||||
enable_initfini_array
|
||||
enable_libctf
|
||||
enable_jansson
|
||||
enable_werror
|
||||
enable_build_warnings
|
||||
enable_nls
|
||||
|
@ -863,6 +869,11 @@ CXXFLAGS
|
|||
CCC
|
||||
CPP
|
||||
CXXCPP
|
||||
PKG_CONFIG
|
||||
PKG_CONFIG_PATH
|
||||
PKG_CONFIG_LIBDIR
|
||||
JANSSON_CFLAGS
|
||||
JANSSON_LIBS
|
||||
YACC
|
||||
YFLAGS'
|
||||
|
||||
|
@ -1527,6 +1538,7 @@ Optional Features:
|
|||
use this default hash style
|
||||
--disable-initfini-array do not use .init_array/.fini_array sections
|
||||
--enable-libctf Handle .ctf type-info sections [default=yes]
|
||||
--enable-jansson enable jansson [default=no]
|
||||
--enable-werror treat compile warnings as errors
|
||||
--enable-build-warnings enable build-time compiler warnings
|
||||
--disable-nls do not use Native Language Support
|
||||
|
@ -1553,6 +1565,15 @@ Some influential environment variables:
|
|||
CXXFLAGS C++ compiler flags
|
||||
CPP C preprocessor
|
||||
CXXCPP C++ preprocessor
|
||||
PKG_CONFIG path to pkg-config utility
|
||||
PKG_CONFIG_PATH
|
||||
directories to add to pkg-config's search path
|
||||
PKG_CONFIG_LIBDIR
|
||||
path overriding pkg-config's built-in search path
|
||||
JANSSON_CFLAGS
|
||||
C compiler flags for JANSSON, overriding pkg-config
|
||||
JANSSON_LIBS
|
||||
linker flags for JANSSON, overriding pkg-config
|
||||
YACC The `Yet Another Compiler Compiler' implementation to use.
|
||||
Defaults to the first program found out of: `bison -y', `byacc',
|
||||
`yacc'.
|
||||
|
@ -11470,7 +11491,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11473 "configure"
|
||||
#line 11494 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -11576,7 +11597,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11579 "configure"
|
||||
#line 11600 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -15555,6 +15576,251 @@ fi
|
|||
|
||||
|
||||
|
||||
# Used to validate --package-metadata= input. Disabled by default.
|
||||
# Check whether --enable-jansson was given.
|
||||
if test "${enable_jansson+set}" = set; then :
|
||||
enableval=$enable_jansson; enable_jansson=$enableval
|
||||
else
|
||||
enable_jansson="no"
|
||||
fi
|
||||
|
||||
|
||||
if test "x$enable_jansson" != "xno"; then
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||||
if test -n "$ac_tool_prefix"; then
|
||||
# Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
|
||||
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_PKG_CONFIG+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $PKG_CONFIG in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
PKG_CONFIG=$ac_cv_path_PKG_CONFIG
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
|
||||
$as_echo "$PKG_CONFIG" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
if test -z "$ac_cv_path_PKG_CONFIG"; then
|
||||
ac_pt_PKG_CONFIG=$PKG_CONFIG
|
||||
# Extract the first word of "pkg-config", so it can be a program name with args.
|
||||
set dummy pkg-config; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $ac_pt_PKG_CONFIG in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
|
||||
if test -n "$ac_pt_PKG_CONFIG"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
|
||||
$as_echo "$ac_pt_PKG_CONFIG" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
if test "x$ac_pt_PKG_CONFIG" = x; then
|
||||
PKG_CONFIG=""
|
||||
else
|
||||
case $cross_compiling:$ac_tool_warned in
|
||||
yes:)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
|
||||
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
|
||||
ac_tool_warned=yes ;;
|
||||
esac
|
||||
PKG_CONFIG=$ac_pt_PKG_CONFIG
|
||||
fi
|
||||
else
|
||||
PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
|
||||
fi
|
||||
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
_pkg_min_version=0.9.0
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
|
||||
$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then :
|
||||
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for jansson" >&5
|
||||
$as_echo_n "checking for jansson... " >&6; }
|
||||
|
||||
if test -n "$JANSSON_CFLAGS"; then
|
||||
pkg_cv_JANSSON_CFLAGS="$JANSSON_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"jansson\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "jansson") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_JANSSON_CFLAGS=`$PKG_CONFIG --cflags "jansson" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$JANSSON_LIBS"; then
|
||||
pkg_cv_JANSSON_LIBS="$JANSSON_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"jansson\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "jansson") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_JANSSON_LIBS=`$PKG_CONFIG --libs "jansson" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
|
||||
if test $pkg_failed = no; then
|
||||
pkg_save_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $pkg_cv_JANSSON_LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LDFLAGS=$pkg_save_LDFLAGS
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
JANSSON_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "jansson" 2>&1`
|
||||
else
|
||||
JANSSON_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "jansson" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$JANSSON_PKG_ERRORS" >&5
|
||||
|
||||
|
||||
as_fn_error $? "Cannot find jansson library" "$LINENO" 5
|
||||
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
as_fn_error $? "Cannot find jansson library" "$LINENO" 5
|
||||
|
||||
else
|
||||
JANSSON_CFLAGS=$pkg_cv_JANSSON_CFLAGS
|
||||
JANSSON_LIBS=$pkg_cv_JANSSON_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
|
||||
|
||||
$as_echo "#define HAVE_JANSSON 1" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
as_fn_error $? "Cannot find pkg-config" "$LINENO" 5
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Set the 'development' global.
|
||||
. $srcdir/../bfd/development.sh
|
||||
|
|
|
@ -289,6 +289,32 @@ fi
|
|||
AM_CONDITIONAL(ENABLE_LIBCTF, test "${enable_libctf}" = yes)
|
||||
AC_SUBST(enable_libctf)
|
||||
|
||||
# Used to validate --package-metadata= input. Disabled by default.
|
||||
AC_ARG_ENABLE([jansson],
|
||||
[AS_HELP_STRING([--enable-jansson],
|
||||
[enable jansson [default=no]])],
|
||||
[enable_jansson=$enableval],
|
||||
[enable_jansson="no"])
|
||||
|
||||
if test "x$enable_jansson" != "xno"; then
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AS_IF([test -n "$PKG_CONFIG"],
|
||||
[
|
||||
PKG_CHECK_MODULES(JANSSON, [jansson],
|
||||
[
|
||||
AC_DEFINE(HAVE_JANSSON, 1, [The jansson library is to be used])
|
||||
AC_SUBST([JANSSON_CFLAGS])
|
||||
AC_SUBST([JANSSON_LIBS])
|
||||
],
|
||||
[
|
||||
AC_MSG_ERROR([Cannot find jansson library])
|
||||
])
|
||||
],
|
||||
[
|
||||
AC_MSG_ERROR([Cannot find pkg-config])
|
||||
])
|
||||
fi
|
||||
|
||||
AM_BINUTILS_WARNINGS
|
||||
|
||||
AM_LC_MESSAGES
|
||||
|
|
|
@ -572,6 +572,7 @@ enum elf_options
|
|||
OPTION_EXCLUDE_LIBS,
|
||||
OPTION_HASH_STYLE,
|
||||
OPTION_BUILD_ID,
|
||||
OPTION_PACKAGE_METADATA,
|
||||
OPTION_AUDIT,
|
||||
OPTION_COMPRESS_DEBUG
|
||||
};
|
||||
|
@ -602,6 +603,7 @@ EOF
|
|||
fi
|
||||
fragment <<EOF
|
||||
{"build-id", optional_argument, NULL, OPTION_BUILD_ID},
|
||||
{"package-metadata", optional_argument, NULL, OPTION_PACKAGE_METADATA},
|
||||
{"compress-debug-sections", required_argument, NULL, OPTION_COMPRESS_DEBUG},
|
||||
EOF
|
||||
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
|
||||
|
@ -650,6 +652,13 @@ gld${EMULATION_NAME}_handle_option (int optc)
|
|||
ldelf_emit_note_gnu_build_id = xstrdup (optarg);
|
||||
break;
|
||||
|
||||
case OPTION_PACKAGE_METADATA:
|
||||
free ((char *) ldelf_emit_note_fdo_package_metadata);
|
||||
ldelf_emit_note_fdo_package_metadata = NULL;
|
||||
if (optarg != NULL && strlen(optarg) > 0)
|
||||
ldelf_emit_note_fdo_package_metadata = xstrdup (optarg);
|
||||
break;
|
||||
|
||||
case OPTION_COMPRESS_DEBUG:
|
||||
if (strcasecmp (optarg, "none") == 0)
|
||||
link_info.compress_debug = COMPRESS_DEBUG_NONE;
|
||||
|
|
12
ld/ld.texi
12
ld/ld.texi
|
@ -2935,6 +2935,18 @@ string identifying the original linked file does not change.
|
|||
|
||||
Passing @code{none} for @var{style} disables the setting from any
|
||||
@code{--build-id} options earlier on the command line.
|
||||
|
||||
@kindex --package-metadata=@var{JSON}
|
||||
@item --package-metadata=@var{JSON}
|
||||
Request the creation of a @code{.note.package} ELF note section. The
|
||||
contents of the note are in JSON format, as per the package metadata
|
||||
specification. For more information see:
|
||||
https://systemd.io/ELF_PACKAGE_METADATA/
|
||||
If the JSON argument is missing/empty then this will disable the
|
||||
creation of the metadata note, if one had been enabled by an earlier
|
||||
occurrence of the --package-metdata option.
|
||||
If the linker has been built with libjansson, then the JSON string
|
||||
will be validated.
|
||||
@end table
|
||||
|
||||
@c man end
|
||||
|
|
135
ld/ldelf.c
135
ld/ldelf.c
|
@ -39,6 +39,9 @@
|
|||
#include <glob.h>
|
||||
#endif
|
||||
#include "ldelf.h"
|
||||
#ifdef HAVE_JANSSON
|
||||
#include <jansson.h>
|
||||
#endif
|
||||
|
||||
struct dt_needed
|
||||
{
|
||||
|
@ -49,6 +52,9 @@ struct dt_needed
|
|||
/* Style of .note.gnu.build-id section. */
|
||||
const char *ldelf_emit_note_gnu_build_id;
|
||||
|
||||
/* Content of .note.package section. */
|
||||
const char *ldelf_emit_note_fdo_package_metadata;
|
||||
|
||||
/* These variables are required to pass information back and forth
|
||||
between after_open and check_needed and stat_needed and vercheck. */
|
||||
|
||||
|
@ -1249,7 +1255,8 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
|
|||
}
|
||||
}
|
||||
|
||||
if (ldelf_emit_note_gnu_build_id != NULL)
|
||||
if (ldelf_emit_note_gnu_build_id != NULL
|
||||
|| ldelf_emit_note_fdo_package_metadata != NULL)
|
||||
{
|
||||
/* Find an ELF input. */
|
||||
for (abfd = link_info.input_bfds;
|
||||
|
@ -1262,11 +1269,20 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
|
|||
/* PR 10555: If there are no ELF input files do not try to
|
||||
create a .note.gnu-build-id section. */
|
||||
if (abfd == NULL
|
||||
|| !ldelf_setup_build_id (abfd))
|
||||
|| (ldelf_emit_note_gnu_build_id != NULL
|
||||
&& !ldelf_setup_build_id (abfd)))
|
||||
{
|
||||
free ((char *) ldelf_emit_note_gnu_build_id);
|
||||
ldelf_emit_note_gnu_build_id = NULL;
|
||||
}
|
||||
|
||||
if (abfd == NULL
|
||||
|| (ldelf_emit_note_fdo_package_metadata != NULL
|
||||
&& !ldelf_setup_package_metadata (abfd)))
|
||||
{
|
||||
free ((char *) ldelf_emit_note_fdo_package_metadata);
|
||||
ldelf_emit_note_fdo_package_metadata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
get_elf_backend_data (link_info.output_bfd)->setup_gnu_properties (&link_info);
|
||||
|
@ -1501,6 +1517,121 @@ ldelf_setup_build_id (bfd *ibfd)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
write_package_metadata (bfd *abfd)
|
||||
{
|
||||
struct elf_obj_tdata *t = elf_tdata (abfd);
|
||||
const char *json;
|
||||
asection *asec;
|
||||
Elf_Internal_Shdr *i_shdr;
|
||||
unsigned char *contents, *json_bits;
|
||||
bfd_size_type size;
|
||||
file_ptr position;
|
||||
Elf_External_Note *e_note;
|
||||
|
||||
json = t->o->package_metadata.json;
|
||||
asec = t->o->package_metadata.sec;
|
||||
if (bfd_is_abs_section (asec->output_section))
|
||||
{
|
||||
einfo (_("%P: warning: .note.package section discarded,"
|
||||
" --package-metadata ignored\n"));
|
||||
return true;
|
||||
}
|
||||
i_shdr = &elf_section_data (asec->output_section)->this_hdr;
|
||||
|
||||
if (i_shdr->contents == NULL)
|
||||
{
|
||||
if (asec->contents == NULL)
|
||||
asec->contents = (unsigned char *) xmalloc (asec->size);
|
||||
contents = asec->contents;
|
||||
}
|
||||
else
|
||||
contents = i_shdr->contents + asec->output_offset;
|
||||
|
||||
e_note = (Elf_External_Note *) contents;
|
||||
size = offsetof (Elf_External_Note, name[sizeof "FDO"]);
|
||||
size = (size + 3) & -(bfd_size_type) 4;
|
||||
json_bits = contents + size;
|
||||
size = asec->size - size;
|
||||
|
||||
/* Clear the package metadata field. */
|
||||
memset (json_bits, 0, size);
|
||||
|
||||
bfd_h_put_32 (abfd, sizeof "FDO", &e_note->namesz);
|
||||
bfd_h_put_32 (abfd, size, &e_note->descsz);
|
||||
bfd_h_put_32 (abfd, FDO_PACKAGING_METADATA, &e_note->type);
|
||||
memcpy (e_note->name, "FDO", sizeof "FDO");
|
||||
memcpy (json_bits, json, strlen(json));
|
||||
|
||||
position = i_shdr->sh_offset + asec->output_offset;
|
||||
size = asec->size;
|
||||
return (bfd_seek (abfd, position, SEEK_SET) == 0
|
||||
&& bfd_bwrite (contents, size, abfd) == size);
|
||||
}
|
||||
|
||||
/* Make .note.package section.
|
||||
https://systemd.io/ELF_PACKAGE_METADATA/ */
|
||||
|
||||
bool
|
||||
ldelf_setup_package_metadata (bfd *ibfd)
|
||||
{
|
||||
asection *s;
|
||||
bfd_size_type size;
|
||||
size_t json_length;
|
||||
flagword flags;
|
||||
|
||||
/* If the option wasn't specified, silently return. */
|
||||
if (!ldelf_emit_note_fdo_package_metadata)
|
||||
return false;
|
||||
|
||||
/* The option was specified, but it's empty, log and return. */
|
||||
json_length = strlen (ldelf_emit_note_fdo_package_metadata);
|
||||
if (json_length == 0)
|
||||
{
|
||||
einfo (_("%P: warning: --package-metadata is empty, ignoring\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_JANSSON
|
||||
json_error_t json_error;
|
||||
json_t *json = json_loads (ldelf_emit_note_fdo_package_metadata,
|
||||
0, &json_error);
|
||||
if (!json)
|
||||
{
|
||||
einfo (_("%P: warning: --package-metadata=%s does not contain valid "
|
||||
"JSON, ignoring: %s\n"),
|
||||
ldelf_emit_note_fdo_package_metadata, json_error.text);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
json_decref (json);
|
||||
#endif
|
||||
|
||||
size = offsetof (Elf_External_Note, name[sizeof "FDO"]);
|
||||
size += json_length + 1;
|
||||
size = (size + 3) & -(bfd_size_type) 4;
|
||||
|
||||
flags = (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
|
||||
| SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
|
||||
s = bfd_make_section_anyway_with_flags (ibfd, ".note.package",
|
||||
flags);
|
||||
if (s != NULL && bfd_set_section_alignment (s, 2))
|
||||
{
|
||||
struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd);
|
||||
t->o->package_metadata.after_write_object_contents
|
||||
= &write_package_metadata;
|
||||
t->o->package_metadata.json = ldelf_emit_note_fdo_package_metadata;
|
||||
t->o->package_metadata.sec = s;
|
||||
elf_section_type (s) = SHT_NOTE;
|
||||
s->size = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
einfo (_("%P: warning: cannot create .note.package section,"
|
||||
" --package-metadata ignored\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Look through an expression for an assignment statement. */
|
||||
|
||||
static void
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
MA 02110-1301, USA. */
|
||||
|
||||
extern const char *ldelf_emit_note_gnu_build_id;
|
||||
extern const char *ldelf_emit_note_fdo_package_metadata;
|
||||
|
||||
extern void ldelf_after_parse (void);
|
||||
extern bool ldelf_load_symbols (lang_input_statement_type *);
|
||||
|
@ -26,6 +27,7 @@ extern void ldelf_before_plugin_all_symbols_read (int, int, int, int,
|
|||
int, const char *);
|
||||
extern void ldelf_after_open (int, int, int, int, int, const char *);
|
||||
extern bool ldelf_setup_build_id (bfd *);
|
||||
extern bool ldelf_setup_package_metadata (bfd *);
|
||||
extern void ldelf_append_to_separated_string (char **, char *);
|
||||
extern void ldelf_before_allocation (char *, char *, const char *);
|
||||
extern bool ldelf_open_dynamic_archive
|
||||
|
|
|
@ -2144,6 +2144,8 @@ elf_static_list_options (FILE *file)
|
|||
fprintf (file, _("\
|
||||
--build-id[=STYLE] Generate build ID note\n"));
|
||||
fprintf (file, _("\
|
||||
--package-metadata[=JSON] Generate package metadata note\n"));
|
||||
fprintf (file, _("\
|
||||
--compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
|
||||
Compress DWARF debug sections using zlib\n"));
|
||||
#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
|
||||
|
|
|
@ -155,6 +155,12 @@ foreach flags $test_flags {
|
|||
set extralibs "$extralibs -lz"
|
||||
}
|
||||
|
||||
# Check if the system's jansson library is used. If so, the object files will
|
||||
# be using symbols from it, so link to it.
|
||||
if { [lindex [remote_exec build grep "-q \"HAVE_JANSSON 1\" config.h" ] 0] == 0 } then {
|
||||
set extralibs "$extralibs -ljansson"
|
||||
}
|
||||
|
||||
# Plugin support requires linking with libdl.
|
||||
if { $plugins == "yes" } {
|
||||
if { ![istarget "*-*-freebsd*"]} {
|
||||
|
|
45
ld/testsuite/ld-elf/package-note.exp
Normal file
45
ld/testsuite/ld-elf/package-note.exp
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Expect script for --package-note tests.
|
||||
# Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of the GNU Binutils.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Exclude non-ELF targets.
|
||||
|
||||
if ![is_elf_format] {
|
||||
return
|
||||
}
|
||||
|
||||
if { !([istarget *-*-linux*]
|
||||
|| [istarget arm*-*-uclinuxfdpiceabi]
|
||||
|| [istarget *-*-nacl*]
|
||||
|| [istarget *-*-gnu*]) } then {
|
||||
return
|
||||
}
|
||||
|
||||
run_ld_link_tests [list \
|
||||
[list \
|
||||
"package-note.o" \
|
||||
"--package-metadata='{\"foo\":\"bar\"}'" \
|
||||
"" \
|
||||
"" \
|
||||
{start.s} \
|
||||
{{readelf {--notes} package-note.rd}} \
|
||||
"package-note.o" \
|
||||
] \
|
||||
]
|
6
ld/testsuite/ld-elf/package-note.rd
Normal file
6
ld/testsuite/ld-elf/package-note.rd
Normal file
|
@ -0,0 +1,6 @@
|
|||
#...
|
||||
Displaying notes found in: \.note\.package
|
||||
\s+Owner\s+Data\s+size\s+Description
|
||||
\s+FDO\s+0x00000010\s+(Unknown note type:\s+\(0xcafe1a7e\)|FDO_PACKAGING_METADATA)
|
||||
\s+(description data:\s+.*|Packaging Metadata:\s+{"foo":"bar"})
|
||||
#pass
|
Loading…
Add table
Reference in a new issue