This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: i386 and "R_386_16 relocation against SEC_MERGE section"
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: Etienne Lorrain <etienne_lorrain at yahoo dot fr>
- Cc: binutils at sources dot redhat dot com
- Date: Thu, 9 May 2002 16:04:16 +0930
- Subject: Re: i386 and "R_386_16 relocation against SEC_MERGE section"
- References: <20020507090036.43490.qmail@web11804.mail.yahoo.com>
On Tue, May 07, 2002 at 11:00:36AM +0200, Etienne Lorrain wrote:
> ld: main.o(.text.menu+0x887): R_386_16 relocation against SEC_MERGE section
This goes a bit overboard and fixes pcrel relocs to SEC_MERGE sections
as well. We're hardly going to branch in a SEC_MERGE section, but I
figured that if I'm supporting more than R_386_32 I might as well do
them all. The overflow checking is quite possibly wrong; If
somebody wants to analyse and correct, please go ahead!
bfd/ChangeLog
* elf32-i386.c (elf_howto_table): Comments.
(elf_i386_relocate_section): Handle more relocs for relocatable
linking and against SEC_MERGE sections.
gas/ChangeLog
* config/tc-i386.c (md_estimate_size_before_relax) Don't lose
reloc when no_cond_jump_promotion.
Index: bfd/elf32-i386.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-i386.c,v
retrieving revision 1.67
diff -c -p -r1.67 elf32-i386.c
*** bfd/elf32-i386.c 4 Apr 2002 19:53:36 -0000 1.67
--- bfd/elf32-i386.c 8 May 2002 04:56:59 -0000
*************** static reloc_howto_type elf_howto_table[
*** 154,160 ****
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
! false),
/* GNU extension to record C++ vtable member usage. */
HOWTO (R_386_GNU_VTENTRY, /* type */
--- 154,160 ----
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
! false), /* pcrel_offset */
/* GNU extension to record C++ vtable member usage. */
HOWTO (R_386_GNU_VTENTRY, /* type */
*************** static reloc_howto_type elf_howto_table[
*** 169,175 ****
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
! false)
#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset)
--- 169,175 ----
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
! false) /* pcrel_offset */
#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset)
*************** elf_i386_relocate_section (output_bfd, i
*** 1724,1729 ****
--- 1724,1730 ----
bfd_vma off;
bfd_vma relocation;
boolean unresolved_reloc;
+ boolean overflow;
bfd_reloc_status_type r;
unsigned int indx;
*************** elf_i386_relocate_section (output_bfd, i
*** 1745,1766 ****
if (info->relocateable)
{
/* This is a relocatable link. We don't have to change
anything, unless the reloc is against a section symbol,
in which case we have to adjust according to where the
section symbol winds up in the output section. */
! if (r_symndx < symtab_hdr->sh_info)
{
! sym = local_syms + r_symndx;
! if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
! bfd_vma val;
!
! sec = local_sections[r_symndx];
! val = bfd_get_32 (input_bfd, contents + rel->r_offset);
! val += sec->output_offset + sym->st_value;
! bfd_put_32 (input_bfd, val, contents + rel->r_offset);
}
}
continue;
}
--- 1746,1811 ----
if (info->relocateable)
{
+ bfd_vma val;
+ bfd_vma addend;
+ bfd_byte *where;
+
/* This is a relocatable link. We don't have to change
anything, unless the reloc is against a section symbol,
in which case we have to adjust according to where the
section symbol winds up in the output section. */
! if (r_symndx >= symtab_hdr->sh_info)
! continue;
!
! sym = local_syms + r_symndx;
! if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
! continue;
!
! sec = local_sections[r_symndx];
! val = sec->output_offset;
! if (val == 0)
! continue;
!
! where = contents + rel->r_offset;
! switch (howto->size)
{
! case 0:
! addend = bfd_get_8 (input_bfd, where);
! if (howto->pc_relative)
! addend = (addend ^ 0x80) - 0x80;
! val += addend;
! bfd_put_8 (input_bfd, val, where);
! if (howto->pc_relative)
! val += 0x80;
! if (val > 0xff)
{
! h = NULL;
! r = bfd_reloc_overflow;
! goto overflow_error;
! }
! break;
! case 1:
! addend = bfd_get_16 (input_bfd, where);
! if (howto->pc_relative)
! addend = (addend ^ 0x8000) - 0x8000;
! val += addend;
! bfd_put_16 (input_bfd, val, where);
! if (howto->pc_relative)
! val += 0x8000;
! if (output_bfd->arch_info->mach != bfd_mach_i386_i8086
! && val > 0xffff)
! {
! h = NULL;
! r = bfd_reloc_overflow;
! goto overflow_error;
}
+ break;
+ case 2:
+ val += bfd_get_32 (input_bfd, where);
+ bfd_put_32 (input_bfd, val, where);
+ break;
+ default:
+ abort ();
}
continue;
}
*************** elf_i386_relocate_section (output_bfd, i
*** 1770,1775 ****
--- 1815,1821 ----
sym = NULL;
sec = NULL;
unresolved_reloc = false;
+ overflow = false;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
*************** elf_i386_relocate_section (output_bfd, i
*** 1782,1805 ****
{
asection *msec;
bfd_vma addend;
! if (howto->src_mask != 0xffffffff)
{
! (*_bfd_error_handler)
! (_("%s(%s+0x%lx): %s relocation against SEC_MERGE section"),
! bfd_archive_filename (input_bfd),
! bfd_get_section_name (input_bfd, input_section),
! (long) rel->r_offset, howto->name);
! return false;
}
- addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
msec = sec;
! addend =
! _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
! - relocation;
addend += msec->output_section->vma + msec->output_offset;
! bfd_put_32 (input_bfd, addend, contents + rel->r_offset);
}
}
else
--- 1828,1895 ----
{
asection *msec;
bfd_vma addend;
+ bfd_byte *where = contents + rel->r_offset;
! switch (howto->size)
{
! case 0:
! addend = bfd_get_8 (input_bfd, where);
! if (howto->pc_relative)
! {
! addend = (addend ^ 0x80) - 0x80;
! addend += 1;
! }
! break;
! case 1:
! addend = bfd_get_16 (input_bfd, where);
! if (howto->pc_relative)
! {
! addend = (addend ^ 0x8000) - 0x8000;
! addend += 2;
! }
! break;
! case 2:
! addend = bfd_get_32 (input_bfd, where);
! if (howto->pc_relative)
! {
! addend = (addend ^ 0x80000000) - 0x80000000;
! addend += 4;
! }
! break;
! default:
! abort ();
}
msec = sec;
! addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
! addend -= relocation;
addend += msec->output_section->vma + msec->output_offset;
!
! switch (howto->size)
! {
! case 0:
! if (howto->pc_relative)
! addend -= 1;
! bfd_put_8 (input_bfd, addend, where);
! if (howto->pc_relative)
! addend += 0x80;
! overflow = addend > 0xff;
! break;
! case 1:
! if (howto->pc_relative)
! addend -= 2;
! bfd_put_16 (input_bfd, addend, where);
! if (howto->pc_relative)
! addend += 0x8000;
! if (output_bfd->arch_info->mach != bfd_mach_i386_i8086)
! overflow = addend > 0xffff;
! break;
! case 2:
! if (howto->pc_relative)
! addend -= 4;
! bfd_put_32 (input_bfd, addend, where);
! break;
! }
}
}
else
*************** elf_i386_relocate_section (output_bfd, i
*** 2082,2088 ****
--- 2172,2181 ----
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, (bfd_vma) 0);
+ if (overflow && r == bfd_reloc_ok)
+ r = bfd_reloc_overflow;
+ overflow_error:
if (r != bfd_reloc_ok)
{
const char *name;
*************** elf_i386_relocate_section (output_bfd, i
*** 2102,2108 ****
if (r == bfd_reloc_overflow)
{
-
if (! ((*info->callbacks->reloc_overflow)
(info, name, howto->name, (bfd_vma) 0,
input_bfd, input_section, rel->r_offset)))
--- 2195,2200 ----
Index: gas/config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.118
diff -u -p -r1.118 tc-i386.c
--- gas/config/tc-i386.c 1 May 2002 00:53:55 -0000 1.118
+++ gas/config/tc-i386.c 9 May 2002 04:59:27 -0000
@@ -4235,10 +4235,8 @@ md_estimate_size_before_relax (fragP, se
break;
case COND_JUMP86:
- if (no_cond_jump_promotion)
- goto relax_guess;
-
- if (size == 2)
+ if (size == 2
+ && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
{
/* Negate the condition, and branch past an
unconditional jump. */
@@ -4258,8 +4256,15 @@ md_estimate_size_before_relax (fragP, se
/* Fall through. */
case COND_JUMP:
- if (no_cond_jump_promotion)
- goto relax_guess;
+ if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
+ {
+ fragP->fr_fix += 1;
+ fix_new (fragP, old_fr_fix, 1,
+ fragP->fr_symbol,
+ fragP->fr_offset, 1,
+ BFD_RELOC_8_PCREL);
+ break;
+ }
/* This changes the byte-displacement jump 0x7N
to the (d)word-displacement jump 0x0f,0x8N. */
@@ -4281,7 +4286,6 @@ md_estimate_size_before_relax (fragP, se
return fragP->fr_fix - old_fr_fix;
}
- relax_guess:
/* Guess size depending on current relax state. Initially the relax
state will correspond to a short jump and we return 1, because
the variable part of the frag (the branch offset) is one byte
--
Alan Modra
IBM OzLabs - Linux Technology Centre