ld: don't generate base relocations in PE output for absolute symbols
authorJan Beulich <jbeulich@suse.com>
Thu, 4 Mar 2021 15:55:01 +0000 (16:55 +0100)
committerJan Beulich <jbeulich@suse.com>
Thu, 4 Mar 2021 15:55:01 +0000 (16:55 +0100)
It is the very nature of absolute symbols that they don't change even
if the loader decides to put the image at other than its link-time base
address. Of the linker-defined (and PE-specific) symbols __image_base__
(and its alias) needs special casing, as it'll still appear to be
absolute at this point.

A new inquiry function in ldexp.c is needed because PE base relocations
get generated before ldexp_finalize_syms() runs, yet whether a
relocation is needed depends on the ultimate property of a symbol.

ld/ChangeLog
ld/ldexp.c
ld/ldexp.h
ld/pe-dll.c
ld/testsuite/ld-pe/pe.exp
ld/testsuite/ld-pe/reloc.d [new file with mode: 0644]
ld/testsuite/ld-pe/reloc.s [new file with mode: 0644]

index 0f1da7fafabaaa509bb942fd93c1016d6776c445..95bb3f6c1a8aab29cc45cc861b46c572b79ad1ba 100644 (file)
@@ -1,3 +1,11 @@
+2021-03-04  Jan Beulich  <jbeulich@suse.com>
+
+       * ldexp.c (ldexp_is_final_sym_absolute): New.
+       * ldexp.h (ldexp_is_final_sym_absolute): Declare.
+       * pe-dll.c (generate_reloc): Skip absolute symbols.
+       * testsuite/ld-pe/reloc.s, testsuite/ld-pe/reloc.d: New.
+       * testsuite/ld-pe/pe.exp: Run new test.
+
 2021-03-03  Alan Modra  <amodra@gmail.com>
 
        PR 27500
index 016784505b2b0fad4dc511729f1e52537a39417b..7a95e561a03e203092d9933c9411715660957248 100644 (file)
@@ -1699,6 +1699,28 @@ ldexp_finalize_syms (void)
   bfd_hash_traverse (&definedness_table, set_sym_sections, NULL);
 }
 
+/* Determine whether a symbol is going to remain absolute even after
+   ldexp_finalize_syms() has run.  */
+
+bfd_boolean
+ldexp_is_final_sym_absolute (const struct bfd_link_hash_entry *h)
+{
+  if (h->type == bfd_link_hash_defined
+      && h->u.def.section == bfd_abs_section_ptr)
+    {
+      const struct definedness_hash_entry *def;
+
+      if (!h->ldscript_def)
+       return TRUE;
+
+      def = symbol_defined (h->root.string);
+      if (def != NULL)
+       return def->final_sec == bfd_abs_section_ptr;
+    }
+
+  return FALSE;
+}
+
 void
 ldexp_finish (void)
 {
index d6096175c05d0299a0c3956f276c7c784fcf161a..1055053e28dd03f03160aa08223a16a72771060e 100644 (file)
@@ -239,6 +239,7 @@ bfd_vma exp_get_abs_int
   (etree_type *, int, char *);
 void ldexp_init (void);
 void ldexp_finalize_syms (void);
+bfd_boolean ldexp_is_final_sym_absolute (const struct bfd_link_hash_entry *);
 void ldexp_finish (void);
 
 #endif
index 3c82f8d60d970f856926d5feeac6e586e0c9a1ed..afcf6fea93e4d8071acc3185d06b89df57844dc6 100644 (file)
@@ -1579,13 +1579,13 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
                  && relocs[i]->howto->type != pe_details->imagebase_reloc)
                {
                  struct bfd_symbol *sym = *relocs[i]->sym_ptr_ptr;
+                 const struct bfd_link_hash_entry *blhe
+                   = bfd_wrapped_link_hash_lookup (abfd, info, sym->name,
+                                                   FALSE, FALSE, FALSE);
 
                  /* Don't create relocs for undefined weak symbols.  */
                  if (sym->flags == BSF_WEAK)
                    {
-                     struct bfd_link_hash_entry *blhe
-                       = bfd_wrapped_link_hash_lookup (abfd, info, sym->name,
-                                               FALSE, FALSE, FALSE);
                      if (blhe && blhe->type == bfd_link_hash_undefweak)
                        {
                          /* Check aux sym and see if it is defined or not. */
@@ -1617,6 +1617,12 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
                      if (!strcmp (s->name, ".eh_frame"))
                        continue;
                    }
+                 /* Nor for absolute symbols.  */
+                 else if (blhe && ldexp_is_final_sym_absolute (blhe)
+                          && (!blhe->linker_def
+                              || (strcmp (sym->name, "__image_base__")
+                                  && strcmp (sym->name, U ("__ImageBase")))))
+                   continue;
 
                  reloc_data[total_relocs].vma = sec_vma + relocs[i]->address;
                  reloc_data[total_relocs].idx = total_relocs;
index de9e104f0f633d0cea43a9c6e976c062bb623d35..b1a200180be58df2371a40b66c3816053e178a76 100644 (file)
@@ -76,6 +76,8 @@ run_dump_test "longsecn-5"
 run_dump_test "orphan"
 run_dump_test "orphan_nu"
 
+run_dump_test "reloc"
+
 run_dump_test "weakdef-1"
 
 run_dump_test "pr19803"
diff --git a/ld/testsuite/ld-pe/reloc.d b/ld/testsuite/ld-pe/reloc.d
new file mode 100644 (file)
index 0000000..55888c3
--- /dev/null
@@ -0,0 +1,14 @@
+#name: PE base relocations
+#ld: --enable-reloc-section
+#objdump: -p
+
+.*:     file format .*
+
+#...
+PE File Base Relocations.*
+Virtual Address: .* Number of fixups 4
+[      ]*reloc    0 offset    0 .* (LOW|HIGHLOW|DIR64)
+[      ]*reloc    1 offset    [248] .* (LOW|HIGHLOW|DIR64)
+[      ]*reloc    2 offset   [124]0 .* (LOW|HIGHLOW|DIR64)
+[      ]*reloc    3 offset    0 .* ABSOLUTE
+#pass
diff --git a/ld/testsuite/ld-pe/reloc.s b/ld/testsuite/ld-pe/reloc.s
new file mode 100644 (file)
index 0000000..3ed2e02
--- /dev/null
@@ -0,0 +1,13 @@
+       .data
+       .p2align 4
+start:
+       .dc.a   __image_base__
+       .dc.a   start
+       .dc.a   __section_alignment__
+       .dc.a   __file_alignment__
+       .dc.a   __major_os_version__
+       .dc.a   __minor_os_version__
+       .dc.a   __major_subsystem_version__
+       .dc.a   __minor_subsystem_version__
+       .dc.a   end
+end: