]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Changes to fix GNU-style hash table handling.
authorUlrich Drepper <drepper@redhat.com>
Tue, 8 Aug 2006 22:00:11 +0000 (22:00 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 8 Aug 2006 22:00:11 +0000 (22:00 +0000)
libelf/ChangeLog
libelf/elf.h
src/ChangeLog
src/elflint.c

index 77bafae300aa83cd2b669d1ff182d50ebe2a1860..029923c085d02483d23dae7a461498cd5dee4220 100644 (file)
@@ -1,3 +1,8 @@
+2006-08-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf.h (DT_VALNUM): Update.
+       (DT_ADDRNUM): Likewise.
+
 2006-07-12  Ulrich Drepper  <drepper@redhat.com>
 
        * elf32_updatefile.c: Adjust for internal_function_def removal.
index 57b099e2fc3f1ea790372df00e2e5603db957239..dcadd60f94c5885228c6ae9ccb19a2d589f313f1 100644 (file)
@@ -692,7 +692,7 @@ typedef struct
 #define DT_SYMINENT    0x6ffffdff      /* Entry size of syminfo */
 #define DT_VALRNGHI    0x6ffffdff
 #define DT_VALTAGIDX(tag)      (DT_VALRNGHI - (tag))   /* Reverse order! */
-#define DT_VALNUM 12
+#define DT_VALNUM 11
 
 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
    Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
@@ -713,7 +713,7 @@ typedef struct
 #define DT_SYMINFO     0x6ffffeff      /* Syminfo table.  */
 #define DT_ADDRRNGHI   0x6ffffeff
 #define DT_ADDRTAGIDX(tag)     (DT_ADDRRNGHI - (tag))  /* Reverse order! */
-#define DT_ADDRNUM 10
+#define DT_ADDRNUM 11
 
 /* The versioning entry types.  The next are defined as part of the
    GNU extension.  */
index 90fce1dcdc9270b4a2706ebd625096c603b1449a..5a12ac62d884d946eab36bcd338e379b5e52f812 100644 (file)
@@ -1,3 +1,13 @@
+2006-08-08  Ulrich Drepper  <drepper@redhat.com>
+
+       * elflint.c (check_dynamic): Don't require DT_HASH for DT_SYMTAB.
+       Keep track of which "high DT" entries are present.
+       Check that either old or GNU-style hash table is present.
+       If GNU-style hash table is used a symbol table is mandatory.
+       Check that if any prelink entry is present all of them are.
+       (check_gnu_hash): Only fail for undefined symbols in GNU-style hash
+       table if they don't refer to functions.
+
 2006-07-17  Roland McGrath  <roland@redhat.com>
 
        * elflint.c (struct version_namelist): Use GElf_Versym for `ndx' field.
index c3e08512f6c40bb9dce93b9a4327140c4de90e3c..c96e8ab0cc3f0214893fa11a0a6ff83716774a7d 100644 (file)
@@ -1469,8 +1469,7 @@ check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
       [DT_PLTRELSZ] = { [DT_JMPREL] = true },
       [DT_HASH] = { [DT_SYMTAB] = true },
       [DT_STRTAB] = { [DT_STRSZ] = true },
-      [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_HASH] = true,
-                     [DT_SYMENT] = true },
+      [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_SYMENT] = true },
       [DT_RELA] = { [DT_RELASZ] = true, [DT_RELAENT] = true },
       [DT_RELASZ] = { [DT_RELA] = true },
       [DT_RELAENT] = { [DT_RELA] = true },
@@ -1487,6 +1486,8 @@ check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
       [DT_PLTRELSZ] = { [DT_JMPREL] = true }
     };
   bool has_dt[DT_NUM];
+  bool has_val_dt[DT_VALNUM];
+  bool has_addr_dt[DT_ADDRNUM];
   static const bool level2[DT_NUM] =
     {
       [DT_RPATH] = true,
@@ -1497,7 +1498,6 @@ check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
   static const bool mandatory[DT_NUM] =
     {
       [DT_NULL] = true,
-      [DT_HASH] = true,
       [DT_STRTAB] = true,
       [DT_SYMTAB] = true,
       [DT_STRSZ] = true,
@@ -1509,6 +1509,8 @@ check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
   GElf_Word pltrelsz = 0;
 
   memset (has_dt, '\0', sizeof (has_dt));
+  memset (has_val_dt, '\0', sizeof (has_val_dt));
+  memset (has_addr_dt, '\0', sizeof (has_addr_dt));
 
   if (++ndynamic == 2)
     ERROR (gettext ("more than one dynamic section present\n"));
@@ -1589,6 +1591,12 @@ section [%2d] '%s': entry %zu: level 2 tag %s used\n"),
 
          has_dt[dyn->d_tag] = true;
        }
+      else if (dyn->d_tag <= DT_VALRNGHI
+              && DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
+       has_val_dt[DT_VALTAGIDX (dyn->d_tag)] = true;
+      else if (dyn->d_tag <= DT_ADDRRNGHI
+              && DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
+       has_addr_dt[DT_ADDRTAGIDX (dyn->d_tag)] = true;
 
       if (dyn->d_tag == DT_PLTREL && dyn->d_un.d_val != DT_REL
          && dyn->d_un.d_val != DT_RELA)
@@ -1711,6 +1719,20 @@ section [%2d] '%s': mandatory tag %s not present\n"),
          }
       }
 
+  /* Make sure we have an hash table.  */
+  if (!has_dt[DT_HASH] && !has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)])
+    ERROR (gettext ("\
+section [%2d] '%s': no hash section present\n"),
+          idx, section_name (ebl, idx));
+
+  /* The GNU-style hash table also needs a symbol table.  */
+  if (!has_dt[DT_HASH] && has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)]
+      && !has_dt[DT_SYMTAB])
+    ERROR (gettext ("\
+section [%2d] '%s': contains %s entry but not %s\n"),
+          idx, section_name (ebl, idx),
+          "DT_GNU_HASH", "DT_SYMTAB");
+
   /* Check the rel/rela tags.  At least one group must be available.  */
   if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT])
       && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT]))
@@ -1725,6 +1747,49 @@ section [%2d] '%s': not all of %s, %s, and %s are present\n"),
 section [%2d] '%s': not all of %s, %s, and %s are present\n"),
           idx, section_name (ebl, idx),
           "DT_REL", "DT_RELSZ", "DT_RELENT");
+
+  /* Check that all prelink sections are present if any of them is.  */
+  if (has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)]
+      || has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)])
+    {
+      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)])
+       ERROR (gettext ("\
+section [%2d] '%s': %s tag missing in DSO marked during prelinking\n"),
+              idx, section_name (ebl, idx), "DT_GNU_PRELINKED");
+      if (!has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)])
+       ERROR (gettext ("\
+section [%2d] '%s': %s tag missing in DSO marked during prelinking\n"),
+              idx, section_name (ebl, idx), "DT_CHECKSUM");
+
+      /* Only DSOs can be marked like this.  */
+      if (ehdr->e_type != ET_DYN)
+       ERROR (gettext ("\
+section [%2d] '%s': non-DSO file marked as dependency during prelink\n"),
+              idx, section_name (ebl, idx));
+    }
+
+  if (has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)]
+      || has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)]
+      || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)]
+      || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)])
+    {
+      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)])
+       ERROR (gettext ("\
+section [%2d] '%s': %s tag missing in prelinked executable\n"),
+              idx, section_name (ebl, idx), "DT_GNU_CONFLICTSZ");
+      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)])
+       ERROR (gettext ("\
+section [%2d] '%s': %s tag missing in prelinked executable\n"),
+              idx, section_name (ebl, idx), "DT_GNU_LIBLISTSZ");
+      if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)])
+       ERROR (gettext ("\
+section [%2d] '%s': %s tag missing in prelinked executable\n"),
+              idx, section_name (ebl, idx), "DT_GNU_CONFLICT");
+      if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)])
+       ERROR (gettext ("\
+section [%2d] '%s': %s tag missing in prelinked executable\n"),
+              idx, section_name (ebl, idx), "DT_GNU_LIBLIST");
+    }
 }
 
 
@@ -1970,7 +2035,8 @@ section [%2d] '%s': hash chain for bucket %zu lower than symbol index bias\n"),
              /* Check that the referenced symbol is not undefined.  */
              GElf_Sym sym_mem;
              GElf_Sym *sym = gelf_getsym (symdata, symidx, &sym_mem);
-             if (sym != NULL && sym->st_shndx == SHN_UNDEF)
+             if (sym != NULL && sym->st_shndx == SHN_UNDEF
+                 && GELF_ST_TYPE (sym->st_info) != STT_FUNC)
                ERROR (gettext ("\
 section [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n"),
                       idx, section_name (ebl, idx), symidx, cnt / 2 - 1);