This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c/88391] New: Request - attribute for adding tags to functions


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88391

            Bug ID: 88391
           Summary: Request - attribute for adding tags to functions
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: david at westcontrol dot com
  Target Milestone: ---

Sometimes it would be very useful to have "tags" on functions, which can be
used to restrict the kinds of functions that can call them or be called by
them.  I can think of two use-cases from the embedded world, and one more
general case:

1. A function that can only be called when interrupts are disabled, has special
powers (such as direct access to locked or atomic data, at least on single-core
systems) and special responsibilities (it should be fast, should not block,
etc.).  It should only be called by a function that disables interrupts.

2. A function that needs to run from ram should not call other functions that
are not also in ram.  This might be for programming code flash, or perhaps to
minimise speed variation in a real-time system with slow external flash.

3. A function that should only be called when you have a certain lock or
resource.

There are many other uses possible uses.  I think that a few general attributes
could allow this to be handled in the C (and C++) front-end, with the compiler
issuing warnings or errors when the "tag" rules are broken.  It would not
affect code generation, name mangling, etc. - it's just a mechanism to help
spot incorrect code.  I am not suggesting that we have attributes that actually
disable interrupts, or place code in ram (though these might be nice!) - all
embedded targets already have mechanisms for that, such as "section"
attributes, and we don't need to duplicate functionality that can be handled by
a macro or two.


My suggestions for function attributes are:

1. __attribute__((tagged("tagname")))

Mark a function as being tagged with "tagname" (or multiple tag names).

2. __attribute__((caller_tag("tagname")))

Mark a function as only being callable by a function with this tag.

3. __attribute__((callee_tag("tagname")))

Mark a function as only being allowed to call functions with this tag.

4. __attribute__((caller_notag("tagname")))

Mark a function as not being callable by a function with this tag.

5. __attribute__((callee_notag("tagname")))

Mark a function as not being allowed to call functions with this tag.


There would also need to be a statement attribute:

__attribute__((tag("tagname")))

Mark the statement as having this tag (and therefore being allowed to call
matching "caller_tag" functions, and not allowed to call matching
"caller_notag" functions).



Example 1
=========

__attribute__((caller_tag("irq_disabled"), tagged("irq_disabled")))
void criticalFunction(void)
{
   // Some code that should never be interrupted
}

void normalFunction(void) {
   // Normal code
   disableInterrupts();
   __attribute__((tag("irq_disabled"))) criticalFunction();
   enableInterrupts();
}


Example 2
=========

__attribute__((tagged("in_ram")), callee_tag("in_ram")))
__attribute__((section("ramcode")))
void flashCommand(uint32_t cmd)
{
   // Write command to flash programming peripheral
}

__attribute__((tagged("in_ram")), callee_tag("in_ram")))
__attribute__((section("ramcode")))
void flashErase(void)
{
   flashCommand(0x12345678);
}

void updateSoftware(void) {
    downloadNewImage();
    flashErase();
    flashProgram();
}


Example 3
=========

__attribute__((caller_notag("got_lock")))
void getLock(void)
{
    mtx_lock(&mutex);
}

__attribute__((caller_tag("got_lock")))
void releaseLock(void)
{
    mtx_unlock(&mutex);
}

__attribute__((caller_tag("got_lock"), tagged("got_lock")))
void accessData(void)
{
    // Use critical data
}

void normalCode(void)
{
    // Collect data
    getLock();
    __attribute__((tag("got_lock")) {
        accessData();
        releaseLock();  // Still tag "got_lock"
    }
}



One big question is the compiler target library.  In small embedded systems,
apparently simple operations like "x = y / z;" may result in a library call if
the processor does not have hardware instructions for the operation.  It is
important in "callee_tag" functions that any such library calls also issue a
warning.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]