avr-libc-dev
[Top][All Lists]
Advanced

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

[avr-libc-dev] Re: AVR GCC 4.1.1 and switch statements


From: Björn Haase
Subject: [avr-libc-dev] Re: AVR GCC 4.1.1 and switch statements
Date: Fri, 3 Nov 2006 23:22:30 +0100
User-agent: KMail/1.7.1

Hello,

I'm just back from vacation, so I've read this thread only right now. I've had 
a brief look at the issue. I come to the conclusion that we are having two 
issues to fix the warning bug.
1.) gcc generates code that refers to the jump table address as if it were a 
code label address. I.e. in fact the label of the jump table does not contain 
code but data. I.e. the data with the address of jump targets. Gcc presently 
uses the gs() macro when accessing the switch table address  while it should 
make use of pm() instead.
2.) With the the presently generated assembly code of gcc, i.e. with gs() the 
warning is justified, but only for the avr6 targets.

The basic issue is that gcc realizes some type of address arithmetic, address 
arithmetic that is dangerous if two conditions are met. 1.) the address needs 
to be a code label and 2.) the target needs to be a >128k device. 

This is what the warning is about ...

Joerg Wunsch wrote on Freitag, 3. November 2006 19:01 :
> As Eric Weddington wrote:
> > I'm working on the RZ200 kit display board firmware and I was
> > getting some strange assembler warning messages (through it's
> > temporary file from GCC).  It seems that AVR GCC doesn't like switch
> > statements that have a lot cases.  I don't know the exact number
> > that is the cutoff point. And I think I saw someone else make this
> > comment too, either on AVR Freaks or on avr-gcc-list (or it could of
> > even been on the gcc list).
>
> I think on avr-gcc-list.  I've been hoping Björn would eventually look
> at it...  It's not a GCC 4.x issue, it's rather an issue with the
> linker stub stuff.
>
> It happens whenever a jump table is created.  Björn added another
> operator for to the assembler, called "gs".  This one is emitted as
> part of the jump table computation:
>
>         subi r30,lo8(-(gs(.L258)))
>         sbci r31,hi8(-(gs(.L258)))
The label .L256 most probably is an address refering to the beginning of a 
jump table that resides in the .progmem.gcc_sw_table sections. Thus, this 
label isn't in fact pointing to code but to progmem data.
>         lsl r30
>         rol r31
>         lpm __tmp_reg__,Z+
>         lpm r31,Z
>         mov r30,__tmp_reg__
>         ijmp
>
> /var/tmp//ccAYIFV3.s: Assembler messages:
> /var/tmp//ccAYIFV3.s:21: Warning: expression dangerous with linker stubs
> /var/tmp//ccAYIFV3.s:22: Warning: expression dangerous with linker stubs
>
> I think what the warning is going to tell is is that if the jump table
> would ever cross a "page" boundary (like a 128 KiB block boundary),
> funny things will happen.
No the reason for me for adding this warning was the following: 

Imagine that somebody is generating or writing assembly code where depending 
on some condition he whishes to jump not to some label, say my_startlabel or 
to an address 10 instructions behind, i.e. (my_startlabel + 20) instead. 
Assume that we are having a >128k target.

Straight forward method would be, that he takes the address of the first 
label, loads it in a register, conditionally adds 10 and makes a relative 
jump, i.e. ijmp. 

What happens depends on where the destination function ends up. If 
"my_startlabel" is below the 128k boundary, everything is fine. 

If it is placed by the linker behind the 128k boundary, there is no way to 
reach the destination address by use of a 16 bit pointer! The linker 
recognizes this and adds a "jmp my_startlabel" instruction below the 128k 
boundary and replaces the value of (my_startlabel) in instructions like 

ldi r30,lo8(-(gs(my_startlabel)) and
ldi r31,hi8(-(gs(my_startlabel))

by the address of the jump instruction. I.e. instead of loading the address of 
the unreachable function itself, it loads the address of the jump 
instruction. If one then does simply a

ijmp

instruction everything works fine. The indirect jump first jumps with its 16 
bits scope to the jump instruction below 128k and the jump instruction with 
it's 23 bit scope will jump to the final target. The problem shows up when 
jumping to the address "my_startlabel" + 20. In case that "my_startlabel" is 
behind the 128k boundary, one would be doing calculations which yield as a 
result some address shortly behind the jump stub! I.e. somewhere in the 
nirvana. This is what the warning is about.

I.e. the message is: The assembler should disallow arithmetics with addresses 
for code and this is what the warning is about.

>
> But I've got no idea about what the luser could do to avoid that
> warning.

The first thing would be to make gas disable this warning for avrX with X < 6. 
The next thing would be to make gcc generate code where this warning is no 
longer generated, i.e. by using the pm() directive instead of the gs() 
directive for the table jump stuff. This would be a bit more work and 
possibly this is not easily feasible since we would need to clearly 
distinguish pointers to code and pointers to data.

>
> OK, now that you bring this up, maybe it's best to just add Björn to
> the Cc list...  Björn, please keep the uriah.heep.sax.de address in
> the reply so I might read it at home.

As I understand that this is not a blocking bug, I'd like to suggest to first 
implement the small change in binutils myself. We maybe should discuss more 
in detail on what to do with gcc. The easiest solution would be to disable 
the casesi pattern for the >128k devices completely. 

Bjoern.




reply via email to

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