Bug 13697

Summary: [avr] Wrong symbol values with --gc-sections
Product: binutils Reporter: Georg-Johann Lay <gjl>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: amodra, childbear0, eric.weddington, matthieu.lemerre
Priority: P2    
Version: 2.24   
Target Milestone: ---   
Host: Target: avr
Build: Last reconfirmed:
Attachments: heap-start.s
heap-start.map
Console Output with -v -Wl,-v
heal-start.elf: Disassembly from avr-objdump -d
Tentative patch: Keep .data

Description Georg-Johann Lay 2012-02-16 10:18:16 UTC
Suppose the following small C program:

int main (void)
{
    extern char __heap_start;
    return (int) & __heap_start;
}

Compile with:

avr-gcc heap-start.c -mmcu=atmega168 -o heal-start.elf -Os -save-temps -Wl,-Map,heap-start.map -Wl,--gc-sections

Assembler output is:


	.file	"heap-start.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
	.section	.text.startup,"ax",@progbits
.global	main
	.type	main, @function
main:
.L__stack_usage = 0
	ldi r24,lo8(__heap_start)
	ldi r25,hi8(__heap_start)
	ret
	.size	main, .-main
	.ident	"GCC: (GNU) 4.7.0 20120206 (experimental)"


ATmega168 has RAM start at 0x100 but the generated map file reads

...
 *(.data)
 *(.data*)
 *(.rodata)
 *(.rodata*)
 *(.gnu.linkonce.d*)
                0x00800100                . = ALIGN (0x2)
                0x00800100                _edata = .
                0x00800100                PROVIDE (__data_end, .)

.bss            0x00800060        0x0
                0x00800060                PROVIDE (__bss_start, .)
 *(.bss)
 *(.bss*)
 *(COMMON)
                0x00800060                PROVIDE (__bss_end, .)
                0x0000008a                __data_load_start = LOADADDR (.data)
                0x0000008a                __data_load_end = (__data_load_start + SIZEOF (.data))

.noinit         0x00800060        0x0
                0x00800060                PROVIDE (__noinit_start, .)
 *(.noinit*)
                0x00800060                PROVIDE (__noinit_end, .)
                0x00800060                _end = .
                0x00800060                PROVIDE (__heap_start, .)
...

That is obviously wrong because .bss starts at RAM 0x60.

Notice that the program does not define data in the static storage.
If data in static storage is added or --gc-sectons is removed, the values are as expected.
Comment 1 Georg-Johann Lay 2012-02-16 10:21:47 UTC
Created attachment 6217 [details]
heap-start.s

avr-gcc's assembler output
Comment 2 Georg-Johann Lay 2012-02-16 10:22:58 UTC
Created attachment 6218 [details]
heap-start.map
Comment 3 Georg-Johann Lay 2012-02-16 10:26:29 UTC
Created attachment 6219 [details]
Console Output with -v -Wl,-v

Console output for the following command:

avr-gcc heap-start.c -mmcu=atmega168 -o heal-start.elf -Os -save-temps -Wl,-Map,heap-start.map -Wl,--gc-sections -v -Wl,-v
Comment 4 Georg-Johann Lay 2012-02-16 10:32:07 UTC
Created attachment 6220 [details]
heal-start.elf: Disassembly from avr-objdump -d

avr-objdump -d heal-start.elf | grep -A 3 '<main>:'

00000080 <main>:
  80:   80 e6           ldi     r24, 0x60       ; 96
  82:   90 e0           ldi     r25, 0x00       ; 0
  84:   08 95           ret
Comment 5 Alan Modra 2012-02-16 11:51:57 UTC
I think this pain is self-inflicted.

You're using -m avr5 -Tdata 0x800100 instead of -m avr51.  So you get the avr5 ld script with the data section fudged to be at 0x800100.  However, the data section is stripped by -gc-sections.  So the address change doesn't affect following sections.  They stay at the avr5 data memory region of 0x800060.
Comment 6 Georg-Johann Lay 2012-02-16 12:30:29 UTC
(In reply to comment #5)
> I think this pain is self-inflicted.
> 
> You're using -m avr5 -Tdata 0x800100 instead of -m avr51.  So you get the avr5
> ld script with the data section fudged to be at 0x800100.  However, the data
> section is stripped by -gc-sections.  So the address change doesn't affect
> following sections.  They stay at the avr5 data memory region of 0x800060.

atmega168 is element of avr5 and not element of avr51 (avr51 has ELPM instruction for example. ATmega168 has no ELPM).

avr-gcc mixes devices with different RAM-start in the same core architecture, see mcu-devices.def:

http://gcc.gnu.org/viewcvs/trunk/gcc/config/avr/avr-mcus.def?revision=184276&content-type=text%2Fplain&view=co
Comment 7 Georg-Johann Lay 2012-05-23 19:36:45 UTC
Created attachment 6417 [details]
Tentative patch: Keep .data

This is a tentative patch to fix the issue by KEEPing .data.

Lightly tested with a small program.

Johann

ld/
	PR 13697
	* scripttempl/avr.sc (.data): Keep it.
Comment 8 Sourceware Commits 2012-06-07 16:53:25 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	nickc@sourceware.org	2012-06-07 16:53:11

Modified files:
	ld             : ChangeLog 
	ld/scripttempl : avr.sc 

Log message:
	PR 13697
	* scripttempl/avr.sc (.data): Keep it.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/ChangeLog.diff?cvsroot=src&r1=1.2454&r2=1.2455
http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/scripttempl/avr.sc.diff?cvsroot=src&r1=1.12&r2=1.13
Comment 9 Georg-Johann Lay 2012-06-07 18:00:55 UTC
Fixed