This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
ld on irix revisited
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: 21 Jun 2003 17:27:23 +0100
- Subject: ld on irix revisited
I think I've finally got ld working on irix6 with shared libraries.
Patches attached below.
First, here's a summary of the differences I found between glibc and
irix rld. I'm sure most of this stuff isn't new, but I need to say
it anyway in order to justify the patches.
glibc 2.2.5's behaviour was:
If the symbol index < DT_MIPS_GOTSYM, add the final symbol value.
Otherwise add the symbol's final GOT entry.
glibc 2.3.2's behaviour is:
If the symbol index < DT_MIPS_GOTSYM, add the base address.
Otherwise add the symbol's final GOT entry.
The irix rld hehaviour seems to be:
If the symbol index < DT_MIPS_GOT_SYM, subtract the symbol's
st_value and add its final value. Otherwise subract the symbol's
initial GOT entry and add its final GOT entry.
See last weekend's postings for a verbose justification of the irix
behaviour. But that's all by-the-bye. Comparing 2.3.2 with rld,
there are three incompatible cases:
A. Relocs against symbol STN_UNDEF
----------------------------------
- glibc adds the base address
- irix rld does nothing (st_value = 0, final symbol value = 0)
(FWIW, glibc seems to be wrong here since the r_info description
in the gABI says:
If the index is STN_UNDEF, the undefined symbol index,
the relocation uses 0 as the "symbol value".
The 64-bit ABI has similar wording.)
B. Relocs against defined external symbols
------------------------------------------
- glibc adds the final symbol value
- irix rld subtracts the initial contents of the GOT (the original
st_value) and adds the final symbol value
This one's the killer. The addend must include the symbol
value when using irix rld but it must not when using glibc.
C. Relocs against undefined external symbols
--------------------------------------------
- glibc adds the final symbol value
- irix rld subtracts the initial contents of the GOT and adds
the final symbol value
At the moment, ld initialises the GOT with the value it found in the
external DSO, so these behaviours aren't compatible. I think we're
supposed to initialise the GOT to zero in this case, see:
http://sources.redhat.com/ml/binutils/2003-06/msg00525.html
for justification.
The attached patches are intended to fix the irix problems while
keeping compatibility with glibc. Where the two loaders need
different behaviour (cases (A) and (B) above), I've used SGI_COMPAT
to select between them.
All the patches are needed in order to get correct irix behaviour:
it doesn't really make sense to apply some and not others. I've split
them up anyway in the hope that they'll be easier to review that way.
Note: the patches are against 2.14.
Patch 1
-------
* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Always
initialize a GOT entry to the symbol's st_value.
Fixes the GOT initailisation for (C). glibc doesn't use the initial
contents in this case, so the change is compatible with both loaders.
Again, see:
http://sources.redhat.com/ml/binutils/2003-06/msg00525.html
for a justification.
Patch 2
-------
* bfd/elfxx-mips.c (mips_elf_create_dynamic_relocation): In SGI-
compatible objects, add the values of defined external symbols
to the addend.
Fixes (B) for irix rld. This is a variation of the patch posted here:
http://sources.redhat.com/ml/binutils/2003-06/msg00533.html
but with the change predicated on SGI_COMPAT since it isn't
compatible with glibc.
Patch 3
-------
* bfd/elfxx-mips.c (mips_elf_create_dynamic_relocation): Treat
forced-local symbols like other locals. Don't create relocations
against STN_UNDEF in irix objects.
Disables this patch:
http://sources.redhat.com/ml/binutils/2003-03/msg00148.html
for SGI objects since relocations against symbol 0 do not have
the desired effect ((A) above).
Also treats forced-local symbols in the same way as other locals.
At the moment, relocations against forced-local symbols are always
turned into relocations against symbol 0. The patch prevents this
for irix targets but keeps it for glibc.
Patch 4
-------
* elfxx-mips.c (mips_elf_link_hash_entry): Remove min_dyn_reloc_index.
(mips_elf_link_hash_newfunc): Don't set it.
(mips_elf_create_dynamic_relocation): Likewise.
(_bfd_mips_elf_copy_indirect_symbol): Likewise.
(bfd_mips_elf_swap_msym_in): Reenable.
(mips_elf_adjust_msym_indices): New function.
(_bfd_mips_elf_finish_dynamic_symbol): Just use a 0 symbol index.
(_bfd_mips_elf_finish_dynamic_sections): After sorting .rel.dyn,
go through .msym and set up the ms_info fields appropriately.
This is the same as the patch posted here:
http://sources.redhat.com/ml/binutils/2003-06/msg00533.html
except that the new version should use more canonical types.
See the message for a full explanation.
Patch 5
-------
* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Don't try to
create .msym entries for forced-local symbols.
At the moment we try this and corrupt the end of the previous section.
Patch 6
-------
* elfxx-mips.c (mips_elf_create_dynamic_relocation): Fix handling
of relocations whose offset is -2.
Fix the handling of .eh_frame if things like language-specific
data are made relative. The .eh_frame code then expects to
have fully-relocated lsda fields, but we never add in the
symbol value.
Patch 7
-------
* elfxx-mips.c (mips_elf_irix6_finish_dynamic_symbol): Make the
symbols protected.
This is something I noticed while looking at other stuff.
It copies the behaviour of the native linker and it seems
fairly obvious, but I'm not aware of anything specific
that breaks without it.
Are these patches likely to be accepted? If so, I'll come up
with something for the testsuite.
The patches were tested on a mipsel-linux-gnu cross compiler and by
bootstrapping and regression testing mips-sgi-irix6.5 --with-gnu-as
--with-gnu-ld. I needed some gcc patches for the irix config: I'll
post them to gcc-patches if the bfd side is accepted.
Richard
*** elfxx-mips.c.cvs Sat Jun 21 15:19:37 2003
--- elfxx-mips.c.1 Sat Jun 21 15:21:02 2003
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6749,6770 ****
bfd_vma offset;
bfd_vma value;
! if (sym->st_value)
! value = sym->st_value;
! else
! {
! /* For an entity defined in a shared object, this will be
! NULL. (For functions in shared objects for
! which we have created stubs, ST_VALUE will be non-NULL.
! That's because such the functions are now no longer defined
! in a shared object.) */
!
! if ((info->shared && h->root.type == bfd_link_hash_undefined)
! || h->root.type == bfd_link_hash_undefweak)
! value = 0;
! else
! value = h->root.u.def.value;
! }
offset = mips_elf_global_got_index (dynobj, output_bfd, h);
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
}
--- 6749,6755 ----
bfd_vma offset;
bfd_vma value;
! value = sym->st_value;
offset = mips_elf_global_got_index (dynobj, output_bfd, h);
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
}
--- elfxx-mips.c.1 Sat Jun 21 15:21:02 2003
+++ elfxx-mips.c.2 Sat Jun 21 16:50:00 2003
@@ -3886,6 +3886,7 @@ mips_elf_create_dynamic_relocation (outp
else
{
long indx;
+ bfd_boolean defined_p;
/* We must now calculate the dynamic symbol table index to use
in the relocation. */
@@ -3898,6 +3899,15 @@ mips_elf_create_dynamic_relocation (outp
become local. */
if (indx == -1)
indx = 0;
+ if (SGI_COMPAT (output_bfd))
+ defined_p = ((h->root.elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) != 0);
+ else
+ /* ??? glibc's ld.so just adds the final GOT entry to the
+ relocation field. It therefore treats relocs against
+ defined symbols in the same way as relocs against
+ undefined symbols. */
+ defined_p = FALSE;
}
else
{
@@ -3927,13 +3937,14 @@ mips_elf_create_dynamic_relocation (outp
useful, after all. This should be a bit more efficient
as well. */
indx = 0;
+ defined_p = TRUE;
}
/* If the relocation was previously an absolute relocation and
this symbol will not be referred to by the relocation, we must
adjust it by the value we give it in the dynamic symbol table.
Otherwise leave the job up to the dynamic linker. */
- if (!indx && r_type != R_MIPS_REL32)
+ if (defined_p && r_type != R_MIPS_REL32)
*addendp += symbol;
/* The relocation is always an REL32 relocation because we don't
*** elfxx-mips.c.2 Sat Jun 21 15:45:55 2003
--- elfxx-mips.c.3 Sat Jun 21 16:30:40 2003
*************** mips_elf_create_dynamic_relocation (outp
*** 3892,3904 ****
in the relocation. */
if (h != NULL
&& (! info->symbolic || (h->root.elf_link_hash_flags
! & ELF_LINK_HASH_DEF_REGULAR) == 0))
! {
! indx = h->root.dynindx;
/* h->root.dynindx may be -1 if this symbol was marked to
become local. */
! if (indx == -1)
! indx = 0;
if (SGI_COMPAT (output_bfd))
defined_p = ((h->root.elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) != 0);
--- 3892,3903 ----
in the relocation. */
if (h != NULL
&& (! info->symbolic || (h->root.elf_link_hash_flags
! & ELF_LINK_HASH_DEF_REGULAR) == 0)
/* h->root.dynindx may be -1 if this symbol was marked to
become local. */
! && h->root.dynindx != -1)
! {
! indx = h->root.dynindx;
if (SGI_COMPAT (output_bfd))
defined_p = ((h->root.elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) != 0);
*************** mips_elf_create_dynamic_relocation (outp
*** 3936,3942 ****
section-relative relocations. It's not like they're
useful, after all. This should be a bit more efficient
as well. */
! indx = 0;
defined_p = TRUE;
}
--- 3935,3946 ----
section-relative relocations. It's not like they're
useful, after all. This should be a bit more efficient
as well. */
! /* ??? Although this behavior is compatible with glibc's ld.so,
! the ABI says that relocations against STN_UNDEF should have
! a symbol value of 0. Irix rld honors this, so relocations
! against STN_UNDEF have no effect. */
! if (!SGI_COMPAT (output_bfd))
! indx = 0;
defined_p = TRUE;
}
*** elfxx-mips.c.3 Sat Jun 21 16:30:40 2003
--- elfxx-mips.c.4 Sat Jun 21 16:30:48 2003
*************** struct mips_elf_link_hash_entry
*** 189,198 ****
a readonly section. */
bfd_boolean readonly_reloc;
- /* The index of the first dynamic relocation (in the .rel.dyn
- section) against this symbol. */
- unsigned int min_dyn_reloc_index;
-
/* We must not create a stub for a symbol that has relocations
related to taking the function's address, i.e. any but
R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
--- 189,194 ----
*************** static void bfd_elf32_swap_compact_rel_o
*** 391,400 ****
PARAMS ((bfd *, const Elf32_compact_rel *, Elf32_External_compact_rel *));
static void bfd_elf32_swap_crinfo_out
PARAMS ((bfd *, const Elf32_crinfo *, Elf32_External_crinfo *));
- #if 0
static void bfd_mips_elf_swap_msym_in
PARAMS ((bfd *, const Elf32_External_Msym *, Elf32_Internal_Msym *));
- #endif
static void bfd_mips_elf_swap_msym_out
PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *));
static int sort_dynamic_relocs
--- 387,394 ----
*************** static bfd_boolean mips_elf_create_got_s
*** 446,451 ****
--- 440,447 ----
PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean));
static asection *mips_elf_create_msym_section
PARAMS ((bfd *));
+ static void mips_elf_adjust_msym_indices
+ PARAMS ((bfd *, asection *, asection *));
static bfd_reloc_status_type mips_elf_calculate_relocation
PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *,
const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *,
*************** mips_elf_link_hash_newfunc (entry, table
*** 732,738 ****
ret->esym.ifd = -2;
ret->possibly_dynamic_relocs = 0;
ret->readonly_reloc = FALSE;
- ret->min_dyn_reloc_index = 0;
ret->no_fn_stub = FALSE;
ret->fn_stub = NULL;
ret->need_fn_stub = FALSE;
--- 728,733 ----
*************** bfd_elf32_swap_crinfo_out (abfd, in, ex)
*** 1194,1200 ****
H_PUT_32 (abfd, in->vaddr, ex->vaddr);
}
- #if 0
/* Swap in an MSYM entry. */
static void
--- 1189,1194 ----
*************** bfd_mips_elf_swap_msym_in (abfd, ex, in)
*** 1206,1212 ****
in->ms_hash_value = H_GET_32 (abfd, ex->ms_hash_value);
in->ms_info = H_GET_32 (abfd, ex->ms_info);
}
! #endif
/* Swap out an MSYM entry. */
static void
--- 1200,1206 ----
in->ms_hash_value = H_GET_32 (abfd, ex->ms_hash_value);
in->ms_info = H_GET_32 (abfd, ex->ms_info);
}
!
/* Swap out an MSYM entry. */
static void
*************** mips_elf_create_msym_section (abfd)
*** 2944,2949 ****
--- 2938,2981 ----
return s;
}
+
+ /* Adjust the contents of .msym after sorting the dynamic relocations.
+ RELDYN and MSYM are the two sections involved. */
+
+ static void
+ mips_elf_adjust_msym_indices (abfd, reldyn, msym)
+ bfd *abfd;
+ asection *reldyn, *msym;
+ {
+ bfd_size_type i, entsize;
+ bfd_vma lastsym;
+
+ entsize = MIPS_ELF_REL_SIZE (abfd);
+ lastsym = (bfd_vma) -1;
+
+ for (i = entsize; i < reldyn->_raw_size; i += entsize)
+ {
+ bfd_vma sym;
+ Elf_Internal_Rela reloc[3];
+
+ (*get_elf_backend_data (abfd)->s->swap_reloc_in)
+ (abfd, reldyn->contents + i, reloc);
+ sym = ELF_R_SYM (abfd, reloc[0].r_info);
+ if (sym != lastsym)
+ {
+ /* This is the first relocation against SYM. Get its .msym
+ record and adjust the ms_info field appropriately. */
+ Elf32_Internal_Msym entry;
+
+ bfd_mips_elf_swap_msym_in
+ (abfd, (Elf32_External_Msym *) msym->contents + sym, &entry);
+ entry.ms_info = ELF32_MS_INFO (i / entsize, 1);
+ bfd_mips_elf_swap_msym_out
+ (abfd, &entry, (Elf32_External_Msym *) msym->contents + sym);
+ lastsym = sym;
+ }
+ }
+ }
/* Calculate the value produced by the RELOCATION (which comes from
the INPUT_BFD). The ADDEND is the addend to use for this
*************** mips_elf_create_dynamic_relocation (outp
*** 3999,4011 ****
(output_bfd, &outrel[0],
(sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
- /* Record the index of the first relocation referencing H. This
- information is later emitted in the .msym section. */
- if (h != NULL
- && (h->min_dyn_reloc_index == 0
- || sreloc->reloc_count < h->min_dyn_reloc_index))
- h->min_dyn_reloc_index = sreloc->reloc_count;
-
/* We've now added another relocation. */
++sreloc->reloc_count;
--- 4031,4036 ----
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6704,6714 ****
asection *smsym;
struct mips_got_info *g, *gg;
const char *name;
- struct mips_elf_link_hash_entry *mh;
dynobj = elf_hash_table (info)->dynobj;
gval = sym->st_value;
- mh = (struct mips_elf_link_hash_entry *) h;
if (h->plt.offset != (bfd_vma) -1)
{
--- 6729,6737 ----
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6831,6837 ****
msym.ms_hash_value = bfd_elf_hash (h->root.root.string);
/* It is undocumented what the `1' indicates, but IRIX6 uses
this value. */
! msym.ms_info = ELF32_MS_INFO (mh->min_dyn_reloc_index, 1);
bfd_mips_elf_swap_msym_out
(dynobj, &msym,
((Elf32_External_Msym *) smsym->contents) + h->dynindx);
--- 6854,6860 ----
msym.ms_hash_value = bfd_elf_hash (h->root.root.string);
/* It is undocumented what the `1' indicates, but IRIX6 uses
this value. */
! msym.ms_info = ELF32_MS_INFO (0, 1);
bfd_mips_elf_swap_msym_out
(dynobj, &msym,
((Elf32_External_Msym *) smsym->contents) + h->dynindx);
*************** _bfd_mips_elf_finish_dynamic_sections (o
*** 7236,7242 ****
(size_t) s->reloc_count - 1,
sizeof (Elf32_External_Rel), sort_dynamic_relocs);
}
! }
return TRUE;
}
--- 7259,7268 ----
(size_t) s->reloc_count - 1,
sizeof (Elf32_External_Rel), sort_dynamic_relocs);
}
!
! if (s != 0 && smsym != 0)
! mips_elf_adjust_msym_indices (output_bfd, s, smsym);
! }
return TRUE;
}
*************** _bfd_mips_elf_copy_indirect_symbol (bed,
*** 7778,7787 ****
dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
if (indmips->readonly_reloc)
dirmips->readonly_reloc = TRUE;
- if (dirmips->min_dyn_reloc_index == 0
- || (indmips->min_dyn_reloc_index != 0
- && indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
- dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
if (indmips->no_fn_stub)
dirmips->no_fn_stub = TRUE;
}
--- 7804,7809 ----
--- elfxx-mips.c.4 Sat Jun 21 16:30:48 2003
+++ elfxx-mips.c.5 Sat Jun 21 16:30:53 2003
@@ -6847,7 +6847,7 @@ _bfd_mips_elf_finish_dynamic_symbol (out
/* Create a .msym entry, if appropriate. */
smsym = bfd_get_section_by_name (dynobj, ".msym");
- if (smsym)
+ if (smsym && h->dynindx != -1)
{
Elf32_Internal_Msym msym;
*** elfxx-mips.c.5 Sat Jun 21 15:42:14 2003
--- elfxx-mips.c.6 Sat Jun 21 15:42:07 2003
*************** mips_elf_create_dynamic_relocation (outp
*** 3906,3914 ****
}
#endif
! if (outrel[0].r_offset == (bfd_vma) -1
! || outrel[0].r_offset == (bfd_vma) -2)
skip = TRUE;
/* If we've decided to skip this relocation, just output an empty
record. Note that R_MIPS_NONE == 0, so that this call to memset
--- 3906,3922 ----
}
#endif
! if (outrel[0].r_offset == (bfd_vma) -1)
! /* The relocation field has been deleted. */
skip = TRUE;
+ else if (outrel[0].r_offset == (bfd_vma) -2)
+ {
+ /* The relocation field has been converted into a relative value of
+ some sort. Functions like _bfd_elf_write_section_eh_frame expect
+ the field to be fully relocated, so add in the symbol's value. */
+ skip = TRUE;
+ *addendp += symbol;
+ }
/* If we've decided to skip this relocation, just output an empty
record. Note that R_MIPS_NONE == 0, so that this call to memset
*** elfxx-mips.c.6 Sat Jun 21 16:31:01 2003
--- elfxx-mips.c.7 Sat Jun 21 16:31:10 2003
*************** mips_elf_irix6_finish_dynamic_symbol (ab
*** 6710,6715 ****
--- 6710,6716 ----
/* All of these symbols are given type STT_SECTION by the
IRIX6 linker. */
sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
+ sym->st_other = STO_PROTECTED;
/* The IRIX linker puts these symbols in special sections. */
if (i == 0)