public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Mangle functions
@ 2008-01-28 10:22 Ron Kreymborg
  2008-01-28 17:22 ` Daniel Lohmann
  2008-01-28 18:12 ` Brian Dessent
  0 siblings, 2 replies; 7+ messages in thread
From: Ron Kreymborg @ 2008-01-28 10:22 UTC (permalink / raw)
  To: gcc-help

Is there a way the C++ pre-processor can access the mangled name of a class
method? This would greatly simplify implementing interrupt handlers as
private class methods in embedded systems where the processor uses an
interrupt vector table. Currently one must manually build the mangled name
and pass it to the gcc "alias" attribute. 

My idea is a macro like:

#define CLASS_ISR(theclassname, themethodname) \
 ISR(theclassname) ISR_ALIASOF(gcc_mangle(theclassname, themethodname)); \
 void theclassname::themethodname(void)

where the "gcc_mangle" function is what I am after.  If this existed it
would allow automating the creation of classes for embedded systems where
the interrupt handler is a private class method and its "friend" status
allows it access to the class data of the owning device manager class. The
abbreviated example class definitions below show the timer overflow
interrupt handler for the Timer0 peripheral of an Atmel AVR microprocessor:

//-------------------------------------------
class CTimer0Interrupt
{
public:
    CTimer0Interrupt();
    ~CTimer0Interrupt();
private:
    // Overflow interrupt handler.
    void TIMER0_OVF_vect(void) __attribute__ ((signal, __INTR_ATTRS));
};

//-------------------------------------------
class CTimer0
{
    friend class CTimer0Interrupt;
public:
    CTimer0();
    ~CTimer0();
    int GetTimer0Flag(void);     // true if overflow occurred
private:
    void SetOverflowFlag(void);  // called from int handler
private:
    volatile bool       mTimer0Flag;
    CTimer0Interrupt    mTimer0Interrupt;
};

And in the cpp class implementation file, the method is:

//---------------------------------------------------------------
// Timer0 overflow interrupt handler.
//
CLASS_ISR(CTimer0Interrupt, TIMER0_OVF_vect)
{
    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
    Timer0.SetOverflowFlag();   // tell our friend
}

Inserting the mangled name by hand in the macro above produces the vector
alias that allows gcc to link the external C vector name while the C++ code
remains unaware of its existence outside the owning class:

extern "C" void __vector_16 (void) __attribute__ ((signal,used,
externally_visible)) ; 
void __vector_16 (void)
__attribute__((alias("_ZN16CTimer0Interrupt11__vector_16Ev"))); 
void CTimer0Interrupt::__vector_16(void)
{
    (*(volatile uint8_t *)((0x32) + 0x20)) = 100;
    Timer0.SetOverflowFlag();
}

Ron Kreymborg




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Mangle functions
  2008-01-28 10:22 Mangle functions Ron Kreymborg
@ 2008-01-28 17:22 ` Daniel Lohmann
  2008-01-28 19:23   ` Andrew Haley
  2008-01-28 18:12 ` Brian Dessent
  1 sibling, 1 reply; 7+ messages in thread
From: Daniel Lohmann @ 2008-01-28 17:22 UTC (permalink / raw)
  To: Ron Kreymborg; +Cc: gcc-help


On 26.01.2008, at 23:15, Ron Kreymborg wrote:

> Is there a way the C++ pre-processor can access the mangled name of  
> a class
> method? This would greatly simplify implementing interrupt handlers as
> private class methods in embedded systems where the processor uses an
> interrupt vector table. Currently one must manually build the  
> mangled name
> and pass it to the gcc "alias" attribute.
>
> My idea is a macro like:
>
> #define CLASS_ISR(theclassname, themethodname) \
> ISR(theclassname) ISR_ALIASOF(gcc_mangle(theclassname,  
> themethodname)); \
> void theclassname::themethodname(void)
>
> where the "gcc_mangle" function is what I am after.  If this existed  
> it
> would allow automating the creation of classes for embedded systems  
> where
> the interrupt handler is a private class method and its "friend"  
> status
> allows it access to the class data of the owning device manager  
> class. The
> abbreviated example class definitions below show the timer overflow
> interrupt handler for the Timer0 peripheral of an Atmel AVR  
> microprocessor:

Hi Ron,

I was looking (and asked for it on this list) for something like that  
as well. Apparently, it does not exist. Even not as an extra  
(external) pre-processor.

A pragmatic solution is to go the other way round. That is, to give  
your C++ identifiers that ought to be interrupt handlers (or otherwise  
involved in interacting with non-C++ code) explicit symbol names that  
are not mangled. This is possible by an g++ extension that allows you  
to explicitly specify the linker name of a symbol via an asm-directive  
in its declaration:

 >>>
lohmann@mocca:~/tmp$ cat test.cpp
class Foo {
   static void IrqHandler() asm("MyFancyIrqHandler");
};

void Foo::IrqHandler() {
}
lohmann@mocca:~/tmp$ g++ -c test.cpp
lohmann@mocca:~/tmp$ nm test.o
00000000 T MyFancyIrqHandler
00000000 A _*MyFancyIrqHandler.eh
<<<

As you can see, the method is exported with the name  
"MyFancyIrqHandler" instead of the mangled name  
"__ZN3Foo10IrqHandlerEv".

BTW: In your example you used a non-static method. You probably know  
that you have to make sure that the this-pointer is passed accordingly  
in this case. I just mention it because it is a common cause of subtle  
errors in C++/Assembly interaction.

Daniel


> //-------------------------------------------
> class CTimer0Interrupt
> {
> public:
>    CTimer0Interrupt();
>    ~CTimer0Interrupt();
> private:
>    // Overflow interrupt handler.
>    void TIMER0_OVF_vect(void) __attribute__ ((signal, __INTR_ATTRS));
> };
>
> //-------------------------------------------
> class CTimer0
> {
>    friend class CTimer0Interrupt;
> public:
>    CTimer0();
>    ~CTimer0();
>    int GetTimer0Flag(void);     // true if overflow occurred
> private:
>    void SetOverflowFlag(void);  // called from int handler
> private:
>    volatile bool       mTimer0Flag;
>    CTimer0Interrupt    mTimer0Interrupt;
> };
>
> And in the cpp class implementation file, the method is:
>
> //---------------------------------------------------------------
> // Timer0 overflow interrupt handler.
> //
> CLASS_ISR(CTimer0Interrupt, TIMER0_OVF_vect)
> {
>    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
>    Timer0.SetOverflowFlag();   // tell our friend
> }
>
> Inserting the mangled name by hand in the macro above produces the  
> vector
> alias that allows gcc to link the external C vector name while the C+ 
> + code
> remains unaware of its existence outside the owning class:
>
> extern "C" void __vector_16 (void) __attribute__ ((signal,used,
> externally_visible)) ;
> void __vector_16 (void)
> __attribute__((alias("_ZN16CTimer0Interrupt11__vector_16Ev")));
> void CTimer0Interrupt::__vector_16(void)
> {
>    (*(volatile uint8_t *)((0x32) + 0x20)) = 100;
>    Timer0.SetOverflowFlag();
> }
>
> Ron Kreymborg
>
>
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Mangle functions
  2008-01-28 10:22 Mangle functions Ron Kreymborg
  2008-01-28 17:22 ` Daniel Lohmann
@ 2008-01-28 18:12 ` Brian Dessent
  1 sibling, 0 replies; 7+ messages in thread
From: Brian Dessent @ 2008-01-28 18:12 UTC (permalink / raw)
  To: Ron Kreymborg; +Cc: gcc-help

Ron Kreymborg wrote:

> My idea is a macro like:
> 
> #define CLASS_ISR(theclassname, themethodname) \
>  ISR(theclassname) ISR_ALIASOF(gcc_mangle(theclassname, themethodname)); \
>  void theclassname::themethodname(void)

As written this is impossible, since the mangling includes the number
and types of arguments.

> Inserting the mangled name by hand in the macro above produces the vector
> alias that allows gcc to link the external C vector name while the C++ code
> remains unaware of its existence outside the owning class:

I can invision a way to automate this, assuming you have a full featured
build environment (i.e. unix toolset.) First define gcc_mangle a macro
that simply expands to a unique identifier name.  For example

#define gcc_mangle(class, method, arg) \
    MANGLED_NAME_##class##_##method##_##arg

This works only for the case of one arg, if you want to support
arbitrary number of args you might have to get creative with the
macros.  It would also break if one of the args was a type like
std::string since that would be an invalid identifier.

Anyway the idea is that you then have an auto-generated header that will
fill in these definitions, e.g. for the above it would have generated:

#define MANGLED_NAME_CTimer0Interrupt___vector_16_void
"_ZN16CTimer0Interrupt11__vector_16Ev"

This header is generated by the build system, via a script that greps
all the source files for occurances of gcc_mangle and adds an entry to
the header for each one.  To get the actual contents of the mangled
string, you can use gcc itself:

$ cat >showmangling.sh <<EOF
#!/bin/sh

echo "struct $1 { void $2 ( $3 ); }; void $1::$2 ( $3 ) { };" \
   | gcc -x c++ -S - -o - \
   | awk '/^.globl/ { print $2; exit }'
EOF

$ ./showmangling.sh CTimer0Interrupt __vector_16 void
_ZN16CTimer0Interrupt11__vector_16Ev

So to sum up: your build system would need:

- a script that scans through a given set of source files for occurances
of gcc_mangle, and runs the above showmangling.sh (or equivalent) with
the macro's args, and appends the results in the form of a #define to
the generated header.
- makefile rules to ensure that the header depends on all source files
that include it, as well as a rule to regenerate the header.
- developers that can remember to always include the autogenerated
header in any file that uses the gcc_mangle (or whatever you call it)
macro.

This is not exactly pretty, but it at least allows you to handle this
automatically.

Brian

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Mangle functions
  2008-01-28 17:22 ` Daniel Lohmann
@ 2008-01-28 19:23   ` Andrew Haley
  2008-01-28 19:25     ` Ron Kreymborg
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Haley @ 2008-01-28 19:23 UTC (permalink / raw)
  To: Daniel Lohmann; +Cc: Ron Kreymborg, gcc-help

Daniel Lohmann wrote:
> 
> On 26.01.2008, at 23:15, Ron Kreymborg wrote:
> 
>> Is there a way the C++ pre-processor can access the mangled name of a 
>> class
>> method? This would greatly simplify implementing interrupt handlers as
>> private class methods in embedded systems where the processor uses an
>> interrupt vector table. Currently one must manually build the mangled 
>> name
>> and pass it to the gcc "alias" attribute.

Why not simply give the handlers C linkage?  That's a much cleaner and simpler
solution, and it's what everyone else does AFAIAA.

Andrew.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: Mangle functions
  2008-01-28 19:23   ` Andrew Haley
@ 2008-01-28 19:25     ` Ron Kreymborg
  2008-01-29  0:54       ` Daniel Lohmann
  0 siblings, 1 reply; 7+ messages in thread
From: Ron Kreymborg @ 2008-01-28 19:25 UTC (permalink / raw)
  To: 'Andrew Haley', 'Daniel Lohmann',
	'Brian Dessent'
  Cc: gcc-help

> Why not simply give the handlers C linkage?  That's a much cleaner and
> simpler
> solution, and it's what everyone else does AFAIAA.

That's the easy way and also the way I have done it in the past:

ISR(TIMER0_OVF_vect)
{
    Timer0.TimerOverflow();
}

The ISR macro gives the vector "C" status so the linker can find the
vectors, and the TimerOverflow method is public. But for just those reasons
it is not the way it should work in C++. 

The interrupt handler should not be public. Nothing outside the driver class
needs to or should know anything about interrupt handlers. The language
should provide for entities like interrupt handlers.

>> #define CLASS_ISR(theclassname, themethodname) \
>>  ISR(theclassname) ISR_ALIASOF(gcc_mangle(theclassname, 
>> themethodname)); \  void theclassname::themethodname(void)
>
> As written this is impossible, since the mangling includes the number 
> and types of arguments.

Interrupt routines never have parameters.

> BTW: In your example you used a non-static method. You probably know 
> that you have to make sure that the this-pointer is passed accordingly 
> in this case. 

The interrupt class does not need a this pointer as it neither calls other
methods in its class or accesses any private class data, so the interrupt
method itself can correctly be non-static. Here is a barely useful example:

//--------------------------------
class CTimer0Interrupt
{
public:
    CTimer0Interrupt();
    ~CTimer0Interrupt();

private:
    void TIMER0_OVF_vect(void) __attribute__ ((signal, __INTR_ATTRS)); 
};

//--------------------------------
class CTimer0
{
    friend class CTimer0Interrupt;
public:
    CTimer0();
    ~CTimer0();
    bool GetOverflowFlag(void);

private:
    void SetOverflowFlag(void);

private:
    volatile bool       mOverflowFlag;
    CTimer0Interrupt    mTimer0Interrupt;
};

and the actual interrupt in the instance of CTimer0Interrupt using the macro
above would be:

//---------------------------------------------------
CLASS_ISR(CTimer0Interrupt, TIMER0_OVF_vect) 
{
    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
    Timer0.SetOverflowFlag();   // tell our friend
}

Because it is a friend of the peripheral driver class, it can call methods
in the driver class and thus cause consequences in that driver class. By
itself it need only manage the various registers, etc concerned with
configuring, managing, and releasing the interrupt hardware concerned, none
of which require a this.

> - a script that scans through a given set of source files for occurrences 
> of gcc_mangle, and runs the above showmangling.sh (or equivalent) with 
> the macro's args, and appends the results in the form of a #define to 
> the generated header.

Yes, I am starting to think a pre- preprocessor is the only way. However, as
I mentioned, in the version of gcc I am using (avr-gcc) interrupt functions
are always mangled exactly the same way. The only unknowns are the number of
characters in the class and interrupt vector names. The former could be done
manually I suppose but the latter typically looks like __vector_1 or
__vector_13, and different processors have different numbers of interrupting
peripherals so the 9/10 boundary is not that easy. If I keep my macro:

CLASS_ISR(theclassname, theinterruptname)
{

the preprocessor can look for this, look up the interrupt vector reference,
compute the two lengths, and then build the correct statements for gcc as it
re-writes the file. Something like:

extern "C" void __vector_16(void)
__attribute__((alias("_ZN16CTimer0Interrupt11__vector_16Ev")));
void CTimer0Interrupt::__vector_16(void)
{

Note that this declares the interrupt vector public and "C" for the linker,
but not the class method - the latter is invisible within the C++
application. For versatility I could provide the mangle description as a
command parameter, something like:
    -m _ZN%d%s%d%sEv

Seems a lot of work for something the language should provide, and it
depends on mangling always being done the same way, but I'll give it a go. 

I would be interested in any further comments.

Ron Kreymborg








E-mail message checked by Spyware Doctor (5.5.0.178)
Database version: 5.09080
http://www.pctools.com/spyware-doctor/

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Mangle functions
  2008-01-28 19:25     ` Ron Kreymborg
@ 2008-01-29  0:54       ` Daniel Lohmann
       [not found]         ` <000301c86303$3be6eae0$b3b4c0a0$@com.au>
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Lohmann @ 2008-01-29  0:54 UTC (permalink / raw)
  To: Ron Kreymborg; +Cc: gcc-help


On 28.01.2008, at 13:11, Ron Kreymborg wrote:
>> BTW: In your example you used a non-static method. You probably know
>> that you have to make sure that the this-pointer is passed  
>> accordingly
>> in this case.
>
> The interrupt class does not need a this pointer as it neither calls  
> other
> methods in its class or accesses any private class data, so the  
> interrupt
> method itself can correctly be non-static.

Well, "correctly" is a bit strong here. In fact, the behaviour is  
undefined and it is just a case of luck (read: compiler-specifica)  
that it works.  Whereas depending on compiler-specifica is acceptable  
for programming on this level, it is just not necessary in your case.

So why do you not just make it a class function (static) instead of a  
member function? They can be private as well, friends as well, their  
calling semantics is defined, and the *compiler* would make sure that  
you do not (accidentally) access any member elements. No  
disadvantages, but more safety.

Moreover, class functions can be given "C" linkage. Andrew is right  
with his comments that this would be the cleaner solution. The asm- 
Statement solution is, however, a suitable alternative if you want to  
encode the class name into the symbol name for scoping purposes, which  
becomes necessary if the IRQ handler methods should always have the  
same name in different driver classes.

Daniel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Mangle functions
       [not found]         ` <000301c86303$3be6eae0$b3b4c0a0$@com.au>
@ 2008-01-31 17:51           ` Daniel Lohmann
  0 siblings, 0 replies; 7+ messages in thread
From: Daniel Lohmann @ 2008-01-31 17:51 UTC (permalink / raw)
  To: Ron Kreymborg; +Cc: gcc-help


On 30.01.2008, at 06:44, Ron Kreymborg wrote:

>>> The interrupt class does not need a this pointer as it neither calls
>>> other
>>> methods in its class or accesses any private class data, so the
>>> interrupt
>>> method itself can correctly be non-static.
>>
>> Well, "correctly" is a bit strong here. In fact, the behaviour is
>> undefined and it is just a case of luck (read: compiler-specifica)
>> that it works.  Whereas depending on compiler-specifica is acceptable
>> for programming on this level, it is just not necessary in your case.
>
> By "correctly" I meant it works fine this way, not that it was the  
> only way.
> Not sure what you mean about undefined. What is undefined?
>>
>> So why do you not just make it a class function (static) instead of a
>> member function? They can be private as well, friends as well, their
>> calling semantics is defined, and the *compiler* would make sure that
>> you do not (accidentally) access any member elements. No
>> disadvantages, but more safety.
>
> Good point. My interrupt classes never have local data, so the  
> possibility
> never came up. But for more general use I agree, "static" is the  
> safer way
> to go.

Undefined means that this situation is not specified by the standard.  
The compiler is free to assume that this points to a valid instance  
and to do what it wants with it.  So if you ever switch to another  
compiler or the gcc folks decide for whatever reason to do something  
fancy in methods, you are lost. This is not very likely, but  
nevertheless an avoidable risk. For principle reasons such risks  
should be avoided.

>
>> Moreover, class functions can be given "C" linkage. Andrew is right
>>

> Yes, this is almost working. In the avr-gcc case, a plethora of  
> processors
> have much the same peripherals and the compiler managers have rightly
> standardized on common names for common peripherals, with the  
> translation to
> the correct vector done via processor specific macros. My last  
> problem looks
> like it should be easy but I have run out of ideas. It is in the  
> method
> declaration. For example:
>
> static void MyOverflowInterrupt(void) asm(TIMER0_OVF_vect)
>                 __attribute__ ((signal, __INTR_ATTRS));
>
> Somewhere in the device header for a particular processor is the line:
>
> #define TIMER0_OVF_vect      _VECTOR(16)
>
> And elsewhere is defined:
>
> #define _VECTOR(N)  __vector_ ## N
>
> So the definition becomes the almost correct:
>
> static void MyOverflowInterrupt(void) asm(__vector_16)
>                 __attribute__ ((signal, __INTR_ATTRS));
>
> How do I get it to be:
>
> static void MyOverflowInterrupt(void) asm("__vector_16")
>                 __attribute__ ((signal, __INTR_ATTRS));

Oh, this one is actually easy :-)

You just need another macro-indirection that uses the "stringify"  
operator (#) of the pre-processor:

 >>>>
lohmann@mocca:~/tmp$ cat test.cpp
#define TIMER0_OVF_vect      _VECTOR(16)
#define _VECTOR(N)  __vector_ ## N

#define IRQ_VECTOR(vec) asm(#vec) __attribute__ ((signal, __INTR_ATTRS))

class Timer0 {
   static void MyOverflowInterrupt(void) IRQ_VECTOR(TIMER0_OVF_vect);
};
<<<<

After pre-processing this becomes:

 >>>>
lohmann@mocca:~/tmp$ g++ -E test.cpp

class Timer0 {
   static void MyOverflowInterrupt(void) asm("TIMER0_OVF_vect")  
__attribute__ ((signal, __INTR_ATTRS));
};
<<<<

Daniel

P.S. Answers to to the list, please. Other readers might  be  
interested and contribute as well.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-01-30  7:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-01-28 10:22 Mangle functions Ron Kreymborg
2008-01-28 17:22 ` Daniel Lohmann
2008-01-28 19:23   ` Andrew Haley
2008-01-28 19:25     ` Ron Kreymborg
2008-01-29  0:54       ` Daniel Lohmann
     [not found]         ` <000301c86303$3be6eae0$b3b4c0a0$@com.au>
2008-01-31 17:51           ` Daniel Lohmann
2008-01-28 18:12 ` Brian Dessent

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).