libebl/
authorRoland McGrath <roland@redhat.com>
Sat, 13 Aug 2005 01:59:10 +0000 (01:59 +0000)
committerRoland McGrath <roland@redhat.com>
Sat, 13 Aug 2005 01:59:10 +0000 (01:59 +0000)
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.

src/
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.

13 files changed:
libebl/ChangeLog
libebl/Makefile.am
libebl/eblopenbackend.c
libebl/libebl.h
libebl/libeblP.h
libebl/libebl_ppc.h
libebl/libebl_ppc64.h
libebl/ppc64_init.c
libebl/ppc64_symbol.c
libebl/ppc_init.c
libebl/ppc_symbol.c
src/ChangeLog
src/elflint.c

index 5553cc4..68ec221 100644 (file)
@@ -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.
index eeac7e5..ead129b 100644 (file)
@@ -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)
 
index a104d73..f3ae7ab 100644 (file)
@@ -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;
+}
index a59d4dd..4637344 100644 (file)
@@ -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;
index 9d47e8c..adf5191 100644 (file)
@@ -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 *);
 
index e3c6d21..03df06d 100644 (file)
@@ -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 */
index 148e224..d8d445f 100644 (file)
@@ -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 */
index 347444c..c8235bb 100644 (file)
@@ -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;
index 457e84e..ef0f5f7 100644 (file)
@@ -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;
+}
index dca780b..d76b1b1 100644 (file)
@@ -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;
index e865eaa..8afabba 100644 (file)
@@ -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;
+}
index 7aae3f9..e353588 100644 (file)
@@ -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.
index ecf6a72..73a4061 100644 (file)
@@ -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);