Minor feature for ld

Pete Gonzalez pgonzalez@bluel.com
Tue Sep 3 11:08:00 GMT 2002


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!  :-)

-Pete



More information about the Binutils mailing list