On Sun, May 23, 2010 at 12:48:20AM +0200, Gerald Pfeifer wrote:
> On Thu, 20 May 2010, Kai Wang wrote:
> > The elf_getbase() API in FreeBSD libelf can only be called using an
> > archive member ELF descriptor. It will return -1 (indicates an error)
> > when called with a "regular" ELF object.
> >
> > The lto_obj_build_section_table() function in lto-elf.c calls
> > elf_getbase() to get the offset base for a "regular" ELF object. On
> > FreeBSD it gets -1. (Side notes: lto-elf.c should really check return
> > values of libelf APIs) And later it uses -1 as base_offset for all the
> > ELF sections thus results in an off-by-one error when passing the
> > section data to zlib to inflate.
> >
> > Could you please try applying the attached patch to the libelf in
> > FreeBSD 7.3 and see if it fixes gcc4.6 lto?
>
> Thanks, Kai!
>
> This patch to FreeBSD's libelf significantly improves test results
> from http://gcc.gnu.org/ml/gcc-testresults/2010-05/msg02081.html
> to http://gcc.gnu.org/ml/gcc-testresults/2010-05/msg02150.html
Thank you all for testing the patch!
> Based on this, it will be great if you can apply your patch to -CURRENT,
> 8-STABLE and 7-STABLE.
I'll see what I can do.
> >From what I can tell, this patch of yours fixes LTO in GCC. Looking
> at the remaining failures, it is now only the somewhat related WHOPR
> optimization in GCC that remains broken:
>
> % cat x.c
> int main() { }
> % gccvs -flto x.c
> % gccvs -fwhopr x.c
> lto1: fatal error: elf_update() failed: Layout constraint violation
> compilation terminated.
> lto-wrapper: gccvs returned 1 exit status
> collect2: lto-wrapper returned 1 exit status
The elf_update() failure is caused by an alignment check inside
FreeBSD elf_update().
FreeBSD elf_update() requires that all Elf_Data d_align must be at
least as equally strict as the section alignment. Function
lto_obj_append_data() in lto-elf.c only set the first Elf_Data d_align
to section alignment while the rest to 1. It seems that this different
alignment is desired because some .gnu_lto_XXX section contains
different kinds of data. For example, gnu.lto_.decls contains
intergers and a string table; My guess is the Elf_Data containing the
string table is set to have alignment 1 intead of padding the string
table to section alignement. I'm not sure if this is the right thing
to do... Maybe FreeBSD elf_update() aligment check is indeed too
strict.
Anyway, I attached a patch for FreeBSD libelf which removes the
d_align check against section aligment. Please try applying it to a
vanilla FreeBSD 7.3 libelf (The patch includes the previous
elf_getbase() change) and run the gcc test suite again...
I've also built a patched libelf here:
http://people.freebsd.org/~kaiw/libelf.so.1
You can instead download this one and set your LD_LIBRARY_PATH to
avoid replacing the system libelf.
Thanks,
Kai
diff -urN libelf.orig/elf_getbase.c libelf/elf_getbase.c
--- libelf.orig/elf_getbase.c 2010-05-20 18:49:43.000000000 +0200
+++ libelf/elf_getbase.c 2010-05-20 18:52:49.000000000 +0200
@@ -34,12 +34,14 @@
off_t
elf_getbase(Elf *e)
{
- if (e == NULL ||
- e->e_parent == NULL) {
+ if (e == NULL) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (off_t) -1;
}
- return ((off_t) ((uintptr_t) e->e_rawfile -
- (uintptr_t) e->e_parent->e_rawfile));
+ if (e->e_parent)
+ return ((off_t) ((uintptr_t) e->e_rawfile -
+ (uintptr_t) e->e_parent->e_rawfile));
+ else
+ return (off_t) 0;
}
diff -urN libelf.orig/elf_update.c libelf/elf_update.c
--- libelf.orig/elf_update.c 2010-05-20 18:49:43.000000000 +0200
+++ libelf/elf_update.c 2010-05-23 16:29:22.000000000 +0200
@@ -149,11 +149,7 @@
LIBELF_SET_ERROR(VERSION, 0);
return (0);
}
- if ((d_align = d->d_align) % sh_align) {
- LIBELF_SET_ERROR(LAYOUT, 0);
- return (0);
- }
- if (d_align == 0 || (d_align & (d_align - 1))) {
+ if ((d_align = d->d_align) == 0 || (d_align & (d_align - 1))) {
LIBELF_SET_ERROR(DATA, 0);
return (0);
}
@@ -168,7 +164,7 @@
if ((uint64_t) d->d_off + d->d_size > scn_size)
scn_size = d->d_off + d->d_size;
} else {
- scn_size = roundup2(scn_size, scn_alignment);
+ scn_size = roundup2(scn_size, d->d_align);
d->d_off = scn_size;
scn_size += d->d_size;
}