This is the mail archive of the
mailing list for the binutils project.
[RFC] Pointer alignment issues in ld's map_input_to_output_sections
- From: Roger Sayle <roger at eyesopen dot com>
- To: binutils at sourceware dot org
- Date: Thu, 8 Jun 2006 17:16:37 -0600 (MDT)
- Subject: [RFC] Pointer alignment issues in ld's map_input_to_output_sections
GNU ld, both 2.16.1 and mainline CVS, currently dump core immediately
at start up on mips-sgi-irix6.5 (when compiled with gcc 3.4 and gcc 4.1).
The point of bus error is the map_input_to_output_sections:1312
s->output_section_statement.all_input_readonly = TRUE;
After much investigation, the problem appears to be that "s" which is
of type lang_statement_union_type* is assumed to be 64-bit aligned
(as the union lang_statement_union_type requires 64-bit alignment),
even though in this instance it's pointing to a
lang_output_section_statement_type which is only 32-bit aligned.
The resulting misaligned double-word load in the bitfield assignment
causes MIPS to fault (in GCC terms a STRICT_ALIGNMENT target).
The reason that "s" is misaligned is that the source of this pointer
is the function output_statement_newfunc, which allocates a new
"struct output_statement_hash_entry" containing a bfd_hash_entry field
(root) followed by a lang_output_section_statement_type (os). It is
a pointer to this "os" field that gets returned and ultimately
assigned to a pointer of lang_statement_union_type.
After much discussion on the #gcc IRC, the consensus seems to be that
the code in ldlang.c is badly broken, if not undefined, on all platforms,
but unfortunately no-one has any clever suggestions on how to fix things.
One suggestion was to change the output_statement_hash_entry struct
to make "os" be a lang_statement_union_type instead of a
lang_output_section_statement_type, but unfortunately this would
mean increasing the size of each hash table entry to the largest
member of that union.
Another suggestion was to swap the order of fields in
output_statement_hash_entry so that the 96 byte "os" comes before
the 4-byte "struct bfd_hash_entry root", but it was pointed out
pointers to this type are also cast to bfd_hash_entry. So the
elements of output_statement_hash_entry are "derived" from two
different types (multiple inheritance), with each field having
differing alignment constraints.
I've no clue how to sort this out. If portability wasn't an issue
one might require the use of GCC's alignment directives to overcome
the undefinedness of the code as written. However, one "workaround"
that appears to hide the problem, is implemented by the patch
attached below, which casts the "s" which is assumed to be 64-bit
aligned, to a "lang_output_section_statement_type*" which is
sufficient to confuse GCC's optimizers into treating the problematic
structure as only 32-bit aligned. It's unclear if this is a GCC
deficiency that may be addressed in future.
I just thought I'd at least post this bug report and workaround
to see what the bright binutils folks make of the problem.
2006-06-08 Roger Sayle <firstname.lastname@example.org>
* ldlang.c (map_input_to_output_sections): Refer to the
output_section_statement field of "s" via a pointer of the
appropriate type to avoid potential alignment problems.
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.222
diff -c -3 -p -r1.222 ldlang.c
*** ldlang.c 7 Jun 2006 04:55:11 -0000 1.222
--- ldlang.c 8 Jun 2006 20:56:35 -0000
*** 3091,3096 ****
--- 3091,3098 ----
(lang_statement_union_type *s, const char *target,
+ lang_output_section_statement_type *sos;
for (; s != NULL; s = s->header.next)
*** 3104,3130 ****
! if (s->output_section_statement.constraint)
! if (s->output_section_statement.constraint != ONLY_IF_RW
! && s->output_section_statement.constraint != ONLY_IF_RO)
! s->output_section_statement.all_input_readonly = TRUE;
! check_input_sections (s->output_section_statement.children.head,
! if ((s->output_section_statement.all_input_readonly
! && s->output_section_statement.constraint == ONLY_IF_RW)
! || (!s->output_section_statement.all_input_readonly
! && s->output_section_statement.constraint == ONLY_IF_RO))
! s->output_section_statement.constraint = -1;
! map_input_to_output_sections (s->output_section_statement.children.head,
--- 3106,3133 ----
! /* The lang_statement_union_type *S may have stricter alignment
! constraints than the lang_output_section_statement_type that
! S actually points to. */
! sos = &s->output_section_statement;
! if (sos->constraint)
! if (sos->constraint != ONLY_IF_RW
! && sos->constraint != ONLY_IF_RO)
! sos->all_input_readonly = TRUE;
! check_input_sections (sos->children.head, sos);
! if ((sos->all_input_readonly
! && sos->constraint == ONLY_IF_RW)
! || (!sos->all_input_readonly
! && sos->constraint == ONLY_IF_RO))
! sos->constraint = -1;
! map_input_to_output_sections (sos->children.head, target, sos);
Roger Sayle, E-mail: email@example.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833