Bug 1564581 - ld problem with LTO optimisation
Summary: ld problem with LTO optimisation
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: binutils
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Nick Clifton
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2018-04-06 16:56 UTC by Tomasz Kłoczko
Modified: 2018-04-30 21:03 UTC (History)
4 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2018-04-30 20:35:23 UTC
Type: Bug


Attachments (Terms of Use)

Description Tomasz Kłoczko 2018-04-06 16:56:57 UTC
After few successful tests with LTO optimisation on smaller and less complicated projects, I've started testing LTO on bigger projects.

I've chosen evolution.
So I've added in evoution.spec file in %build section before %cmake:

LDFLAGS="%{build_ldflags} -Wl,--as-needed -flto -fwhole-program" \
CFLAGS="%{build_cflags} -flto -fwhole-program" \
AR="gcc-ar" RANLIB="gcc-ranlib" NM="gcc-nm" \
%cmake -G "Unix Makefiles" \

Package build failed with:

[ 59%] Linking C executable evolution-alarm-notify
cd /home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/calendar/alarm-notify && /usr/bin/cmake -E cmake_link_script CMakeFiles/evolution-alarm-notify.dir/link.txt --verbose=1
/usr/bin/cc -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -mcet -fcf-protection -flto -fwhole-program -Werror-implicit-function-declaration -Wformat -Wformat-security -Winit-self -Wmissing-declarations -Wmissing-noreturn -Wpointer-arith -Wredundant-decls -Wundef -Wwrite-strings -fno-strict-aliasing -Wno-deprecated-declarations -Wdeclaration-after-statement -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -Wnested-externs  -Wl,-z,relro  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,--as-needed -flto -Wl,--no-undefined -rdynamic CMakeFiles/evolution-alarm-notify.dir/alarm.c.o CMakeFiles/evolution-alarm-notify.dir/alarm-notify.c.o CMakeFiles/evolution-alarm-notify.dir/alarm-notify-dialog.c.o CMakeFiles/evolution-alarm-notify.dir/alarm-queue.c.o CMakeFiles/evolution-alarm-notify.dir/config-data.c.o CMakeFiles/evolution-alarm-notify.dir/notify-main.c.o CMakeFiles/evolution-alarm-notify.dir/util.c.o  -o evolution-alarm-notify -Wl,-rpath,/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/calendar/gui:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/calendar/importers:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/composer:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/em-format:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/gui/contact-list-editor:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/gui/contact-editor:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/gui/widgets:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/printing:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/addressbook/util:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/smime/gui:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/smime/lib:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/libemail-engine:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/shell:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/e-util:/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0/src/libgnomecanvas: ../gui/libevolution-calendar.so ../importers/libevolution-calendar-importers.so ../../composer/libevolution-mail-composer.so ../../em-format/libevolution-mail-formatter.so -lcanberra-gtk3 -lX11 -lcanberra -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lcamel-1.2 -lsqlite3 -lssl3 -lsmime3 -lnss3 -lnssutil3 -lplds4 -lplc4 -lnspr4 -lpthread -ldl -lebook-1.2 -lglib-2.0 -lglib-2.0 -ledata-book-1.2 -lglib-2.0 -lebook-contacts-1.2 -lglib-2.0 -lecal-1.2 -L/usr/lib -lical -licalss -licalvcal -lglib-2.0 -lglib-2.0 -ledataserverui-1.2 -lglib-2.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lglib-2.0 -lebackend-1.2 -ledataserver-1.2 -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0 -lsecret-1 -lxml2 -lsoup-2.4 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lgailutil-3 -lgcr-ui-3 -lgcr-base-3 -lgck-1 -lp11-kit -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0 -lgnome-desktop-3 -lxml2 -lwebkit2gtk-4.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lsoup-2.4 -lgio-2.0 -lgobject-2.0 -ljavascriptcoregtk-4.0 -lglib-2.0 -lnotify -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 ../../addressbook/gui/contact-list-editor/libecontactlisteditor.so ../../addressbook/gui/contact-editor/libecontacteditor.so ../../addressbook/gui/widgets/libeabwidgets.so ../../addressbook/printing/libecontactprint.so ../../addressbook/util/libeabutil.so ../../smime/gui/libevolution-smime.so ../../smime/lib/libessmime.so ../../libemail-engine/libemail-engine.so ../../shell/libevolution-shell.so ../../e-util/libevolution-util.so -lgnome-autoar-0 -larchive -lgnome-autoar-gtk-0 -lenchant -lgtkspell3-3 -lenchant -lgtkspell3-3 -L/usr/lib64 -lresolv -llber -lldap -L/usr/lib ../../libgnomecanvas/libgnomecanvas.so -Wl,--export-dynamic -pthread -lm -lcamel-1.2 -lsqlite3 -lssl3 -lsmime3 -lnss3 -lnssutil3 -lplds4 -lplc4 -lnspr4 -lpthread -ldl -lebook-1.2 -ledata-book-1.2 -lebook-contacts-1.2 -lecal-1.2 -lical -licalss -licalvcal -ledataserverui-1.2 -lebackend-1.2 -ledataserver-1.2 -lsecret-1 -lgailutil-3 -lgcr-ui-3 -lgcr-base-3 -lgck-1 -lp11-kit -lgmodule-2.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lxml2 -lsoup-2.4 -lgnome-desktop-3 -lwebkit2gtk-4.0 -ljavascriptcoregtk-4.0 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lxml2 -lsoup-2.4 -lgnome-desktop-3 -lwebkit2gtk-4.0 -ljavascriptcoregtk-4.0 
/usr/bin/ld: Dwarf Error: Could not find abbrev number 1473.
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `timet_to_str_with_zone':
<artificial>:(.text+0x445): undefined reference to `e_datetime_format_format_tm'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `ensure_inited.part.0':
<artificial>:(.text+0x4cc): undefined reference to `e_util_ref_settings'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `location_activate_link_cb':
<artificial>:(.text+0x12d2): undefined reference to `e_show_uri'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `fill_in_labels.isra.0':
<artificial>:(.text+0x2dd4): undefined reference to `e_buffer_tagger_disconnect'
<artificial>:(.text+0x2e74): undefined reference to `e_buffer_tagger_connect'
<artificial>:(.text+0x2e87): undefined reference to `e_buffer_tagger_update_tags'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `open_alarm_dialog':
<artificial>:(.text+0x357b): undefined reference to `e_load_ui_builder_definition'
<artificial>:(.text+0x358a): undefined reference to `e_builder_get_widget'
<artificial>:(.text+0x359d): undefined reference to `e_builder_get_widget'
<artificial>:(.text+0x35b0): undefined reference to `e_builder_get_widget'
<artificial>:(.text+0x35c3): undefined reference to `e_builder_get_widget'
<artificial>:(.text+0x35d6): undefined reference to `e_builder_get_widget'
/tmp/ccNTk8fA.ltrans0.ltrans.o:<artificial>:(.text+0x35e9): more undefined references to `e_builder_get_widget' follow
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `open_alarm_dialog':
<artificial>:(.text+0x37dc): undefined reference to `e_buffer_tagger_connect'
<artificial>:(.text+0x394c): undefined reference to `e_builder_get_widget'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `display_notification.isra.12':
<artificial>:(.text+0x4081): undefined reference to `e_util_is_running_gnome'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `notify_dialog_cb':
<artificial>:(.text+0x58a6): undefined reference to `print_comp'
/tmp/ccNTk8fA.ltrans0.ltrans.o: In function `main':
<artificial>:(.text.startup+0x17d): undefined reference to `e_util_cleanup_settings'
collect2: error: ld returned 1 exit status
make[2]: *** [src/calendar/alarm-notify/CMakeFiles/evolution-alarm-notify.dir/build.make:192: src/calendar/alarm-notify/evolution-alarm-notify] Error 1
make[2]: Leaving directory '/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0'
make[1]: *** [CMakeFiles/Makefile2:3012: src/calendar/alarm-notify/CMakeFiles/evolution-alarm-notify.dir/all] Error 2
make[1]: Leaving directory '/home/tkloczko/rpmbuild/BUILD/evolution-3.28.0'
make: *** [Makefile:144: all] Error 2
error: Bad exit status from /var/tmp/rpm-tmp.JiQnYF (%build)

Looks like LTO optimisation caused not add some symbols to some libraries.
Is it a bug or a normal result of optimizing libraries?

Comment 1 Nick Clifton 2018-04-12 10:47:43 UTC
Hi Tomasz,

  Would you mind running a test for me please ?  I have had reports that
  that the annobin plugin does not interact with LTO very well, although
  I have never been able to track the problem down myself.  So, please
  could you try adding:

%undefine _annotated_build

  to your LTO-enabled version of the evolution.spec file, and see if this
  fixes the problem.  Personally I am hoping that it will not, but it does
  seem to work for some people.

Cheers
  Nick

Comment 2 Tomasz Kłoczko 2018-04-12 17:03:46 UTC
It failed in exactly the same place.

BTW. I found another issue with the same LTO optimisation settings in case zabbix. After add LTO zabbix_agentd binary crashes with SEGV. Should I open new ticket?

Comment 3 Tomasz Kłoczko 2018-04-13 07:46:36 UTC
I've spend today a bit more time to investigate this case.
I found that issue is with libevolution-util.so which is generated in src/e-util  in evolution source code tree.

Looks like really this library is almost completely empty.

[tkloczko@domek e-util]$ size libevolution-util.so 
   text	   data	    bss	    dec	    hex	filename
   1076	    616	   1920	   3612	    e1c	libevolution-util.so

However:

[tkloczko@domek e-util]$ nm libevolution-util.so | wc -l; ls -la libevolution-util.so 
14829
-rwxrwxr-x 1 tkloczko tkloczko 5172088 Apr 13 08:02 libevolution-util.so


The same library when evolution is build without LTO compile and linking options looks like:

[tkloczko@domek e-util]$ size libevolution-util.so; ls -l libevolution-util.so
   text	   data	    bss	    dec	    hex	filename
2565949	  56328	   7464	2629741	 28206d	libevolution-util.so
-rwxr-xr-x 1 tkloczko tkloczko 2677136 Apr  7 23:26 libevolution-util.so

but it is stripped library:

$ file libevolution-util.so 
libevolution-util.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=3fe671f280e875feaf0d378615c00f477b9dccd1, stripped, too many notes (256)


I see some possible explanation of above.

As long I don't see that during linking is used not used something like '-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libevolution-util.sym"' and because this is library and by this there is no main() in linked library LTO on linking removed almost everything. If it is true I see one possible cure in form of force combining --version-script or similar regexp param specifying list of symbols which needs to be provided by linked library when -shared options is used.

This if widely used may even cause better control of ABI of all libraries as library developer/maintainer will be forced to maintain sym file or similar with versioned ABI interface definition :)

Comment 4 Tomasz Kłoczko 2018-04-23 18:51:32 UTC
Just tested the same on libdtrace-ctf which has versioned ABI interface and seems effect is the same.

Library without LTO:

$ size libdtrace-ctf.so.1.3.0
   text	   data	    bss	    dec	    hex	filename
  58683	   2244	     16	  60943	   ee0f	libdtrace-ctf.so.1.3.0
$ nm -C -D libdtrace-ctf.so.1.3.0 
                 U __assert_fail
                 U close
                 U compress
                 U compressBound
0000000000006670 T ctf_add_array
0000000000006d50 T ctf_add_const
0000000000006ae0 T ctf_add_enum
0000000000006d70 T ctf_add_enumerator
0000000000006650 T ctf_add_float
0000000000006bc0 T ctf_add_forward
00000000000067a0 T ctf_add_function
0000000000006640 T ctf_add_integer
0000000000007390 T ctf_add_member
0000000000006fc0 T ctf_add_member_offset
0000000000006660 T ctf_add_pointer
0000000000006d60 T ctf_add_restrict
0000000000006920 T ctf_add_struct
00000000000074b0 T ctf_add_type
0000000000006cb0 T ctf_add_typedef
0000000000006a00 T ctf_add_union
00000000000073a0 T ctf_add_variable
0000000000006d40 T ctf_add_volatile
0000000000004c70 T ctf_arc_close
0000000000004e10 T ctf_archive_iter
0000000000004af0 T ctf_arc_open
0000000000004c90 T ctf_arc_open_by_name
0000000000004450 T ctf_arc_write
000000000000ac50 T ctf_array_info
00000000000031a0 T ctf_bufopen
0000000000002d70 T ctf_close
0000000000008ec0 T ctf_compress_write
00000000000051b0 T ctf_create
0000000000006610 T ctf_discard
000000000000a090 T ctf_enum_iter
000000000000b320 T ctf_enum_name
000000000000b440 T ctf_enum_value
0000000000007f00 T ctf_errmsg
0000000000007f50 T ctf_errno
00000000000085f0 T ctf_fdopen
00000000000097f0 T ctf_func_args
0000000000009680 T ctf_func_info
0000000000004400 T ctf_getmodel
0000000000004420 T ctf_getspecific
0000000000008e40 T ctf_gzwrite
0000000000003060 T ctf_import
00000000000084e0 T ctf_label_info
00000000000083e0 T ctf_label_iter
0000000000008350 T ctf_label_topmost
0000000000009160 T ctf_lookup_by_name
0000000000009540 T ctf_lookup_by_symbol
0000000000009470 T ctf_lookup_variable
000000000000aaa0 T ctf_member_info
0000000000009ef0 T ctf_member_iter
0000000000008de0 T ctf_open
0000000000002ff0 T ctf_parent_file
0000000000003000 T ctf_parent_name
0000000000003010 T ctf_parent_name_set
0000000000006500 T ctf_rollback
0000000000006710 T ctf_set_array
0000000000003140 T ctf_setmodel
0000000000004410 T ctf_setspecific
00000000000064d0 T ctf_snapshot
000000000000ae60 T ctf_type_align
000000000000aa30 T ctf_type_cmp
000000000000b060 T ctf_type_compat
000000000000a960 T ctf_type_encoding
0000000000009cf0 T ctf_type_iter
000000000000a7c0 T ctf_type_kind
000000000000a3c0 T ctf_type_lname
000000000000a780 T ctf_type_name
000000000000a880 T ctf_type_pointer
000000000000a800 T ctf_type_reference
0000000000009e20 T ctf_type_resolve
000000000000ad10 T ctf_type_size
000000000000b570 T ctf_type_visit
0000000000005390 T ctf_update
0000000000009d80 T ctf_variable_iter
00000000000090e0 T ctf_version
0000000000009060 T ctf_write
                 U __ctype_b_loc
                 w __cxa_finalize
                 U __errno_location
                 U free
                 U fwrite
                 U __fxstat
                 U getenv
                 U getpagesize
                 w __gmon_start__
                 U gzwrite
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000000 A LIBDTRACE_CTF_1.0
0000000000000000 A LIBDTRACE_CTF_1.1
0000000000000000 A LIBDTRACE_CTF_1.2
0000000000000000 A LIBDTRACE_CTF_1.3
                 U lseek
                 U malloc
                 U memmove
                 U memset
                 U mmap
                 U mprotect
                 U msync
                 U munmap
                 U open
                 U pread
                 U qsort_r
                 U __stack_chk_fail
                 U stderr
                 U strchr
                 U strcmp
                 U strcpy
                 U strerror
                 U strlen
                 U strncmp
                 U strpbrk
                 U uncompress
                 U unlink
                 U __vfprintf_chk
                 U __vsnprintf_chk
                 U write
                 U zError


And the same with LTO:

$ size libdtrace-ctf.so.1.3.0
   text	   data	    bss	    dec	    hex	filename
   1409	    648	      8	   2065	    811	libdtrace-ctf.so.1.3.0
$ nm -C -D libdtrace-ctf.so.1.3.0 
                 w __cxa_finalize
                 U getenv
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000000 A LIBDTRACE_CTF_1.0
0000000000000000 A LIBDTRACE_CTF_1.1
0000000000000000 A LIBDTRACE_CTF_1.2
0000000000000000 A LIBDTRACE_CTF_1.3

Comment 5 Nick Clifton 2018-04-30 16:38:22 UTC
(In reply to Tomasz Kłoczko from comment #2)
> It failed in exactly the same place.

Darn.  (Well actually this is good - it means that annobin is not blame).

> BTW. I found another issue with the same LTO optimisation settings in case
> zabbix. After add LTO zabbix_agentd binary crashes with SEGV. Should I open
> new ticket?

Yes please.

Cheers
  Nick

Comment 6 Tomasz Kłoczko 2018-04-30 18:54:05 UTC
Just FTR:

I found what has been causing emptying shared library during linking.
It happens when combination of two flags during linking are used: -flto and -fwhole-program

As I've changed to "-flto -fuse-linker-plugin" everything seems is OK. This set of flags gives the same size reduction on linking executables as with "-flto -fwhole-program" flags.

I was told on #gcc irc channel that -fwhole-program flag should be not used now because -fwhole-program is obsolete.
If it is true this flag should be removed or at least someone should investigate why it causes generate empty shared libraries.

In other words as long as I found kind of solution I think that this ticket should be kept as opened as long as something with -fwhole-program will be not done.

PS. I've already have second LTO related ticket which address crashing issue #1567112.

Comment 7 Jakub Jelinek 2018-04-30 19:14:30 UTC
Linking a shared library with -fwhole-program makes no sense at all, unless you mark all the external entrypoints from the shared library with externally_visible attribute (as documented).  The only exception is main, but most shared libraries don't contain main...

Comment 8 Tomasz Kłoczko 2018-04-30 20:31:04 UTC
That is the problem that even if library is linked with linking script which specifies precise list of symbols which needs to be provided by linked library what is produces does NOT contain any of those symbols!!!

In other words in such cases -fwhole-program is used is produced wrong library and/or it looks like it works when main() is present (on linking executable.

What I've presented about libdtrace-ctf in my prev comment describes exactly such case.

Comment 9 Jakub Jelinek 2018-04-30 20:35:23 UTC
If you want the linker to provide what needs to stay and what can be optimized away, then don't use -fwhole-program.  -fwhole-program does what is documented, it assumes the single TU or in case of LTO everything you link with LTO together is the whole program and exports only main and externally_visible marked functions.  It works exactly as documented.

Comment 10 Tomasz Kłoczko 2018-04-30 21:03:54 UTC
Jakub IMO -fwhole-program option is useless in rall case scenarios.
It can be replaced by -fuse-linker-plugin and it trashes linking libraries (it does not produce for example error that main() is missing in linked binary).

As compile and linking optimisation options are passed over CFLAGS and LDFLAGS in env variables during configure source code tree and if in such tree are build executables and libraries are linked all libraries will be broken/empty.

Whole idea of use cmake or automake is to hide compiler and linker specific options and use/add them on source code configuration stage. Because -fwhole-program is linking some libraries files without even warning that ell has been removed from linked library it causes that in project which produces libraries and executables it would be necessary to specify -fuse-linker-plugin or -fwhole-program depends on what is linked. However thi is in collision course with hiding in build framework all linker types details.

Using -fuse-linker-plugin on linking libraries I don't see any size reduction as looks like this option assumes that all library function should be added to public symbols list.

If -fwhole-program would be able to produce non-empty library when it is used with --version-script=<sym_file> it would allow produce some class of OSS project with strict control of ABI interface.
So far looks like LTO does not support/is not going to stimulate such long term changes.


Note You need to log in before you can comment on or make changes to this bug.