[arm-gnu] Some symbols computation does not work right in LD

Carlos O'Donell carlos_odonell at mentor.com
Wed Apr 11 16:50:21 UTC 2012


On 3/23/2012 5:21 AM, Bruno Richard wrote:
> I found a problem in the ARM-EABI linker:
> In .ld files, when some symbols are computed, their results when computed by LD look invalid.
> 
> This problem was not showing on GCC versions up to 4.5.2, and is present with 4.6.1.
> 
> To show the problem, use the following command line:
> arm-none-eabi-ld.exe" -T test.ld main.o -o main.elf -Map main.map
> 
> Here is an excerpt of the linker file that shows the problem:
>     _eidata1 = (_sidata +  _edata) - _sdata ;       /* 0x08000004 in map file */
>     _eidata2 =  _sidata + (_edata  - _sdata);       /* 0x08000004 in map file */
>     same = (_eidata1 == _eidata2) ? 0x1 : 0x0;      /* 0x00000000 in map file !!!*/
> 
> The "same" Symbol should be 1, not 0.
> 
> I attach a zip file containing the files necessary to reproduce the problem.

I believe your linker script is wrong.

Please read:
http://sourceware.org/binutils/docs/ld/Expression-Section.html#Expression-Section

Symbols in a section are section relative by default.

Use ABSOLUTE() when assigning to symbols that should have absolute VMA values, or use ABSOLUTE() when doing the computation to avoid the normal rules LD applies when mixing relative and non-relative addressing.

For example:

_sidata = 0xd4 (relative to .text 0x08000000 VMA FLASH)
_edata = 0xc (relative to .data 0x20000000 VMA RAM)
_sdata = 0x0 (relative to .data 0x20000000 VMA RAM)

_eidata1 = (_sidata + _edata) - _sdata;
Linker converts _sidata and _edata to absolute via rule: binary operator on two relative operands in different sections implicitly converts to absolute addressing.
_edata1 = (0x080000d4 + 0x2000000c) - _sdata;
        = (0x280000e0) - _sdata
Linker converts _sdata to absolute via previously stated rule.
        = 0x280000e0 - 0x20000000;
        = 0x080000e0;

_eidata2 = _sidata + (_edata - _sdata);
Linker doesn't convert _edata and _sdata because they are in the same section.
         = _sidata + (0xc - 0x0);
Linker converts result of .data section relative 0xc to absolute.
         = _sidata + (0xc);
         = 0x080000d4 + 0x2000000c;
         = 0x280000e0;

Therefore _eidata1 != _eidata2.

In the past you might have gotten lucky with the numbers working out.

With ABSOLUTE() I get:

                0x080000e0                _eidata1 = ((_sidata + _edata) - _sdata)
                0x080000e0                _eidata2 = (_sidata + (_edata - _sdata))
                0x00000001                same = (_eidata1 == _eidata2)?0x1:0x0

Note: 
- I have seen LD *print* the wrong VMA  in the address column, but I haven't investigated this bug.

Cheers,
Carlos.
-- 
Carlos O'Donell
Mentor Graphics / CodeSourcery
carlos_odonell at mentor.com
carlos at codesourcery.com
+1 (613) 963 1026



More information about the arm-gnu mailing list