[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] Relocating Code
From: |
Theodore A. Roth |
Subject: |
Re: [avr-gcc-list] Relocating Code |
Date: |
Thu, 12 Aug 2004 08:26:43 -0700 (PDT) |
On Thu, 12 Aug 2004, Ramkumar Rengaswamy wrote:
> Hi,
> I have an application where I am interested in relocating a particular
> function to a fixed location in the program memory.
> I do this by defining the __attribute__((section(".myfunction"))) in my C
> code and passing the option -Wl,--section-start=.myfunction=0x5000
> My .text section starts at address 0 and occupies only 4000 bytes.
> The code compiles fine but when I call the relocated function with a
> pointer parameter, the AVR resets.
> Is there any reason for such a behavior ?
> In general, are there any constraints for relocating a function in the
> program memory ?
How are you calling your relocated function? Are you assigning it's
address manually or letting the compiler/linker handle it?
Are you accounting for the fact that gcc does everything in terms of
byte addresses and calling a function in your code requires a word
address? For example, you are forcing the function to be at byte address
0x5000, but it's word address is really 0x2800, which is what call/rcall
need.
Here's an example program that demostrates what I'm talking about
(tested this with a mega128):
/*****************************/
#include <avr/io.h>
void foo (unsigned char arg) __attribute__((section(".myfunction")));
void
foo (unsigned char arg)
{
PORTB |= arg; /* Turn of the LEDS. */
}
typedef void (*func_ptr) (unsigned char arg);
void
call_fp (func_ptr fp, unsigned char arg)
{
fp (arg);
}
int main (void)
{
PORTB = 0x00; /* Turn on the LEDS. */
DDRB = 0xff;
call_fp (foo, 0x0f); /* Turn off the lower 4 LEDS. */
call_fp ((func_ptr) 0x5000, 0xf0); /* Turn off the upper 4 LEDS. */
return 0;
}
/*****************************/
Here's the relevant disassembled code:
000000d2 <main>:
d2: cf ef ldi r28, 0xFF ; 255
d4: d0 e1 ldi r29, 0x10 ; 16
d6: de bf out 0x3e, r29 ; 62
d8: cd bf out 0x3d, r28 ; 61
da: 18 ba out 0x18, r1 ; 24
dc: 8f ef ldi r24, 0xFF ; 255
de: 87 bb out 0x17, r24 ; 23
e0: 6f e0 ldi r22, 0x0F ; 15
e2: 80 e0 ldi r24, 0x00 ; 0
e4: 98 e2 ldi r25, 0x28 ; 40
e6: 0e 94 65 00 call 0xca
ea: 60 ef ldi r22, 0xF0 ; 240
ec: 80 e0 ldi r24, 0x00 ; 0
ee: 90 e5 ldi r25, 0x50 ; 80
f0: 0e 94 65 00 call 0xca
f4: 80 e0 ldi r24, 0x00 ; 0
f6: 90 e0 ldi r25, 0x00 ; 0
f8: 0c 94 7e 00 jmp 0xfc
000000fc <_exit>:
fc: ff cf rjmp .-2 ; 0xfc
Disassembly of section .myfunction:
00005000 <foo>:
5000: 98 b3 in r25, 0x18 ; 24
5002: 98 2b or r25, r24
5004: 98 bb out 0x18, r25 ; 24
5006: 08 95 ret
Notice the addresses being passed via r24/r25 to the function calls:
e0: 6f e0 ldi r22, 0x0F ; 15
e2: 80 e0 ldi r24, 0x00 ; 0
e4: 98 e2 ldi r25, 0x28 ; 40
e6: 0e 94 65 00 call 0xca
The above is the one that works.
ea: 60 ef ldi r22, 0xF0 ; 240
ec: 80 e0 ldi r24, 0x00 ; 0
ee: 90 e5 ldi r25, 0x50 ; 80
f0: 0e 94 65 00 call 0xca
This second one jumps you deep into no-mans-land and the program counter
will eventually wrap around back to the reset vector (address 0x0000).
It's usually a bad idea to try to outsmart the compiler and linker. I
try to avoid it myself, but obviously, that's not always possible
(jumping into a bootloader comes to mind).
---
Ted Roth
PGP Key ID: 0x18F846E9
Jabber ID: address@hidden