aboutsummaryrefslogtreecommitdiff
path: root/ld/ldelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/ldelf.c')
-rw-r--r--ld/ldelf.c135
1 files changed, 133 insertions, 2 deletions
diff --git a/ld/ldelf.c b/ld/ldelf.c
index 4094640..bfa0d54 100644
--- a/ld/ldelf.c
+++ b/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