]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
authorXi Ruoyao <xry111@xry111.site>
Sun, 30 Jun 2024 07:18:21 +0000 (15:18 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Fri, 5 Jul 2024 04:11:10 +0000 (12:11 +0800)
We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:

    $ cat t.s
    .data
    x:
        .4byte x
.4byte 0xdeadbeef
    $ as/as-new t.s -o t.o
    $ ld/ld-new -shared t.o
    $ objdump -R
    a.out:     file format elf64-loongarch

    DYNAMIC RELOCATION RECORDS
    OFFSET           TYPE              VALUE
    00000000000001a8 R_LARCH_RELATIVE  *ABS*+0x00000000000001a8

But this is just wrong: at runtime the dynamic linker will run
*(uintptr *)&x += load_address, clobbering the next 4 bytes of data
("0xdeadbeef" in the example).

If we keep the R_LARCH_32 reloc as-is in ELFCLASS64, it'll be rejected
by the Glibc dynamic linker anyway.  And it does not make too much sense
to modify Glibc to support it.  So we can just reject it like x86_64:

    relocation R_X86_64_32 against `.data' can not be used when making a
    shared object; recompile with -fPIC

or RISC-V:

    relocation R_RISCV_32 against non-absolute symbol `a local symbol'
    can not be used in RV64 when making a shared object

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
bfd/elfnn-loongarch.c
ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s [new file with mode: 0644]

index da84aabc1ae61c214ad9debf7b4fc2327225023d..41463ea5c75ba806ff3b3d9a029aee31ced60c13 100644 (file)
@@ -1036,8 +1036,32 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          only_need_pcrel = 1;
          break;
 
-       case R_LARCH_JUMP_SLOT:
        case R_LARCH_32:
+         if (ARCH_SIZE > 32
+             && bfd_link_pic (info)
+             && (sec->flags & SEC_ALLOC) != 0)
+           {
+             bool is_abs_symbol = false;
+
+             if (r_symndx < symtab_hdr->sh_info)
+               is_abs_symbol = isym->st_shndx == SHN_ABS;
+             else
+               is_abs_symbol = bfd_is_abs_symbol (&h->root);
+
+             if (!is_abs_symbol)
+               {
+                 _bfd_error_handler
+                   (_("%pB: relocation R_LARCH_32 against non-absolute "
+                      "symbol `%s' cannot be used in ELFCLASS64 when "
+                      "making a shared object or PIE"),
+                    abfd, h ? h->root.root.string : "a local symbol");
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
+           }
+
+         /* Fall through.  */
+       case R_LARCH_JUMP_SLOT:
        case R_LARCH_64:
 
          need_dynreloc = 1;
@@ -2859,8 +2883,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  outrel.r_addend = relocation + rel->r_addend;
                }
 
-             /* No alloc space of func allocate_dynrelocs.  */
+             /* No alloc space of func allocate_dynrelocs.
+                No alloc space of invalid R_LARCH_32 in ELFCLASS64.  */
              if (unresolved_reloc
+                 && (ARCH_SIZE == 32 || r_type != R_LARCH_32)
                  && !(h && (h->is_weakalias || !h->dyn_relocs)))
                loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
            }
index 2d67c4f266897f3ad6791f1739e6892fec6ee6e7..4d9f4aebaffc410cf0da163dc622b0668a3f6d6f 100644 (file)
@@ -132,6 +132,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "reloc_le_with_shared"
     run_dump_test "reloc_ler_with_shared"
     run_dump_test "reloc_abs_with_shared"
+    run_dump_test "r_larch_32_elf64"
   }
 
   if [check_pie_support] {
diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
new file mode 100644 (file)
index 0000000..3431329
--- /dev/null
@@ -0,0 +1,4 @@
+#name: R_LARCH_32 in ELFCLASS64
+#source: r_larch_32_elf64.s
+#ld: -shared -melf64loongarch
+#error: R_LARCH_32 .* cannot be used in ELFCLASS64
diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
new file mode 100644 (file)
index 0000000..6649f2b
--- /dev/null
@@ -0,0 +1,3 @@
+.data
+x:
+       .4byte x