This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[patch] RFD: Incorrect R_MIPS_26 handling for RELA
- From: "Maciej W. Rozycki" <macro at ds2 dot pg dot gda dot pl>
- To: binutils at sources dot redhat dot com, Thiemo Seufer <ica2_ts at csv dot ica dot uni-stuttgart dot de>
- Cc: Ralf Baechle <ralf at oss dot sgi dot com>
- Date: Wed, 5 Jun 2002 13:51:19 +0200 (MET DST)
- Subject: [patch] RFD: Incorrect R_MIPS_26 handling for RELA
- Organization: Technical University of Gdansk
On Tue, 4 Jun 2002, Maciej W. Rozycki wrote:
> How about R_MIPS_26 relocs? I discovered they are broken for the 64 ABI
> (likely a RELA problem) and I am currently working on a fix. As a result
> of the bug a kernel executable is useless.
OK, I've tracked the bug down. The problem is for RELA R_MIPS_26
relocations the addend isn't shifted right. I get a broken executable for
the following simple program:
$ cat r_mips_26.s
.file 1 "r_mips_26.c"
.section .text
.version "01.01"
gcc2_compiled.:
.text
.align 2
.globl dummy
.ent dummy
dummy:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, extra= 0
.mask 0x00000000,0
.fmask 0x00000000,0
j $31
.end dummy
.align 2
.ent test
test:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, extra= 0
.mask 0x00000000,0
.fmask 0x00000000,0
j $31
.end test
.align 2
.globl __start
.ent __start
__start:
.frame $sp,16,$31 # vars= 0, regs= 1/0, args= 0, extra= 0
.mask 0x80000000,-16
.fmask 0x00000000,0
dsubu $sp,$sp,16
sd $31,0($sp)
jal test
ld $31,0($sp)
#nop
.set noreorder
.set nomacro
j $31
daddu $sp,$sp,16
.set macro
.set reorder
.end __start
$ mips64el-linux-as -mips3 -64 -o r_mips_26.o r_mips_26.s
$ mips64el-linux-objdump -Sr r_mips_26.o
r_mips_26.o: file format elf64-tradlittlemips
Disassembly of section .text:
0000000000000000 <dummy>:
0: 03e00008 jr ra
4: 00000000 nop
0000000000000008 <test>:
8: 03e00008 jr ra
c: 00000000 nop
0000000000000010 <__start>:
10: 67bdfff0 daddiu sp,sp,-16
14: ffbf0000 sd ra,0(sp)
18: 0c000000 jal 0 <dummy>
18: R_MIPS_26 .text+0x8
1c: 00000000 nop
20: dfbf0000 ld ra,0(sp)
24: 03e00008 jr ra
28: 67bd0010 daddiu sp,sp,16
2c: 00000000 nop
So far, so good. Or at least it looks so.
$ mips64el-linux-ld -o r_mips_26 r_mips_26.o
$ mips64el-linux-objdump -S r_mips_26
r_mips_26: file format elf64-tradlittlemips
Disassembly of section .text:
00000001200000e0 <dummy>:
1200000e0: 03e00008 jr ra
1200000e4: 00000000 nop
00000001200000e8 <test>:
1200000e8: 03e00008 jr ra
1200000ec: 00000000 nop
00000001200000f0 <__start>:
1200000f0: 67bdfff0 daddiu sp,sp,-16
1200000f4: ffbf0000 sd ra,0(sp)
1200000f8: 0c000040 jal 120000100 <__start+0x10>
1200000fc: 00000000 nop
120000100: dfbf0000 ld ra,0(sp)
120000104: 03e00008 jr ra
120000108: 67bd0010 daddiu sp,sp,16
12000010c: 00000000 nop
Now it doesn't even look good anymore.
Here is a patch I created that makes binutils produce good executables.
It right-shifts R_MIPS_26 addends for writing to RELA sections like it
does for REL. I'm unsure if that's the optimal solution. The alternative
could be not to left-shift R_MIPS_26 addends when reading from RELA
sections.
I chose this approach is there is nowhere stated R_MIPS_26 addends should
be calculated differently depending on whether REL or RELA is used.
Specifically, "64-bit ELF Object File Specification" from SGI (basically
the MIPS supplement for the 64-bit ABI) specifies this calculation
uniformly for both relocation formats (table 32 in section 2.9.2), even
though it contains explicit statements about REL and RELA specifics with
respect to other relocation types. Also "System V Application Binary
Interface" (aka the General ABI) doesn't provide any specific comments
about addends in RELA relocations.
From the technical point of view, there is no advantage with either
approach, apart from, possibly a better aesthetical consistency with the
one I chose. Therefore I think the decision should be taken based upon
how original MIPS and/or SGI tools handle this case. Can anyone please
check what they do?
A patch follows. With the patch I get:
$ mips64el-linux-objdump -Sr r_mips_26-1.o
r_mips_26-1.o: file format elf64-tradlittlemips
Disassembly of section .text:
0000000000000000 <dummy>:
0: 03e00008 jr ra
4: 00000000 nop
0000000000000008 <test>:
8: 03e00008 jr ra
c: 00000000 nop
0000000000000010 <__start>:
10: 67bdfff0 daddiu sp,sp,-16
14: ffbf0000 sd ra,0(sp)
18: 0c000000 jal 0 <dummy>
18: R_MIPS_26 .text+0x2
1c: 00000000 nop
20: dfbf0000 ld ra,0(sp)
24: 03e00008 jr ra
28: 67bd0010 daddiu sp,sp,16
2c: 00000000 nop
The output will have to be fixed for this approach for the final patch.
$ mips64el-linux-objdump -S r_mips_26-1
r_mips_26-1: file format elf64-tradlittlemips
Disassembly of section .text:
00000001200000e0 <dummy>:
1200000e0: 03e00008 jr ra
1200000e4: 00000000 nop
00000001200000e8 <test>:
1200000e8: 03e00008 jr ra
1200000ec: 00000000 nop
00000001200000f0 <__start>:
1200000f0: 67bdfff0 daddiu sp,sp,-16
1200000f4: ffbf0000 sd ra,0(sp)
1200000f8: 0c00003a jal 1200000e8 <test>
1200000fc: 00000000 nop
120000100: dfbf0000 ld ra,0(sp)
120000104: 03e00008 jr ra
120000108: 67bd0010 daddiu sp,sp,16
12000010c: 00000000 nop
The executable is correct.
Maciej
--
+ Maciej W. Rozycki, Technical University of Gdansk, Poland +
+--------------------------------------------------------------+
+ e-mail: macro@ds2.pg.gda.pl, PGP key available +
binutils-2.12.90-20020603-mips64_26.patch
diff -up --recursive --new-file binutils.macro/bfd/elf64-mips.c binutils/bfd/elf64-mips.c
--- binutils.macro/bfd/elf64-mips.c 2002-04-05 03:25:28.000000000 +0000
+++ binutils/bfd/elf64-mips.c 2002-06-05 08:32:38.000000000 +0000
@@ -106,6 +106,8 @@ static bfd_reloc_status_type mips_elf64_
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type mips_elf64_highest_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type mips_elf64_26_reloca
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type mips_elf64_gprel16_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type mips_elf64_gprel16_reloca
@@ -745,7 +747,7 @@ static reloc_howto_type mips_elf64_howto
/* This needs complex overflow
detection, because the upper 36
bits must match the PC + 4. */
- bfd_elf_generic_reloc, /* special_function */
+ mips_elf64_26_reloca, /* special_function */
"R_MIPS_26", /* name */
false, /* partial_inplace */
0, /* src_mask */
@@ -1614,6 +1616,35 @@ mips_elf64_final_gp (output_bfd, symbol,
return bfd_reloc_ok;
}
+/* Do a R_MIPS_26 RELA relocation. */
+
+bfd_reloc_status_type
+mips_elf64_26_reloca (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ /* If we're relocating, and this is an external symbol with no
+ addend, we don't want to change anything. We will only have an
+ addend if this is a newly created reloc, not read from an ELF
+ file. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ reloc_entry->addend >>= 2;
+ return bfd_reloc_continue;
+}
+
/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must
become the offset from the gp register. */