summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libebl/ChangeLog28
-rw-r--r--libebl/Makefile.am3
-rw-r--r--libebl/eblopenbackend.c22
-rw-r--r--libebl/libebl.h12
-rw-r--r--libebl/libeblP.h8
-rw-r--r--libebl/libebl_ppc.h10
-rw-r--r--libebl/libebl_ppc64.h10
-rw-r--r--libebl/ppc64_init.c2
-rw-r--r--libebl/ppc64_symbol.c26
-rw-r--r--libebl/ppc_init.c2
-rw-r--r--libebl/ppc_symbol.c66
-rw-r--r--src/ChangeLog15
-rw-r--r--src/elflint.c110
13 files changed, 272 insertions, 42 deletions
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index 5553cc49..68ec2217 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,31 @@
+2005-08-12 Roland McGrath <roland@redhat.com>
+
+ * libeblP.h (struct ebl): Add bss_plt_p hook.
+ * eblopenbackend.c (default_bss_plt_p): New function.
+ (fill_defaults): Use it.
+ * eblbsspltp.c: New file.
+ * Makefile.am (gen_SOURCES): Add it.
+ * libebl.h: Declare ebl_bss_plt_p.
+ * ppc_symbol.c (ppc_bss_plt_p): New function.
+ * libebl_ppc.h: Declare it.
+ * ppc_init.c (ppc_init): Use it.
+ * ppc64_symbol.c (ppc64_bss_plt_p): New function.
+ * libebl_ppc64.h: Declare it.
+ * ppc64_init.c (ppc64_init): Use it.
+
+ * ebl_check_special_symbol.c: New file.
+ * Makefile.am (gen_SOURCES): Add it.
+ * libebl.h: Declare ebl_check_special_symbol.
+ * libeblP.h (struct ebl): Add check_special_symbol hook.
+ * eblopenbackend.c (default_check_special_symbol): New function.
+ (fill_defaults): Use it.
+ * ppc_symbol.c (ppc_check_special_symbol): New function.
+ * libebl_ppc.h: Add prototype.
+ * ppc_init.c (ppc_init): Use it.
+ * ppc64_symbol.c (ppc64_check_special_symbol): New function.
+ * libebl_ppc64.h: Add prototype.
+ * ppc64_init.c (ppc64_init): Use it.
+
2005-08-07 Ulrich Drepper <drepper@redhat.com>
* ppc_init.c: Add support for new DT_PPC_* and R_PPC_* values.
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index eeac7e54..ead129bd 100644
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -48,7 +48,8 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \
ebldynamictagcheck.c eblcorenotetypename.c eblobjnotetypename.c \
eblcorenote.c eblobjnote.c ebldebugscnp.c \
eblgotpcreloccheck.c eblcopyrelocp.c eblsectionstripp.c \
- eblelfclass.c eblelfdata.c eblelfmachine.c
+ eblelfclass.c eblelfdata.c eblelfmachine.c \
+ ebl_check_special_symbol.c eblbsspltp.c
libebl_a_SOURCES = $(gen_SOURCES)
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index a104d737..f3ae7ab1 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -153,6 +153,11 @@ static bool default_object_note (const char *name, uint32_t type,
uint32_t descsz, const char *desc);
static bool default_debugscn_p (const char *name);
static bool default_copy_reloc_p (int reloc);
+static bool default_check_special_symbol (Elf *elf,
+ const GElf_Sym *sym,
+ const char *name,
+ const GElf_Shdr *destshdr);
+static bool default_bss_plt_p (Elf *elf);
static void
@@ -181,6 +186,8 @@ fill_defaults (Ebl *result)
result->object_note = default_object_note;
result->debugscn_p = default_debugscn_p;
result->copy_reloc_p = default_copy_reloc_p;
+ result->check_special_symbol = default_check_special_symbol;
+ result->bss_plt_p = default_bss_plt_p;
result->destr = default_destr;
}
@@ -553,3 +560,18 @@ default_copy_reloc_p (int reloc __attribute__ ((unused)))
{
return false;
}
+
+static bool
+default_check_special_symbol (Elf *elf __attribute__ ((unused)),
+ const GElf_Sym *sym __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ const GElf_Shdr *destshdr __attribute__ ((unused)))
+{
+ return false;
+}
+
+static bool
+default_bss_plt_p (Elf *elf __attribute__ ((unused)))
+{
+ return false;
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index a59d4dd4..46373441 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -112,6 +112,12 @@ extern const char *ebl_dynamic_tag_name (Ebl *ebl, int64_t tag,
/* Check dynamic tag. */
extern bool ebl_dynamic_tag_check (Ebl *ebl, int64_t tag);
+/* Check whether given symbol's st_value and st_size are OK despite failing
+ normal checks. */
+extern bool ebl_check_special_symbol (Ebl *ebl,
+ const GElf_Sym *sym, const char *name,
+ const GElf_Shdr *destshdr);
+
/* Return combined section header flags value. */
extern GElf_Word ebl_sh_flags_combine (Ebl *ebl, GElf_Word flags1,
GElf_Word flags2);
@@ -142,12 +148,14 @@ extern bool ebl_debugscn_p (Ebl *ebl, const char *name);
/* Check whether given relocation is a copy relocation. */
extern bool ebl_copy_reloc_p (Ebl *ebl, int reloc);
-
-/* CHeck whether section should be stripped. */
+/* Check whether section should be stripped. */
extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr,
const GElf_Shdr *shdr, const char *name,
bool remove_comment, bool only_remove_debug);
+/* Check if backend uses a bss PLT in this file. */
+extern bool ebl_bss_plt_p (Ebl *ebl);
+
/* ELF string table handling. */
struct Ebl_Strtab;
diff --git a/libebl/libeblP.h b/libebl/libeblP.h
index 9d47e8c4..adf51913 100644
--- a/libebl/libeblP.h
+++ b/libebl/libeblP.h
@@ -105,6 +105,14 @@ struct ebl
/* Check whether given relocation is a copy relocation. */
bool (*copy_reloc_p) (int);
+ /* Check whether given symbol's value is ok despite normal checks. */
+ bool (*check_special_symbol) (Elf *elf,
+ const GElf_Sym *sym, const char *name,
+ const GElf_Shdr *destshdr);
+
+ /* Check if backend uses a bss PLT in this file. */
+ bool (*bss_plt_p) (Elf *elf);
+
/* Destructor for ELF backend handle. */
void (*destr) (struct ebl *);
diff --git a/libebl/libebl_ppc.h b/libebl/libebl_ppc.h
index e3c6d21c..03df06db 100644
--- a/libebl/libebl_ppc.h
+++ b/libebl/libebl_ppc.h
@@ -50,4 +50,14 @@ extern bool ppc_dynamic_tag_check (int64_t tag);
/* Check whether given relocation is a copy relocation. */
extern bool ppc_copy_reloc_p (int reloc);
+/* Check whether given symbol's st_value and st_size are OK despite normal
+ checks. */
+extern bool ppc_check_special_symbol (Elf *elf,
+ const GElf_Sym *sym, const char *name,
+ const GElf_Shdr *destshdr);
+
+/* Check if backend uses a bss PLT in this file. */
+extern bool ppc_bss_plt_p (Elf *elf);
+
+
#endif /* libebl_ppc.h */
diff --git a/libebl/libebl_ppc64.h b/libebl/libebl_ppc64.h
index 148e2249..d8d445ff 100644
--- a/libebl/libebl_ppc64.h
+++ b/libebl/libebl_ppc64.h
@@ -50,4 +50,14 @@ extern bool ppc64_dynamic_tag_check (int64_t tag);
/* Check whether given relocation is a copy relocation. */
extern bool ppc64_copy_reloc_p (int reloc);
+/* Check whether given symbol's st_value and st_size are OK despite normal
+ checks. */
+extern bool ppc64_check_special_symbol (Elf *elf,
+ const GElf_Sym *sym, const char *name,
+ const GElf_Shdr *destshdr);
+
+/* Check if backend uses a bss PLT in this file. */
+extern bool ppc64_bss_plt_p (Elf *elf);
+
+
#endif /* libebl_ppc.h */
diff --git a/libebl/ppc64_init.c b/libebl/ppc64_init.c
index 347444c0..c8235bb1 100644
--- a/libebl/ppc64_init.c
+++ b/libebl/ppc64_init.c
@@ -39,6 +39,8 @@ ppc64_init (elf, machine, eh, ehlen)
eh->dynamic_tag_name = ppc64_dynamic_tag_name;
eh->dynamic_tag_check = ppc64_dynamic_tag_check;
eh->copy_reloc_p = ppc64_copy_reloc_p;
+ eh->check_special_symbol = ppc64_check_special_symbol;
+ eh->bss_plt_p = ppc64_bss_plt_p;
eh->destr = ppc64_destr;
return MODVERSION;
diff --git a/libebl/ppc64_symbol.c b/libebl/ppc64_symbol.c
index 457e84e6..ef0f5f70 100644
--- a/libebl/ppc64_symbol.c
+++ b/libebl/ppc64_symbol.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include <elf.h>
#include <stddef.h>
+#include <string.h>
#include <libebl_ppc64.h>
@@ -242,3 +243,28 @@ ppc64_copy_reloc_p (int reloc)
{
return reloc == R_PPC64_COPY;
}
+
+
+/* Check whether given symbol's st_size is ok despite normal check failing. */
+bool
+ppc64_check_special_symbol (Elf *elf,
+ const GElf_Sym *sym __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ const GElf_Shdr *destshdr)
+{
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return false;
+ const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name);
+ if (sname == NULL)
+ return false;
+ return !strcmp (sname, ".opd");
+}
+
+/* Check if backend uses a bss PLT in this file. */
+bool
+ppc64_bss_plt_p (Elf *elf __attribute__ ((unused)))
+{
+ return true;
+}
diff --git a/libebl/ppc_init.c b/libebl/ppc_init.c
index dca780b5..d76b1b13 100644
--- a/libebl/ppc_init.c
+++ b/libebl/ppc_init.c
@@ -39,6 +39,8 @@ ppc_init (elf, machine, eh, ehlen)
eh->dynamic_tag_name = ppc_dynamic_tag_name;
eh->dynamic_tag_check = ppc_dynamic_tag_check;
eh->copy_reloc_p = ppc_copy_reloc_p;
+ eh->check_special_symbol = ppc_check_special_symbol;
+ eh->bss_plt_p = ppc_bss_plt_p;
eh->destr = ppc_destr;
return MODVERSION;
diff --git a/libebl/ppc_symbol.c b/libebl/ppc_symbol.c
index e865eaab..8afabba2 100644
--- a/libebl/ppc_symbol.c
+++ b/libebl/ppc_symbol.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include <elf.h>
#include <stddef.h>
+#include <string.h>
#include <libebl_ppc.h>
@@ -201,3 +202,68 @@ ppc_copy_reloc_p (int reloc)
{
return reloc == R_PPC_COPY;
}
+
+/* Check whether given symbol's value is ok despite failing normal checks. */
+bool
+ppc_check_special_symbol (Elf *elf,
+ const GElf_Sym *sym,
+ const char *name,
+ const GElf_Shdr *destshdr)
+{
+ if (name == NULL)
+ return false;
+
+ if (!strcmp (name, "_GLOBAL_OFFSET_TABLE_"))
+ {
+ return sym->st_value == destshdr->sh_addr + 4;
+ }
+
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return false;
+ const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name);
+ if (sname == NULL)
+ return false;
+
+ if (!strcmp (name, "_SDA_BASE_"))
+ return (!strcmp (sname, ".sdata")
+ && sym->st_value == destshdr->sh_addr + 0x8000
+ && sym->st_size == 0);
+
+ if (!strcmp (name, "_SDA2_BASE_"))
+ return (!strcmp (sname, ".sdata2")
+ && sym->st_value == destshdr->sh_addr + 0x8000
+ && sym->st_size == 0);
+
+ return false;
+}
+
+/* Check if backend uses a bss PLT in this file. */
+bool
+ppc_bss_plt_p (Elf *elf)
+{
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
+ {
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ break;
+ for (unsigned int i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
+ {
+ GElf_Dyn dyn_mem;
+ GElf_Dyn *dyn = gelf_getdyn (data, i, &dyn_mem);
+ if (dyn == NULL)
+ break;
+ if (dyn->d_tag == DT_PPC_GOT)
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/src/ChangeLog b/src/ChangeLog
index 7aae3f98..e3535884 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,18 @@
+2005-08-12 Roland McGrath <roland@redhat.com>
+
+ * elflint.c (check_symtab): Check that _GLOBAL_OFFSET_TABLE_ st_shndx
+ refers to the right section if it's not SHN_ABS.
+ Let ebl_check_special_symbol override _G_O_T_ value and size checks.
+
+ * elflint.c (check_sections): Don't complain about a non-NOBITS
+ section taking no segment space, if it's sh_size is 0.
+
+ * elflint.c (check_sections): Use ebl_bss_plt_p to see if .plt should
+ be PROGBITS or NOBITS.
+
+ * elflint.c (check_symtab): Use ebl_check_special_symbol to override
+ standard st_value and st_size checks.
+
2005-07-28 Roland McGrath <roland@redhat.com>
* addr2line.c (options, parse_opt): Don't handle -e here.
diff --git a/src/elflint.c b/src/elflint.c
index ecf6a723..73a4061a 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -713,12 +713,16 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
{
if (GELF_ST_TYPE (sym->st_info) != STT_TLS)
{
- if ((sym->st_value - destshdr->sh_addr) > destshdr->sh_size)
+ bool special = ebl_check_special_symbol (ebl, sym, name,
+ destshdr);
+ if ((sym->st_value - destshdr->sh_addr) > destshdr->sh_size
+ && !special)
ERROR (gettext ("\
section [%2d] '%s': symbol %zu: st_value out of bounds\n"),
idx, section_name (ebl, idx), cnt);
else if ((sym->st_value - destshdr->sh_addr + sym->st_size)
- > destshdr->sh_size)
+ > destshdr->sh_size
+ && !special)
ERROR (gettext ("\
section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
idx, section_name (ebl, idx), cnt,
@@ -821,59 +825,79 @@ section [%2d] '%s': symbol %zu: non-local section symbol\n"),
{
if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
{
- /* Check that address and size match the global offset
- table. We have to locate the GOT by searching for a
- section named ".got". */
- Elf_Scn *gscn = NULL;
- GElf_Addr addr = 0;
- GElf_Xword size = 0;
- bool found = false;
-
- while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL)
+ /* Check that address and size match the global offset table. */
+
+ GElf_Shdr destshdr_mem;
+ GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx),
+ &destshdr_mem);
+
+ if (destshdr == NULL && xndx == SHN_ABS)
{
- GElf_Shdr gshdr_mem;
- GElf_Shdr *gshdr = gelf_getshdr (gscn, &gshdr_mem);
- assert (gshdr != NULL);
+ /* In a DSO, we have to find the GOT section by name. */
- const char *sname = elf_strptr (ebl->elf, ehdr->e_shstrndx,
- gshdr->sh_name);
- if (sname != NULL)
+ Elf_Scn *gscn = NULL;
+
+ Elf_Scn *gotscn = NULL;
+ while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL)
{
- if (strcmp (sname, ".got.plt") == 0)
- {
- addr = gshdr->sh_addr;
- size = gshdr->sh_size;
- found = true;
- break;
- }
- if (strcmp (sname, ".got") == 0)
+ destshdr = gelf_getshdr (gscn, &destshdr_mem);
+ assert (destshdr != NULL);
+ const char *sname = elf_strptr (ebl->elf,
+ ehdr->e_shstrndx,
+ destshdr->sh_name);
+ if (sname != NULL)
{
- addr = gshdr->sh_addr;
- size = gshdr->sh_size;
- found = true;
- /* Do not stop looking. There might be a
- .got.plt section. */
+ if (!strcmp (sname, ".got.plt"))
+ break;
+ if (!strcmp (sname, ".got"))
+ /* Do not stop looking.
+ There might be a .got.plt section. */
+ gotscn = gscn;
}
+
+ destshdr = NULL;
}
+
+ if (destshdr == NULL && gotscn != NULL)
+ destshdr = gelf_getshdr (gotscn, &destshdr_mem);
}
- if (found)
+ const char *sname = (destshdr == NULL ? NULL
+ : elf_strptr (ebl->elf, ehdr->e_shstrndx,
+ destshdr->sh_name));
+ if (sname == NULL)
+ ERROR (gettext ("\
+section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to bad section\n"),
+ idx, section_name (ebl, idx));
+ else if (strcmp (sname, ".got.plt") != 0
+ && strcmp (sname, ".got") != 0)
+ ERROR (gettext ("\
+section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to '%s' section\n"),
+ idx, section_name (ebl, idx), sname);
+
+ if (destshdr != NULL)
{
/* Found it. */
- if (sym->st_value != addr)
+
+ bool special = ebl_check_special_symbol (ebl, sym, name,
+ destshdr);
+
+ if (sym->st_value != destshdr->sh_addr && !special)
/* This test is more strict than the psABIs which
usually allow the symbol to be in the middle of
the .got section, allowing negative offsets. */
ERROR (gettext ("\
-section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match .got section address %#" PRIx64 "\n"),
+section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match %s section address %#" PRIx64 "\n"),
idx, section_name (ebl, idx),
- (uint64_t) sym->st_value, (uint64_t) addr);
+ (uint64_t) sym->st_value,
+ sname, (uint64_t) destshdr->sh_addr);
- if (!gnuld && sym->st_size != size)
+ if (!gnuld && sym->st_size != destshdr->sh_size && !special)
ERROR (gettext ("\
-section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match .got section size %" PRIu64 "\n"),
+section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match %s section size %" PRIu64 "\n"),
idx, section_name (ebl, idx),
- (uint64_t) sym->st_size, (uint64_t) size);
+ (uint64_t) sym->st_size,
+ sname, (uint64_t) destshdr->sh_size);
}
else
ERROR (gettext ("\
@@ -2562,7 +2586,13 @@ cannot get section header for section [%2zu] '%s': %s\n"),
char stbuf2[100];
char stbuf3[100];
- if (shdr->sh_type != special_sections[s].type
+ GElf_Word good_type = special_sections[s].type;
+ if (special_sections[s].namelen == sizeof ".plt" &&
+ !memcmp (special_sections[s].name, ".plt", sizeof ".plt")
+ && ebl_bss_plt_p (ebl))
+ good_type = SHT_NOBITS;
+
+ if (shdr->sh_type != good_type
&& !(is_debuginfo && shdr->sh_type == SHT_NOBITS))
ERROR (gettext ("\
section [%2d] '%s' has wrong type: expected %s, is %s\n"),
@@ -2759,7 +2789,9 @@ section [%2zu] '%s' has type NOBITS but is read from the file in segment of prog
}
else
{
- if (shdr->sh_offset >= phdr->p_offset + phdr->p_filesz)
+ const GElf_Off end = phdr->p_offset + phdr->p_filesz;
+ if (shdr->sh_offset > end ||
+ (shdr->sh_offset == end && shdr->sh_size != 0))
ERROR (gettext ("\
section [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"),
cnt, section_name (ebl, cnt), pcnt);