x86: Only allow S + A relocations against absolute symbol
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 1 Apr 2020 21:31:47 +0000 (14:31 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 1 Apr 2020 21:31:47 +0000 (14:31 -0700)
Since value of non-preemptible absolute symbol (SHN_ABS) won't change,
only relocations, which can be resolved as absolute value + addend, and
GOTPCREL relocations, where absolute value + addend is stored in the GOT
slot, against non-preemptible absolute symbol are allowed in PIE and
shared library.

Also convert load relocation to R_386_32, R_X86_64_32S or R_X86_64_32 for
relocation against non-preemptible absolute symbol.  Don't convert to
R_X86_64_32S nor R_X86_64_32 for non-preemptible absolute symbol if they
overflow.

bfd/

PR ld/25749
PR ld/25754
* elf32-i386.c (elf_i386_convert_load_reloc): Convert load
relocation to R_386_32 for relocation against non-preemptible
absolute symbol.
(elf_i386_check_relocs): Call _bfd_elf_x86_valid_reloc_p.  Don't
allocate dynamic relocation for non-preemptible absolute symbol.
(elf_i386_relocate_section): Pass sec to
GENERATE_DYNAMIC_RELOCATION_P.
* elf64-x86-64.c (R_X86_64_converted_reloc_bit): Moved.
(elf_x86_64_convert_load_reloc): Covert load relocation to
R_X86_64_32S or R_X86_64_32 for relocation against non-preemptible
absolute symbol.  Don't convert to R_X86_64_32S nor R_X86_64_32
for non-preemptible absolute symbol if they overflow.
(elf_x86_64_check_relocs): Call _bfd_elf_x86_valid_reloc_p.  Set
tls_type for GOT slot to GOT_ABS for non-preemptible absolute
symbol.  Don't allocate dynamic relocation for non-preemptible
absolute symbol.
(elf_x86_64_relocate_section): Don't generate relative relocation
for GOTPCREL relocations aganst local absolute symbol.  Pass sec
to GENERATE_DYNAMIC_RELOCATION_P.
* elfxx-x86.c (elf_x86_allocate_dynrelocs): No dynamic relocation
against non-preemptible absolute symbol.
(_bfd_elf_x86_valid_reloc_p): New function.
(_bfd_x86_elf_size_dynamic_sections): No dynamic relocation for
GOT_ABS GOT slot.
* elfxx-x86.h (GENERATE_DYNAMIC_RELOCATION_P): Add an SEC
argument.  Don't generate dynamic relocation against
non-preemptible absolute symbol.
(ABS_SYMBOL_P): New.
(GENERATE_RELATIVE_RELOC_P): Don't generate relative relocation
against non-preemptible absolute symbol.
(GOT_ABS): New.
(R_X86_64_converted_reloc_bit): New.  Moved from elf64-x86-64.c.
(_bfd_elf_x86_valid_reloc_p): New.

ld/

PR ld/25749
PR ld/25754
* testsuite/ld-elf/linux-x86.exp: Run ld/25749 tests.
* testsuite/ld-elf/pr25749-1.c: New file.
* testsuite/ld-elf/pr25749-1a.c: Likewise.
* testsuite/ld-elf/pr25749-1b.c: Likewise.
* testsuite/ld-elf/pr25749-1b.err: Likewise.
* testsuite/ld-elf/pr25749-1c.c: Likewise.
* testsuite/ld-elf/pr25749-1d.c: Likewise.
* testsuite/ld-elf/pr25749-2.c: Likewise.
* testsuite/ld-elf/pr25749-2a.s: Likewise.
* testsuite/ld-elf/pr25749-2b.s: Likewise.
* testsuite/ld-elf/pr25749.rd: Likewise.
* testsuite/ld-elf/pr25754-1a.c: Likewise.
* testsuite/ld-elf/pr25754-1b.s: Likewise.
* testsuite/ld-elf/pr25754-2a.c: Likewise.
* testsuite/ld-elf/pr25754-2b.err: Likewise.
* testsuite/ld-elf/pr25754-2b.s: Likewise.
* testsuite/ld-elf/pr25754-3a.c: Likewise.
* testsuite/ld-elf/pr25754-3b.s: Likewise.
* testsuite/ld-elf/pr25754-4a.c: Likewise.
* testsuite/ld-elf/pr25754-4b.s: Likewise.
* testsuite/ld-elf/pr25754-4c.s: Likewise.
* testsuite/ld-elf/pr25754-5a.c: Likewise.
* testsuite/ld-elf/pr25754-5b.s: Likewise.
* testsuite/ld-elf/pr25754-5c.s: Likewise.
* testsuite/ld-elf/pr25754-6a.c: Likewise.
* testsuite/ld-elf/pr25754-6b.s: Likewise.
* testsuite/ld-x86-64/pr19609-6a.d: Don't expect linker error.

32 files changed:
bfd/ChangeLog
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/elfxx-x86.c
bfd/elfxx-x86.h
ld/ChangeLog
ld/testsuite/ld-elf/linux-x86.exp
ld/testsuite/ld-elf/pr25749-1.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-1a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-1b.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-1b.err [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-1c.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-1d.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-2.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-2a.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749-2b.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25749.rd [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-1a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-1b.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-2a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-2b.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-3a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-3b.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-4a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-4b.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-4c.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-5a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-5b.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-5c.s [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-6a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr25754-6b.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr19609-6a.d

index bea9526d2a1201db1977cfeaa9a7640d6b214637..2ed10465791c9c768d6f29725b55319664ac9803 100644 (file)
@@ -1,3 +1,41 @@
+2020-04-01  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/25749
+       PR ld/25754
+       * elf32-i386.c (elf_i386_convert_load_reloc): Convert load
+       relocation to R_386_32 for relocation against non-preemptible
+       absolute symbol.
+       (elf_i386_check_relocs): Call _bfd_elf_x86_valid_reloc_p.  Don't
+       allocate dynamic relocation for non-preemptible absolute symbol.
+       (elf_i386_relocate_section): Pass sec to
+       GENERATE_DYNAMIC_RELOCATION_P.
+       * elf64-x86-64.c (R_X86_64_converted_reloc_bit): Moved.
+       (elf_x86_64_convert_load_reloc): Covert load relocation to
+       R_X86_64_32S or R_X86_64_32 for relocation against non-preemptible
+       absolute symbol.  Don't convert to R_X86_64_32S nor R_X86_64_32
+       for non-preemptible absolute symbol if they overflow.
+       (elf_x86_64_check_relocs): Call _bfd_elf_x86_valid_reloc_p.  Set
+       tls_type for GOT slot to GOT_ABS for non-preemptible absolute
+       symbol.  Don't allocate dynamic relocation for non-preemptible
+       absolute symbol.
+       (elf_x86_64_relocate_section): Don't generate relative relocation
+       for GOTPCREL relocations aganst local absolute symbol.  Pass sec
+       to GENERATE_DYNAMIC_RELOCATION_P.
+       * elfxx-x86.c (elf_x86_allocate_dynrelocs): No dynamic relocation
+       against non-preemptible absolute symbol.
+       (_bfd_elf_x86_valid_reloc_p): New function.
+       (_bfd_x86_elf_size_dynamic_sections): No dynamic relocation for
+       GOT_ABS GOT slot.
+       * elfxx-x86.h (GENERATE_DYNAMIC_RELOCATION_P): Add an SEC
+       argument.  Don't generate dynamic relocation against
+       non-preemptible absolute symbol.
+       (ABS_SYMBOL_P): New.
+       (GENERATE_RELATIVE_RELOC_P): Don't generate relative relocation
+       against non-preemptible absolute symbol.
+       (GOT_ABS): New.
+       (R_X86_64_converted_reloc_bit): New.  Moved from elf64-x86-64.c.
+       (_bfd_elf_x86_valid_reloc_p): New.
+
 2020-04-01  Tamar Christina  <tamar.christina@arm.com>
 
        PR ld/16017
index eb7e1f8b34e2f64706d1764a91159590c03f928f..51c3e863044b7b5e525c735b305414ccb4fd6ca4 100644 (file)
@@ -1226,6 +1226,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   bfd_vma nop_offset;
   bfd_boolean is_pic;
   bfd_boolean to_reloc_32;
+  bfd_boolean abs_symbol;
   unsigned int r_type;
   unsigned int r_symndx;
   bfd_vma roff = irel->r_offset;
@@ -1249,6 +1250,21 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   modrm = bfd_get_8 (abfd, contents + roff - 1);
   baseless = (modrm & 0xc7) == 0x5;
 
+  if (h)
+    {
+      /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P.  */
+      local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
+      isym = NULL;
+      abs_symbol = ABS_SYMBOL_P (h);
+    }
+  else
+    {
+      local_ref = TRUE;
+      isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd,
+                                   r_symndx);
+      abs_symbol = isym->st_shndx == SHN_ABS;
+    }
+
   if (baseless && is_pic)
     {
       /* For PIC, disallow R_386_GOT32X without a base register
@@ -1256,11 +1272,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       const char *name;
 
       if (h == NULL)
-       {
-         isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd,
-                                       r_symndx);
-         name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
-       }
+       name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
       else
        name = h->root.root.string;
 
@@ -1294,9 +1306,6 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
        goto convert_load;
     }
 
-  /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P.  */
-  local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
-
   /* Undefined weak symbol is only bound locally in executable
      and its reference is resolved as 0.  */
   if (h->root.type == bfd_link_hash_undefweak
@@ -1396,6 +1405,9 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
        convert_load:
          if (opcode == 0x8b)
            {
+             if (abs_symbol && local_ref)
+               to_reloc_32 = TRUE;
+
              if (to_reloc_32)
                {
                  /* Convert "mov foo@GOT[(%reg1)], %reg2" to
@@ -1519,6 +1531,7 @@ elf_i386_check_relocs (bfd *abfd,
       Elf_Internal_Sym *isym;
       const char *name;
       bfd_boolean size_reloc;
+      bfd_boolean no_dynreloc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1587,6 +1600,10 @@ elf_i386_check_relocs (bfd *abfd,
            goto error_return;
        }
 
+      if (!_bfd_elf_x86_valid_reloc_p (sec, info, htab, rel, h, isym,
+                                      symtab_hdr, &no_dynreloc))
+       return FALSE;
+
       if (! elf_i386_tls_transition (info, abfd, sec, contents,
                                     symtab_hdr, sym_hashes,
                                     &r_type, GOT_UNKNOWN,
@@ -1827,8 +1844,9 @@ elf_i386_check_relocs (bfd *abfd,
 
          size_reloc = FALSE;
        do_size:
-         if (NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
-                                        R_386_32))
+         if (!no_dynreloc
+             && NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
+                                           R_386_32))
            {
              struct elf_dyn_relocs *p;
              struct elf_dyn_relocs **head;
@@ -2704,7 +2722,7 @@ elf_i386_relocate_section (bfd *output_bfd,
              || is_vxworks_tls)
            break;
 
-         if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type,
+         if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, sec,
                                             FALSE, resolved_to_zero,
                                             (r_type == R_386_PC32)))
            {
index 90e27023343a7140c88959d899a2ccaa73789239..4c9ad78dd74a600a3da7a45f8fbf2e7d2d2b5cca 100644 (file)
@@ -196,9 +196,6 @@ static reloc_howto_type x86_64_elf_howto_table[] =
        FALSE)
 };
 
-/* Set if a relocation is converted from a GOTPCREL relocation.  */
-#define R_X86_64_converted_reloc_bit (1 << 7)
-
 #define X86_PCREL_TYPE_P(TYPE)         \
   (   ((TYPE) == R_X86_64_PC8)         \
    || ((TYPE) == R_X86_64_PC16)                \
@@ -1509,6 +1506,8 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
   bfd_boolean no_overflow;
   bfd_boolean relocx;
   bfd_boolean to_reloc_pc32;
+  bfd_boolean abs_symbol;
+  bfd_boolean local_ref;
   asection *tsec;
   bfd_signed_vma raddend;
   unsigned int opcode;
@@ -1516,6 +1515,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
   unsigned int r_type = *r_type_p;
   unsigned int r_symndx;
   bfd_vma roff = irel->r_offset;
+  bfd_vma abs_relocation;
 
   if (roff < (r_type == R_X86_64_REX_GOTPCRELX ? 3 : 2))
     return TRUE;
@@ -1559,6 +1559,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
                   || no_overflow
                   || is_pic);
 
+  abs_symbol = FALSE;
+  abs_relocation = 0;
+
   /* Get the symbol referred to by the reloc.  */
   if (h == NULL)
     {
@@ -1569,8 +1572,13 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
       if (isym->st_shndx == SHN_UNDEF)
        return TRUE;
 
+      local_ref = TRUE;
       if (isym->st_shndx == SHN_ABS)
-       tsec = bfd_abs_section_ptr;
+       {
+         tsec = bfd_abs_section_ptr;
+         abs_symbol = TRUE;
+         abs_relocation = isym->st_value;
+       }
       else if (isym->st_shndx == SHN_COMMON)
        tsec = bfd_com_section_ptr;
       else if (isym->st_shndx == SHN_X86_64_LCOMMON)
@@ -1586,9 +1594,11 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
         GOTPCRELX relocations since we need to modify REX byte.
         It is OK convert mov with R_X86_64_GOTPCREL to
         R_X86_64_PC32.  */
-      bfd_boolean local_ref;
       struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
 
+      abs_symbol = ABS_SYMBOL_P (h);
+      abs_relocation = h->root.u.def.value;
+
       /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P.  */
       local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
       if ((relocx || opcode == 0x8b)
@@ -1728,6 +1738,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 
       if (opcode == 0x8b)
        {
+         if (abs_symbol && local_ref)
+           to_reloc_pc32 = FALSE;
+
          if (to_reloc_pc32)
            {
              /* Convert "mov foo@GOTPCREL(%rip), %reg" to
@@ -1788,6 +1801,21 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
          r_type = (rex & REX_W) != 0 ? R_X86_64_32S : R_X86_64_32;
 
        rewrite_modrm_rex:
+         if (abs_relocation)
+           {
+             /* Check if R_X86_64_32S/R_X86_64_32 fits.  */
+             if (r_type == R_X86_64_32S)
+               {
+                 if ((abs_relocation + 0x80000000) > 0xffffffff)
+                   return TRUE;
+               }
+             else
+               {
+                 if (abs_relocation > 0xffffffff)
+                   return TRUE;
+               }
+           }
+
          bfd_put_8 (abfd, modrm, contents + roff - 1);
 
          if (rex)
@@ -1879,6 +1907,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       const char *name;
       bfd_boolean size_reloc;
       bfd_boolean converted_reloc;
+      bfd_boolean no_dynreloc;
 
       r_symndx = htab->r_sym (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1983,6 +2012,10 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            converted = TRUE;
        }
 
+      if (!_bfd_elf_x86_valid_reloc_p (sec, info, htab, rel, h, isym,
+                                      symtab_hdr, &no_dynreloc))
+       return FALSE;
+
       if (! elf_x86_64_tls_transition (info, abfd, sec, contents,
                                       symtab_hdr, sym_hashes,
                                       &r_type, GOT_UNKNOWN,
@@ -2029,12 +2062,26 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
            switch (r_type)
              {
-             default: tls_type = GOT_NORMAL; break;
-             case R_X86_64_TLSGD: tls_type = GOT_TLS_GD; break;
-             case R_X86_64_GOTTPOFF: tls_type = GOT_TLS_IE; break;
+             default:
+               tls_type = GOT_NORMAL;
+               if (h)
+                 {
+                   if (ABS_SYMBOL_P (h))
+                     tls_type = GOT_ABS;
+                 }
+               else if (isym->st_shndx == SHN_ABS)
+                 tls_type = GOT_ABS;
+               break;
+             case R_X86_64_TLSGD:
+               tls_type = GOT_TLS_GD;
+               break;
+             case R_X86_64_GOTTPOFF:
+               tls_type = GOT_TLS_IE;
+               break;
              case R_X86_64_GOTPC32_TLSDESC:
              case R_X86_64_TLSDESC_CALL:
-               tls_type = GOT_TLS_GDESC; break;
+               tls_type = GOT_TLS_GDESC;
+               break;
              }
 
            if (h != NULL)
@@ -2245,8 +2292,9 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
          size_reloc = FALSE;
        do_size:
-         if (NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type,
-                                        htab->pointer_r_type))
+         if (!no_dynreloc
+             && NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type,
+                                           htab->pointer_r_type))
            {
              struct elf_dyn_relocs *p;
              struct elf_dyn_relocs **head;
@@ -2880,7 +2928,14 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                              base_got->contents + off);
                  local_got_offsets[r_symndx] |= 1;
 
-                 if (bfd_link_pic (info))
+                 /* NB: GOTPCREL relocations against local absolute
+                    symbol store relocation value in the GOT slot
+                    without relative relocation.  */
+                 if (bfd_link_pic (info)
+                     && !(sym->st_shndx == SHN_ABS
+                          && (r_type == R_X86_64_GOTPCREL
+                              || r_type == R_X86_64_GOTPCRELX
+                              || r_type == R_X86_64_REX_GOTPCRELX)))
                    relative_reloc = TRUE;
                }
            }
@@ -3175,7 +3230,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                                    && (X86_PCREL_TYPE_P (r_type)
                                        || X86_SIZE_TYPE_P (r_type)));
 
-         if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type,
+         if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, sec,
                                             need_copy_reloc_in_pie,
                                             resolved_to_zero, FALSE))
            {
index 108e04a1588e0f48ed9c5a186b21afbc2756d9d6..0fc75fbedfb7f6086b0c803dcc2f4b01de76a7fc 100644 (file)
@@ -347,7 +347,8 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we
         need two), R_386_TLS_GD and R_X86_64_TLSGD need one if local
         symbol and two if global.  No dynamic relocation against
-        resolved undefined weak symbol in executable.  */
+        resolved undefined weak symbol in executable.  No dynamic
+        relocation against non-preemptible absolute symbol.  */
       if (tls_type == GOT_TLS_IE_BOTH)
        htab->elf.srelgot->size += 2 * htab->sizeof_reloc;
       else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
@@ -359,7 +360,9 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
               && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                    && !resolved_to_zero)
                   || h->root.type != bfd_link_hash_undefweak)
-              && (bfd_link_pic (info)
+              && ((bfd_link_pic (info)
+                   && !(h->dynindx == -1
+                        && ABS_SYMBOL_P (h)))
                   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
        htab->elf.srelgot->size += htab->sizeof_reloc;
       if (GOT_TLS_GDESC_P (tls_type))
@@ -952,6 +955,100 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
   return _bfd_elf_link_check_relocs (abfd, info);
 }
 
+bfd_boolean
+_bfd_elf_x86_valid_reloc_p (asection *input_section,
+                           struct bfd_link_info *info,
+                           struct elf_x86_link_hash_table *htab,
+                           const Elf_Internal_Rela *rel,
+                           struct elf_link_hash_entry *h,
+                           Elf_Internal_Sym *sym,
+                           Elf_Internal_Shdr *symtab_hdr,
+                           bfd_boolean *no_dynreloc_p)
+{
+  bfd_boolean valid_p = TRUE;
+
+  *no_dynreloc_p = FALSE;
+
+  /* Check If relocation against non-preemptible absolute symbol is
+     valid in PIC.  FIXME: Can't use SYMBOL_REFERENCES_LOCAL_P since
+     it may call _bfd_elf_link_hide_sym_by_version and result in
+     ld-elfvers/ vers21 test failure.  */
+  if (bfd_link_pic (info)
+      && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, h)))
+    {
+      const struct elf_backend_data *bed;
+      unsigned int r_type;
+      Elf_Internal_Rela irel;
+
+      /* Skip non-absolute symbol.  */
+      if (h)
+       {
+         if (!ABS_SYMBOL_P (h))
+           return valid_p;
+       }
+      else if (sym->st_shndx != SHN_ABS)
+       return valid_p;
+
+      bed = get_elf_backend_data (input_section->owner);
+      r_type = ELF32_R_TYPE (rel->r_info);
+      irel = *rel;
+
+      /* Only allow relocations against absolute symbol, which can be
+        resolved as absolute value + addend.  GOTPCREL relocations
+        are allowed since absolute value + addend is stored in the
+        GOT slot.  */
+      if (bed->target_id == X86_64_ELF_DATA)
+       {
+         r_type &= ~R_X86_64_converted_reloc_bit;
+         valid_p = (r_type == R_X86_64_64
+                    || r_type == R_X86_64_32
+                    || r_type == R_X86_64_32S
+                    || r_type == R_X86_64_16
+                    || r_type == R_X86_64_8
+                    || r_type == R_X86_64_GOTPCREL
+                    || r_type == R_X86_64_GOTPCRELX
+                    || r_type == R_X86_64_REX_GOTPCRELX);
+         if (!valid_p)
+           {
+             unsigned int r_symndx = htab->r_sym (rel->r_info);
+             irel.r_info = htab->r_info (r_symndx, r_type);
+           }
+       }
+      else
+       valid_p = (r_type == R_386_32
+                  || r_type == R_386_16
+                  || r_type == R_386_8);
+
+      if (valid_p)
+       *no_dynreloc_p = TRUE;
+      else
+       {
+         const char *name;
+         arelent internal_reloc;
+
+         if (!bed->elf_info_to_howto (input_section->owner,
+                                      &internal_reloc, &irel)
+             || internal_reloc.howto == NULL)
+           abort ();
+
+         if (h)
+           name = h->root.root.string;
+         else
+           name = bfd_elf_sym_name (input_section->owner, symtab_hdr,
+                                    sym, NULL);
+         info->callbacks->einfo
+           /* xgettext:c-format */
+           (_("%F%P: %pB: relocation %s against absolute symbol "
+              "`%s' in section `%pA' is disallowed\n"),
+            input_section->owner, internal_reloc.howto->name, name,
+            input_section);
+         bfd_set_error (bfd_error_bad_value);
+       }
+    }
+
+  return valid_p;
+}
+
 /* Set the sizes of the dynamic sections.  */
 
 bfd_boolean
@@ -1065,7 +1162,7 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
                      || *local_tls_type == GOT_TLS_IE_BOTH)
                    s->size += htab->got_entry_size;
                }
-             if (bfd_link_pic (info)
+             if ((bfd_link_pic (info) && *local_tls_type != GOT_ABS)
                  || GOT_TLS_GD_ANY_P (*local_tls_type)
                  || (*local_tls_type & GOT_TLS_IE))
                {
index bef17dc2bac30486ba768a12150d501416503c78..6e91f242622baa8caf99ff209a5f04341b0d577c 100644 (file)
    Copy dynamic function pointer relocations.  Don't generate dynamic
    relocations against resolved undefined weak symbols in PIE, except
    when PC32_RELOC is TRUE.  Undefined weak symbol is bound locally
-   when PIC is false.  */
-#define GENERATE_DYNAMIC_RELOCATION_P(INFO, EH, R_TYPE, \
+   when PIC is false.  Don't generate dynamic relocations against
+   non-preemptible absolute symbol.  */
+#define GENERATE_DYNAMIC_RELOCATION_P(INFO, EH, R_TYPE, SEC, \
                                      NEED_COPY_RELOC_IN_PIE, \
                                      RESOLVED_TO_ZERO, PC32_RELOC) \
   ((bfd_link_pic (INFO) \
+    && !(bfd_is_abs_section (SEC) \
+        && ((EH) == NULL \
+            || SYMBOL_REFERENCES_LOCAL (INFO, &(EH)->elf))) \
     && !(NEED_COPY_RELOC_IN_PIE) \
     && ((EH) == NULL \
        || ((ELF_ST_VISIBILITY ((EH)->elf.other) == STV_DEFAULT \
    || ((struct elf_x86_link_hash_entry *) (H))->linker_def \
    || ELF_COMMON_DEF_P (H))
 
+/* Return TRUE if the symbol described by a linker hash entry H is
+   going to be absolute.  Similar to bfd_is_abs_symbol, but excluding
+   all linker-script defined symbols.  */
+#define ABS_SYMBOL_P(H) \
+  (bfd_is_abs_symbol (&(H)->root) && !(H)->root.ldscript_def)
+
 /* TRUE if relative relocation should be generated.  GOT reference to
    global symbol in PIC will lead to dynamic symbol.  It becomes a
    problem when "time" or "times" is defined as a variable in an
    executable, clashing with functions of the same name in libc.  If a
    symbol isn't undefined weak symbol, don't make it dynamic in PIC and
-   generate relative relocation.  */
+   generate relative relocation.   Don't generate relative relocation
+   against non-preemptible absolute symbol.  */
 #define GENERATE_RELATIVE_RELOC_P(INFO, H) \
   ((H)->dynindx == -1 \
    && !(H)->forced_local \
    && (H)->root.type != bfd_link_hash_undefweak \
-   && bfd_link_pic (INFO))
+   && bfd_link_pic (INFO) \
+   && !ABS_SYMBOL_P (H))
 
 /* TRUE if this is a pointer reference to a local IFUNC.  */
 #define POINTER_LOCAL_IFUNC_P(INFO, H) \
@@ -414,6 +426,7 @@ struct elf_x86_plt_layout
 #define GOT_TLS_IE_NEG 6
 #define GOT_TLS_IE_BOTH 7
 #define GOT_TLS_GDESC  8
+#define GOT_ABS                9
 #define GOT_TLS_GD_BOTH_P(type)        \
   ((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
 #define GOT_TLS_GD_P(type) \
@@ -601,6 +614,9 @@ struct elf_x86_plt
   long count;
 };
 
+/* Set if a relocation is converted from a GOTPCREL relocation.  */
+#define R_X86_64_converted_reloc_bit (1 << 7)
+
 #define elf_x86_tdata(abfd) \
   ((struct elf_x86_obj_tdata *) (abfd)->tdata.any)
 
@@ -652,6 +668,11 @@ extern int _bfd_x86_elf_compare_relocs
 extern bfd_boolean _bfd_x86_elf_link_check_relocs
   (bfd *, struct bfd_link_info *);
 
+extern bfd_boolean _bfd_elf_x86_valid_reloc_p
+  (asection *, struct bfd_link_info *, struct elf_x86_link_hash_table *,
+   const Elf_Internal_Rela *, struct elf_link_hash_entry *,
+   Elf_Internal_Sym *, Elf_Internal_Shdr *, bfd_boolean *);
+
 extern bfd_boolean _bfd_x86_elf_size_dynamic_sections
   (bfd *, struct bfd_link_info *);
 
index 1395fb24dc8b07111d5be9d8068324c407f5f471..6c95224f0baadb877cd24f606be3963e74b1de3c 100644 (file)
@@ -1,3 +1,35 @@
+2020-04-01  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/25749
+       PR ld/25754
+       * testsuite/ld-elf/linux-x86.exp: Run ld/25749 tests.
+       * testsuite/ld-elf/pr25749-1.c: New file.
+       * testsuite/ld-elf/pr25749-1a.c: Likewise.
+       * testsuite/ld-elf/pr25749-1b.c: Likewise.
+       * testsuite/ld-elf/pr25749-1b.err: Likewise.
+       * testsuite/ld-elf/pr25749-1c.c: Likewise.
+       * testsuite/ld-elf/pr25749-1d.c: Likewise.
+       * testsuite/ld-elf/pr25749-2.c: Likewise.
+       * testsuite/ld-elf/pr25749-2a.s: Likewise.
+       * testsuite/ld-elf/pr25749-2b.s: Likewise.
+       * testsuite/ld-elf/pr25749.rd: Likewise.
+       * testsuite/ld-elf/pr25754-1a.c: Likewise.
+       * testsuite/ld-elf/pr25754-1b.s: Likewise.
+       * testsuite/ld-elf/pr25754-2a.c: Likewise.
+       * testsuite/ld-elf/pr25754-2b.err: Likewise.
+       * testsuite/ld-elf/pr25754-2b.s: Likewise.
+       * testsuite/ld-elf/pr25754-3a.c: Likewise.
+       * testsuite/ld-elf/pr25754-3b.s: Likewise.
+       * testsuite/ld-elf/pr25754-4a.c: Likewise.
+       * testsuite/ld-elf/pr25754-4b.s: Likewise.
+       * testsuite/ld-elf/pr25754-4c.s: Likewise.
+       * testsuite/ld-elf/pr25754-5a.c: Likewise.
+       * testsuite/ld-elf/pr25754-5b.s: Likewise.
+       * testsuite/ld-elf/pr25754-5c.s: Likewise.
+       * testsuite/ld-elf/pr25754-6a.c: Likewise.
+       * testsuite/ld-elf/pr25754-6b.s: Likewise.
+       * testsuite/ld-x86-64/pr19609-6a.d: Don't expect linker error.
+
 2020-04-01  Tamar Christina  <tamar.christina@arm.com>
 
        PR ld/16017
index 63a321b9668469b9dff7e997641c13b338b6299a..7186dede711e9da4d7cdc1e60101873a35e35244 100644 (file)
@@ -115,3 +115,170 @@ elfedit_test "--disable-x86-feature shstk" x86-feature-1 x86-feature-1c
 elfedit_test "--disable-x86-feature ibt" x86-feature-1 x86-feature-1d
 elfedit_test "--enable-x86-feature ibt --enable-x86-feature shstk" \
                x86-feature-1 x86-feature-1e
+
+proc check_pr25749a {testname srcfilea srcfileb cflags ldflags lderror} {
+    global objcopy
+    global srcdir
+    global subdir
+
+    if { [istarget "i?86-*-linux*"] } {
+       set output_arch "i386:i386"
+       set output_target "elf32-i386"
+    } else {
+       set output_arch "i386:x86-64"
+       if {[istarget "x86_64-*-linux*-gnux32"]} {
+           set output_target "elf32-x86-64"
+       } else {
+           set output_target "elf64-x86-64"
+       }
+    }
+
+    exec cp $srcdir/$subdir/$srcfilea $srcfilea
+    set pr25749_bin "$objcopy -B $output_arch -I binary -O $output_target $srcfilea tmpdir/pr25749-bin.o"
+    send_log "$pr25749_bin\n"
+    set got [remote_exec host "$pr25749_bin"]
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+       send_log "$got\n"
+       fail "Convert $srcfilea to $output_target"
+       return
+    }
+
+    if {"$lderror" == ""} {
+       run_cc_link_tests [list \
+           [list \
+               "Build $testname ($ldflags $cflags)" \
+               "$ldflags tmpdir/pr25749-bin.o" \
+               "$cflags" \
+               [list $srcfilea $srcfileb]\
+               {{readelf {-Wr} pr25749.rd}}  \
+               "${testname}a" \
+           ] \
+       ]
+       run_ld_link_exec_tests [list \
+           [list \
+               "Run ${testname}a ($ldflags $cflags)" \
+               "$ldflags tmpdir/pr25749-bin.o" \
+               "" \
+               [list $srcfilea $srcfileb]\
+               "${testname}a" \
+               "pass.out" \
+               "$cflags" \
+           ] \
+       ]
+    } else {
+       run_cc_link_tests [list \
+           [list \
+               "Build $testname ($ldflags $cflags)" \
+               "$ldflags tmpdir/pr25749-bin.o" \
+               "$cflags" \
+               [list $srcfilea $srcfileb]\
+               [list [list error_output $lderror]] \
+               "$testname" \
+           ] \
+       ]
+    }
+}
+
+check_pr25749a "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749a "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "-fPIE" "-pie" ""
+check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+if { [istarget "i?86-*-linux*"] } {
+    check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" ""
+} else {
+    check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" "pr25749-1b.err"
+}
+check_pr25749a "pr25749-1c" "pr25749-1.c" "pr25749-1c.c" "-fPIC" "-shared" "pr25749-1b.err"
+check_pr25749a "pr25749-2a" "pr25749-2.c" "pr25749-2a.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749a "pr25749-2a" "pr25749-2.c" "pr25749-2a.s" "-fPIE" "-pie" ""
+check_pr25749a "pr25749-2b" "pr25749-2.c" "pr25749-2b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749a "pr25749-2b" "pr25749-2.c" "pr25749-2b.s" "-fPIE" "-pie" ""
+check_pr25749a "pr25754-1a" "pr25754-1a.c" "pr25754-1b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749a "pr25754-1b" "pr25754-1a.c" "pr25754-1b.s" "-fPIE" "$NOPIE_LDFLAGS" ""
+check_pr25749a "pr25754-1c" "pr25754-1a.c" "pr25754-1b.s" "-fPIC" "$NOPIE_LDFLAGS" ""
+check_pr25749a "pr25754-1d" "pr25754-1a.c" "pr25754-1b.s" "-fPIC" "-pie" ""
+if { [istarget "i?86-*-linux*"] || [istarget "x86_64-*-linux*-gnux32"]} {
+    check_pr25749a "pr25754-2a" "pr25754-2a.c" "pr25754-2b.s" "-fPIC" "$NOPIE_LDFLAGS" ""
+    check_pr25749a "pr25754-2b" "pr25754-2a.c" "pr25754-2b.s" "-fPIC" "-pie" ""
+} else {
+    check_pr25749a "pr25754-3a" "pr25754-3a.c" "pr25754-3b.s" "-fPIC" "$NOPIE_LDFLAGS" ""
+    check_pr25749a "pr25754-3b" "pr25754-3a.c" "pr25754-3b.s" "-fPIC" "-pie" ""
+}
+if { [istarget "i?86-*-linux*"] } {
+    check_pr25749a "pr25754-4a" "pr25754-4a.c" "pr25754-4b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+    check_pr25749a "pr25754-4b" "pr25754-4a.c" "pr25754-4b.s" "-fpie" "-pie" ""
+    check_pr25749a "pr25754-5a" "pr25754-5a.c" "pr25754-5b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+    check_pr25749a "pr25754-5b" "pr25754-5a.c" "pr25754-5b.s" "-fpie" "-pie" ""
+} else {
+    check_pr25749a "pr25754-4a" "pr25754-4a.c" "pr25754-4c.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+    check_pr25749a "pr25754-4b" "pr25754-4a.c" "pr25754-4c.s" "-fpie" "-pie" ""
+    check_pr25749a "pr25754-5a" "pr25754-5a.c" "pr25754-5c.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+    check_pr25749a "pr25754-5b" "pr25754-5a.c" "pr25754-5c.s" "-fpie" "-pie" ""
+    if { ![istarget "x86_64-*-linux*-gnux32"]} {
+       check_pr25749a "pr25754-6a" "pr25754-6a.c" "pr25754-6b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+       check_pr25749a "pr25754-6b" "pr25754-6a.c" "pr25754-6b.s" "-fpie" "-pie" ""
+    }
+}
+
+proc check_pr25749b {testname srcfilea srcfileb cflags ldflags dsoldflags} {
+    global objcopy
+    global srcdir
+    global subdir
+
+    if { [istarget "i?86-*-linux*"] } {
+       set output_arch "i386:i386"
+       set output_target "elf32-i386"
+    } else {
+       set output_arch "i386:x86-64"
+       if {[istarget "x86_64-*-linux*-gnux32"]} {
+           set output_target "elf32-x86-64"
+       } else {
+           set output_target "elf64-x86-64"
+       }
+    }
+
+    exec cp $srcdir/$subdir/$srcfilea $srcfilea
+    set pr25749_bin "$objcopy -B $output_arch -I binary -O $output_target $srcfilea tmpdir/pr25749-bin.o"
+    send_log "$pr25749_bin\n"
+    set got [remote_exec host "$pr25749_bin"]
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+       send_log "$got\n"
+       fail "Convert $srcfilea to $output_target"
+       return
+    }
+
+    run_cc_link_tests [list \
+       [list \
+           "Build lib${testname}.so ($dsoldflags)" \
+           "-shared $dsoldflags tmpdir/pr25749-bin.o" \
+           "-fPIC" \
+           [list $srcfileb] \
+           {{readelf {-Wr} pr25749.rd}}  \
+           "lib${testname}.so" \
+       ] \
+    ]
+    run_ld_link_exec_tests [list \
+       [list \
+           "Run ${testname}b ($ldflags $cflags)" \
+           "$ldflags -Wl,--no-as-needed tmpdir/lib${testname}.so" \
+           "" \
+           [list $srcfilea]\
+           "${testname}b" \
+           "pass.out" \
+           "$cflags" \
+       ] \
+    ]
+}
+
+check_pr25749b "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749b "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "-fPIE" "-pie" ""
+check_pr25749b "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "-fPIE" "-pie" "-Wl,-Bsymbolic"
+check_pr25749b "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749b "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" ""
+check_pr25749b "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" "-Wl,-Bsymbolic"
+check_pr25749b "pr25749-1d" "pr25749-1.c" "pr25749-1d.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" "-Wl,-defsym=_begin=0"
+check_pr25749b "pr25749-1d" "pr25749-1.c" "pr25749-1d.c" "-fPIE" "-pie" "-Wl,-defsym=_begin=0"
+check_pr25749b "pr25749-1d" "pr25749-1.c" "pr25749-1d.c" "-fPIE" "-pie" "-Wl,-Bsymbolic -Wl,-defsym=_begin=0"
+check_pr25749b "pr25749-2a" "pr25749-2.c" "pr25749-2a.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749b "pr25749-2a" "pr25749-2.c" "pr25749-2a.s" "-fPIE" "-pie" ""
+check_pr25749b "pr25749-2b" "pr25749-2.c" "pr25749-2b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
+check_pr25749b "pr25749-2b" "pr25749-2.c" "pr25749-2b.s" "-fPIE" "-pie" ""
diff --git a/ld/testsuite/ld-elf/pr25749-1.c b/ld/testsuite/ld-elf/pr25749-1.c
new file mode 100644 (file)
index 0000000..5b37af0
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern intptr_t size (void);
+
+int
+main ()
+{
+  if (size () == 147)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25749-1a.c b/ld/testsuite/ld-elf/pr25749-1a.c
new file mode 100644 (file)
index 0000000..775623b
--- /dev/null
@@ -0,0 +1,11 @@
+#include <bfd_stdint.h>
+
+extern void *_binary_pr25749_1_c_start;
+extern void *_binary_pr25749_1_c_end;
+
+intptr_t
+size (void)
+{
+  return ((intptr_t) &_binary_pr25749_1_c_end
+         - (intptr_t) &_binary_pr25749_1_c_start);
+}
diff --git a/ld/testsuite/ld-elf/pr25749-1b.c b/ld/testsuite/ld-elf/pr25749-1b.c
new file mode 100644 (file)
index 0000000..f02a408
--- /dev/null
@@ -0,0 +1,9 @@
+#include <bfd_stdint.h>
+
+extern void *_binary_pr25749_1_c_size;
+
+intptr_t
+size (void)
+{
+  return (intptr_t) &_binary_pr25749_1_c_size;
+}
diff --git a/ld/testsuite/ld-elf/pr25749-1b.err b/ld/testsuite/ld-elf/pr25749-1b.err
new file mode 100644 (file)
index 0000000..bb38917
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+.*: .* against absolute symbol `_binary_pr25749_1_c_size' .* is disallowed
+#pass
diff --git a/ld/testsuite/ld-elf/pr25749-1c.c b/ld/testsuite/ld-elf/pr25749-1c.c
new file mode 100644 (file)
index 0000000..f2847d7
--- /dev/null
@@ -0,0 +1,9 @@
+#include <bfd_stdint.h>
+
+extern void *_binary_pr25749_1_c_size __attribute__ ((visibility("hidden")));
+
+intptr_t
+size (void)
+{
+  return (intptr_t) &_binary_pr25749_1_c_size;
+}
diff --git a/ld/testsuite/ld-elf/pr25749-1d.c b/ld/testsuite/ld-elf/pr25749-1d.c
new file mode 100644 (file)
index 0000000..33b869d
--- /dev/null
@@ -0,0 +1,19 @@
+#include <bfd_stdint.h>
+
+extern void *_binary_pr25749_1_c_start;
+extern void *_binary_pr25749_1_c_end;
+
+intptr_t
+size (void)
+{
+  return ((intptr_t) &_binary_pr25749_1_c_end
+         - (intptr_t) &_binary_pr25749_1_c_start);
+}
+
+extern void *_begin __attribute__ ((visibility("hidden")));
+
+intptr_t
+size_p (void)
+{
+  return (intptr_t) &_begin;
+}
diff --git a/ld/testsuite/ld-elf/pr25749-2.c b/ld/testsuite/ld-elf/pr25749-2.c
new file mode 100644 (file)
index 0000000..820bebc
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern intptr_t size;
+
+int
+main ()
+{
+  if (size == 137)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25749-2a.s b/ld/testsuite/ld-elf/pr25749-2a.s
new file mode 100644 (file)
index 0000000..df486fe
--- /dev/null
@@ -0,0 +1,6 @@
+       .data
+       .globl  size
+       .type   size, %object
+size:
+       .dc.a   _binary_pr25749_2_c_size
+       .size size, .-size
diff --git a/ld/testsuite/ld-elf/pr25749-2b.s b/ld/testsuite/ld-elf/pr25749-2b.s
new file mode 100644 (file)
index 0000000..ba82c45
--- /dev/null
@@ -0,0 +1,7 @@
+       .data
+       .hidden _binary_pr25749_2_c_size
+       .globl  size
+       .type   size, %object
+size:
+       .dc.a   _binary_pr25749_2_c_size
+       .size size, .-size
diff --git a/ld/testsuite/ld-elf/pr25749.rd b/ld/testsuite/ld-elf/pr25749.rd
new file mode 100644 (file)
index 0000000..fbc68bf
--- /dev/null
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_.*_NONE.*
+#...
diff --git a/ld/testsuite/ld-elf/pr25754-1a.c b/ld/testsuite/ld-elf/pr25754-1a.c
new file mode 100644 (file)
index 0000000..2b048ec
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern uintptr_t bar;
+
+uintptr_t *
+__attribute__ ((noinline, noclone))
+get_bar (void)
+{
+  return &bar;
+}
+
+int
+main ()
+{
+  if ((uintptr_t) get_bar () == 42)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25754-1b.s b/ld/testsuite/ld-elf/pr25754-1b.s
new file mode 100644 (file)
index 0000000..99d585d
--- /dev/null
@@ -0,0 +1,3 @@
+       .data
+       .global bar
+       bar = 42
diff --git a/ld/testsuite/ld-elf/pr25754-2a.c b/ld/testsuite/ld-elf/pr25754-2a.c
new file mode 100644 (file)
index 0000000..7c9f581
--- /dev/null
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern uintptr_t bar;
+
+uintptr_t *
+__attribute__ ((noinline, noclone))
+get_bar (void)
+{
+  return &bar;
+}
+
+int
+main ()
+{
+  if ((uintptr_t) get_bar () == 0xfffffff0U)
+    printf ("PASS\n");
+  return 0;
+}
+#include <stdio.h>
diff --git a/ld/testsuite/ld-elf/pr25754-2b.s b/ld/testsuite/ld-elf/pr25754-2b.s
new file mode 100644 (file)
index 0000000..9cab993
--- /dev/null
@@ -0,0 +1,3 @@
+       .data
+       .global bar
+       bar = 0xfffffff0
diff --git a/ld/testsuite/ld-elf/pr25754-3a.c b/ld/testsuite/ld-elf/pr25754-3a.c
new file mode 100644 (file)
index 0000000..2d4f02a
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern uintptr_t bar;
+
+uintptr_t *
+__attribute__ ((noinline, noclone))
+get_bar (void)
+{
+  return &bar;
+}
+
+int
+main ()
+{
+  if ((uintptr_t) get_bar () == -0x80000001LL)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25754-3b.s b/ld/testsuite/ld-elf/pr25754-3b.s
new file mode 100644 (file)
index 0000000..aad3e45
--- /dev/null
@@ -0,0 +1,3 @@
+       .data
+       .global bar
+       bar = -0x80000001
diff --git a/ld/testsuite/ld-elf/pr25754-4a.c b/ld/testsuite/ld-elf/pr25754-4a.c
new file mode 100644 (file)
index 0000000..e2c2f8d
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern uintptr_t *get_bar (void);
+
+int
+main ()
+{
+  if ((uintptr_t) get_bar () == 0x7fffffffULL)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25754-4b.s b/ld/testsuite/ld-elf/pr25754-4b.s
new file mode 100644 (file)
index 0000000..448406d
--- /dev/null
@@ -0,0 +1,23 @@
+       .text
+       .p2align 4
+       .globl  get_bar
+       .type   get_bar, @function
+get_bar:
+       .cfi_startproc
+       call    __x86.get_pc_thunk.ax
+       addl    $_GLOBAL_OFFSET_TABLE_, %eax
+       movl    bar@GOT(%eax), %eax
+       ret
+       .cfi_endproc
+       .size   get_bar, .-get_bar
+       bar = 0x7fffffff
+       .section        .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
+       .globl  __x86.get_pc_thunk.ax
+       .hidden __x86.get_pc_thunk.ax
+       .type   __x86.get_pc_thunk.ax, @function
+__x86.get_pc_thunk.ax:
+       .cfi_startproc
+       movl    (%esp), %eax
+       ret
+       .cfi_endproc
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-elf/pr25754-4c.s b/ld/testsuite/ld-elf/pr25754-4c.s
new file mode 100644 (file)
index 0000000..de450fe
--- /dev/null
@@ -0,0 +1,12 @@
+       .text
+       .p2align 4
+       .globl  get_bar
+       .type   get_bar, @function
+get_bar:
+       .cfi_startproc
+       movq    bar@GOTPCREL(%rip), %rax
+       ret
+       .cfi_endproc
+       .size   get_bar, .-get_bar
+       bar = 0x7fffffff
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-elf/pr25754-5a.c b/ld/testsuite/ld-elf/pr25754-5a.c
new file mode 100644 (file)
index 0000000..cb791dd
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern uintptr_t *get_bar (void);
+
+int
+main ()
+{
+  if ((uintptr_t) get_bar () == 0xfffffff0ULL)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25754-5b.s b/ld/testsuite/ld-elf/pr25754-5b.s
new file mode 100644 (file)
index 0000000..2923c32
--- /dev/null
@@ -0,0 +1,23 @@
+       .text
+       .p2align 4
+       .globl  get_bar
+       .type   get_bar, @function
+get_bar:
+       .cfi_startproc
+       call    __x86.get_pc_thunk.ax
+       addl    $_GLOBAL_OFFSET_TABLE_, %eax
+       movl    bar@GOT(%eax), %eax
+       ret
+       .cfi_endproc
+       .size   get_bar, .-get_bar
+       bar = 0xfffffff0
+       .section        .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
+       .globl  __x86.get_pc_thunk.ax
+       .hidden __x86.get_pc_thunk.ax
+       .type   __x86.get_pc_thunk.ax, @function
+__x86.get_pc_thunk.ax:
+       .cfi_startproc
+       movl    (%esp), %eax
+       ret
+       .cfi_endproc
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-elf/pr25754-5c.s b/ld/testsuite/ld-elf/pr25754-5c.s
new file mode 100644 (file)
index 0000000..0195f19
--- /dev/null
@@ -0,0 +1,12 @@
+       .text
+       .p2align 4
+       .globl  get_bar
+       .type   get_bar, @function
+get_bar:
+       .cfi_startproc
+       movq    bar@GOTPCREL(%rip), %rax
+       ret
+       .cfi_endproc
+       .size   get_bar, .-get_bar
+       bar = 0xfffffff0
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-elf/pr25754-6a.c b/ld/testsuite/ld-elf/pr25754-6a.c
new file mode 100644 (file)
index 0000000..59633a3
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <bfd_stdint.h>
+
+extern uintptr_t *get_bar (void);
+
+int
+main ()
+{
+  if ((uintptr_t) get_bar () == 0xffffffffffffff0ULL)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr25754-6b.s b/ld/testsuite/ld-elf/pr25754-6b.s
new file mode 100644 (file)
index 0000000..2532480
--- /dev/null
@@ -0,0 +1,12 @@
+       .text
+       .p2align 4
+       .globl  get_bar
+       .type   get_bar, @function
+get_bar:
+       .cfi_startproc
+       movq    bar@GOTPCREL(%rip), %rax
+       ret
+       .cfi_endproc
+       .size   get_bar, .-get_bar
+       bar = 0xffffffffffffff0
+       .section        .note.GNU-stack,"",@progbits
index 3c011d9b057f173d1ebbbe69da2ebbc20de7beb1..b340287f48b179a0d83a3e76c881aea8888fefb6 100644 (file)
@@ -1,4 +1,13 @@
 #source: pr19609-6.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 --defsym foobar=0x80000000
-#error: failed to convert GOTPCREL relocation; relink with --no-relax
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[      ]*[a-f0-9]+:    48 8b 05 ([0-9a-f]{2} ){4} *    mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.got>
+#pass