bug-gnu-utils
[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: Mon, 15 Mar 2004 11:38:57 -0500
User-agent: KMail/1.5.3

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(32, 20);
        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 the -c option, and link with ld (version 
2.14) using only with 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.  As far as I can tell, 
the problem is that the linker relaxation step is run after the linker turns 
symbols in jump and call instructions are turned 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 is off by 2 bytes, 
which is the length of one instruction.  If a call to bar() is inserted into 
foo(), that will produce a second redundant page instruction, and if you 
compile, link and disassemble, 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]