bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ld bug when linking for Ubicom IP2K processor using --relax option


From: Ryan Stone
Subject: ld bug when linking for Ubicom IP2K processor using --relax option
Date: Tue, 16 Mar 2004 14:40:11 -0500
User-agent: KMail/1.5.3

I originally posted this to address@hidden  Hopefully I'm sending it 
to the right mailing list now.

ld has a bug when using the --relax option that causes it to generate invalid 
code for the Ubicom IP2022 processor.  Some jumps and calls go to the wrong 
address in memory.  It's easiest to show this with a small testcase:

void foo(unsigned char x, unsigned char y) __attribute__((section(".pram")));
void bar() __attribute__((section(".pram")));


int main(int argc, char * argv)
{
        foo('r', 's');
        bar();
        return 0;
}

void foo(unsigned char x, unsigned char y)
{
}

void bar()
{
}


I compiled this with the gcc(version 3.3.3 20040105 (prerelease)) 
cross-compiler for the IP2K using only the -c option, and link with ld 
(version 2.14) using only the --relax option.  I'll show some snippets of the 
disassembly to illustrate the bug:

in main:
/*calling bar()*/
page $00000
call $00010

However, bar() starts at address 0x0000e, not 0x00010.  This bug does not 
occur if --relax is not used.  In main, it still calls address 0x00010, but 
bar() really does start at that address if --relax is not used.

As far as I can tell,  the problem is that linker relaxation is run after the 
linker turns symbols in jump and call instructions into absolute addresses.  
The relaxation step removes any redundant page instructions.  This moves any 
instructions after the page instruction up two bytes in memory.  But jumps 
and calls have already reference absolute addresses.  These absolute 
addresses are invalid if the relaxation has stripped out any page 
instructions.

Unfortunately, this is a chicken-and-the-egg problem.  The relaxation phase 
can only remove page instructions if it is sure that the page instruction and 
the symbol it references are in the same page in flash.  So it needs to 
compare absolute addresses.  But after the relaxation, those addresses might 
be invalid.  So assigning addresses to symbols has to be done after 
relaxation.  I'm not sure how to fix this, if this really is the problem.  It 
definitely seems to be.  In my example above, the call to bar is off by 2 
bytes,  which is the length of one instruction.  There will be a single 
redundant page instruction in foo() that eliminated by linker relaxation.  If 
a call to bar() is inserted into foo(), that will produce a second redundant 
page instruction, and if you compile, link and then look at the disassembly, 
the call to bar() in main() is off by 4 bytes.

I'm not sure if my explanation of the bug was coherent enough, so I'll give a 
really small example below:

.global _main

_main:
        page foo
        jmp foo

foo:
        ret

Here's what will happen when this is assembled and linked(with relaxation):

* _main is assigned an absolute address(let's say 0x00000)
* foo is assigned the address 0x00004 (_main + 2 instructions).  The symbol 
foo in the jmp instruction is turned into the absolute address of 0x0004
* The relaxation phase sees that the page instruction is redundant, and 
removes it.  The jmp instruction is now at address 0x00000, and the ret 
instruction is now at 0x00002.  The jmp instruction still jumps to 0x00004.

I'd suggest that anyone who uses ld for linking for the IP2K not use linker 
relaxation unless this bug is fixed.

Ryan Stone





reply via email to

[Prev in Thread] Current Thread [Next in Thread]