This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: Minor feature for ld
On Tue, Sep 03, 2002 at 02:07:49PM -0400, Pete Gonzalez wrote:
> At 12:03 PM 9/3/2002, you wrote:
> >> __attribute__((section("/0x123456/"))) int IOPort;
> >> IOPort = x;
> >> *(int *)0x123456 = x;
> >
> >It's easy enough to do this in C by doing
> > int* IOPort = (int*) 0x123456;
> > *IOPort = x;
> >
> >In most uses you will want volatile, as in
> > volatile int* IOPort = (int*) 0x123456;
> >
> >What's the advantage of doing it in a linker section?
>
> I'm working on an embedded system whose only input and output is
> through a large number of DMA ports. Your suggestion above would
> allocate memory to store each global variable. The obvious workaround
> is to use macros like this:
>
> #define SOME_PORT (*(int *)0x123456)
>
> This is the C approach. However, my problem is a little more complex
> because the ports are bit-fields. So I have definitions (in C++)
> like this:
>
> PORTDEF_BEGIN(0x400000C,REG_BG2CNT);
> PORTDEF_FIELD_O ( 0, 2, int, priority);
> PORTDEF_FIELD_O ( 2, 2, REG_BG::TDataPage, tileDataPage);
> PORTDEF_FIELD_O ( 6, 1, bool, enableMosaic);
> PORTDEF_FIELD_O ( 7, 1, bool, useGlobalPalette);
> PORTDEF_FIELD_O ( 8, 5, REG_BG::TMapPage, tileMapPage);
> PORTDEF_FIELD_O (13, 1, bool, areaOverflow);
> PORTDEF_FIELD_O (14, 2, REG_BG::TTileMode, tileMode);
> PORTDEF_END;
>
> void test() {
> // BG2CNT is a 16-bit register at 0x400000C
> REG_BG2CNT::priority = 3; // assigns to bits 0..1
> REG_BG2CNT::useGlobalPalette = true; // assigns to bit 7
> REG_BG2CNT::tileMode = MODE_TEXT_32x64; // assigns to bits 14..15
> }
>
> These macros are implemented using template classes and preprocessor
> hacks. They also depend on the linker to discard ("/DISCARD/")
> a lot of auxiliary allocations which exist because of an ANSI
> requirement that memory be allocated for variables with sizeof(x) = 0.
> There are more hacks so that it compiles optimally (under -O2)
> and handles volatile addresses, etc.
>
> All this complexity was worth it, because it dramatically simplifies
> the rest of the code, which previously was littered with C macros
> and error-prone bit twiddling.
>
> But then it occurred to me that the hacks could be eliminated,
> if you could just map variables onto the ports. In fact, most of
> cases could be handled with ordinary C bitfields:
>
> __attribute__((section("/0x400000C/"))) struct {
> int priority : 2;
> TDataPage tileDataPage : 2;
> bool enableMosaic : 1;
> // etc.
> } REG_BG2CNT __attribute__((packed));
>
> Well, you asked! :-)
You can still do this... you need to define types for the variables in
a header, and declare them as "extern", then define them to the right
address in a linker script. No need to use sections at all.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer