Linker script values as absolute / relative / number confusion

Andrew Burgess aburgess@broadcom.com
Fri Sep 14 16:21:00 GMT 2012


I trying to take a linker script that used to work on older linkers and 
get it running on a more recent (2.22) linker.

I'm running into confusion relating to changes in how symbols in the 
linker script are treated as absolute, relative, or just numbers, and 
converted from one type to another.

I have a simple example,

 > cat obj.s
         .text
         .4byte 0x0
 > as -o obj.o obj.s
 > ld -T memmap1.ld -Map link1.map -o obj.x obj.o
 > cat memmap1.ld
SECTIONS
{
   . = 0x100;

   .text :
   {
     *(.text*)
   }

   _pad_to = 0x200;

   .padding :
   {
     BYTE(0); . = ALIGN(8);
     . += (. < _pad_to) ? (_pad_to - .) : 0;
   }

   .end :
   {
     BYTE(0);
   }

   /DISCARD/ : { *(*) }
}
 > grep "\.end" link1.map

## END ##

Ok, so, you'll notice a grep at the end, that's how I'm judging success 
/ failure.  There's probably lots wrong with the script, so here's what 
I'm trying to do,

The ".padding" section should fill enough space so that the section 
/after/ it starts at the address in _pad_to.  The address of ".end" then 
should be 0x200, and the output from the grep, would I hope look like this:
  .end            0x0000000000000200        0x1

[ I know there are "correct" ways to force the start address of ".end" 
to the right place, lets pretend there's a /really/ good reason why I 
want to do things this way for now. ]

On ld 2.19 I do get the behaviour I'd like.  On current HEAD I don't, 
instead I get:
.end            0x0000000000000304        0x1

The problem it turns out is the line:
   . += (. < _pad_to) ? (_pad_to - .) : 0;

So, I read up in the documentation, and in this page:
 
http://sourceware.org/binutils/docs-2.22/ld/Expression-Section.html#Expression-Section

If I look at the line in bits, first ". < _pad_to", whether "." is 
treated as relative or absolute it will be less than "_pad_to", so it's 
the "_pad_to - ." that's causing the problem.

The docs say that absolute symbols in output sections are treated as 
plain numbers, so I have "<plain-number: 0x200> - <relative-addr: 0x8>". 
  The docs further suggest that the result of this will be 0x1fc, 
leading to my change in behaviour.

Ok, so I apply the following patch to "fix" my linker script, the line 
in question now becomes:
   . += (ABSOLUTE(.) < _pad_to) ? (_pad_to - ABSOLUTE(.)) : 0;

Now I rerun the test, and grep for my output line .... and nothing has 
changed.

So docs again, and indeed, binary operations involving an absolute 
address and a plain-number convert the number to an absolute. Gah.

Ok, so I throw a few more ABSOLUTEs at the thing, and I get:
   . += (ABSOLUTE(.) < ABSOLUTE(_pad_to)) ? (ABSOLUTE(_pad_to) - 
ABSOLUTE(.)) : 0;

Now I rerun the test and joy, things work again.

So, finally, my questions,

(1) The thing I've ended up with doesn't feel great.  I create _pad_to 
as an absolute symbol, but then need to wrap it in ABSOLUTE in order to 
use it as an absolute symbol.  Is this /really/ the intended behaviour. 
  I'm sure there's a really good reason for the whole absolute addresses 
to numbers behaviour, but even after reading the docs I don't understand 
why we'd want it this way, I'm hoping someone can help me understand.

(2) In my second attempt, with the version of the line:
   . += (ABSOLUTE(.) < _pad_to) ? (_pad_to - ABSOLUTE(.)) : 0;
I see the size of "_pad_to - ABSOLUTE(.)" as "0x1fc", given that the 
".padding" section starts at 0x104, contains 1 byte then rounds up to an 
0x8 bounday, I think the value of ABSOLUTE(.) should be 0x108.  Given 
that then after converting the number 0x200 to be an absolute address ld 
comes up with the value "0x1fc + 0x108" = "0x304".  Given that 0x200 
(the original value of _pad_to) must be involved somewhere, then all I 
can think is that ld believes the absolute address for where this line 
is being executed is at 0x104, but this seems wrong to me, should it not 
be 0x108?


So, last bit of info is to figure out where all the changes came from. 
I'm using the git mirror (git://sourceware.org/git/binutils.git), the 
commit that actually changed the behaviour was 
dc027516e99b4795b1fba7179de6fe00606910, which was added as a result of 
bug, http://sourceware.org/bugzilla/show_bug.cgi?id=12066, which was 
raised as a result of commit 557189b0dd1f3dec6b00b91b9b0c5459ece72a52.

The mailing list thread for commit 557189b0 is:
   http://sourceware.org/ml/binutils/2010-08/msg00118.html

Thanks for your time,

Andrew













Question 1:








More information about the Binutils mailing list