This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Convert absolute personalities into PC-relative ones
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: binutils at sourceware dot org
- Cc: mark at codesourcery dot com
- Date: Sun, 13 Sep 2009 20:53:38 +0100
- Subject: Convert absolute personalities into PC-relative ones
As discussed with Mark recently, this patch allows the linker to turn
absolute-but-locally-binding personality pointers into PC-relative ones,
under the usual "info->shared && we support this" condition. MIPS needs
this to work for indirect pointers too, and that shows up a problem in
the current elf-eh-frame.c code: it treats the top nibble as an enum
of the base address, whereas DW_EH_PE_indirect is really a separate
flag. So, for example, when adjusting PC-relative offsets to account
for things like removed CIEs and FDEs, we use:
(encoding & 0xf0) == DW_EH_PE_pcrel
even though (AIUI) the adjustment ought to be applied to
DW_EH_PE_pcrel | DW_EH_PE_indirect as well.
The patch goes through elf-eh-frame.c and replaces 0xf0 with 0x70.
This wasn't just mechanical though! I did try to justify that each
one was correct. And I think each one is. However:
switch (ent->fde_encoding & 0xf0)
{
case DW_EH_PE_indirect:
case DW_EH_PE_textrel:
BFD_ASSERT (hdr_info == NULL);
break;
case DW_EH_PE_datarel:
{
asection *got = bfd_get_section_by_name (abfd, ".got");
BFD_ASSERT (got != NULL);
address += got->vma;
}
break;
case DW_EH_PE_pcrel:
value += (bfd_vma) ent->offset - ent->new_offset;
address += (sec->output_section->vma
+ sec->output_offset
+ ent->offset + 8);
break;
}
is an interesting case. It seems to be asserting that we only have
an .eh_frame_hdr (and thus only use "address") in cases where we can
correctly calculate the address of the target code. That sounds like
a good idea in principle, but as mentioned above, we ought to exclude
all DW_EH_PE_indirect encodings, not just:
DW_EH_PE_indirect | DW_EH_PE_absptr
Admittedly that's probably only of academic interest, since no-one is
likely to use indirect pointers for the FDE ranges (are they? ;-)).
More importantly, we don't seem to actually enforce the asserted
condition anywhere, so I'm wondering whether we ought to have
something like the second (completely untested) patch as well.
I tested the first patch in combination with the third (gcc) patch
on mips64octeon-linux-gnu. There were no regressions from unpatched
GCC and binutils. After the patches, libstdc++.so still has a read-only
.eh_frame, but it is free from text relocations.
Any objections to the first patch? Any thoughts on the second?
If the first patch is OK, is it too invasive for the branch?
I'd ideally like to get this into 2.20, so that the feature is
in a released binutils when GCC 4.5 comes out.
If the first patch goes in, I'll apply the GCC one too, and then
do a follow-up to check for the correct linker version. I'll make
-fno-dwarf2-cfi-asm the default when this linker version check fails.
I'll also make -fno-dwarf2-cfi-asm the unconditional default for MIPS
GCC 4.4, as long as Mark or another GCC release manager agress.
Richard
bfd/
* elf-bfd.h (eh_cie_fde): Add personality_offset and
make_per_encoding_relative to the CIE structure. Add a padding field.
* elf-eh-frame.c (_bfd_elf_eh_frame_section_offset): Use 0x70
rather than 0xf0 when masking out the base address encoding
Record the offset of personality data from the start of the CIE.
Remove a repeated elf_backend_can_make_relative_eh_frame check.
(find_merged_cie): Take an info argument. If the personality
binds locally, try converting an absolute personality into
a local one.
(_bfd_elf_discard_section_eh_frame): Use 0x70 rather than 0xf0
when masking out the base address encoding. Update the call to
find_merged_cie.
(_bfd_elf_eh_frame_section_offset): Discard relocations against
the personality data if we are converting into PC-relative form.
(_bfd_elf_write_section_eh_frame): Use 0x70 rather than 0xf0
when masking out the base address encoding. Handle
make_per_encoding_relative.
ld/testsuite/
* ld-mips-elf/eh-frame5.s, ld-mips-elf/eh-frame5.ld,
ld-mips-elf/eh-frame5.d: New test.
* ld-mips-elf/mips-elf.exp: Run it.
Index: bfd/elf-bfd.h
===================================================================
--- bfd/elf-bfd.h 2009-09-13 18:18:04.000000000 +0100
+++ bfd/elf-bfd.h 2009-09-13 18:36:01.000000000 +0100
@@ -305,6 +305,10 @@ struct eh_cie_fde
asection *sec;
} u;
+ /* The offset of the personality data from the start of the CIE,
+ or 0 if the CIE doesn't have any. */
+ unsigned int personality_offset : 8;
+
/* True if we have marked relocations associated with this CIE. */
unsigned int gc_mark : 1;
@@ -312,8 +316,13 @@ struct eh_cie_fde
a PC-relative one. */
unsigned int make_lsda_relative : 1;
- /* True if the CIE contains personality data and if that data
- uses a PC-relative encoding. */
+ /* True if we have decided to turn an absolute personality
+ encoding into a PC-relative one. */
+ unsigned int make_per_encoding_relative : 1;
+
+ /* True if the CIE contains personality data and if that
+ data uses a PC-relative encoding. Always true when
+ make_per_encoding_relative is. */
unsigned int per_encoding_relative : 1;
/* True if we need to add an 'R' (FDE encoding) entry to the
@@ -322,6 +331,9 @@ struct eh_cie_fde
/* True if we have merged this CIE with another. */
unsigned int merged : 1;
+
+ /* Unused bits. */
+ unsigned int pad1 : 18;
} cie;
} u;
unsigned int reloc_index;
Index: bfd/elf-eh-frame.c
===================================================================
--- bfd/elf-eh-frame.c 2009-09-13 18:18:04.000000000 +0100
+++ bfd/elf-eh-frame.c 2009-09-13 18:36:01.000000000 +0100
@@ -675,11 +675,12 @@ #define GET_RELOC(buf) \
per_width = get_DW_EH_PE_width (cie->per_encoding,
ptr_size);
REQUIRE (per_width);
- if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned)
+ if ((cie->per_encoding & 0x70) == DW_EH_PE_aligned)
{
length = -(buf - ehbuf) & (per_width - 1);
REQUIRE (skip_bytes (&buf, end, length));
}
+ this_inf->u.cie.personality_offset = buf - start;
ENSURE_NO_RELOCS (buf);
/* Ensure we have a reloc here. */
REQUIRE (GET_RELOC (buf));
@@ -705,27 +706,23 @@ #define GET_RELOC(buf) \
->elf_backend_can_make_relative_eh_frame
(abfd, info, sec)))
{
- if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr)
+ if ((cie->fde_encoding & 0x70) == DW_EH_PE_absptr)
this_inf->make_relative = 1;
/* If the CIE doesn't already have an 'R' entry, it's fairly
easy to add one, provided that there's no aligned data
after the augmentation string. */
else if (cie->fde_encoding == DW_EH_PE_omit
- && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned)
+ && (cie->per_encoding & 0x70) != DW_EH_PE_aligned)
{
if (*cie->augmentation == 0)
this_inf->add_augmentation_size = 1;
this_inf->u.cie.add_fde_encoding = 1;
this_inf->make_relative = 1;
}
- }
- if (info->shared
- && (get_elf_backend_data (abfd)
- ->elf_backend_can_make_lsda_relative_eh_frame
- (abfd, info, sec))
- && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr)
- cie->can_make_lsda_relative = 1;
+ if ((cie->lsda_encoding & 0x70) == DW_EH_PE_absptr)
+ cie->can_make_lsda_relative = 1;
+ }
/* If FDE encoding was not specified, it defaults to
DW_EH_absptr. */
@@ -843,7 +840,7 @@ #define GET_RELOC(buf) \
cie->length -= end - insns_end;
}
if (set_loc_count
- && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel
+ && ((cie->fde_encoding & 0x70) == DW_EH_PE_pcrel
|| this_inf->make_relative))
{
unsigned int cnt;
@@ -963,7 +960,7 @@ _bfd_elf_gc_mark_fdes (struct bfd_link_i
relocations in REL. */
static struct eh_cie_fde *
-find_merged_cie (bfd *abfd, asection *sec,
+find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec,
struct eh_frame_hdr_info *hdr_info,
struct elf_reloc_cookie *cookie,
struct eh_cie_fde *cie_inf)
@@ -993,6 +990,8 @@ find_merged_cie (bfd *abfd, asection *se
if (cie->per_encoding != DW_EH_PE_omit)
{
+ bfd_boolean per_binds_local;
+
/* Work out the address of personality routine, either as an absolute
value or as a symbol. */
rel = cookie->rels + cie->personality.reloc_index;
@@ -1016,6 +1015,7 @@ find_merged_cie (bfd *abfd, asection *se
h = (struct elf_link_hash_entry *) h->root.u.i.link;
cie->personality.h = h;
+ per_binds_local = SYMBOL_REFERENCES_LOCAL (info, h);
}
else
{
@@ -1036,6 +1036,17 @@ find_merged_cie (bfd *abfd, asection *se
cie->personality.val = (sym->st_value
+ sym_sec->output_offset
+ sym_sec->output_section->vma);
+ per_binds_local = TRUE;
+ }
+
+ if (per_binds_local
+ && info->shared
+ && (cie->per_encoding & 0x70) == DW_EH_PE_absptr
+ && (get_elf_backend_data (abfd)
+ ->elf_backend_can_make_relative_eh_frame (abfd, info, sec)))
+ {
+ cie_inf->u.cie.make_per_encoding_relative = 1;
+ cie_inf->u.cie.per_encoding_relative = 1;
}
}
@@ -1110,9 +1121,9 @@ find_merged_cie (bfd *abfd, asection *se
if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie))
{
if (info->shared
- && (((ent->fde_encoding & 0xf0) == DW_EH_PE_absptr
+ && (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr
&& ent->make_relative == 0)
- || (ent->fde_encoding & 0xf0) == DW_EH_PE_aligned))
+ || (ent->fde_encoding & 0x70) == DW_EH_PE_aligned))
{
/* If a shared library uses absolute pointers
which we cannot turn into PC relative,
@@ -1125,8 +1136,8 @@ find_merged_cie (bfd *abfd, asection *se
}
ent->removed = 0;
hdr_info->fde_count++;
- ent->u.fde.cie_inf = find_merged_cie (abfd, sec, hdr_info, cookie,
- ent->u.fde.cie_inf);
+ ent->u.fde.cie_inf = find_merged_cie (abfd, info, sec, hdr_info,
+ cookie, ent->u.fde.cie_inf);
}
}
@@ -1276,6 +1287,14 @@ _bfd_elf_eh_frame_section_offset (bfd *o
if (sec_info->entry[mid].removed)
return (bfd_vma) -1;
+ /* If converting personality pointers to DW_EH_PE_pcrel, there will be
+ no need for run-time relocation against the personality field. */
+ if (sec_info->entry[mid].cie
+ && sec_info->entry[mid].u.cie.make_per_encoding_relative
+ && offset == (sec_info->entry[mid].offset + 8
+ + sec_info->entry[mid].u.cie.personality_offset))
+ return (bfd_vma) -2;
+
/* If converting to DW_EH_PE_pcrel, there will be no need for run-time
relocation against FDE's initial_location field. */
if (!sec_info->entry[mid].cie
@@ -1452,12 +1471,14 @@ _bfd_elf_write_section_eh_frame (bfd *ab
buf++;
break;
case 'P':
+ if (ent->u.cie.make_per_encoding_relative)
+ *buf |= DW_EH_PE_pcrel;
per_encoding = *buf++;
per_width = get_DW_EH_PE_width (per_encoding, ptr_size);
BFD_ASSERT (per_width != 0);
BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel)
== ent->u.cie.per_encoding_relative);
- if ((per_encoding & 0xf0) == DW_EH_PE_aligned)
+ if ((per_encoding & 0x70) == DW_EH_PE_aligned)
buf = (contents
+ ((buf - contents + per_width - 1)
& ~((bfd_size_type) per_width - 1)));
@@ -1467,8 +1488,15 @@ _bfd_elf_write_section_eh_frame (bfd *ab
val = read_value (abfd, buf, per_width,
get_DW_EH_PE_signed (per_encoding));
- val += (bfd_vma) ent->offset - ent->new_offset;
- val -= extra_string + extra_data;
+ if (ent->u.cie.make_per_encoding_relative)
+ val -= (sec->output_section->vma
+ + sec->output_offset
+ + (buf - contents));
+ else
+ {
+ val += (bfd_vma) ent->offset - ent->new_offset;
+ val -= extra_string + extra_data;
+ }
write_value (abfd, buf, val, per_width);
action &= ~4;
}
@@ -1511,9 +1539,8 @@ _bfd_elf_write_section_eh_frame (bfd *ab
address = value;
if (value)
{
- switch (ent->fde_encoding & 0xf0)
+ switch (ent->fde_encoding & 0x70)
{
- case DW_EH_PE_indirect:
case DW_EH_PE_textrel:
BFD_ASSERT (hdr_info == NULL);
break;
@@ -1550,7 +1577,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
+ ent->new_offset);
}
- if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel
+ if ((ent->lsda_encoding & 0x70) == DW_EH_PE_pcrel
|| cie->u.cie.make_lsda_relative)
{
buf += ent->lsda_offset;
@@ -1559,7 +1586,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
get_DW_EH_PE_signed (ent->lsda_encoding));
if (value)
{
- if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel)
+ if ((ent->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
value += (bfd_vma) ent->offset - ent->new_offset;
else if (cie->u.cie.make_lsda_relative)
value -= (sec->output_section->vma
@@ -1598,7 +1625,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
if (!value)
continue;
- if ((ent->fde_encoding & 0xf0) == DW_EH_PE_pcrel)
+ if ((ent->fde_encoding & 0x70) == DW_EH_PE_pcrel)
value += (bfd_vma) ent->offset + 8 - new_offset;
if (ent->make_relative)
value -= (sec->output_section->vma
Index: ld/testsuite/ld-mips-elf/eh-frame5.s
===================================================================
--- /dev/null 2009-09-12 23:43:45.501816639 +0100
+++ ld/testsuite/ld-mips-elf/eh-frame5.s 2009-09-13 18:57:26.000000000 +0100
@@ -0,0 +1,107 @@
+ .cfi_startproc
+ .cfi_personality 0x0,local_pers
+ .cfi_lsda 0x0,LSDA
+ .ent f1
+f1:
+ nop
+ .end f1
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x0,hidden_pers
+ .cfi_lsda 0x0,LSDA
+ .ent f2
+f2:
+ nop
+ .end f2
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x0,global_pers
+ .cfi_lsda 0x0,LSDA
+ .ent f3
+f3:
+ nop
+ .end f3
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x0,extern_pers
+ .cfi_lsda 0x0,LSDA
+ .ent f4
+f4:
+ nop
+ .end f4
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x80,local_indirect_ptr
+ .cfi_lsda 0x0,LSDA
+ .ent f5
+f5:
+ nop
+ .end f5
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x80,hidden_indirect_ptr
+ .cfi_lsda 0x0,LSDA
+ .ent f6
+f6:
+ nop
+ .end f6
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x80,global_indirect_ptr
+ .cfi_lsda 0x0,LSDA
+ .ent f7
+f7:
+ nop
+ .end f7
+ .cfi_endproc
+
+ .cfi_startproc
+ .cfi_personality 0x80,extern_indirect_ptr
+ .cfi_lsda 0x0,LSDA
+ .ent f8
+f8:
+ nop
+ .end f8
+ .cfi_endproc
+
+
+ .ent local_pers
+local_pers:
+ nop
+ .end local_pers
+
+ .globl hidden_pers
+ .hidden hidden_pers
+ .ent hidden_pers
+hidden_pers:
+ nop
+ .end hidden_pers
+
+ .globl global_pers
+ .ent global_pers
+global_pers:
+ nop
+ .end global_pers
+
+ .section .data,"aw",@progbits
+
+local_indirect_ptr:
+ .4byte pers1
+
+ .globl hidden_indirect_ptr
+ .hidden hidden_indirect_ptr
+hidden_indirect_ptr:
+ .4byte pers2
+
+ .globl global_indirect_ptr
+global_indirect_ptr:
+ .4byte pers3
+
+LSDA:
+ .4byte 0
Index: ld/testsuite/ld-mips-elf/eh-frame5.ld
===================================================================
--- /dev/null 2009-09-12 23:43:45.501816639 +0100
+++ ld/testsuite/ld-mips-elf/eh-frame5.ld 2009-09-13 18:56:54.000000000 +0100
@@ -0,0 +1,18 @@
+SECTIONS
+{
+ . = 0;
+ .reginfo : { *(.reginfo) }
+ .dynamic : { *(.dynamic) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.dyn : { *(.rel.dyn) }
+ . = 0x800;
+ .text : { *(.text) }
+ . = 0xc00;
+ .eh_frame : { *(.eh_frame) }
+ . = 0x10000;
+ .data : { *(.data) }
+ . = 0x10400;
+ _gp = . + 0x7ff0;
+ .got : { *(.got) }
+}
Index: ld/testsuite/ld-mips-elf/eh-frame5.d
===================================================================
--- /dev/null 2009-09-12 23:43:45.501816639 +0100
+++ ld/testsuite/ld-mips-elf/eh-frame5.d 2009-09-13 19:25:38.000000000 +0100
@@ -0,0 +1,278 @@
+
+Relocation section '.rel.dyn' at offset 0x101f0 contains 8 entries:
+ Offset Info Type Sym.Value Sym. Name
+00000000 .* R_MIPS_NONE *
+#
+# The order of the relocations doesn't really matter, but they must
+# be some permutation of the list below.
+#
+00010008 .* R_MIPS_REL32 00000000 pers3
+00000c7b .* R_MIPS_REL32 00000828 global_pers
+00000d7f .* R_MIPS_REL32 00000000 extern_indirect_ptr
+00010000 .* R_MIPS_REL32 00000000 pers1
+00010004 .* R_MIPS_REL32 00000000 pers2
+00000caf .* R_MIPS_REL32 00000000 extern_pers
+00000d4b .* R_MIPS_REL32 00010008 global_indirect_ptr
+Contents of the \.eh_frame section:
+
+# Text addresses
+# --------------
+# f1 = 0x800
+# f2 = 0x804
+# f3 = 0x808
+# f4 = 0x80c
+# f5 = 0x810
+# f6 = 0x814
+# f7 = 0x818
+# f8 = 0x81c
+# local_pers = 0x820
+# hidden_pers = 0x824
+# global_pers = 0x828
+
+# Data addresses
+# --------------
+# local_indirect_ptr = 0x10000
+# hidden_indirect_ptr = 0x10004
+# global_indirect_ptr = 0x10008
+# LSDA = 0x1000c
+
+#-------------------------------------------------------------------------
+# f1
+#-------------------------------------------------------------------------
+00000000 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xc12: DW_EH_PE_pcrel for personality encoding
+# 0xc13: 0x820 - 0xc13 (local_pers - .)
+# 0xc17: DW_EH_PE_pcrel for LDSA encoding
+# 0xc18: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 10 ff ff fc 0d 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+0000001c 00000014 00000020 FDE cie=00000000 pc=00000800..00000804
+#
+# 0xc2d: 0x1000c - 0xc2d (LDSA - .)
+#
+ Augmentation data: 00 00 f3 df
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f2
+#-------------------------------------------------------------------------
+00000034 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xc46: DW_EH_PE_pcrel for personality encoding
+# 0xc47: 0x824 - 0xc47 (hidden_pers - .)
+# 0xc4d: DW_EH_PE_pcrel for LDSA encoding
+# 0xc4e: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 10 ff ff fb dd 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+00000050 00000014 00000020 FDE cie=00000034 pc=00000804..00000808
+#
+# 0xc61: 0x1000c - 0xc61 (LDSA - .)
+#
+ Augmentation data: 00 00 f3 ab
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f3
+#-------------------------------------------------------------------------
+00000068 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xc7a: DW_EH_PE_absptr for personality encoding
+# 0xc7b: global_pers (reloc above)
+# 0xc7f: DW_EH_PE_pcrel for LDSA encoding
+# 0xc80: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 00 00 00 00 00 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+00000084 00000014 00000020 FDE cie=00000068 pc=00000808..0000080c
+#
+# 0xc95: 0x1000c - 0xc95 (LDSA - .)
+#
+ Augmentation data: 00 00 f3 77
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f4
+#-------------------------------------------------------------------------
+0000009c 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xcae: DW_EH_PE_absptr for personality encoding
+# 0xcaf: extern_pers (reloc above)
+# 0xcb3: DW_EH_PE_pcrel for LDSA encoding
+# 0xcb4: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 00 00 00 00 00 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+000000b8 00000014 00000020 FDE cie=0000009c pc=0000080c..00000810
+#
+# 0xcc9: 0x1000c - 0xcc9 (LDSA - .)
+#
+ Augmentation data: 00 00 f3 43
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f5
+#-------------------------------------------------------------------------
+000000d0 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xce2: DW_EH_PE_indirect | DW_EH_PE_pcrel for personality encoding
+# 0xce3: 0x10000 - 0xce3 (local_indirect_ptr - .)
+# 0xce7: DW_EH_PE_pcrel for LDSA encoding
+# 0xce8: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 90 00 00 f3 1d 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+000000ec 00000014 00000020 FDE cie=000000d0 pc=00000810..00000814
+#
+# 0xcfd: 0x1000c - 0xcfd (LDSA - .)
+#
+ Augmentation data: 00 00 f3 0f
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f6
+#-------------------------------------------------------------------------
+00000104 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xd16: DW_EH_PE_pcrel for personality encoding
+# 0xd17: 0x10004 - 0xd17 (hidden_indirect_ptr - .)
+# 0xd1d: DW_EH_PE_pcrel for LDSA encoding
+# 0xd1e: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 90 00 00 f2 ed 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+00000120 00000014 00000020 FDE cie=00000104 pc=00000814..00000818
+#
+# 0xd31: 0x1000c - 0xd31 (LDSA - .)
+#
+ Augmentation data: 00 00 f2 db
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f7
+#-------------------------------------------------------------------------
+00000138 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xd4a: DW_EH_PE_indirect | DW_EH_PE_absptr for personality encoding
+# 0xd4b: global_indirect_ptr (reloc above)
+# 0xd4f: DW_EH_PE_pcrel for LDSA encoding
+# 0xd50: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 80 00 00 00 00 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+00000154 00000014 00000020 FDE cie=00000138 pc=00000818..0000081c
+#
+# 0xd65: 0x1000c - 0xd65 (LDSA - .)
+#
+ Augmentation data: 00 00 f2 a7
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
+#-------------------------------------------------------------------------
+# f8
+#-------------------------------------------------------------------------
+0000016c 00000018 00000000 CIE
+ Version: 1
+ Augmentation: "zPLR"
+ Code alignment factor: 1
+ Data alignment factor: -4
+ Return address column: 31
+#
+# 0xd7e: DW_EH_PE_indirect | DW_EH_PE_absptr for personality encoding
+# 0xd7f: extern_indirect_ptr (reloc above)
+# 0xd83: DW_EH_PE_pcrel for LDSA encoding
+# 0xd84: DW_EH_PE_pcrel | DW_EH_PE_sdata4 for FDE encoding
+#
+ Augmentation data: 80 00 00 00 00 10 1b
+
+ DW_CFA_def_cfa_register: r29
+ DW_CFA_nop
+
+00000188 00000014 00000020 FDE cie=0000016c pc=0000081c..00000820
+#
+# 0xd99: 0x1000c - 0xd99 (LDSA - .)
+#
+ Augmentation data: 00 00 f2 73
+
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- ld/testsuite/ld-mips-elf/mips-elf.exp 2009-09-13 19:21:55.000000000 +0100
+++ ld/testsuite/ld-mips-elf/mips-elf.exp 2009-09-13 19:34:36.000000000 +0100
@@ -304,6 +304,17 @@ if {$embedded_elf} {
run_dump_test "eh-frame3"
run_dump_test "eh-frame4"
}
+if {$linux_gnu} {
+ set eh_frame5_test {
+ {"MIPS eh-frame 5"
+ "-melf32btsmip -shared -Teh-frame5.ld"
+ "-32 -EB"
+ {eh-frame5.s}
+ {{readelf {--relocs -wf} eh-frame5.d}}
+ "eh-frame5.so"}
+ }
+ run_ld_link_tests $eh_frame5_test
+}
run_dump_test "jaloverflow"
run_dump_test "jaloverflow-2"
bfd/
* elf-eh-frame.c (can_identify_fde_code_p): New function.
(_bfd_elf_discard_section_eh_frame): Use it.
Index: bfd/elf-eh-frame.c
===================================================================
--- bfd/elf-eh-frame.c 2009-09-13 20:19:46.000000000 +0100
+++ bfd/elf-eh-frame.c 2009-09-13 20:28:12.000000000 +0100
@@ -1086,6 +1086,30 @@ find_merged_cie (bfd *abfd, struct bfd_l
return new_cie->cie_inf;
}
+/* Return true if ENT's FDE encoding allows us to identify the target
+ code at link time. */
+
+static bfd_boolean
+can_identify_fde_code_p (struct bfd_link_info *info, struct eh_cie_fde *ent)
+{
+ if ((ent->fde_encoding & DW_EH_PE_indirect) != 0)
+ return FALSE;
+
+ switch (ent->fde_encoding & 0x70)
+ {
+ case DW_EH_PE_aligned:
+ case DW_EH_PE_absptr:
+ return !info->shared || ent->make_relative;
+
+ case DW_EH_PE_pcrel:
+ case DW_EH_PE_datarel:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
/* This function is called for each input file before the .eh_frame
section is relocated. It discards duplicate CIEs and FDEs for discarded
functions. The function returns TRUE iff any entries have been
@@ -1120,10 +1144,7 @@ find_merged_cie (bfd *abfd, struct bfd_l
&& cookie->rel->r_offset == ent->offset + 8);
if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie))
{
- if (info->shared
- && (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr
- && ent->make_relative == 0)
- || (ent->fde_encoding & 0x70) == DW_EH_PE_aligned))
+ if (!can_identify_fde_code_p (info, ent))
{
/* If a shared library uses absolute pointers
which we cannot turn into PC relative,
gcc/
* config/mips/mips.h (ASM_PREFERRED_EH_DATA_FORMAT): Use indirect
pointers for global data on true PIC targets.
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h 2009-09-13 02:51:11.000000000 +0100
+++ gcc/config/mips/mips.h 2009-09-13 02:51:11.000000000 +0100
@@ -3174,3 +3174,10 @@ #define FINAL_PRESCAN_INSN(INSN, OPVEC,
/* This is necessary to avoid a warning about comparing different enum
types. */
#define mips_tune_attr ((enum attr_cpu) mips_tune)
+
+/* Use indirect pointers for global data so that the .eh_frame section
+ can be read-only. The linker will turn absolute relocations into
+ relative ones. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
+ (((GLOBAL) && flag_pic && !TARGET_ABSOLUTE_ABICALLS ? DW_EH_PE_indirect : 0) \
+ | DW_EH_PE_absptr)
Index: gcc/dwarf2asm.c
===================================================================
--- gcc/dwarf2asm.c 2009-09-13 08:13:55.000000000 +0100
+++ gcc/dwarf2asm.c 2009-09-13 08:13:58.000000000 +0100
@@ -446,6 +446,8 @@ #define S(p, v) case p: return v;
S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
+ S(DW_EH_PE_indirect | DW_EH_PE_absptr, "indirect absolute")
+
S(DW_EH_PE_indirect | DW_EH_PE_absptr | DW_EH_PE_pcrel,
"indirect pcrel")
S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,