14

I am writing a bootloader in C11. When the bootloader needs to transfer the control to the firmware, it reads a function pointer at a predefined memory address and calls it. The code looks like this:

typedef void (FirmwareBootFn)(void);

typedef struct
{
    uint32_t stackPointer;
    FirmwareBootFn* programCounter;
}
FirmwareBootControl;

static FirmwareBootControl g_bootControl __attribute__ ((section (".boot_control")));

void
Firmware_boot( void )
{
    setStackPointer( g_bootControl.stackPointer );
    g_bootControl.programCounter();
}

Function Firmware_boot() never returns, so it made sense to declare it as noreturn:

#include <stdnoreturn.h>

noreturn void
Firmware_boot( void );

But I need to declare FirmwareBootFn as noreturn as well to avoid the compiler complaining that Firmware_boot() may return.

I tried (possibly) every permutation of the noreturn in the typedef without any result. Also I understood that the attribute can't be set in the typedef because it is not part of the type.

Is there a way to tag my Firmware_boot() as noreturn avoiding the warning (well without cheating with warning suppression :-))?

Morwenn
  • 21,684
  • 12
  • 93
  • 152
MaxP
  • 2,664
  • 2
  • 15
  • 16
  • I just found a workaround for gcc: using **__builtin_unreachable**() marks a specific point of code as "this line will never be executed" thus granting the noreturn property. Despite this works, it is not portable and do not allow the compiler to understand that (at least IMO) g_bootControl.programCounter() doesn't return and to apply proper optimization. – MaxP Feb 26 '15 at 09:49
  • 1
    @MaxP, both the documentation and the assembler output of a small test program seem to indicate it is used for optimization. (If `foo` is declared `_Noreturn` and `bar` isn't, `foo();` and `bar(); __builtin_unreachable();` generate equivalent code.) – mafso Feb 26 '15 at 10:28
  • If you are willing to use an extension, use an `attribute`. Please see my answer. – Jens Gustedt Feb 26 '15 at 12:01

1 Answers1

11

_Noreturn in C11 can only be applied to function definitions or declarations. The fact that the function doesn't return is not part of the prototype, unfortunately.

Since you seem to have gcc you could use an extension

typedef struct
{
    uint32_t stackPointer;
    __attribute__((__noreturn__)) FirmwareBootFn* programCounter;
}
FirmwareBootControl;

to mark the function pointer as not returning. Unfortunately though, there doesn't seem to be a way to ensure that the function that you assign to that really has that property by syntax, allone.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Meaning that in C11 if a "noreturn" function ends itself by calling a function via a pointer, you cannot call the function "noreturn". Clever. – Bruce K Aug 09 '18 at 15:50
  • @BruceK, I don't know what you are implying with your "Clever", but changes to the C standard are usually difficult compromises between the new semantic and the imperative to be backwards compatible. In particular, `_Noreturn` was meant as a property that could be attached to existing functions such as `exit` by remaining binary compatible between new libraries and old executables. That is not a simple task. – Jens Gustedt Aug 09 '18 at 19:49
  • I understand the constraints. The committee has GCC folks contributing and GCC seems to have no trouble with applying the meaning of _Noreturn to a function pointer. It is not rocket science. Programmers are creative people. Either _Noreturn could have been deemed an attribute attributable to function pointers, or some other syntax could have been invented, a la that of GCC, for example. WRT assigning a function that returns to such a pointer, well, no linguistic design will prevent bugs. The attribute is an optimization hint that can go awry. – Bruce K Aug 11 '18 at 15:07
  • @BruceK, I think you are completely mistaken in your ideas of how the committee works and where the difficulties are when you want to change standards incrementally. When I was speaking of a difficult task, I meant the standardization of such a feature that doesn't invalidate existing C libraries. Bashing on your favorite enemy among compiler implementors without actually knowing what is going on, or who even made which argument or proposal in a discussion that took place about 10 years is just shameful. – Jens Gustedt Aug 12 '18 at 09:43