PowerPC32 treatment of absolute symbols
authorAlan Modra <amodra@gmail.com>
Wed, 30 Mar 2022 21:11:03 +0000 (07:41 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 4 May 2022 05:11:56 +0000 (14:41 +0930)
As already done for PowerPC64, fix dynamic relocs for absolute symbols.
The patch also tidies the dynamic reloc handling code in check_relocs,
removing leftover comments and code from when check_relocs was called
as each object file was read in.

bfd/
* elf32-ppc.c (ppc_elf_check_relocs): Set isym and ifunc earlier.
Rearrange tests for dynamic relocs, handling absolute symbols.
(allocate_dynrelocs): Don't allocate dynamic relocs for locally
defined absolute symbols.
(ppc_elf_size_dynamic_sections): Similarly.
(ppc_elf_relocate_section): Similarly.
ld/
* testsuite/ld-powerpc/abs32-pie.d,
* testsuite/ld-powerpc/abs32-pie.r,
* testsuite/ld-powerpc/abs32-reloc.s,
* testsuite/ld-powerpc/abs32-shared.d,
* testsuite/ld-powerpc/abs32-shared.r,
* testsuite/ld-powerpc/abs32-static.d,
* testsuite/ld-powerpc/abs32-static.r: New tests.
* testsuite/ld-powerpc/powerpc.exp: Run them.

bfd/elf32-ppc.c
ld/testsuite/ld-powerpc/abs32-pie.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/abs32-pie.r [new file with mode: 0644]
ld/testsuite/ld-powerpc/abs32-reloc.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/abs32-shared.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/abs32-shared.r [new file with mode: 0644]
ld/testsuite/ld-powerpc/abs32-static.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/abs32-static.r [new file with mode: 0644]
ld/testsuite/ld-powerpc/powerpc.exp

index 42273ca06fe740fa82e3b6d3143f6632b50b7a60..6dbb69013aa4487d52098ceced93775868b674b3 100644 (file)
@@ -2929,6 +2929,7 @@ ppc_elf_check_relocs (bfd *abfd,
       unsigned long r_symndx;
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *isym;
       int tls_type;
       struct plt_entry **ifunc;
       struct plt_entry **pltent;
@@ -2936,13 +2937,19 @@ ppc_elf_check_relocs (bfd *abfd,
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
-       h = NULL;
+       {
+         h = NULL;
+         isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx);
+         if (isym == NULL)
+           return false;
+       }
       else
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
+         isym = NULL;
        }
 
       /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
@@ -2962,13 +2969,16 @@ ppc_elf_check_relocs (bfd *abfd,
       tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
       ifunc = NULL;
-      if (h == NULL && htab->elf.target_os != is_vxworks)
+      if (h != NULL)
+       {
+         if (h->type == STT_GNU_IFUNC)
+           {
+             h->needs_plt = 1;
+             ifunc = &h->plt.plist;
+           }
+       }
+      else if (htab->elf.target_os != is_vxworks)
        {
-         Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
-                                                         abfd, r_symndx);
-         if (isym == NULL)
-           return false;
-
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
              /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
@@ -3294,12 +3304,10 @@ ppc_elf_check_relocs (bfd *abfd,
              htab->plt_type = PLT_OLD;
              htab->old_bfd = abfd;
            }
-         if (h != NULL && h->type == STT_GNU_IFUNC)
-           {
-             h->needs_plt = 1;
-             if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
-               return false;
-           }
+         if (h != NULL
+             && ifunc != NULL
+             && !update_plt_info (abfd, ifunc, NULL, 0))
+           return false;
          break;
 
          /* This relocation describes the C++ object vtable hierarchy.
@@ -3347,12 +3355,6 @@ ppc_elf_check_relocs (bfd *abfd,
                 reliably deduce the GOT pointer value needed for
                 PLT call stubs.  */
              asection *s;
-             Elf_Internal_Sym *isym;
-
-             isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
-                                           abfd, r_symndx);
-             if (isym == NULL)
-               return false;
 
              s = bfd_section_from_elf_index (abfd, isym->st_shndx);
              if (s == got2)
@@ -3421,38 +3423,21 @@ ppc_elf_check_relocs (bfd *abfd,
            }
 
        dodyn:
-         /* If we are creating a shared library, and this is a reloc
-            against a global symbol, or a non PC relative reloc
-            against a local symbol, then we need to copy the reloc
-            into the shared library.  However, if we are linking with
-            -Bsymbolic, we do not need to copy a reloc against a
-            global symbol which is defined in an object we are
-            including in the link (i.e., DEF_REGULAR is set).  At
-            this point we have not seen all the input files, so it is
-            possible that DEF_REGULAR is not set now but will be set
-            later (it is never cleared).  In case of a weak definition,
-            DEF_REGULAR may be cleared later by a strong definition in
-            a shared library.  We account for that possibility below by
-            storing information in the dyn_relocs field of the hash
-            table entry.  A similar situation occurs when creating
-            shared libraries and symbol visibility changes render the
-            symbol local.
-
-            If on the other hand, we are creating an executable, we
-            may need to keep relocations for symbols satisfied by a
-            dynamic library if we manage to avoid copy relocs for the
-            symbol.  */
-         if ((bfd_link_pic (info)
-              && (must_be_dyn_reloc (info, r_type)
-                  || (h != NULL
-                      && (!SYMBOLIC_BIND (info, h)
-                          || h->root.type == bfd_link_hash_defweak
-                          || !h->def_regular))))
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular)))
+         /* Set up information for symbols that might need dynamic
+            relocations.  At this point in linking we have read all
+            the input files and resolved most symbols, but have not
+            yet decided whether symbols are dynamic or finalized
+            symbol flags.  In some cases we might be setting dynamic
+            reloc info for symbols that do not end up needing such.
+            That's OK, adjust_dynamic_symbol and allocate_dynrelocs
+            work together with this code.  */
+         if ((h != NULL
+              && !SYMBOL_REFERENCES_LOCAL (info, h))
+             || (bfd_link_pic (info)
+                 && (h != NULL
+                     ? !bfd_is_abs_symbol (&h->root)
+                     : isym->st_shndx != SHN_ABS)
+                 && must_be_dyn_reloc (info, r_type)))
            {
 #ifdef DEBUG
              fprintf (stderr,
@@ -3507,12 +3492,6 @@ ppc_elf_check_relocs (bfd *abfd,
                  bool is_ifunc;
                  asection *s;
                  void *vpp;
-                 Elf_Internal_Sym *isym;
-
-                 isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
-                                               abfd, r_symndx);
-                 if (isym == NULL)
-                   return false;
 
                  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
                  if (s == NULL)
@@ -3520,7 +3499,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
                  vpp = &elf_section_data (s)->local_dynrel;
                  rel_head = (struct ppc_dyn_relocs **) vpp;
-                 is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
+                 is_ifunc = ifunc != NULL;
                  p = *rel_head;
                  if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
                    p = p->next;
@@ -5170,7 +5149,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
          if (((bfd_link_pic (info)
                && !((eh->tls_mask & TLS_TLS) != 0
                     && bfd_link_executable (info)
-                    && SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
+                    && SYMBOL_REFERENCES_LOCAL (info, &eh->elf))
+               && !bfd_is_abs_symbol (&h->root))
               || (htab->elf.dynamic_sections_created
                   && eh->elf.dynindx != -1
                   && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
@@ -5540,6 +5520,8 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      Elf_Internal_Sym *isym;
 
       if (!is_ppc_elf (ibfd))
        continue;
@@ -5596,8 +5578,18 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       local_plt = (struct plt_entry **) end_local_got;
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (char *) end_local_plt;
+      local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (local_syms == NULL && locsymcount != 0)
+       {
+         local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+                                            0, NULL, NULL, NULL);
+         if (local_syms == NULL)
+           return false;
+       }
 
-      for (; local_got < end_local_got; ++local_got, ++lgot_masks)
+      for (isym = local_syms;
+          local_got < end_local_got;
+          ++local_got, ++lgot_masks, ++isym)
        if (*local_got > 0)
          {
            unsigned int need;
@@ -5611,7 +5603,8 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                *local_got = allocate_got (htab, need);
                if (bfd_link_pic (info)
                    && !((*lgot_masks & TLS_TLS) != 0
-                        && bfd_link_executable (info)))
+                        && bfd_link_executable (info))
+                   && isym->st_shndx != SHN_ABS)
                  {
                    asection *srel;
 
@@ -5684,6 +5677,15 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
            else
              ent->plt.offset = (bfd_vma) -1;
        }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
     }
 
   /* Allocate space for global sym dynamic relocs.  */
@@ -7796,7 +7798,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
                            && !(tls_ty != 0
                                 && bfd_link_executable (info)
-                                && SYMBOL_REFERENCES_LOCAL (info, h))))
+                                && SYMBOL_REFERENCES_LOCAL (info, h))
+                           && (h != NULL
+                               ? !bfd_is_abs_symbol (&h->root)
+                               : sym->st_shndx != SHN_ABS)))
                      {
                        asection *rsec = htab->elf.srelgot;
                        bfd_byte * loc;
diff --git a/ld/testsuite/ld-powerpc/abs32-pie.d b/ld/testsuite/ld-powerpc/abs32-pie.d
new file mode 100644 (file)
index 0000000..7f99121
--- /dev/null
@@ -0,0 +1,26 @@
+#source: abs32-reloc.s
+#as: -a32
+#ld: -melf32ppc -pie --hash-style=sysv --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678
+#objdump: -dr
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+00000138 <_start>:
+ 138:  (80 fe ff f0|f0 ff fe 80)       lwz     r7,-16\(r30\)
+ 13c:  (81 1e ff f8|f8 ff 1e 81)       lwz     r8,-8\(r30\)
+ 140:  (81 3e ff ec|ec ff 3e 81)       lwz     r9,-20\(r30\)
+ 144:  (81 5e ff f4|f4 ff 5e 81)       lwz     r10,-12\(r30\)
+
+Disassembly of section \.got:
+
+000101d8 <\.got>:
+   101d8:      (00 00 00 02|02 00 00 00)       .*
+   101dc:      (00 00 00 00|00 00 00 00)       .*
+   101e0:      (12 34 56 78|78 56 34 12)       .*
+   101e4:      (00 00 00 01|01 00 00 00)       .*
+   101e8:      (4e 80 00 21|21 00 80 4e)       blrl
+
+000101ec <_GLOBAL_OFFSET_TABLE_>:
+   101ec:      (00 01 01 48|48 01 01 00) 00 00 00 00 00 00 00 00 .*
diff --git a/ld/testsuite/ld-powerpc/abs32-pie.r b/ld/testsuite/ld-powerpc/abs32-pie.r
new file mode 100644 (file)
index 0000000..6a45fbf
--- /dev/null
@@ -0,0 +1,9 @@
+#source: abs32-reloc.s
+#as: -a32
+#ld: -melf32ppc -pie --hash-style=sysv --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678
+#readelf: -rW
+
+Relocation section '\.rela\.dyn' at offset .* contains 2 entries:
+ Offset     Info    Type                Sym\. Value  Symbol's Name \+ Addend
+000101c8  00000016 R_PPC_RELATIVE                    101c8
+000101dc  00000016 R_PPC_RELATIVE                    101c8
diff --git a/ld/testsuite/ld-powerpc/abs32-reloc.s b/ld/testsuite/ld-powerpc/abs32-reloc.s
new file mode 100644 (file)
index 0000000..70776c8
--- /dev/null
@@ -0,0 +1,22 @@
+ .globl x
+ .hidden x
+
+ .data
+ .p2align 2
+x:
+ .long x
+ .long a
+ .long b
+ .long c
+
+ .text
+ .p2align 2
+ .globl _start
+ .type _start,@function
+_start:
+0:
+ lwz 7,x@got(30)
+ lwz 8,a@got(30)
+ lwz 9,b@got(30)
+ lwz 10,c@got(30)
+ .size _start,.-_start
diff --git a/ld/testsuite/ld-powerpc/abs32-shared.d b/ld/testsuite/ld-powerpc/abs32-shared.d
new file mode 100644 (file)
index 0000000..a08930b
--- /dev/null
@@ -0,0 +1,24 @@
+#source: abs32-reloc.s
+#as: -a32
+#ld: -melf32ppc -shared --hash-style=sysv --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678
+#objdump: -dr
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+00000160 <_start>:
+ 160:  (80 fe ff f0|f0 ff fe 80)       lwz     r7,-16\(r30\)
+ 164:  (81 1e ff f8|f8 ff 1e 81)       lwz     r8,-8\(r30\)
+ 168:  (81 3e ff ec|ec ff 3e 81)       lwz     r9,-20\(r30\)
+ 16c:  (81 5e ff f4|f4 ff 5e 81)       lwz     r10,-12\(r30\)
+
+Disassembly of section \.got:
+
+000101f0 <\.got>:
+   101f0:      (00 00 00 02|02 00 00 00)       .*
+       .\.\.
+   10200:      (4e 80 00 21|21 00 80 4e)       blrl
+
+00010204 <_GLOBAL_OFFSET_TABLE_>:
+   10204:      (00 01 01 70|70 01 01 00) 00 00 00 00 00 00 00 00 .*
diff --git a/ld/testsuite/ld-powerpc/abs32-shared.r b/ld/testsuite/ld-powerpc/abs32-shared.r
new file mode 100644 (file)
index 0000000..d0cd80f
--- /dev/null
@@ -0,0 +1,13 @@
+#source: abs32-reloc.s
+#as: -a32
+#ld: -melf32ppc -shared --hash-style=sysv --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678
+#readelf: -rW
+
+Relocation section '\.rela\.dyn' at offset .* contains 6 entries:
+ Offset     Info    Type                Sym\. Value  Symbol's Name \+ Addend
+000101e0  00000016 R_PPC_RELATIVE                    101e0
+000101f4  00000016 R_PPC_RELATIVE                    101e0
+000101e4  00000401 R_PPC_ADDR32           00000001   a \+ 0
+000101fc  00000414 R_PPC_GLOB_DAT         00000001   a \+ 0
+000101ec  00000301 R_PPC_ADDR32           12345678   c \+ 0
+000101f8  00000314 R_PPC_GLOB_DAT         12345678   c \+ 0
diff --git a/ld/testsuite/ld-powerpc/abs32-static.d b/ld/testsuite/ld-powerpc/abs32-static.d
new file mode 100644 (file)
index 0000000..f37f104
--- /dev/null
@@ -0,0 +1,26 @@
+#source: abs32-reloc.s
+#as: -a32
+#ld: -melf32ppc -static --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678
+#objdump: -dr
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+01800074 <_start>:
+ 1800074:      (80 fe ff f0|f0 ff fe 80)       lwz     r7,-16\(r30\)
+ 1800078:      (81 1e ff f8|f8 ff 1e 81)       lwz     r8,-8\(r30\)
+ 180007c:      (81 3e ff ec|ec ff 3e 81)       lwz     r9,-20\(r30\)
+ 1800080:      (81 5e ff f4|f4 ff 5e 81)       lwz     r10,-12\(r30\)
+
+Disassembly of section \.got:
+
+01810094 <\.got>:
+ 1810094:      (00 00 00 02|02 00 00 00)       .*
+ 1810098:      (01 81 00 84|84 00 81 01)       .*
+ 181009c:      (12 34 56 78|78 56 34 12)       .*
+ 18100a0:      (00 00 00 01|01 00 00 00)       .*
+ 18100a4:      (4e 80 00 21|21 00 80 4e)       blrl
+
+018100a8 <_GLOBAL_OFFSET_TABLE_>:
+       \.\.\.
diff --git a/ld/testsuite/ld-powerpc/abs32-static.r b/ld/testsuite/ld-powerpc/abs32-static.r
new file mode 100644 (file)
index 0000000..3eca877
--- /dev/null
@@ -0,0 +1,6 @@
+#source: abs32-reloc.s
+#as: -a32
+#ld: -melf32ppc -static --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678
+#readelf: -rW
+
+There are no relocations in this file.
index 9eff14fc89f0ee91e2150c4752b0c11c42f77225..1c7a378aebc6b4bcafd680ab8baba2bfa508840b 100644 (file)
@@ -173,6 +173,18 @@ set ppcelftests {
      {{objdump -dr relaxrl.d}}
      "rrelax"}
     {"build empty shared library" "-shared" "" "" "empty.s" {} "empty.so"}
+    {"abs32-static" "-melf32ppc -static --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678" ""
+       "-a32" {abs32-reloc.s}
+       {{objdump {-dr} abs32-static.d}
+        {readelf {-rW} abs32-static.r}} "abs32-static"}
+    {"abs32-pie" "-melf32ppc -pie --hash-style=sysv --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678" ""
+       "-a32" {abs32-reloc.s}
+       {{objdump {-dr} abs32-pie.d}
+        {readelf {-rW} abs32-pie.r}} "abs32-pie"}
+    {"abs32-shared" "-melf32ppc -shared --hash-style=sysv --defsym a=1 --defsym 'HIDDEN(b=2)' --defsym c=0x12345678" ""
+       "-a32" {abs32-reloc.s}
+       {{objdump {-dr} abs32-shared.d}
+        {readelf {-rW} abs32-shared.r}} "abs32-shared"}
 }
 
 set ppc64elftests {