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)
Created attachment 1273 [details] test case
Created attachment 1274 [details] test case
Please also provide the source and the assembly output. It is possible that the assembly output doesn't follow the ia64 psABI.
Created attachment 1278 [details] preprocessed source
Created attachment 1279 [details] asm
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.
(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.
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.
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)
> > _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.
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.
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.