Есть такой макрос для взятия адреса, может быть Вам будет чем-то полезен.
CODE
/* GET_FAR_ADDRESS() macro
*
* This macro facilitates the obtention of a 32 bit "far" pointer (only 24 bits
* used) to data even passed the 64KB limit for the 16 bit ordinary pointer. It
* is similar to the '&' operator, with some limitations.
*
* Comments:
*
* - The overhead is minimal and it's mainly due to the 32 bit size operation.
*
* - 24 bit sizes guarantees the code compatibility for use in future devices.
*
* - hh8() is an undocumented feature but seems to give the third significant byte
* of a 32 bit data and accepts symbols, complementing the functionality of hi8()
* and lo8(). There is not an equivalent assembler function to get the high
* significant byte.
*
* - 'var' has to be resolved at linking time as an existing symbol, i.e, a simple
* type variable name, an array name (not an indexed element of the array, if the
* index is a constant the compiler does not complain but fails to get the address
* if optimization is enabled), a struct name or a struct field name, a function
* identifier, a linker defined identifier,...
*
* - The natural place for this macro should be the header avr/pgmspace.h and the
* name... pgm_get_far_address?
*
* - The returned value is the identifier's VMA (virtual memory address) determined
* by the linker and falls in the corresponding memory region. The AVR Harvard
* architecture requires non overlapping VMA areas for the multiple address spaces
* in the processor: Flash ROM, RAM, and EEPROM. Typical offset for this are
* 0x00000000, 0x00800xx0, and 0x00810000 respectively, derived from the linker
* script used and linker options. The value returned can be seen then as a
* universal pointer.
*
*/
#ifndef _FAR_ADDRESS_H_
#define _FAR_ADDRESS_H_
#define GET_FAR_ADDRESS(var) \
({ \
uint_farptr_t tmp; \
\
__asm__ __volatile__( \
\
"ldi %A0, lo8(%1)" "\n\t" \
"ldi %B0, hi8(%1)" "\n\t" \
"ldi %C0, hh8(%1)" "\n\t" \
"clr %D0" "\n\t" \
: \
"=d" (tmp) \
: \
"p" (&(var)) \
); \
tmp; \
})
#endif