Skip to content

[avr] Wrong code to indirect call functions located beyond the first 128KiB code segment. #58856

@sprintersb

Description

@sprintersb

Consider the following C code:

int func (void);

int main (void)
{
    int (*f)(void) = func;
    __asm ("" : "+r" (f));
    return f();
}

and compiled with:

> clang --target=avr foo.c -Os -save-temps -mmcu=atmega2560 -Os -o foo.elf -Wl,--defsym,func=0x22222
> avr-objdump -d foo.elf > foo.lst
> avr-objdump -dr foo.o > foo.lss

So that the code mimics a function func located at 0x22222. There are problems with the generated code:

  • main is using icall to execute f(), but icall will always target the low 128KiB segment. The correct instruction is eicall resp. eijmp for tail-calls.
  • The compiler uses the wrong relocations like pm_lo8(sym) and pm_hi8(sym), where the correct code will use lo8(gs(sym)) and hi8(gs(sym)); so the GNU linker will generate stubs as needed. Correct RELOCs are R_AVR_LO8_LDI_GS resp. R_AVR_HI8_LDI_GS.
  • If main was located beyond the first 128KiB segment, icall/ijmp won't work either, correct are eicall/eijmp, cf. also startup-code.

FYI, the disassembly of main is as of foo.lst is:

0000012c <main>:
 12c:	e1 e1       	ldi	r30, 0x11	; 17
 12e:	f1 e1       	ldi	r31, 0x11	; 17
 130:	09 95       	icall
 132:	08 95       	ret

so the call will target 0x2222, not 0x22222.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions