[PATCH v4] ld: Add --encoded-package-metadata
H.J. Lu
hjl.tools@gmail.com
Sat Jul 20 22:34:16 GMT 2024
On Thu, Jul 18, 2024, 5:05 PM Benjamin Drung <benjamin.drung@canonical.com>
wrote:
> Specifying the compiler flag `-Wl,--package-metadata=<JSON>` might not
> work, because the shells might eat the quotation marks and the compiler
> splits the JSON at the commas.
>
> Ubuntu tried to using a specs file to set `--package-metadata` but that
> turned out to be too fragile. autopkgtests might use the compiler flags
> but the needed environment variables are not set in the test
> environment. Debugging a crash of an application build with the -spec
> parameter lacks the environment variables. People like to iteratively
> continue building the software in the build directory while hacking on
> the package and then have no environment variable set.
>
> So introduce a `--encoded-package-metadata` linker flag that takes a
> percent-encoded JSON. Percent-encoding is used because it is a
> standard and simple to implement.
>
Please open a bug report for this feature request.
A test case is needed to show why this feature is needed.
Thanks.
> Bug-Ubutru: https://bugs.launchpad.net/bugs/2071468
> Signed-off-by: Benjamin Drung <benjamin.drung@canonical.com>
> ---
> ld/NEWS | 5 +++
> ld/emultempl/elf.em | 19 +++++++++++
> ld/ld.texi | 15 ++++++++-
> ld/ldlex.h | 1 +
> ld/ldmisc.c | 49 ++++++++++++++++++++++++++++
> ld/ldmisc.h | 1 +
> ld/lexsup.c | 2 ++
> ld/testsuite/ld-elf/package-note.exp | 18 ++++++++++
> ld/testsuite/ld-elf/package-note2.rd | 6 ++++
> 9 files changed, 115 insertions(+), 1 deletion(-)
> create mode 100644 ld/testsuite/ld-elf/package-note2.rd
>
> diff --git a/ld/NEWS b/ld/NEWS
> index e0b9341a8ef..250ce353068 100644
> --- a/ld/NEWS
> +++ b/ld/NEWS
> @@ -12,6 +12,11 @@
>
> * Add -plugin-save-temps to store plugin intermediate files permanently.
>
> +* The ELF linker now supports a new --encoded-package-metadata option that
> + is equivalent to --package-metadata, but takes the JSON payload
> + percent-encoded to ease passing around this option without getting the
> + JSON payload corrupted.
> +
> Changes in 2.42:
>
> * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT
> diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
> index 863657e12f5..1a893f35416 100644
> --- a/ld/emultempl/elf.em
> +++ b/ld/emultempl/elf.em
> @@ -813,6 +813,7 @@ EOF
> fi
> fragment <<EOF
> {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
> + {"encoded-package-metadata", optional_argument, NULL,
> OPTION_ENCODED_PACKAGE_METADATA},
> {"package-metadata", optional_argument, NULL,
> OPTION_PACKAGE_METADATA},
> {"compress-debug-sections", required_argument, NULL,
> OPTION_COMPRESS_DEBUG},
> {"rosegment", no_argument, NULL, OPTION_ROSEGMENT},
> @@ -864,6 +865,24 @@ gld${EMULATION_NAME}_handle_option (int optc)
> ldelf_emit_note_gnu_build_id = xstrdup (optarg);
> break;
>
> + case OPTION_ENCODED_PACKAGE_METADATA:
> + free ((char *) ldelf_emit_note_fdo_package_metadata);
> + ldelf_emit_note_fdo_package_metadata = NULL;
> + if (optarg != NULL)
> + {
> + size_t optarg_len = strlen (optarg);
> + if (optarg_len > 0)
> + {
> + char *package_metadata = xmalloc (optarg_len + 1);
> + int len = percent_decode (optarg, package_metadata);
> + if (len < 0)
> + einfo (_("%F%P: Failed to decode percent-encoded package"
> + " metadata \`%s'\n"), optarg);
> + ldelf_emit_note_fdo_package_metadata = package_metadata;
> + }
> + }
> + break;
> +
> case OPTION_PACKAGE_METADATA:
> free ((char *) ldelf_emit_note_fdo_package_metadata);
> ldelf_emit_note_fdo_package_metadata = NULL;
> diff --git a/ld/ld.texi b/ld/ld.texi
> index 89e3913317a..28733b1ae8e 100644
> --- a/ld/ld.texi
> +++ b/ld/ld.texi
> @@ -3234,6 +3234,19 @@ 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 --encoded-package-metadata=@var{PERCENT_ENCODED_JSON}
> +@item --encoded-package-metadata=@var{PERCENT_ENCODED_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 PERCENT_ENCODED_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 --encoded-package-metadata or
> +--package-metadata option. PERCENT_ENCODED_JSON will be percent-decoded.
> +If the linker has been built with libjansson, then the JSON string
> +will be validated.
> +
> @kindex --package-metadata=@var{JSON}
> @item --package-metadata=@var{JSON}
> Request the creation of a @code{.note.package} ELF note section. The
> @@ -3242,7 +3255,7 @@ 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-metadata option.
> +occurrence of the --encoded-package-metadata or --package-metadata option.
> If the linker has been built with libjansson, then the JSON string
> will be validated.
> @end table
> diff --git a/ld/ldlex.h b/ld/ldlex.h
> index defe3fcbbb9..225d95b1e90 100644
> --- a/ld/ldlex.h
> +++ b/ld/ldlex.h
> @@ -284,6 +284,7 @@ enum option_values
> OPTION_EH_FRAME_HDR,
> OPTION_NO_EH_FRAME_HDR,
> OPTION_HASH_STYLE,
> + OPTION_ENCODED_PACKAGE_METADATA,
> OPTION_PACKAGE_METADATA,
> OPTION_AUDIT,
> OPTION_COMPRESS_DEBUG,
> diff --git a/ld/ldmisc.c b/ld/ldmisc.c
> index 180b24b3448..ff98226afd6 100644
> --- a/ld/ldmisc.c
> +++ b/ld/ldmisc.c
> @@ -770,3 +770,52 @@ ld_abort (const char *file, int line, const char *fn)
> einfo (_("%F%P: please report this bug\n"));
> xexit (1);
> }
> +
> +/* Decode a hexadecimal character. Return -1 on error. */
> +static int
> +hexdecode (char c)
> +{
> + if ('0' <= c && c <= '9')
> + return c - '0';
> + if ('A' <= c && c <= 'F')
> + return c - 'A' + 10;
> + if ('a' <= c && c <= 'f')
> + return c - 'a' + 10;
> + return -1;
> +}
> +
> +/* Decode a percent-encoded string. dst must be at least the same size as
> src.
> + It can be converted in place. Returns the lenght of the decoded string
> + (without training null character) or -1 on error. */
> +int
> +percent_decode (const char *src, char *dst)
> +{
> + int length = 0;
> + while (*src != '\0')
> + {
> + char c = *src++;
> + if (c != '%')
> + {
> + *dst++ = c;
> + length += 1;
> + continue;
> + }
> + char next1 = *src++;
> + if (next1 == '%')
> + {
> + *dst++ = '%';
> + length += 1;
> + continue;
> + }
> + int hex1 = hexdecode (next1);
> + if (hex1 == -1)
> + return -1;
> + int hex2 = hexdecode (*src++);
> + if (hex2 == -1)
> + return -1;
> + *dst++ = (char) ((hex1 << 4) + hex2);
> + length += 1;
> + }
> + *dst = '\0';
> + return length;
> +}
> diff --git a/ld/ldmisc.h b/ld/ldmisc.h
> index 20289127c0a..815e8ccb548 100644
> --- a/ld/ldmisc.h
> +++ b/ld/ldmisc.h
> @@ -39,5 +39,6 @@ do { info_assert(__FILE__,__LINE__); } while (0)
> extern void print_spaces (int);
> #define print_space() print_spaces (1)
> extern void print_nl (void);
> +extern int percent_decode (const char *, char *);
>
> #endif
> diff --git a/ld/lexsup.c b/ld/lexsup.c
> index 4aa0124ce2f..60e329a713f 100644
> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -2279,6 +2279,8 @@ elf_static_list_options (FILE *file)
> fprintf (file, _("\
> --build-id[=STYLE] Generate build ID note\n"));
> fprintf (file, _("\
> + --encoded-package-metadata[=PERCENT_ENCODED_JSON] Generate package
> metadata note\n"));
> + fprintf (file, _("\
> --package-metadata[=JSON] Generate package metadata note\n"));
> fprintf (file, _("\
> --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi|zstd]\n\
> diff --git a/ld/testsuite/ld-elf/package-note.exp
> b/ld/testsuite/ld-elf/package-note.exp
> index 9f18705bd65..b4feef541b4 100644
> --- a/ld/testsuite/ld-elf/package-note.exp
> +++ b/ld/testsuite/ld-elf/package-note.exp
> @@ -42,4 +42,22 @@ run_ld_link_tests [list \
> {{readelf {--notes} package-note.rd}} \
> "package-note.o" \
> ] \
> + [list \
> + "package-note1b.o" \
> + "--encoded-package-metadata=%7B%22foo%22%3A%22bar%22%7D" \
> + "" \
> + "" \
> + {start.s} \
> + {{readelf {--notes} package-note.rd}} \
> + "package-note1b.o" \
> + ] \
> + [list \
> + "package-note2.o" \
> +
> "--encoded-package-metadata=%7B%22name%22:%22binutils%22%2C%22foo%22%3A%22bar%22%7d"
> \
> + "" \
> + "" \
> + {start.s} \
> + {{readelf {--notes} package-note2.rd}} \
> + "package-note2.o" \
> + ] \
> ]
> diff --git a/ld/testsuite/ld-elf/package-note2.rd
> b/ld/testsuite/ld-elf/package-note2.rd
> new file mode 100644
> index 00000000000..c24c37825ad
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/package-note2.rd
> @@ -0,0 +1,6 @@
> +#...
> +Displaying notes found in: \.note\.package
> +\s+Owner\s+Data\s+size\s+Description
> +\s+FDO\s+0x00000020\s+(Unknown note
> type:\s+\(0xcafe1a7e\)|FDO_PACKAGING_METADATA)
> +\s+(description data:\s+.*|Packaging
> Metadata:\s+{"name":"binutils","foo":"bar"})
> +#pass
> --
> 2.43.0
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20240721/e1af3334/attachment-0001.htm>
More information about the Binutils
mailing list