summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-01-31 19:44:12 +0000
committerUlrich Drepper <drepper@redhat.com>2008-01-31 19:44:12 +0000
commit89759c76ee1e3231ee89d4aafed3a88772ce2245 (patch)
treea712bb1ae7718f8ba422cd6c934d8a2f1a77584f
parentb61c4cc4ab5d61d5d7c1a31e700bff8ad39fa079 (diff)
downloadelfutils-89759c76ee1e3231ee89d4aafed3a88772ce2245.tar.gz
Implement --build-id command line parameter for ld.
-rw-r--r--lib/ChangeLog5
-rw-r--r--lib/Makefile.am6
-rw-r--r--libelf/ChangeLog5
-rw-r--r--libelf/elf_strptr.c24
-rw-r--r--src/ChangeLog9
-rw-r--r--src/elf32-i386.script2
-rw-r--r--src/ld.c40
-rw-r--r--src/ld.h7
-rw-r--r--src/ldgeneric.c183
-rw-r--r--src/ldlex.l4
10 files changed, 274 insertions, 11 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog
index cc2850c3..1697d00e 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,8 @@
+2008-01-31 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile.am (libeu_a_SOURCES): Add md5.c.
+ (noinst_HEADERS): Add md5.h.
+
2006-04-04 Ulrich Drepper <drepper@redhat.com>
* Makefile.am (libeu_a_SOURCES): We don't need xstrdup in the moment.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 4218e963..7ee03463 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to create Makefile.in
##
-## Copyright (C) 1996-2001, 2002, 2004, 2005 Red Hat, Inc.
+## Copyright (C) 1996-2001, 2002, 2004, 2005, 2008 Red Hat, Inc.
## This file is part of Red Hat elfutils.
##
## Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -36,9 +36,9 @@ INCLUDES = -I$(srcdir)/../libelf -I..
noinst_LIBRARIES = libeu.a
libeu_a_SOURCES = xstrndup.c xmalloc.c next_prime.c \
- crc32.c crc32_file.c
+ crc32.c crc32_file.c md5.c
-noinst_HEADERS = fixedsizehash.h system.h dynamicsizehash.h list.h
+noinst_HEADERS = fixedsizehash.h system.h dynamicsizehash.h list.h md5.h
EXTRA_DIST = dynamicsizehash.c
if !GPROF
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 0688cbdb..17633ba7 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2008-01-31 Ulrich Drepper <drepper@redhat.com>
+
+ * elf_strptr.c (elf_strptr): Don't fail if the ELF file is currently
+ under construction and no raw data can be read from disk.
+
2008-01-20 Roland McGrath <roland@redhat.com>
* elf_getaroff.c: Calculate from start_offset, instead of using
diff --git a/libelf/elf_strptr.c b/libelf/elf_strptr.c
index 28042211..c1ea60de 100644
--- a/libelf/elf_strptr.c
+++ b/libelf/elf_strptr.c
@@ -1,5 +1,5 @@
/* Return string pointer from string section.
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2008 Red Hat, Inc.
This file is part of Red Hat elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
@@ -140,12 +140,30 @@ elf_strptr (elf, idx, offset)
}
}
- if (strscn->rawdata_base == NULL
+ if (strscn->rawdata_base == NULL && ! strscn->data_read
/* Read the section data. */
&& __libelf_set_rawdata (strscn) != 0)
goto out;
- result = &strscn->rawdata_base[offset];
+ if (likely (strscn->rawdata_base != NULL))
+ result = &strscn->rawdata_base[offset];
+ else
+ {
+ /* This is a file which is currently created. Use the list of
+ data blocks. */
+ struct Elf_Data_List *dl = &strscn->data_list;
+ while (dl != NULL)
+ {
+ if (offset >= (size_t) dl->data.d.d_off
+ && offset < dl->data.d.d_off + dl->data.d.d_size)
+ {
+ result = (char *) dl->data.d.d_buf + (offset - dl->data.d.d_off);
+ break;
+ }
+
+ dl = dl->next;
+ }
+ }
out:
rwlock_unlock (elf->lock);
diff --git a/src/ChangeLog b/src/ChangeLog
index bbc2708c..6f5f4337 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
+2008-01-31 Ulrich Drepper <drepper@redhat.com>
+
+ * elf32-i386.script: Add .note.ABI-tag and .note.gnu.build-id sections.
+ * ld.c: Recognize --build-id command line parameter.
+ * ld.h: Define scn_dot_note_gnu_build_id.
+ (struct ld_state): Add build_id and buildidscnidx elements.
+ * ldgeneric.c: Implement --build-id command line parameter.
+ * ldlex.l (ID): Recognize - as valid character after the first one.
+
2008-01-29 Ulrich Drepper <drepper@redhat.com>
* ld.c (replace_args): New function.
diff --git a/src/elf32-i386.script b/src/elf32-i386.script
index e3f6906c..1c46b690 100644
--- a/src/elf32-i386.script
+++ b/src/elf32-i386.script
@@ -18,6 +18,8 @@ SEGMENT [RX]
#endif
.interp;
+ .note.ABI-tag;
+ .note.gnu.build-id;
.hash;
.gnu.hash;
.dynsym;
diff --git a/src/ld.c b/src/ld.c
index 6f8048f5..3b422bc6 100644
--- a/src/ld.c
+++ b/src/ld.c
@@ -74,6 +74,7 @@ enum
ARGP_no_as_needed,
ARGP_eh_frame_hdr,
ARGP_hash_style,
+ ARGP_build_id,
#if YYDEBUG
ARGP_yydebug,
#endif
@@ -164,12 +165,14 @@ Default rules of extracting from archive; weak references are not enough."),
{ "dynamic-linker", 'I', "NAME", 0, N_("Set the dynamic linker name."), 0 },
{ NULL, 'Q', "YN", OPTION_HIDDEN, NULL, 0 },
{ "-Q y | n", 'Q', NULL, OPTION_DOC,
- N_("Add/suppress addition indentifying link-editor to .comment section"),
+ N_("Add/suppress addition indentifying link-editor to .comment section."),
0 },
{ "eh-frame-hdr", ARGP_eh_frame_hdr, NULL, 0,
N_("Create .eh_frame_hdr section"), 0 },
{ "hash-style", ARGP_hash_style, "STYLE", 0,
N_("Set hash style to sysv, gnu or both."), 0 },
+ { "build-id", ARGP_build_id, "STYLE", OPTION_ARG_OPTIONAL,
+ N_("Generate build ID note (md5 (default), uuid)."), 0 },
{ NULL, 0, NULL, 0, N_("Linker Operation Control:"), 0 },
{ "verbose", 'v', NULL, 0, N_("Verbose messages."), 0 },
@@ -519,6 +522,30 @@ replace_args (int argc, char *argv[])
}
+static int
+valid_hexarg (const char *arg)
+{
+ if (strncasecmp (arg, "0x", 2) != 0)
+ return 0;
+
+ arg += 2;
+ do
+ {
+ if (isxdigit (arg[0]) && isxdigit (arg[1]))
+ {
+ arg += 2;
+ if (arg[0] == '-' || arg[0] == ':')
+ ++arg;
+ }
+ else
+ return 0;
+ }
+ while (*arg != '\0');
+
+ return 1;
+}
+
+
/* Quick scan of the parameter list for options with global effect. */
static error_t
parse_opt_1st (int key, char *arg,
@@ -659,6 +686,17 @@ parse_opt_1st (int key, char *arg,
error (EXIT_FAILURE, 0, gettext ("invalid hash style '%s'"), arg);
break;
+ case ARGP_build_id:
+ if (arg == NULL)
+ ld_state.build_id = "md5";
+ else if (strcmp (arg, "uuid") != 0
+ && strcmp (arg, "md5") != 0
+ && !valid_hexarg (arg))
+ error (EXIT_FAILURE, 0, gettext ("invalid build-ID style '%s'"), arg);
+ else
+ ld_state.build_id = arg;
+ break;
+
case 's':
if (arg == NULL)
{
diff --git a/src/ld.h b/src/ld.h
index d4ad8f9d..860bcdb4 100644
--- a/src/ld.h
+++ b/src/ld.h
@@ -689,7 +689,8 @@ struct scnhead
scn_dot_plt, /* Generated .plt section. */
scn_dot_pltrel, /* Generated .rel.plt section. */
scn_dot_version, /* Generated .gnu.version section. */
- scn_dot_version_r /* Generated .gnu.version_r section. */
+ scn_dot_version_r, /* Generated .gnu.version_r section. */
+ scn_dot_note_gnu_build_id /* Generated .note.gnu.build-id section. */
} kind;
/* True is the section is used in the output. */
@@ -1044,6 +1045,10 @@ struct ld_state
the dynamic symbol table. */
bool export_all_dynamic;
+ /* Build-ID style. NULL is none. */
+ const char *build_id;
+ Elf32_Word buildidscnidx;
+
/* If DSO is generated, this is the SONAME. */
const char *soname;
diff --git a/src/ldgeneric.c b/src/ldgeneric.c
index a1076a0d..6674887b 100644
--- a/src/ldgeneric.c
+++ b/src/ldgeneric.c
@@ -28,6 +28,7 @@
#endif
#include <assert.h>
+#include <ctype.h>
#include <dlfcn.h>
#include <errno.h>
#include <error.h>
@@ -44,9 +45,11 @@
#include <sys/param.h>
#include <sys/stat.h>
-#include <system.h>
+#include <elf-knowledge.h>
#include "ld.h"
#include "list.h"
+#include <md5.h>
+#include <system.h>
/* Header of .eh_frame_hdr section. */
@@ -2432,6 +2435,11 @@ ld_generic_generate_sections (struct ld_state *statep)
/* The relocation section type. */
int rel_type = REL_TYPE (&ld_state) == DT_REL ? SHT_REL : SHT_RELA;
+ /* When requested, every output file will have a build ID section. */
+ if (statep->build_id != NULL)
+ new_generated_scn (scn_dot_note_gnu_build_id, ".note.gnu.build-id",
+ SHT_NOTE, SHF_ALLOC, 0, 4);
+
/* When building dynamically linked object we have to include a
section containing a string describing the interpreter. This
should be at the very beginning of the file together with the
@@ -4089,6 +4097,163 @@ cannot create hash table section for output file: %s"),
}
+static void
+create_build_id_section (Elf_Scn *scn)
+{
+ /* We know how large the section will be so we can create it now. */
+ Elf_Data *d = elf_newdata (scn);
+ if (d == NULL)
+ error (EXIT_FAILURE, 0, gettext ("cannot create build ID section: %s"),
+ elf_errmsg (-1));
+
+ d->d_type = ELF_T_BYTE;
+ d->d_version = EV_CURRENT;
+
+ /* The note section header. */
+ assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
+ d->d_size = sizeof (GElf_Nhdr);
+ /* The string is four bytes long. */
+ d->d_size += sizeof (ELF_NOTE_GNU);
+ assert (d->d_size % 4 == 0);
+
+ if (strcmp (ld_state.build_id, "md5") == 0
+ || strcmp (ld_state.build_id, "uuid") == 0)
+ d->d_size += 16;
+ else
+ {
+ assert (ld_state.build_id[0] == '0' && ld_state.build_id[1] == 'x');
+ /* Use an upper limit of the possible number of bytes generated
+ from the string. */
+ d->d_size += strlen (ld_state.build_id) / 2;
+ }
+
+ d->d_buf = xcalloc (d->d_size, 1);
+ d->d_off = 0;
+ d->d_align = 0;
+}
+
+
+/* Iterate over the sections */
+static void
+compute_build_id (void)
+{
+ Elf_Data *d = elf_getdata (elf_getscn (ld_state.outelf,
+ ld_state.buildidscnidx), NULL);
+ assert (d != NULL);
+
+ GElf_Nhdr *hdr = d->d_buf;
+ hdr->n_namesz = sizeof (ELF_NOTE_GNU);
+ hdr->n_type = NT_GNU_BUILD_ID;
+ char *dp = mempcpy (hdr + 1, ELF_NOTE_GNU, sizeof (ELF_NOTE_GNU));
+
+ if (strcmp (ld_state.build_id, "md5") == 0)
+ {
+ /* Compute the MD5 sum of various parts of the generated file.
+ We compute the hash sum over the external representation. */
+ struct md5_ctx ctx;
+ md5_init_ctx (&ctx);
+
+ /* The call cannot fail. */
+ size_t shstrndx;
+ (void) elf_getshstrndx (ld_state.outelf, &shstrndx);
+
+ const char *ident = elf_getident (ld_state.outelf, NULL);
+ bool same_byte_order = ((ident[EI_DATA] == ELFDATA2LSB
+ && __BYTE_ORDER == __LITTLE_ENDIAN)
+ || (ident[EI_DATA] == ELFDATA2MSB
+ && __BYTE_ORDER == __BIG_ENDIAN));
+
+ /* Iterate over all sections to find those which are not strippable. */
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (ld_state.outelf, scn)) != NULL)
+ {
+ /* Get the section header. */
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ assert (shdr != NULL);
+
+ if (SECTION_STRIP_P (shdr,
+ elf_strptr (ld_state.outelf, shstrndx,
+ shdr->sh_name), true))
+ /* The section can be stripped. Don't use it. */
+ continue;
+
+ /* Do not look at NOBITS sections. */
+ if (shdr->sh_type == SHT_NOBITS)
+ continue;
+
+ /* Iterate through the list of data blocks. */
+ Elf_Data *data = NULL;
+ while ((data = INTUSE(elf_getdata) (scn, data)) != NULL)
+ /* If the file byte order is the same as the host byte order
+ process the buffer directly. If the data is just a stream
+ of bytes which the library will not convert we can use it
+ as well. */
+ if (likely (same_byte_order) || data->d_type == ELF_T_BYTE)
+ md5_process_bytes (data->d_buf, data->d_size, &ctx);
+ else
+ {
+ /* Convert the data to file byte order. */
+ if (gelf_xlatetof (ld_state.outelf, data, data, ident[EI_DATA])
+ == NULL)
+ error (EXIT_FAILURE, 0, gettext ("\
+cannot convert section data to file format: %s"),
+ elf_errmsg (-1));
+
+ md5_process_bytes (data->d_buf, data->d_size, &ctx);
+
+ /* And convert it back. */
+ if (gelf_xlatetom (ld_state.outelf, data, data, ident[EI_DATA])
+ == NULL)
+ error (EXIT_FAILURE, 0, gettext ("\
+cannot convert section data to memory format: %s"),
+ elf_errmsg (-1));
+ }
+
+ /* We are done computing the checksum. */
+ (void) md5_finish_ctx (&ctx, dp);
+
+ hdr->n_descsz = 16;
+ }
+ }
+ else if (strcmp (ld_state.build_id, "uuid") == 0)
+ {
+ int fd = open ("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ error (EXIT_FAILURE, errno, gettext ("cannot open '%s'"),
+ "/dev/urandom");
+
+ if (TEMP_FAILURE_RETRY (read (fd, dp, 16)) != 16)
+ error (EXIT_FAILURE, 0, gettext ("cannot read enough data for UUID"));
+
+ close (fd);
+
+ hdr->n_descsz = 16;
+ }
+ else
+ {
+ const char *cp = ld_state.build_id + 2;
+
+ /* The form of the string has been verified before so here we can
+ simplify the scanning. */
+ do
+ {
+ if (isxdigit (cp[0]))
+ {
+ char ch1 = tolower (cp[0]);
+ char ch2 = tolower (cp[1]);
+
+ *dp++ = (((isdigit (ch1) ? ch1 - '0' : ch1 - 'a' + 10) << 4)
+ | (isdigit (ch2) ? ch2 - '0' : ch2 - 'a' + 10));
+ }
+ else
+ ++cp;
+ }
+ while (*cp != '\0');
+ }
+}
+
+
/* Create the output file.
For relocatable files what basically has to happen is that all
@@ -4485,6 +4650,16 @@ ld_generic_create_outfile (struct ld_state *statep)
continue;
}
+ if (unlikely (head->kind == scn_dot_note_gnu_build_id))
+ {
+ /* Remember the index of this section. */
+ ld_state.buildidscnidx = elf_ndxscn (scn);
+
+ create_build_id_section (scn);
+
+ continue;
+ }
+
/* If we come here we must be handling a normal section. */
assert (head->kind == scn_normal);
@@ -6695,6 +6870,12 @@ internal error: nobits section follows nobits section"));
/* Finalize the .plt section and what else belongs to it. */
FINALIZE_PLT (statep, nsym, nsym_local, ndxtosym);
+
+ /* Finally, if we have to compute the build ID. */
+ if (ld_state.build_id != NULL)
+ compute_build_id ();
+
+
/* We don't need the map from the symbol table index to the symbol
structure anymore. */
free (ndxtosym);
diff --git a/src/ldlex.l b/src/ldlex.l
index 17d5be78..eb15c7be 100644
--- a/src/ldlex.l
+++ b/src/ldlex.l
@@ -1,5 +1,5 @@
%{
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2001.
@@ -79,7 +79,7 @@ static int handle_ifdef (void);
static void invalid_char (int ch);
%}
-ID [a-zA-Z0-9_.*?]+
+ID [a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]*
FILENAMECHAR1 [a-zA-Z0-9_/.\\~]
FILENAMECHAR [^][{}[:space:]():;]+
HEX 0[xX][0-9a-fA-F]+[kKmM]?