]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
MIPS: Fix linker for REL TLS HI16/LO16 relocs
authorAlan Modra <amodra@gmail.com>
Sat, 12 Jul 2025 00:25:53 +0000 (01:25 +0100)
committerMaciej W. Rozycki <macro@orcam.me.uk>
Sat, 12 Jul 2025 00:25:53 +0000 (01:25 +0100)
With REL targets TLS HI16/LO16 relocations need to combine the low part
with the high part just as all the remaining HI16/LO16 relocations, so
as to determine the borrow in calculation correctly.

2025-07-12  Alan Modra  <amodra@gmail.com>

bfd/
PR 19977
* elfxx-mips.c (tls_hi16_reloc_p): New function.
(mips_elf_add_lo16_rel_addend): Handle tls relocs.
(_bfd_mips_elf_relocate_section): Likewise.

2025-07-12  Maciej W. Rozycki  <macro@orcam.me.uk>

ld/
PR 19977
* testsuite/ld-mips-elf/pr19977.d: New test.
* testsuite/ld-mips-elf/pr19977-mips16.d: New test.
* testsuite/ld-mips-elf/pr19977-micromips.d: New test.
* testsuite/ld-mips-elf/pr19977-r.d: New test.
* testsuite/ld-mips-elf/pr19977-r-mips16.d: New test.
* testsuite/ld-mips-elf/pr19977-r-micromips.d: New test.
* testsuite/ld-mips-elf/pr19977-r.s: New test source.
* testsuite/ld-mips-elf/pr19977.ld: New test linker script.
* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.

bfd/elfxx-mips.c
ld/testsuite/ld-mips-elf/mips-elf.exp
ld/testsuite/ld-mips-elf/pr19977-micromips.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977-mips16.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977-r-micromips.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977-r-mips16.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977-r.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977-r.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/pr19977.ld [new file with mode: 0644]

index 7d1dff1d7212f4eafd69b77869a87f85be05bde9..3c38f51aefd78e23eb8dbbbf381251b4bc47cbe1 100644 (file)
@@ -2293,6 +2293,17 @@ lo16_reloc_p (int r_type)
          || r_type == R_MIPS_PCLO16);
 }
 
+static inline bool
+tls_hi16_reloc_p (int r_type)
+{
+  return (r_type == R_MIPS_TLS_DTPREL_HI16
+         || r_type == R_MIPS_TLS_TPREL_HI16
+         || r_type == R_MIPS16_TLS_DTPREL_HI16
+         || r_type == R_MIPS16_TLS_TPREL_HI16
+         || r_type == R_MICROMIPS_TLS_DTPREL_HI16
+         || r_type == R_MICROMIPS_TLS_TPREL_HI16);
+}
+
 static inline bool
 mips16_call_reloc_p (int r_type)
 {
@@ -8312,14 +8323,44 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
   bfd_vma l;
 
   r_type = ELF_R_TYPE (abfd, rel->r_info);
-  if (mips16_reloc_p (r_type))
-    lo16_type = R_MIPS16_LO16;
-  else if (micromips_reloc_p (r_type))
-    lo16_type = R_MICROMIPS_LO16;
-  else if (r_type == R_MIPS_PCHI16)
-    lo16_type = R_MIPS_PCLO16;
-  else
-    lo16_type = R_MIPS_LO16;
+  switch (r_type)
+    {
+    case R_MIPS_HI16:
+    case R_MIPS_GOT16:
+      lo16_type = R_MIPS_LO16;
+      break;
+    case R_MIPS_PCHI16:
+      lo16_type = R_MIPS_PCLO16;
+      break;
+    case R_MIPS_TLS_DTPREL_HI16:
+      lo16_type = R_MIPS_TLS_DTPREL_LO16;
+      break;
+    case R_MIPS_TLS_TPREL_HI16:
+      lo16_type = R_MIPS_TLS_TPREL_LO16;
+      break;
+    case R_MIPS16_HI16:
+    case R_MIPS16_GOT16:
+      lo16_type = R_MIPS16_LO16;
+      break;
+    case R_MIPS16_TLS_DTPREL_HI16:
+      lo16_type = R_MIPS16_TLS_DTPREL_LO16;
+      break;
+    case R_MIPS16_TLS_TPREL_HI16:
+      lo16_type = R_MIPS16_TLS_TPREL_LO16;
+      break;
+    case R_MICROMIPS_HI16:
+    case R_MICROMIPS_GOT16:
+      lo16_type = R_MICROMIPS_LO16;
+      break;
+    case R_MICROMIPS_TLS_DTPREL_HI16:
+      lo16_type = R_MICROMIPS_TLS_DTPREL_LO16;
+      break;
+    case R_MICROMIPS_TLS_TPREL_HI16:
+      lo16_type = R_MICROMIPS_TLS_TPREL_LO16;
+      break;
+    default:
+      abort ();
+    }
 
   /* The combined value is the sum of the HI16 addend, left-shifted by
      sixteen bits, and the LO16 addend, sign extended.  (Usually, the
@@ -10547,7 +10588,8 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              if (hi16_reloc_p (r_type)
                  || (got16_reloc_p (r_type)
                      && mips_elf_local_relocation_p (input_bfd, rel,
-                                                     local_sections)))
+                                                     local_sections))
+                 || tls_hi16_reloc_p (r_type))
                {
                  if (!mips_elf_add_lo16_rel_addend (input_bfd, input_section,
                                                     rel, relend,
@@ -10585,7 +10627,9 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          if (!rela_relocation_p && rel->r_addend)
            {
              addend += rel->r_addend;
-             if (hi16_reloc_p (r_type) || got16_reloc_p (r_type))
+             if (hi16_reloc_p (r_type)
+                 || got16_reloc_p (r_type)
+                 || tls_hi16_reloc_p (r_type))
                addend = mips_elf_high (addend);
              else if (r_type == R_MIPS_HIGHER)
                addend = mips_elf_higher (addend);
index 6fc960dfc10bc1ec163d588b1fdaf1c5ef278daf..e8a1d42791e1c6df92be964337503c8542f975d4 100644 (file)
@@ -867,6 +867,16 @@ run_dump_test_n64 "pcrel-hilo-srec" \
        [list [list name (n64)] \
              [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
 
+run_dump_test_o32 "pr19977"
+run_dump_test_n32 "pr19977" [list [list name (n32)]]
+run_dump_test_o32 "pr19977-mips16" noarch
+run_dump_test_n32 "pr19977-mips16" [list noarch [list name (n32)]]
+run_dump_test_o32 "pr19977-micromips" noarch
+run_dump_test_n32 "pr19977-micromips" [list noarch [list name (n32)]]
+run_dump_test_o32 "pr19977-r"
+run_dump_test_o32 "pr19977-r-mips16" noarch
+run_dump_test_o32 "pr19977-r-micromips" noarch
+
 if { $linux_gnu } {
     run_dump_test_n32 "textrel-1"
     run_dump_test "got-page-1"
diff --git a/ld/testsuite/ld-mips-elf/pr19977-micromips.d b/ld/testsuite/ld-mips-elf/pr19977-micromips.d
new file mode 100644 (file)
index 0000000..021b29c
--- /dev/null
@@ -0,0 +1,25 @@
+#name: pr19977 microMIPS
+#source: ../../../gas/testsuite/gas/mips/pr19977.s
+#as: -mmicromips -march=mips64r2
+#objdump: -d
+#ld: -Tpr19977.ld -e 0 -N
+#notarget: mips*el-ps2-elf*
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+
+10000000 <[^>]*>:
+10000000:      3060 1122       li      v1,4386
+10000004:      0063 8000       sll     v1,v1,0x10
+10000008:      3063 2988       addiu   v1,v1,10632
+1000000c:      3060 1122       li      v1,4386
+10000010:      0063 8000       sll     v1,v1,0x10
+10000014:      3063 1988       addiu   v1,v1,6536
+10000018:      3060 1122       li      v1,4386
+1000001c:      0063 8000       sll     v1,v1,0x10
+10000020:      3063 a988       addiu   v1,v1,-22136
+10000024:      3060 1122       li      v1,4386
+10000028:      0063 8000       sll     v1,v1,0x10
+1000002c:      3063 9988       addiu   v1,v1,-26232
+#pass
diff --git a/ld/testsuite/ld-mips-elf/pr19977-mips16.d b/ld/testsuite/ld-mips-elf/pr19977-mips16.d
new file mode 100644 (file)
index 0000000..c927357
--- /dev/null
@@ -0,0 +1,24 @@
+#name: pr19977 MIPS16
+#source: ../../../gas/testsuite/gas/mips/pr19977.s
+#as: -mips16 -march=mips3
+#objdump: -d
+#ld: -Tpr19977.ld -e 0 -N
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+
+10000000 <[^>]*>:
+10000000:      f122 6b02       li      v1,4386
+10000004:      f400 3360       sll     v1,16
+10000008:      f185 4b08       addiu   v1,10632
+1000000c:      f122 6b02       li      v1,4386
+10000010:      f400 3360       sll     v1,16
+10000014:      f183 4b08       addiu   v1,6536
+10000018:      f122 6b02       li      v1,4386
+1000001c:      f400 3360       sll     v1,16
+10000020:      f195 4b08       addiu   v1,-22136
+10000024:      f122 6b02       li      v1,4386
+10000028:      f400 3360       sll     v1,16
+1000002c:      f193 4b08       addiu   v1,-26232
+#pass
diff --git a/ld/testsuite/ld-mips-elf/pr19977-r-micromips.d b/ld/testsuite/ld-mips-elf/pr19977-r-micromips.d
new file mode 100644 (file)
index 0000000..db99b97
--- /dev/null
@@ -0,0 +1,8 @@
+#name: pr19977 microMIPS -r
+#source: pr19977-r.s
+#source: ../../../gas/testsuite/gas/mips/pr19977.s
+#as: -mmicromips -march=mips64r2
+#objdump: -dr
+#ld: -r
+#notarget: mips*el-ps2-elf*
+#dump: pr19977-r.d
diff --git a/ld/testsuite/ld-mips-elf/pr19977-r-mips16.d b/ld/testsuite/ld-mips-elf/pr19977-r-mips16.d
new file mode 100644 (file)
index 0000000..dafa793
--- /dev/null
@@ -0,0 +1,7 @@
+#name: pr19977 MIPS16 -r
+#source: pr19977-r.s
+#source: ../../../gas/testsuite/gas/mips/pr19977.s
+#as: -mips16 -march=mips3
+#objdump: -dr
+#ld: -r
+#dump: pr19977-r.d
diff --git a/ld/testsuite/ld-mips-elf/pr19977-r.d b/ld/testsuite/ld-mips-elf/pr19977-r.d
new file mode 100644 (file)
index 0000000..166194b
--- /dev/null
@@ -0,0 +1,32 @@
+#name: pr19977 MIPS -r
+#source: pr19977-r.s
+#source: ../../../gas/testsuite/gas/mips/pr19977.s
+#objdump: -dr
+#ld: -r
+
+.*
+
+Disassembly of section \.text:
+
+0+ <foo>:
+   0:  .*      li      v1,4387
+                       0: R_(|MICRO)MIPS(|16)_TLS_TPREL_HI16   \$loc0
+   4:  .*      sll     .*
+   8:  .*      addiu   v1(|,v1),-26232
+                       8: R_(|MICRO)MIPS(|16)_TLS_TPREL_LO16   \$loc0
+   c:  .*      li      v1,4387
+                       c: R_(|MICRO)MIPS(|16)_TLS_DTPREL_HI16  \$loc0
+  10:  .*      sll     .*
+  14:  .*      addiu   v1(|,v1),-26232
+                       14: R_(|MICRO)MIPS(|16)_TLS_DTPREL_LO16 \$loc0
+  18:  .*      li      v1,4387
+                       18: R_(|MICRO)MIPS(|16)_TLS_TPREL_HI16  \.tdata
+  1c:  .*      sll     .*
+  20:  .*      addiu   v1(|,v1),-30328
+                       20: R_(|MICRO)MIPS(|16)_TLS_TPREL_LO16  \.tdata
+  24:  .*      li      v1,4387
+                       24: R_(|MICRO)MIPS(|16)_TLS_DTPREL_HI16 \.tdata
+  28:  .*      sll     .*
+  2c:  .*      addiu   v1(|,v1),-30328
+                       2c: R_(|MICRO)MIPS(|16)_TLS_DTPREL_LO16 \.tdata
+#pass
diff --git a/ld/testsuite/ld-mips-elf/pr19977-r.s b/ld/testsuite/ld-mips-elf/pr19977-r.s
new file mode 100644 (file)
index 0000000..4a46b30
--- /dev/null
@@ -0,0 +1,2 @@
+ .section .tdata,"awT",%progbits
+ .space 28672
diff --git a/ld/testsuite/ld-mips-elf/pr19977.d b/ld/testsuite/ld-mips-elf/pr19977.d
new file mode 100644 (file)
index 0000000..145f697
--- /dev/null
@@ -0,0 +1,23 @@
+#name: pr19977 MIPS
+#source: ../../../gas/testsuite/gas/mips/pr19977.s
+#objdump: -d
+#ld: -Tpr19977.ld -e 0 -N
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+
+10000000 <[^>]*>:
+10000000:      24031122        li      v1,4386
+10000004:      00031c00        sll     v1,v1,0x10
+10000008:      24632988        addiu   v1,v1,10632
+1000000c:      24031122        li      v1,4386
+10000010:      00031c00        sll     v1,v1,0x10
+10000014:      24631988        addiu   v1,v1,6536
+10000018:      24031122        li      v1,4386
+1000001c:      00031c00        sll     v1,v1,0x10
+10000020:      2463a988        addiu   v1,v1,-22136
+10000024:      24031122        li      v1,4386
+10000028:      00031c00        sll     v1,v1,0x10
+1000002c:      24639988        addiu   v1,v1,-26232
+#pass
diff --git a/ld/testsuite/ld-mips-elf/pr19977.ld b/ld/testsuite/ld-mips-elf/pr19977.ld
new file mode 100644 (file)
index 0000000..0b2f7c1
--- /dev/null
@@ -0,0 +1,14 @@
+MEMORY
+{
+  text (rx) : ORIGIN = 0x10000000, LENGTH = 0x40000
+  data (w) : ORIGIN = 0x34560000, LENGTH = 0x40000
+}
+SECTIONS
+{
+  .text : { *(.text) } >text
+  .tdata : { *(.tdata) } >data
+  .symtab : { *(.symtab) }
+  .strtab : { *(.strtab) }
+  .shstrtab : { *(.shstrtab) }
+  /DISCARD/ : { *(*) }
+}