summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-08-08 22:00:11 +0000
committerUlrich Drepper <drepper@redhat.com>2006-08-08 22:00:11 +0000
commit231c590fbe9d6f3a8e22796ded9c6a378628eb09 (patch)
treec4750e82af3d55c774b447527f516d8f3dc89ea9
parentc812a8394a9300eb050712192ff5f493a85d72c5 (diff)
downloadelfutils-231c590fbe9d6f3a8e22796ded9c6a378628eb09.tar.gz
Changes to fix GNU-style hash table handling.
-rw-r--r--libelf/ChangeLog5
-rw-r--r--libelf/elf.h4
-rw-r--r--src/ChangeLog10
-rw-r--r--src/elflint.c74
4 files changed, 87 insertions, 6 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 77bafae3..029923c0 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -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.
diff --git a/libelf/elf.h b/libelf/elf.h
index 57b099e2..dcadd60f 100644
--- a/libelf/elf.h
+++ b/libelf/elf.h
@@ -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. */
diff --git a/src/ChangeLog b/src/ChangeLog
index 90fce1dc..5a12ac62 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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.
diff --git a/src/elflint.c b/src/elflint.c
index c3e08512..c96e8ab0 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -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);