This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Fix ld/418
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: Jakub Jelinek <jakub at redhat dot com>
- Cc: binutils at sources dot redhat dot com, mendell at ca dot ibm dot com
- Date: Fri, 1 Oct 2004 00:06:57 +0930
- Subject: Fix ld/418
Hi Jakub,
I'd like your opinion on the following patch to fix
http://sources.redhat.com/bugzilla/show_bug.cgi?id=418. xlc apparently
uses a LSDA that isn't a pointer, thus making it pc-relative doesn't
really make much sense. The changelog below should make it clear
what I'm doing.
* elf-bfd.h (struct eh_cie_fde): Add need_relative and
need_lsda_relative.
* elf-eh-frame.c (_bfd_elf_eh_frame_section_offset): Set
need_relative or need_lsda_relative if we are processing an
offset for a reloc on a FDE initial loc or LSDA field
respectively.
(_bfd_elf_write_section_eh_frame): Test need_relative and
need_lsda_relative in place of corresponding make_* field
when deciding to use pc-relative encodings.
BTW, I haven't tested this very well yet, just binutils testsuite runs
and checking that this cures the testcase. I intend to build gcc and
glibc overnight, and verify that it doesn't cause regressions before
committing.
An alternative hack that works in this particular case is to not
translate lsda to pcrel if lsda is too small to be a pointer.
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.158
diff -u -p -r1.158 elf-bfd.h
--- bfd/elf-bfd.h 17 Sep 2004 07:14:25 -0000 1.158
+++ bfd/elf-bfd.h 30 Sep 2004 14:00:31 -0000
@@ -296,7 +296,9 @@ struct eh_cie_fde
unsigned int cie : 1;
unsigned int removed : 1;
unsigned int make_relative : 1;
+ unsigned int need_relative : 1;
unsigned int make_lsda_relative : 1;
+ unsigned int need_lsda_relative : 1;
unsigned int per_encoding_relative : 1;
};
Index: bfd/elf-eh-frame.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-eh-frame.c,v
retrieving revision 1.31
diff -u -p -r1.31 elf-eh-frame.c
--- bfd/elf-eh-frame.c 24 Jun 2004 04:46:17 -0000 1.31
+++ bfd/elf-eh-frame.c 30 Sep 2004 13:59:52 -0000
@@ -775,7 +775,10 @@ _bfd_elf_eh_frame_section_offset (bfd *o
if (sec_info->entry[mid].make_relative
&& ! sec_info->entry[mid].cie
&& offset == sec_info->entry[mid].offset + 8)
- return (bfd_vma) -2;
+ {
+ sec_info->entry[mid].need_relative = 1;
+ return (bfd_vma) -2;
+ }
/* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need
for run-time relocation against LSDA field. */
@@ -783,7 +786,10 @@ _bfd_elf_eh_frame_section_offset (bfd *o
&& ! sec_info->entry[mid].cie
&& (offset == (sec_info->entry[mid].offset + 8
+ sec_info->entry[mid].lsda_offset)))
- return (bfd_vma) -2;
+ {
+ sec_info->entry[mid].need_lsda_relative = 1;
+ return (bfd_vma) -2;
+ }
return (offset + sec_info->entry[mid].new_offset
- sec_info->entry[mid].offset);
@@ -850,8 +856,8 @@ _bfd_elf_write_section_eh_frame (bfd *ab
{
/* CIE */
cie_offset = sec_info->entry[i].new_offset;
- if (sec_info->entry[i].make_relative
- || sec_info->entry[i].make_lsda_relative
+ if (sec_info->entry[i].need_relative
+ || sec_info->entry[i].need_lsda_relative
|| sec_info->entry[i].per_encoding_relative)
{
unsigned char *aug;
@@ -860,8 +866,8 @@ _bfd_elf_write_section_eh_frame (bfd *ab
/* Need to find 'R' or 'L' augmentation's argument and modify
DW_EH_PE_* value. */
- action = (sec_info->entry[i].make_relative ? 1 : 0)
- | (sec_info->entry[i].make_lsda_relative ? 2 : 0)
+ action = (sec_info->entry[i].need_relative ? 1 : 0)
+ | (sec_info->entry[i].need_lsda_relative ? 2 : 0)
| (sec_info->entry[i].per_encoding_relative ? 4 : 0);
buf = contents + sec_info->entry[i].offset;
/* Skip length, id and version. */
@@ -968,7 +974,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
+ sec_info->entry[i].offset + 8);
break;
}
- if (sec_info->entry[i].make_relative)
+ if (sec_info->entry[i].need_relative)
value -= (sec->output_section->vma + sec->output_offset
+ sec_info->entry[i].new_offset + 8);
write_value (abfd, buf, value, width);
@@ -983,7 +989,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
}
if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel
- || sec_info->entry[i].make_lsda_relative)
+ || sec_info->entry[i].need_lsda_relative)
{
buf += sec_info->entry[i].lsda_offset;
width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding,
@@ -997,7 +1003,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
== DW_EH_PE_pcrel)
value += (sec_info->entry[i].offset
- sec_info->entry[i].new_offset);
- else if (sec_info->entry[i].make_lsda_relative)
+ else if (sec_info->entry[i].need_lsda_relative)
value -= (sec->output_section->vma + sec->output_offset
+ sec_info->entry[i].new_offset + 8
+ sec_info->entry[i].lsda_offset);
--
Alan Modra
IBM OzLabs - Linux Technology Centre