Bug 38549 - [avr] eicall not properly set for > 128K program space
Summary: [avr] eicall not properly set for > 128K program space
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 38057 38550 38551 (view as bug list)
Depends on:
Blocks:
 
Reported: 2008-12-17 10:33 UTC by ilyas
Modified: 2014-02-16 13:13 UTC (History)
8 users (show)

See Also:
Host:
Target: avr-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2009-03-23 16:43:12


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ilyas 2008-12-17 10:33:00 UTC
Hello, i use winavr gcc for programming atmega2561 microcontroller.
2561 has 256 K program memory our code works good below 128 K but when our code becomes larger than 128 K byte, does not work properly. this is because eicall assembler command. there must be an EIND=1 command before accessing the memory after 128 K. when this is done, there is no problem.
you have to fix this problem as soon as possible. we cannot use half of our program memory right now.

http://sourceforge.net/tracker/index.php?func=detail&aid=2229892&group_id=68108&atid=520074

regards..
ilyas
Comment 1 Andrew Pinski 2008-12-21 22:34:25 UTC
*** Bug 38550 has been marked as a duplicate of this bug. ***
Comment 2 Andrew Pinski 2008-12-21 22:34:29 UTC
*** Bug 38551 has been marked as a duplicate of this bug. ***
Comment 3 Thiago A. Correa 2009-03-23 16:33:14 UTC
Bug #38057 reports the same issue. Perhaps this should be changed to CONFIRMED and one of the bug reports set as duplicate.
Comment 4 Eric Weddington 2009-03-23 16:42:52 UTC
*** Bug 38057 has been marked as a duplicate of this bug. ***
Comment 5 johnstonj 2010-11-02 20:25:05 UTC
I can confirm this is indeed a problem.  I am developing a bootloader for ATxmega128A1 (128 KB app flash + 8 KB bootloader = 136 KB flash total).  My code:

#define PROG_START         0x0000
  (*((void(*)(void))PROG_START))();            //jump

This emits the following:

# Notice on reset, EIND register is written to a 1 as shown here.
# I searched the entire emitted disassembly and found no other
# reference to the I/O address for EIND.
000202e0 <__ctors_end>:
...
   202ec:	01 e0       	ldi	r16, 0x01	; 1
   202ee:	0c bf       	out	0x3c, r16	; 60


# Notice that Z is set to 0, as expected.  However, EIND is not
# set to 0 and so the processor attempts to do the jump to
# the location specified by EIND == 1 and Z == 0, which isn't a valid
# place to jump to.
  (*((void(*)(void))PROG_START))();            //jump
   20590:	e0 e0       	ldi	r30, 0x00	; 0
   20592:	f0 e0       	ldi	r31, 0x00	; 0
   20594:	19 95       	eicall

Presumably this will come up much more frequently now that the ATxmega processors are available:  all of these have so much flash that I would imagine this will be a frequent problem.

I assume the problem happens with EIJMP which also uses EIND.

I notice that eicall / eijmp are used in libgcc.s.  I wouldn't be surprised if there are bugs there, too - but did not investigate further.

My fix is simple; just set EIND = 0 before my jump.  However it leaves little faith in my compiler for the application itself, since I don't know if it will work reliably on AVR with large flash space for all jumps and calls, etc.
Comment 6 Georg-Johann Lay 2011-10-23 15:24:15 UTC
Closed as INVALID.

In the remainder you find an ouline of how to cope with indirect jumps on devices with more than >128 KiB of code.

Actually, the flaw is that the following explanation is not yet part of the documentation, see PR50820.

* The compiler never sets EIND.

* The startup code from libgcc never sets EIND.
  Notice that startup code is a blend of code from libgcc and avr-libc.
  For the impact of avr-libc on EIND, see avr-libc documentation.

* The compiler uses EIND in EICALL/EIJMP instructions or might read
  EIND directly.

* The compiler assumes that EIND is not changed during startup code or
  run of the application. In particular, EIND is not saved/restored in
  function or interrupt service routine prologue/epilogue.

* It is legitimate for user-specific startup code to setup EIND
  early, for example by means of initialization code located in
  section .init3 prior to general startup code that initializes
  RAM and calls constructors.

* For indirect calls to functions and computed goto, the linker will
  generate stubs. Stubs are jump pads sometimes also called trampolines.
  Thus, the indirect call/jump will jump to such a stub.
  The stub contains a direct jump to the desired address.

* Jump pads will be generated automatically by the linker if
  - the address of label is taken like so
       LDI r24, lo8(gs(func))
       LDI r25, hi8(gs(func))
  - and if the final location of that label is in a code segment
   *outside* the segment where the stubs are located.

  The compiler will emit gs() relocations (short for generate
  stubs) if the address of a label is taken.

* Addresses of labals are taken in the following situations:
  - Taking address of of a function or code label
  - Computed goto
  - If prologue-save function is used, see -mcall-prologues
    command line option
  - Switch/case dispatch tables. If you do not want such dispatch
    tables you can specify the -fno-jump-tables command line option.
  - C and C++ constructors called during startup
  - C and C++ destructors called during shutdown
  - If the tools hit a gs() directive explained above

* The default linker script is arranged for code with EIND = 0.
  If code is supposed to work for a setup with EIND != 0, a custom
  linker script has to be used in order to place the sections whose
  name start with .trampolines into the segment where EIND points to.

* Jumping to a non-symbolic addresse like so:

    int main (void)
    {
        // Call function at word address 0x2
        return ((int(*)(void)) 0x2)();
    }

  is /not/ supported.  Instead, a stub has to be set up like so:

    int main (void)
    {
        extern int func_4 (void);

        // Call function at byte address 0x4
        return func_4();
    }

   and the application be linked with -Wl,-defsym=func_4=0x4
Comment 7 Jackie Rosen 2014-02-16 13:13:49 UTC Comment hidden (spam)