This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
RFC: using ld 2.14 on irix
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: 14 Jun 2003 10:30:35 +0100
- Subject: RFC: using ld 2.14 on irix
I've been trying to get ld 2.14 to work on irix6. In an earlier message,
I rather optimistically said that it seemed to be in good shape. I'd like
to retract that, please. ;)
Here's a reduced test case:
------------------------------------------------------------------
$ cat foo.c
extern char __us_rsthread_stdio[];
extern char __iob[];
extern char __month_size[];
void *f1 = __us_rsthread_stdio;
void *f2 = __iob;
void *f3 = __month_size;
int main () { printf ("%p %p %p\n", f1, f2, f3); return 0; }
------------------------------------------------------------------
(cheesily borrowing symbols from libc.so). Compile and link with:
$ cc foo.c -c
$ $LD /usr/lib32/crt1.o foo.o /usr/lib32/libc.so.1 /usr/lib32/crtn.o
With $LD=ld (the SGI linker) I get the expected:
$ ./a.out
fb51e00 fb52520 fb0d1c8
With $LD set to ld 2.14, I get:
$ ./a.out
0 0 0
There seem to be two problems:
1. the way the GOT is initialised
2. the contents of .msym
First, the GOT. Here's what it looks like after linking with ld 2.14:
------------------------------------------------------------------
Index Content gp_reladdr Address
[ 7]: 0x10100960 -32724(gp), 0x101008fc [__Argc]
==> [ 8]: 0x0fb52520 -32720(gp), 0x10100900 [__iob]
[ 9]: 0x10000598 -32716(gp), 0x10100904 [exit]
[ 10]: 0x1010061c -32712(gp), 0x10100908 [f1]
[ 11]: 0x1000045c -32708(gp), 0x1010090c [__istart]
==> [ 12]: 0x0fb51e00 -32704(gp), 0x10100910 [__us_rsthread_stdio]
[ 13]: 0x100005c0 -32700(gp), 0x10100914 [main]
[ 14]: 0x10100620 -32696(gp), 0x10100918 [f2]
[ 15]: 0x10100624 -32692(gp), 0x1010091c [f3]
==> [ 16]: 0x0fb0d1c8 -32688(gp), 0x10100920 [__month_size]
[ 17]: 0x0fb52378 -32684(gp), 0x10100924 [_environ]
[ 18]: 0x10000588 -32680(gp), 0x10100928 [__readenv_sigfpe]
[ 19]: 0x10100950 -32676(gp), 0x1010092c [__Argv]
[ 20]: 0x0fa46210 -32672(gp), 0x10100930 [printf]
------------------------------------------------------------------
where the entries marked with "==>" are referenced by dynamic relocations:
------------------------------------------------------------------
Relocation section '.rel.dyn' at offset 0x430 contains 4 entries:
Offset Info Type Sym.Value Sym. Name
00000000 00000000 R_MIPS_NONE
10100620 00000c03 R_MIPS_REL32 00000000 __iob
1010061c 00001003 R_MIPS_REL32 00000000 __us_rsthread_stdio
10100624 00001403 R_MIPS_REL32 00000000 __month_size
------------------------------------------------------------------
As you can see, the GOT entries for external symbols are initialised
with the st_value from libc.so. The following code in elfxx-mips.c
is responsible for picking this 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;
}
That's fine for QuickStart, but I thought that wasn't supported.
And the current behaviour seems to conflict with the ABI for
non-QuickStart objects.
In terms of the code above, it's the st_value == 0 case that
I'm worried about. The ABI says:
--------------------------------------------------------------------
Section Type st_value GOT Entry Relocation
[A] SHN_UNDEF STT_FUNC 0 0/QS 1
SHN_UNDEF STT_FUNC stub addr stub addr 2
SHN_UNDEF STT_FUNC stub addr != stub addr 3
[B] SHN_UNDEF all others any 0/QS 1
SHN_COMMON
[C] all others STT_FUNC address stub address 2
!= address*
[D] all others all others address address 1
* Stub address must be in this executable and can only be
applied the first time the GOT is modified.
Relocation:
1: resolve immediately or use Quickstart value
2: add run-time displacement to GOT entry
3: set GOT entry to stub address plus run-time displacement
--------------------------------------------------------------------
[A], [B], [C] and [D] are the cases where st_value is or might be 0.
I don't believe GNU ld uses case [C]. And [A], [B] & [D] seem to
imply that if st_value is 0, the GOT entry should also be 0 in
non-QuickStart objects.
Anyway, the ABI also says:
The value EA used by the dynamic linker to relocate an R_MIPS_REL32
relocation depends on its r_symndx value. If the relocation entry
r_symndx is less than DT_MIPS_GOTSYM, the value of EA is the symbol
st_value plus displacement. Otherwise, the value of EA is the
value in the GOT entry corresponding to the relocation entry
r_symndx.
In the object created by ld 2.14, f1, f2 and f3 are initialised to 0:
Contents of section .data:
1010061c 00000000 00000000 00000000 ............
So the three dynamic relocations will be calculated as:
A - EA + S
where A = addend (0 in all three cases)
EA = contents of GOT
S = final symbol value
Since libc.so.1 is loaded at its QuickStart address, EA = S,
and all three variables stay as 0.
I guess we could fix this by including the external symbol value
in the relocation field, just like the native linker does:
a.out: file format elf32-nbigmips
Contents of section .data:
1001400c 0fb51e00 0fb52520 0fb0d1c8 ......% ....
I have no idea what effect this would have on backwards compatibility.
But from the ABI stuff quoted above, it seems more correct to
initialise the GOT with the (local) st_value in all cases.
Simply replacing the elfxx-mips.c code with:
value = sym->st_value;
gives the following, which seems correct to me:
------------------------------------------------------------------
[ 7]: 0x10100960 -32724(gp), 0x101008fc [__Argc]
==> [ 8]: 0x00000000 -32720(gp), 0x10100900 [__iob]
[ 9]: 0x10000598 -32716(gp), 0x10100904 [exit]
[ 10]: 0x1010061c -32712(gp), 0x10100908 [f1]
[ 11]: 0x1000045c -32708(gp), 0x1010090c [__istart]
==> [ 12]: 0x00000000 -32704(gp), 0x10100910 [__us_rsthread_stdio]
[ 13]: 0x100005c0 -32700(gp), 0x10100914 [main]
[ 14]: 0x10100620 -32696(gp), 0x10100918 [f2]
[ 15]: 0x10100624 -32692(gp), 0x1010091c [f3]
==> [ 16]: 0x00000000 -32688(gp), 0x10100920 [__month_size]
[ 17]: 0x00000000 -32684(gp), 0x10100924 [_environ]
[ 18]: 0x10000588 -32680(gp), 0x10100928 [__readenv_sigfpe]
[ 19]: 0x10100950 -32676(gp), 0x1010092c [__Argv]
[ 20]: 0x00000000 -32672(gp), 0x10100930 [printf]
------------------------------------------------------------------
With that change I get slightly better results:
$ ./a.out
0 0 fb0d1c8
But then we come to the .msym problem. We're creating the
.msym entries in _bfd_mips_elf_finish_dynamic_symbol, but that's
_before_ we've sorted .rel.dyn. So the ms_info field refers to
the unsorted index instead of the final one.
The ABI says that .msym is an optional section, so we could just
remove it. That indeed fixes the problem and makes the test case
work correctly.
I've had a go at fixing the problem "properly" though. I haven't
hacked this area of bfd before, so I'm probably doing it all wrong.
It's for information only. ;)
With these changes I was able to successfully bootstrap gcc 3.4
using GNU as & ld. There seem to be some problems with the DSOs
it created, looking at that now. (The DSOs created by the unpatched
linker fail too, so it might not be caused by these patches.)
Anyway, what do you think? Am I just talking rubbish here? ;)
Richard
* elfxx-mips.c (_bfd_mips_elf_finish_dynamic_symbol): Always
initialize a GOT entry to the symbol's st_value.
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.51.4.3
diff -c -d -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.51.4.3 elfxx-mips.c
*** bfd/elfxx-mips.c 30 May 2003 20:13:05 -0000 1.51.4.3
--- bfd/elfxx-mips.c 14 Jun 2003 07:29:20 -0000
*************** _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);
}
--- 6777,6783 ----
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 (_bfd_mips_elf_create_dynamic_sections): Disable
the creation of .msym.
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.51.4.3
diff -u -d -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.51.4.3 elfxx-mips.c
--- bfd/elfxx-mips.c 30 May 2003 20:13:05 -0000 1.51.4.3
+++ bfd/elfxx-mips.c 14 Jun 2003 09:14:17 -0000
@@ -4913,7 +4913,7 @@ _bfd_mips_elf_create_dynamic_sections (a
/* Create the .msym section on IRIX6. It is used by the dynamic
linker to speed up dynamic relocations, and to avoid computing
the ELF hash for symbols. */
- if (IRIX_COMPAT (abfd) == ict_irix6
+ if (IRIX_COMPAT (abfd) == ict_irix6 && 0
&& !mips_elf_create_msym_section (abfd))
return FALSE;
* 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.
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.51.4.3
diff -c -d -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.51.4.3 elfxx-mips.c
*** bfd/elfxx-mips.c 30 May 2003 20:13:05 -0000 1.51.4.3
--- bfd/elfxx-mips.c 14 Jun 2003 07:27:59 -0000
*************** 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;
+ {
+ size_t i, entsize, lastsym;
+
+ entsize = MIPS_ELF_REL_SIZE (abfd);
+ lastsym = (size_t) -1;
+
+ for (i = entsize; i < reldyn->_raw_size; i += entsize)
+ {
+ size_t 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 .rel.dyn entry for this symbol.
+ Get the symbol's .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
*** 3984,3996 ****
(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;
--- 4021,4026 ----
*************** _bfd_mips_elf_finish_dynamic_symbol (out
*** 6689,6699 ****
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)
{
--- 6719,6727 ----
*************** _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);
--- 6837,6843 ----
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;
}
--- 7242,7251 ----
(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;
}
--- 7787,7792 ----