PR ld/22966: Fix n64 MIPS `.got.plt' range checks

The addressable signed 32-bit range for n64 MIPS `.got.plt' references
is from 0xffffffff7fff8000 to 0x7fff7fff, due to how the composition of
an LUI and an LD instruction works for address calculation in the 64-bit
addressing mode, such as when CP0.Status.UX=1.

We currently have a range check in `mips_finish_exec_plt', however it is
not correct as it verifies that the `.got.plt' start address referred is
between 0xffffffff80000000 and 0x7fffffff.  It is also implemented as an
assertion rather than a proper error message despite that the situation
can be triggered by user input.  Additionally there is no check made for
individual `.got.plt' entries referred even though they can be out of
range while the `.got.plt' start address is not.

Fix all these problems and use the correct range for the check, limiting
it to n64 output files, and then issue a proper error message both in
`mips_finish_exec_plt' and in `_bfd_mips_elf_finish_dynamic_symbol',
suggesting the use of the `-Ttext-segment=...' option that will often
work and with the default linker scripts in particular.  Add suitable
tests covering boundary cases.

	bfd/
	PR ld/22966
	* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Verify the
	`.got.plt' entry referred is in range.
	(mips_finish_exec_plt): Correct the range check for `.got.plt'
	start.  Replace the assertion used for that with a proper error
	message.

	ld/
	PR ld/22966
	* testsuite/ld-mips-elf/n64-plt-1.dd: New test.
	* testsuite/ld-mips-elf/n64-plt-1.gd: New test.
	* testsuite/ld-mips-elf/n64-plt-2.ed: New test.
	* testsuite/ld-mips-elf/n64-plt-3.ed: New test.
	* testsuite/ld-mips-elf/n64-plt-4.dd: New test.
	* testsuite/ld-mips-elf/n64-plt-4.gd: New test.
	* testsuite/ld-mips-elf/n64-plt-1.ld: New test linker script.
	* testsuite/ld-mips-elf/n64-plt-2.ld: New test linker script.
	* testsuite/ld-mips-elf/n64-plt-3.ld: New test linker script.
	* testsuite/ld-mips-elf/n64-plt-4.ld: New test linker script.
	* testsuite/ld-mips-elf/n64-plt.s: New test source.
	* testsuite/ld-mips-elf/n64-plt-lib.s: New test source.
	* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.
This commit is contained in:
Maciej W. Rozycki 2018-06-20 00:37:51 +01:00
parent 6a382bcead
commit 789ff5b6c2
16 changed files with 300 additions and 2 deletions

View File

@ -1,3 +1,12 @@
2018-06-19 Maciej W. Rozycki <macro@mips.com>
PR ld/22966
* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Verify the
`.got.plt' entry referred is in range.
(mips_finish_exec_plt): Correct the range check for `.got.plt'
start. Replace the assertion used for that with a proper error
message.
2018-06-19 Maciej W. Rozycki <macro@mips.com>
* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Fix

View File

@ -10602,6 +10602,22 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
got_address_low = got_address & 0xffff;
/* The PLT sequence is not safe for N64 if .got.plt entry's address
cannot be loaded in two instructions. */
if (ABI_64_P (output_bfd)
&& ((got_address + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: `%pA' entry VMA of %#" PRIx64 " outside the 32-bit range "
"supported; consider using `-Ttext-segment=...'"),
output_bfd,
htab->root.sgotplt->output_section,
(int64_t) got_address);
bfd_set_error (bfd_error_no_error);
return FALSE;
}
/* Initially point the .got.plt entry at the PLT header. */
loc = (htab->root.sgotplt->contents
+ got_index * MIPS_ELF_GOT_SIZE (dynobj));
@ -11246,8 +11262,19 @@ mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
/* The PLT sequence is not safe for N64 if .got.plt's address can
not be loaded in two instructions. */
BFD_ASSERT ((gotplt_value & ~(bfd_vma) 0x7fffffff) == 0
|| ~(gotplt_value | 0x7fffffff) == 0);
if (ABI_64_P (output_bfd)
&& ((gotplt_value + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: `%pA' start VMA of %#" PRIx64 " outside the 32-bit range "
"supported; consider using `-Ttext-segment=...'"),
output_bfd,
htab->root.sgotplt->output_section,
(int64_t) gotplt_value);
bfd_set_error (bfd_error_no_error);
return FALSE;
}
/* Install the PLT header. */
loc = htab->root.splt->contents;

View File

@ -1,3 +1,20 @@
2018-06-19 Maciej W. Rozycki <macro@mips.com>
PR ld/22966
* testsuite/ld-mips-elf/n64-plt-1.dd: New test.
* testsuite/ld-mips-elf/n64-plt-1.gd: New test.
* testsuite/ld-mips-elf/n64-plt-2.ed: New test.
* testsuite/ld-mips-elf/n64-plt-3.ed: New test.
* testsuite/ld-mips-elf/n64-plt-4.dd: New test.
* testsuite/ld-mips-elf/n64-plt-4.gd: New test.
* testsuite/ld-mips-elf/n64-plt-1.ld: New test linker script.
* testsuite/ld-mips-elf/n64-plt-2.ld: New test linker script.
* testsuite/ld-mips-elf/n64-plt-3.ld: New test linker script.
* testsuite/ld-mips-elf/n64-plt-4.ld: New test linker script.
* testsuite/ld-mips-elf/n64-plt.s: New test source.
* testsuite/ld-mips-elf/n64-plt-lib.s: New test source.
* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.
2018-06-19 Maciej W. Rozycki <macro@mips.com>
* testsuite/ld-elf/shared.exp: XFAIL DT_TEXTREL map file warning

View File

@ -1167,6 +1167,50 @@ if { $linux_gnu } {
}
}
# Verify graceful handling of n64 PLT 32-bit range overflows. Given
# that the alignment of `.got.plt' is 8 the highest usable positive
# address is 0x7fff7ff8 and the lowest usable negative address is
# 0xffffffff7fff8000.
if { $linux_gnu } {
run_ld_link_tests [list \
[list "Shared library for MIPS n64 PLT 32-bit range tests" \
"-shared $abi_ldflags(n64)" "" \
"$abi_asflags(n64)" \
{ n64-plt-lib.s } \
{} \
"n64-plt-lib.so"] \
[list "MIPS n64 PLT 32-bit range test 1" \
"$abi_ldflags(n64) -T n64-plt-1.ld -e foo" \
"tmpdir/n64-plt-lib.so" \
"$abi_asflags(n64)" \
{ n64-plt.s } \
{ { objdump -d n64-plt-1.dd } \
{ readelf -A n64-plt-1.gd } } \
"n64-plt-1"] \
[list "MIPS n64 PLT 32-bit range test 2" \
"$abi_ldflags(n64) -T n64-plt-2.ld -e foo" \
"tmpdir/n64-plt-lib.so" \
"$abi_asflags(n64)" \
{ n64-plt.s } \
{ { ld n64-plt-2.ed } } \
"n64-plt-2"] \
[list "MIPS n64 PLT 32-bit range test 3" \
"$abi_ldflags(n64) -T n64-plt-3.ld -e foo" \
"tmpdir/n64-plt-lib.so" \
"$abi_asflags(n64)" \
{ n64-plt.s } \
{ { ld n64-plt-3.ed } } \
"n64-plt-3"] \
[list "MIPS n64 PLT 32-bit range test 4" \
"$abi_ldflags(n64) -T n64-plt-4.ld -e foo" \
"tmpdir/n64-plt-lib.so" \
"$abi_asflags(n64)" \
{ n64-plt.s } \
{ { objdump -d n64-plt-4.dd } \
{ readelf -A n64-plt-4.gd } } \
"n64-plt-4"]]
}
# PR ld/19908 export class tests.
if { $linux_gnu } {
run_ld_link_tests [list \

View File

@ -0,0 +1,26 @@
.*: +file format .*mips.*
Disassembly of section \.plt:
0000000010000280 <_PROCEDURE_LINKAGE_TABLE_>:
10000280: 3c0e7fff lui t2,0x7fff
10000284: ddd97fe8 ld t9,32744\(t2\)
10000288: 25ce7fe8 addiu t2,t2,32744
1000028c: 030ec023 subu t8,t8,t2
10000290: 03e07825 move t3,ra
10000294: 0018c0c2 srl t8,t8,0x3
10000298: 0320f809 jalr t9
1000029c: 2718fffe addiu t8,t8,-2
00000000100002a0 <bar@plt>:
100002a0: 3c0f7fff lui t3,0x7fff
100002a4: ddf97ff8 ld t9,32760\(t3\)
100002a8: 03200008 jr t9
100002ac: 25f87ff8 addiu t8,t3,32760
Disassembly of section \.text:
00000000100002b0 <foo>:
100002b0: 080000a8 j 100002a0 <bar@plt>
100002b4: 00000000 nop
\.\.\.

View File

@ -0,0 +1,18 @@
Primary GOT:
Canonical gp value: 000000007ffffff0
Reserved entries:
Address Access Initial Purpose
000000007fff8000 -32752\(gp\) 0000000000000000 Lazy resolver
000000007fff8008 -32744\(gp\) 8000000000000000 Module pointer \(GNU extension\)
PLT GOT:
Reserved entries:
Address Initial Purpose
000000007fff7fe8 0000000000000000 PLT lazy resolver
000000007fff7ff0 0000000000000000 Module pointer
Entries:
Address Initial Sym\.Val\. Type Ndx Name
000000007fff7ff8 0000000010000280 0000000000000000 FUNC UND bar

View File

@ -0,0 +1,22 @@
MEMORY
{
text (rx) : ORIGIN = 0x10000000, LENGTH = 0x10000
data (w) : ORIGIN = 0x7fff7fe8, LENGTH = 0x10000
}
SECTIONS
{
.dynamic : { *(.dynamic) } >text
.hash : { *(.hash) } >text
.dynsym : { *(.dynsym) } >text
.dynstr : { *(.dynstr) } >text
.rel.plt : { *(.rel.plt) } >text
.plt : { *(.plt) } >text
.text : { *(.text) } >text
.interp : { *(.interp) } >text
.got.plt : { *(.got.plt) } >data
.got : { *(.got) } >data
.symtab : { *(.symtab) }
.strtab : { *(.strtab) }
.shstrtab : { *(.shstrtab) }
/DISCARD/ : { *(*) }
}

View File

@ -0,0 +1 @@
[^\n]*: `\.got\.plt' entry VMA of 0x7fff8000 outside the 32-bit range supported; consider using `-Ttext-segment=\.\.\.'

View File

@ -0,0 +1,23 @@
MEMORY
{
text (rx) : ORIGIN = 0x10000000, LENGTH = 0x10000
data (w) : ORIGIN = 0x7fff7ff0, LENGTH = 0x10000
}
SECTIONS
{
.dynamic : { *(.dynamic) } >text
.hash : { *(.hash) } >text
.dynsym : { *(.dynsym) } >text
.dynstr : { *(.dynstr) } >text
.rel.plt : { *(.rel.plt) } >text
.plt : { *(.plt) } >text
.text : { *(.text) } >text
.interp : { *(.interp) } >text
.got.plt : { *(.got.plt) } >data
.rld.map : { *(.rld.map) } >data
.got : { *(.got) } >data
.symtab : { *(.symtab) }
.strtab : { *(.strtab) }
.shstrtab : { *(.shstrtab) }
/DISCARD/ : { *(*) }
}

View File

@ -0,0 +1 @@
[^\n]*: `\.got\.plt' start VMA of 0xffffffff7fff7ff0 outside the 32-bit range supported; consider using `-Ttext-segment=\.\.\.'

View File

@ -0,0 +1,23 @@
MEMORY
{
text (rx) : ORIGIN = 0xffffffff10000000, LENGTH = 0x10000
data (w) : ORIGIN = 0xffffffff7fff7ff0, LENGTH = 0x10000
}
SECTIONS
{
.dynamic : { *(.dynamic) } >text
.hash : { *(.hash) } >text
.dynsym : { *(.dynsym) } >text
.dynstr : { *(.dynstr) } >text
.rel.plt : { *(.rel.plt) } >text
.plt : { *(.plt) } >text
.text : { *(.text) } >text
.interp : { *(.interp) } >text
.got.plt : { *(.got.plt) } >data
.rld.map : { *(.rld.map) } >data
.got : { *(.got) } >data
.symtab : { *(.symtab) }
.strtab : { *(.strtab) }
.shstrtab : { *(.shstrtab) }
/DISCARD/ : { *(*) }
}

View File

@ -0,0 +1,26 @@
.*: +file format .*mips.*
Disassembly of section \.plt:
ffffffff10000280 <_PROCEDURE_LINKAGE_TABLE_>:
ffffffff10000280: 3c0e8000 lui t2,0x8000
ffffffff10000284: ddd98000 ld t9,-32768\(t2\)
ffffffff10000288: 25ce8000 addiu t2,t2,-32768
ffffffff1000028c: 030ec023 subu t8,t8,t2
ffffffff10000290: 03e07825 move t3,ra
ffffffff10000294: 0018c0c2 srl t8,t8,0x3
ffffffff10000298: 0320f809 jalr t9
ffffffff1000029c: 2718fffe addiu t8,t8,-2
ffffffff100002a0 <bar@plt>:
ffffffff100002a0: 3c0f8000 lui t3,0x8000
ffffffff100002a4: ddf98010 ld t9,-32752\(t3\)
ffffffff100002a8: 03200008 jr t9
ffffffff100002ac: 25f88010 addiu t8,t3,-32752
Disassembly of section \.text:
ffffffff100002b0 <foo>:
ffffffff100002b0: 080000a8 j ffffffff100002a0 <bar@plt>
ffffffff100002b4: 00000000 nop
\.\.\.

View File

@ -0,0 +1,18 @@
Primary GOT:
Canonical gp value: ffffffff80000010
Reserved entries:
Address Access Initial Purpose
ffffffff7fff8020 -32752\(gp\) 0000000000000000 Lazy resolver
ffffffff7fff8028 -32744\(gp\) 8000000000000000 Module pointer \(GNU extension\)
PLT GOT:
Reserved entries:
Address Initial Purpose
ffffffff7fff8000 0000000000000000 PLT lazy resolver
ffffffff7fff8008 0000000000000000 Module pointer
Entries:
Address Initial Sym\.Val\. Type Ndx Name
ffffffff7fff8010 ffffffff10000280 0000000000000000 FUNC UND bar

View File

@ -0,0 +1,23 @@
MEMORY
{
text (rx) : ORIGIN = 0xffffffff10000000, LENGTH = 0x10000
data (w) : ORIGIN = 0xffffffff7fff8000, LENGTH = 0x10000
}
SECTIONS
{
.dynamic : { *(.dynamic) } >text
.hash : { *(.hash) } >text
.dynsym : { *(.dynsym) } >text
.dynstr : { *(.dynstr) } >text
.rel.plt : { *(.rel.plt) } >text
.plt : { *(.plt) } >text
.text : { *(.text) } >text
.interp : { *(.interp) } >text
.got.plt : { *(.got.plt) } >data
.rld.map : { *(.rld.map) } >data
.got : { *(.got) } >data
.symtab : { *(.symtab) }
.strtab : { *(.strtab) }
.shstrtab : { *(.shstrtab) }
/DISCARD/ : { *(*) }
}

View File

@ -0,0 +1,11 @@
.abicalls
.text
.globl bar
.ent bar
bar:
.frame $sp, 0, $31
.mask 0x00000000, 0
.fmask 0x00000000, 0
jr $31
.end bar

View File

@ -0,0 +1,9 @@
.abicalls
.option pic0
.text
.globl foo
.ent foo
foo:
j bar
.end foo