Add support for IRELATIVE relocations.
authorUlrich Drepper <drepper@redhat.com>
Mon, 1 Jun 2009 14:38:32 +0000 (07:38 -0700)
committerUlrich Drepper <drepper@redhat.com>
Mon, 1 Jun 2009 14:38:32 +0000 (07:38 -0700)
That's the second part of the IFUNC support.  So far x86 and x86-64
only.

backends/ChangeLog
backends/i386_reloc.def
backends/x86_64_reloc.def
libelf/ChangeLog
libelf/elf.h
src/ChangeLog
src/readelf.c

index c764f9e..a1aa351 100644 (file)
@@ -1,3 +1,8 @@
+2009-06-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * i386_reloc.def: Add IRELATIVE entry.
+       * x86_64_reloc.def: Likewise.
+
 2009-04-16  Roland McGrath  <roland@redhat.com>
 
        * arm_regs.c (arm_register_info): Handle VFP registers.
index bc1b835..1befd1b 100644 (file)
@@ -1,5 +1,5 @@
 /* List the relocation types for i386. -*- C -*-
-   Copyright (C) 2000, 2001, 2002, 2003, 2005 Red Hat, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2005, 2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -64,3 +64,4 @@ RELOC_TYPE (TLS_TPOFF32,      EXEC|DYN)
 RELOC_TYPE (TLS_GOTDESC,       REL)
 RELOC_TYPE (TLS_DESC_CALL,     REL)
 RELOC_TYPE (TLS_DESC,          EXEC)
+RELOC_TYPE (IRELATIVE,         EXEC|DYN)
index e6c5a84..5d70f47 100644 (file)
@@ -1,5 +1,5 @@
 /* List the relocation types for x86-64.  -*- C -*-
-   Copyright (C) 2000, 2001, 2002, 2003, 2005 Red Hat, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2005, 2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -49,3 +49,4 @@ RELOC_TYPE (TLSLD,    REL)
 RELOC_TYPE (DTPOFF32,  REL)
 RELOC_TYPE (GOTTPOFF,  REL)
 RELOC_TYPE (TPOFF32,   REL)
+RELOC_TYPE (IRELATIVE, EXEC|DYN)
index bfc3ee5..2fd5381 100644 (file)
@@ -1,3 +1,7 @@
+2009-06-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf.h: Update from glibc.
+
 2009-04-14  Roland McGrath  <roland@redhat.com>
 
        * elf.h: Update from glibc.
index 062ef00..8fdf74b 100644 (file)
@@ -1177,8 +1177,9 @@ typedef struct
                                           pointer to code and to
                                           argument, returning the TLS
                                           offset for the symbol.  */
+#define R_386_IRELATIVE           42           /* Adjust indirectly by program base */
 /* Keep this the last entry.  */
-#define R_386_NUM         42
+#define R_386_NUM         43
 
 /* SUN SPARC specific definitions.  */
 
@@ -2625,8 +2626,9 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_X86_64_TLSDESC_CALL   35     /* Marker for call through TLS
                                           descriptor.  */
 #define R_X86_64_TLSDESC        36     /* TLS descriptor.  */
+#define R_X86_64_IRELATIVE     37      /* Adjust indirectly by program base */
 
-#define R_X86_64_NUM           37
+#define R_X86_64_NUM           38
 
 
 /* AM33 relocations.  */
index f6fd86f..01a2414 100644 (file)
@@ -1,3 +1,11 @@
+2009-06-01  Ulrich Drepper  <drepper@redhat.com>
+
+       * readelf.c (print_relocs): Expect ELF header argument and pass on
+       to handle_relocs_rel* functions. Adjust caller.
+       (handle_relocs_rel): Add ELF header argument.  Add special case for
+       the IRELATIVE relocations in statically linked executables.
+       (handle_relocs_rela): Likewise.
+
 2009-04-29  Ulrich Drepper  <drepper@redhat.com>
 
        * elflint.c (check_symtab): Add tests of st_other field.
index 1c79065..9ce4604 100644 (file)
@@ -211,9 +211,11 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_scngrp (Ebl *ebl);
 static void print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr);
-static void print_relocs (Ebl *ebl);
-static void handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
-static void handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
+static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+                              GElf_Shdr *shdr);
+static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+                               GElf_Shdr *shdr);
 static void print_symtab (Ebl *ebl, int type);
 static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void print_verinfo (Ebl *ebl);
@@ -652,7 +654,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
   if (print_dynamic_table)
     print_dynamic (ebl, ehdr);
   if (print_relocations)
-    print_relocs (pure_ebl);
+    print_relocs (pure_ebl, ehdr);
   if (print_histogram)
     handle_hash (ebl);
   if (print_symbol_table)
@@ -1449,7 +1451,7 @@ print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr)
 
 /* Print relocations.  */
 static void
-print_relocs (Ebl *ebl)
+print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
 {
   /* Find all relocation sections and handle them.  */
   Elf_Scn *scn = NULL;
@@ -1463,9 +1465,9 @@ print_relocs (Ebl *ebl)
       if (likely (shdr != NULL))
        {
          if (shdr->sh_type == SHT_REL)
-           handle_relocs_rel (ebl, scn, shdr);
+           handle_relocs_rel (ebl, ehdr, scn, shdr);
          else if (shdr->sh_type == SHT_RELA)
-           handle_relocs_rela (ebl, scn, shdr);
+           handle_relocs_rela (ebl, ehdr, scn, shdr);
        }
     }
 }
@@ -1473,7 +1475,7 @@ print_relocs (Ebl *ebl)
 
 /* Handle a relocation section.  */
 static void
-handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
 {
   int class = gelf_getclass (ebl->elf);
   int nentries = shdr->sh_size / shdr->sh_entsize;
@@ -1545,6 +1547,7 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   Offset              Type                 Value               Name\n"),
         stdout);
 
+  int is_statically_linked = 0;
   for (int cnt = 0; cnt < nentries; ++cnt)
     {
       GElf_Rel relmem;
@@ -1558,16 +1561,56 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                                            GELF_R_SYM (rel->r_info),
                                            &symmem, &xndx);
          if (unlikely (sym == NULL))
-           printf ("  %#0*" PRIx64 "  %-20s <%s %ld>\n",
-                   class == ELFCLASS32 ? 10 : 18, rel->r_offset,
-                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
-                   /* Avoid the leading R_ which isn't carrying any
-                      information.  */
-                   ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
-                                          buf, sizeof (buf)) + 2
-                   : gettext ("<INVALID RELOC>"),
-                   gettext ("INVALID SYMBOL"),
-                   (long int) GELF_R_SYM (rel->r_info));
+           {
+             /* As a special case we have to handle relocations in static
+                executables.  This only happens for IRELATIVE relocations
+                (so far).  There is no symbol table.  */
+             if (is_statically_linked == 0)
+               {
+                 /* Find the program header and look for a PT_INTERP entry. */
+                 is_statically_linked = -1;
+                 if (ehdr->e_type == ET_EXEC)
+                   {
+                     is_statically_linked = 1;
+
+                     for (size_t inner = 0; inner < ehdr->e_phnum; ++inner)
+                       {
+                         GElf_Phdr phdr_mem;
+                         GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
+                                                         &phdr_mem);
+                         if (phdr != NULL && phdr->p_type == PT_INTERP)
+                           {
+                             is_statically_linked = -1;
+                             break;
+                           }
+                       }
+                   }
+               }
+
+             if (is_statically_linked > 0 && shdr->sh_link == 0)
+               printf ("\
+  %#0*" PRIx64 "  %-20s %*s  %s\n",
+                       class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       /* Avoid the leading R_ which isn't carrying any
+                          information.  */
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf)) + 2
+                       : gettext ("<INVALID RELOC>"),
+                       class == ELFCLASS32 ? 10 : 18, "",
+                       elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+             else
+               printf ("  %#0*" PRIx64 "  %-20s <%s %ld>\n",
+                       class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       /* Avoid the leading R_ which isn't carrying any
+                          information.  */
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf)) + 2
+                       : gettext ("<INVALID RELOC>"),
+                       gettext ("INVALID SYMBOL"),
+                       (long int) GELF_R_SYM (rel->r_info));
+           }
          else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
            printf ("  %#0*" PRIx64 "  %-20s %#0*" PRIx64 "  %s\n",
                    class == ELFCLASS32 ? 10 : 18, rel->r_offset,
@@ -1618,7 +1661,7 @@ handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
 /* Handle a relocation section.  */
 static void
-handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
 {
   int class = gelf_getclass (ebl->elf);
   int nentries = shdr->sh_size / shdr->sh_entsize;
@@ -1676,6 +1719,7 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
   Offset              Type            Value               Addend Name\n"),
                  stdout);
 
+  int is_statically_linked = 0;
   for (int cnt = 0; cnt < nentries; ++cnt)
     {
       GElf_Rela relmem;
@@ -1690,16 +1734,57 @@ handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
                                            &symmem, &xndx);
 
          if (unlikely (sym == NULL))
-           printf ("  %#0*" PRIx64 "  %-15s <%s %ld>\n",
-                   class == ELFCLASS32 ? 10 : 18, rel->r_offset,
-                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
-                   /* Avoid the leading R_ which isn't carrying any
-                      information.  */
-                   ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
-                                          buf, sizeof (buf)) + 2
-                   : gettext ("<INVALID RELOC>"),
-                   gettext ("INVALID SYMBOL"),
-                   (long int) GELF_R_SYM (rel->r_info));
+           {
+             /* As a special case we have to handle relocations in static
+                executables.  This only happens for IRELATIVE relocations
+                (so far).  There is no symbol table.  */
+             if (is_statically_linked == 0)
+               {
+                 /* Find the program header and look for a PT_INTERP entry. */
+                 is_statically_linked = -1;
+                 if (ehdr->e_type == ET_EXEC)
+                   {
+                     is_statically_linked = 1;
+
+                     for (size_t inner = 0; inner < ehdr->e_phnum; ++inner)
+                       {
+                         GElf_Phdr phdr_mem;
+                         GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
+                                                         &phdr_mem);
+                         if (phdr != NULL && phdr->p_type == PT_INTERP)
+                           {
+                             is_statically_linked = -1;
+                             break;
+                           }
+                       }
+                   }
+               }
+
+             if (is_statically_linked > 0 && shdr->sh_link == 0)
+               printf ("\
+  %#0*" PRIx64 "  %-15s %*s  %#6" PRIx64 " %s\n",
+                       class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       /* Avoid the leading R_ which isn't carrying any
+                          information.  */
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf)) + 2
+                       : gettext ("<INVALID RELOC>"),
+                       class == ELFCLASS32 ? 10 : 18, "",
+                       rel->r_addend,
+                       elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+             else
+               printf ("  %#0*" PRIx64 "  %-15s <%s %ld>\n",
+                       class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       /* Avoid the leading R_ which isn't carrying any
+                          information.  */
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf)) + 2
+                       : gettext ("<INVALID RELOC>"),
+                       gettext ("INVALID SYMBOL"),
+                       (long int) GELF_R_SYM (rel->r_info));
+           }
          else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
            printf ("\
   %#0*" PRIx64 "  %-15s %#0*" PRIx64 "  %+6" PRId64 " %s\n",