Bug 3169 - elfxx-ia64.c doesn't support @ltoff(@fptr(_DYNAMIC#))
Summary: elfxx-ia64.c doesn't support @ltoff(@fptr(_DYNAMIC#))
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.18
: P2 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-09-03 10:36 UTC by Martin Michlmayr
Modified: 2006-09-13 21:27 UTC (History)
2 users (show)

See Also:
Host:
Target: ia64-linux-gnu
Build:
Last reconfirmed:


Attachments
test case (9.30 KB, application/octet-stream)
2006-09-03 10:37 UTC, Martin Michlmayr
Details
test case (1.08 KB, application/octet-stream)
2006-09-03 10:37 UTC, Martin Michlmayr
Details
preprocessed source (32.14 KB, application/octet-stream)
2006-09-04 20:42 UTC, Martin Michlmayr
Details
asm (23.89 KB, application/octet-stream)
2006-09-04 20:42 UTC, Martin Michlmayr
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Michlmayr 2006-09-03 10:36:48 UTC
I get the following ld segfault on an object file generated by Osprey, an
alternative GCC backend for IA64.

It fails both with Debian binutils 2.17 and current CVS HEAD.
/gcc-lib/ia64-linux-gnu/3.3.6/../../../crti.o symbol.s.o
/usr/bin/ld: BFD 2.17 Debian GNU/Linux assertion fail elf64-ia64.c:4874
Segmentation fault


(osprey)tbm@coconut0:~/src/mpatrol-1.4.8/build/unix$
/home/tbm/scratch/src/ld/ld-new -shared -o libmpa
trol.so.1.4 /usr/lib/gcc-lib/ia64-linux-gnu/3.3.6/../../../crti.o symbol.s.o
/home/tbm/scratch/src/ld/ld-new: BFD 2.17.50 20060903 assertion fail
elf64-ia64.c:4882
Segmentation fault

(gdb) run -shared -o libmpatrol.so.1.4
/usr/lib/gcc-lib/ia64-linux-gnu/3.3.6/../../../crti.o symbol.s.o
Starting program: /home/tbm/scratch/src/ld/ld-new -shared -o libmpatrol.so.1.4
/usr/lib/gcc-lib/ia64-l
inux-gnu/3.3.6/../../../crti.o symbol.s.o
/home/tbm/scratch/src/ld/ld-new: BFD 2.17.50 20060903 assertion fail
elf64-ia64.c:4882
Program received signal SIGSEGV, Segmentation fault.
0x4000000000080670 in set_fptr_entry (abfd=0x60000000000224f0,
info=0x6000000000024a70, dyn_i=0x50,
    value=86624) at elf64-ia64.c:4203
4203          bfd_put_64 (abfd, value, fptr_sec->contents + dyn_i->fptr_offset);
(gdb) where
#0  0x4000000000080670 in set_fptr_entry (abfd=0x60000000000224f0,
info=0x6000000000024a70,
    dyn_i=0x50, value=86624) at elf64-ia64.c:4203
#1  0x4000000000082940 in elf64_ia64_relocate_section
(output_bfd=0x60000000000224f0,
    info=0x600000000000f290, input_bfd=0x600000000004cfd0,
input_section=0x600000000004f438,
    contents=0x6000000000062860 "\b 9\016\200\005▒@\005", relocs=0x600000000004e668,
    local_syms=0x60000000000316f0, local_sections=0x600000000007c310) at
elf64-ia64.c:4545
#2  0x40000000000bc780 in elf_link_input_bfd (finfo=0x60000fffffffb5f0,
input_bfd=0x600000000004cfd0)
    at elflink.c:7217
#3  0x40000000000c1d40 in bfd_elf_final_link (abfd=0x60000000000224f0,
info=0x600000000000f290)
    at elflink.c:8191
#4  0x4000000000081420 in elf64_ia64_final_link (abfd=0x60000000000224f0,
info=0x600000000000f290)
    at elf64-ia64.c:4467
#5  0x4000000000030310 in ldwrite () at ldwrite.c:548
#6  0x400000000002a9f0 in main (argc=6, argv=0x60000fffffffb9d8) at
../ld/ldmain.c:481
(gdb)
Comment 1 Martin Michlmayr 2006-09-03 10:37:11 UTC
Created attachment 1273 [details]
test case
Comment 2 Martin Michlmayr 2006-09-03 10:37:32 UTC
Created attachment 1274 [details]
test case
Comment 3 H.J. Lu 2006-09-04 20:32:01 UTC
Please also provide the source and the assembly output. It is possible that
the assembly output doesn't follow the ia64 psABI.
Comment 4 Martin Michlmayr 2006-09-04 20:42:19 UTC
Created attachment 1278 [details]
preprocessed source
Comment 5 Martin Michlmayr 2006-09-04 20:42:43 UTC
Created attachment 1279 [details]
asm
Comment 6 H.J. Lu 2006-09-04 21:59:08 UTC
Here is a very small testcase

[hjl@gnu-11 3169]$ cat foo.s
        .proc   foo#
        .global foo#
foo#:
        .weak   _DYNAMIC#
        addl r16=@ltoff(@fptr(_DYNAMIC#)),gp
        .endp foo
[hjl@gnu-11 3169]$ cat bar.S
        .text
        .align 16
        .proc bar#
bar:
        addl r14 = @ltoff(@fptr(foo#)), gp
        .endp bar#

[hjl@gnu-11 3169]$ make
cc -c bar.S
cc -c foo.s
./ld -o libfoo.so -shared bar.o foo.o
./ld: BFD 2.17.50 20060904 assertion fail elf64-ia64.c:4882
make: *** [libfoo.so] Segmentation fault
make: *** Deleting file `libfoo.so'
[hjl@gnu-11 3169]$

_DYNAMIC is a special symbol. I don't think Osprey uses it correctly, if it
should be used by compiler at all.
Comment 7 Martin Michlmayr 2006-09-04 22:18:20 UTC
(In reply to comment #6)
> _DYNAMIC is a special symbol. I don't think Osprey uses it correctly, if it
> should be used by compiler at all.

Thanks, I'll let them know about it.
Comment 8 wilson@specifix.com 2006-09-11 20:26:42 UTC
Subject: Re:  New: ld elf64-ia64.c segfault in set_fptr_entry

On Sun, 2006-09-03 at 10:36 +0000, tbm at cyrius dot com wrote:
> It fails both with Debian binutils 2.17 and current CVS HEAD.
> /gcc-lib/ia64-linux-gnu/3.3.6/../../../crti.o symbol.s.o
> /usr/bin/ld: BFD 2.17 Debian GNU/Linux assertion fail elf64-ia64.c:4874
> Segmentation fault

There is a bug in the source code.  It has
#pragma weak _DYNAMIC
void _DYNAMIC(void);
    if ((&_DYNAMIC != __null) && (d = (Elf64_Dyn *) _DYNAMIC))
     ...process d as if it points to dynamic entries...

This won't work on IA-64, as taking the address of a function returns
the address of the function pointer.  You would then have to redirect
through the function pointer to get the actual function address you
want.  But to do so would be pointless.  It is better to declare
_DYNAMIC properly in the first place.  If you use this
  extern char _DYNAMIC[0];
then you won't get a linker segfault, and you will also get code that
has a chance of working.

The linker shouldn't be segfaulting of course though.  The linker bug
appears to be in allocate_fptr in bfd/el64-ia64.c.  This function
returns false in this case, as a
bfd_elf_link_record_local_dynamic_symbol call fails.  I didn't look into
this routine in detail, but this failure seems OK, as we can't make
_DYNAMIC a local symbol presumably.  The failure return result from
allocate_fptr gets lost though, as it is called from a hash table
traversal routine that throws away return values.  Thus no error is
emitted here, and no fptr section space is allocated.  When we
eventually try to generate the descriptor, we get the segfault as we are
writing as no space was ever allocated for it.

So the solution here seems to be to either fix the
elf64_ia64_dyn_sym_traverse function to return failure results, or else
emit the error in allocate_fptr directly.  The latter seems easier.

My problem at the moment now is that I'm not quite sure what the error
message should be.  Is there such a thing as a global dynamic symbol?
If so, maybe the error should be something like
  "can't resolve fptr reloc for global dynamic symbol"
Or maybe something more general like
  "invalid fptr reloc"
or
  "failed to allocate fptr reloc"
is more appropriate.
Comment 9 H.J. Lu 2006-09-11 22:17:36 UTC
I used

--- elf64-ia64.c        2006-09-11 15:13:43.000000000 -0700
+++ elf64-ia64.c.new    2006-09-07 16:12:39.000000000 -0700
@@ -3275,7 +3275,14 @@ allocate_fptr (dyn_i, data)
              if (!bfd_elf_link_record_local_dynamic_symbol
                    (x->info, h->root.u.def.section->owner,
                     global_sym_index (h)))
-               return FALSE;
+               {
+                 /* Something is really wrong. If we continue, we will
+                    run into more problems later.  */
+                 (*_bfd_error_handler)
+                   (_("%B: failed to record local dynamic symbol `%s'"),
+                    h->root.u.def.section->owner, h->root.root.string);
+                 abort ();
+               }
            }

          dyn_i->want_fptr = 0;

However, it doesn't work for this:
[hjl@gnu-13 3169]$ cat foo.s
        .hidden __bss_start
        .text
        .proc   foo#
        .global foo#
foo#:
        addl r16=@ltoff(@fptr(_DYNAMIC#)),gp
        .endp foo
[hjl@gnu-13 3169]$ cat bar.s
        .text
        .proc bar#
bar:
//      addl r14 = @ltoff(@fptr(foo#)), gp
        .endp bar#

[hjl@gnu-13 3169]$ make
./as -x -o bar.o bar.s
./as -x -o foo.o foo.s
./ld -o libfoo.so -shared bar.o foo.o
make: *** [libfoo.so] Segmentation fault
make: *** Deleting file `libfoo.so'
[hjl@gnu-13 3169]$ gdb ld
GNU gdb 6.5.50.20060816-cvs
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu"...
Using host libthread_db library "/lib64/libthread_db.so.1".
(gdb) r  -o libfoo.so -shared bar.o foo.o
Starting program: /export/home/hjl/bugs/binutils/3169/ld -o libfoo.so -shared
bar.o foo.o

Program received signal SIGSEGV, Segmentation fault.
0x0000000000436c1c in global_sym_index (h=0x6e5960) at elf64-ia64.c:3239
3239      for (p = elf_sym_hashes (obj); *p != h; ++p)
(gdb) p obj
No symbol "obj" in current context.
(gdb) p ((h->root.u.def.section->owner) -> tdata.elf_obj_data)->sym_hashes
$1 = (struct elf_link_hash_entry **) 0x0
(gdb)
Comment 10 Martin Michlmayr 2006-09-13 10:22:17 UTC
> > _DYNAMIC is a special symbol. I don't think Osprey uses it correctly, if it
> should be used by compiler at all.

I just noticed that GCC 4.1 and 4.2 use _DYNAMIC as well and lead to this ld
segfault.
Comment 11 wilson@specifix.com 2006-09-13 21:01:03 UTC
Subject: Re:  elfxx-ia64.c doesn't support
	@ltoff(@fptr(_DYNAMIC#))

On Mon, 2006-09-11 at 22:17 +0000, hjl at lucon dot org wrote:
> +                 (*_bfd_error_handler)
> +                   (_("%B: failed to record local dynamic symbol `%s'"),
> +                    h->root.u.def.section->owner, h->root.root.string);

That looks like a good solution for this problem.

> However, it doesn't work for this:

Yes, this is another complication.  The problem here is that _DYNAMIC is
a magic linker variable.  It isn't a variable that came from one of the
object files.  The variable gets created by a call to
_bfd_elf_define_linkage_sym, which puts it in the global symbol hash
table, but not the symbol list for the bar.o file as it didn't come from
bar.o.  However, it is in the bar.o .dynamic section which has a
section->owner which points to bar.o.  So in allocate_fptr, we call
global_sym_index, which then assumes that it must be in bar.o, and
segfaults because it doesn't handle the failure case.

There are a few interesting things about your testcase.  I get the same
error if I use _GLOBAL_OFFSET_TABLE_ instead of _DYNAMIC.  I get no
error if I switch the order of the .o files on the link line.  This is
because section->owner now points to foo.o, and the variable is in
foo.o's symbol table because it was explicitly referenced there.

I think we can handle this with a simple extension of your current
patch.  First we fix global_sym_index to handle the failure case where p
== 0.  We can just return 0 in that case.  Second, we fix allocate_fptr
to check for a 0 return value from global_sym_index, and emit the same
error message as above.

I don't think there is any field in a symbol that says this is a magic
linker created variable.  That would be convenient if it existed.
Comment 12 H.J. Lu 2006-09-13 21:27:00 UTC
It will be nice to add a bit to struct elf_link_hash_entry to indicate
a definiton is created by linker so that a backend can catch such a problem
much earlier.