Bug 13683 - usage tracking by --gc-sections ignores a --defsym mapping
Summary: usage tracking by --gc-sections ignores a --defsym mapping
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.19
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2012-02-11 21:18 UTC by Don Kinzer
Modified: 2012-03-05 23:09 UTC (History)
2 users (show)

See Also:
Last reconfirmed:

test case makefile and C source (591 bytes, application/x-compressed)
2012-02-11 21:18 UTC, Don Kinzer
test case makefile (373 bytes, text/plain)
2012-02-11 21:19 UTC, Don Kinzer
test case C source (120 bytes, text/x-csrc)
2012-02-11 21:19 UTC, Don Kinzer
Re-evaluate --defsym options (1.56 KB, patch)
2012-02-14 17:30 UTC, Nick Clifton
Details | Diff
early lang_do_assignments (1.00 KB, patch)
2012-02-16 02:00 UTC, Alan Modra
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Don Kinzer 2012-02-11 21:18:06 UTC
Created attachment 6208 [details]
test case makefile and C source

I have a use case where I need to perform link-time mapping of a function call to one of several differently named candidates having the same parameter lists and return type. In the actual use case all of the candidate functions are in a library but that fact is not relevant to the problem that arises.

The attached .c and makefile can be used to observe the problem when compiled for an AVR target. In this simple test case, main calls a non-existent function "foo" and the linker option --defsym,foo=foo2 is used to map the call to the desired function. If the link step is performed without the --gc-sections option, the resulting executable is correct as shown in this .lss excerpt:

000000e0 <main>:
e0: f7 df rcall .-18 ; 0xd0 <foo2>
e2: ff cf rjmp .-2 ; 0xe2 <main+0x2>

However, adding --gc-sections to the link options produces this incorrect code with no warning or error messages:
000000c8 <main>:
c8: 9b df rcall .-202 ; 0x0 <__vectors>
ca: ff cf rjmp .-2 ; 0xca <main+0x2>

The resulting load image contains none of the three candidate functions indicating the the linker code that eliminates unused functions determined that they were all unused even though "foo2" should have been marked as used.

I attempted to confirm this issue for an x86 target (ld v2.21.1) but it appeared that --gc-sections didn't remove any unused functions.
Comment 1 Don Kinzer 2012-02-11 21:19:32 UTC
Created attachment 6209 [details]
test case makefile
Comment 2 Don Kinzer 2012-02-11 21:19:59 UTC
Created attachment 6210 [details]
test case C source
Comment 3 Nick Clifton 2012-02-14 17:30:54 UTC
Created attachment 6212 [details]
Re-evaluate --defsym options
Comment 4 Nick Clifton 2012-02-14 17:31:41 UTC
Hi Don,

  Please could you try out the uploaded patch and let me know if it works for you.

Comment 5 Don Kinzer 2012-02-14 21:36:11 UTC
Thanks for the quick response on this.  The version of avr-ld that I am using is part of the WinAVR_20100110 release but I'll see if I can build the equivalent avr-ld from sources+patches and then add your patch.


Don Kinzer
Comment 6 Alan Modra 2012-02-14 22:15:31 UTC
Nick, can you just run lang_do_assignments before lang_gc_sections instead?
Comment 7 Nick Clifton 2012-02-15 09:57:43 UTC
Hi Alan,

> can you just run lang_do_assignments before lang_gc_sections instead?

I tried that, but could not find a way to make it work.  If you run it with lang_first_phase_enum it does not recompute the defsym assignments.  If you run it with any other enum it fails the "output section size must be non-zero" assertion in lamg_size_sections_1.  

I agree however that re-invoking lang_do_assignments would be a better way to fix the problem.  I will investigate some more and see if I can persuade it to work.

Comment 8 Don Kinzer 2012-02-15 16:48:20 UTC
I back-ported the patch to ld 2.19.1.  In doing so, I had to modify the patch slightly because that version of the source doesn't have the function exp_defsym().  I created a similar function and changed the yacc grammar action to invoke it when the --defsym option is seen.

In testing, I can see that a defsym_node structure is created and put on the defsym_list list.  Further, that single node is processed when ldexp_rerun_defsyms() is called and the two conditions therein are true allowing exp_fold_tree() to be called.  This all suggests that I've patched my version correctly but the resulting executable image is the same as before:

000000c8 <main>:
  c8:	9b df       	rcall	.-202    	; 0x0 <__vectors>
  ca:	ff cf       	rjmp	.-2      	; 0xca <main+0x2>

If it works on your version of ld then it appears that there may be other changes required for v2.19.1.


Don Kinzer
Comment 9 Alan Modra 2012-02-16 02:00:09 UTC
Created attachment 6215 [details]
early lang_do_assignments

This also seems to work.
Comment 10 Alan Modra 2012-02-22 02:32:37 UTC
Hmm, running lang_do_assignments before lang_gc_sections does change a few things in the symbol table, leading to some cris-elf testsuite failures.

What's happening is that elf_gc_sweep now sees all the link script defined symbols, so they become subject to garbage collecting (well, forcing local).  For the first test that fails, the expected symbol table is

00080074 l    d  .text	00000000 .text
00082078 l    d  .got	00000000 .got
00082078 l     O .got	00000000 _GLOBAL_OFFSET_TABLE_
00080074 g       .text	00000000 _start
00082084 g       *ABS*	00000000 __bss_start
00082084 g       *ABS*	00000000 _edata
000820a0 g       *ABS*	00000000 _end

but we now get

00080074 l    d  .text	00000000 .text
00082078 l    d  .got	00000000 .got
00082084 l       *ABS*	00000000 __bss_start
00082084 l       *ABS*	00000000 _edata
00082078 l     O .got	00000000 _GLOBAL_OFFSET_TABLE_
000820a0 l       *ABS*	00000000 _end
00080074 g       .text	00000000 _start

Note how __bss_start, _edata, _end are now local since no dynamic objects referred to them.  I don't think that is a great concern, but of course means tweaking the cris testsuite when/if this patch goes in.
Comment 11 cvs-commit@gcc.gnu.org 2012-02-22 16:27:42 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	nickc@sourceware.org	2012-02-22 16:27:35

Modified files:
	ld             : ChangeLog ldexp.c ldexp.h ldlang.c 
	ld/testsuite   : ChangeLog 
	ld/testsuite/ld-cris: tls-gc-68.d tls-gc-69.d tls-gc-70.d 
	                      tls-gc-71.d tls-gc-75.d tls-gc-76.d 
	ld/testsuite/ld-gc: gc.exp 
Added files:
	ld/testsuite/ld-gc: pr13683.c pr13683.d 

Log message:
	PR ld/13683
	* ldlang.c (lang_process): Rerun lang_do_assignments before
	starting garbage collection.
	* ldexp.c (fold_name): Generate a reloc for defined symbols
	found without an associated output section during the mark phase.
	(exp_fold_tree_1): Continue processing an expression, even if we
	are unable to fold it, if we are in the first two evaluation
	* ldexp.h (enum lang_phase_type): Add descriptions of the phases.
	* ld-gc/pr13683.c: New test source file.
	* ld-gc/pr13683.d: New test control and output file.
	* ld-gc/gc.exp: Run the pr13683 test.
	* ld-cris/tls-gc-68: Update expected symbol table dump.
	* ld-cris/tls-gc-69: Likewise.
	* ld-cris/tls-gc-70: Likewise.
	* ld-cris/tls-gc-71: Likewise.
	* ld-cris/tls-gc-75: Likewise.
	* ld-cris/tls-gc-76.d: Likewise.
	* ld-cris/tls-gc-79.d: Likewise.

Comment 12 Nick Clifton 2012-02-22 16:29:39 UTC
Hi Guys,

  Alan's patch is better than mine, so I have checked it in, along with a new linker testcase and some tweaks to the cris linker tests that were affected.  (No other target showed regressions because of this patch).

Comment 13 cvs-commit@gcc.gnu.org 2012-03-05 23:09:15 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	amodra@sourceware.org	2012-03-05 23:09:11

Modified files:
	ld/testsuite   : ChangeLog 
	ld/testsuite/ld-gc: pr13683.d 

Log message:
	PR ld/13683
	* ld-gc/pr13683.d: Allow non-zero top address digit.