1

I'm implementing a small system in C for a microcontroller. That system has multiple sensors. Inspired by Linux kernel I would like to create sensors-core module and separated sensors for each type of sensor.

When implementing a new module in kernel, there's a macro module_init. That macro takes a pointer of a structure and stores it in the predefined memory section. At the kernel start, all init functions from all modules are called, one by one, based on that memory section with function pointers.

I'm trying to do something similar with my sensors and sensor-core modules. Let's say my sensors-core module has an array of pointers. Each sensor creates its own configuration structure. I would like to write a macro which would copy pointer of such structure and place it in the array in sensors-core module - all at the compilation time.

sensors-core.h:

struct sensor_config {
    void (*init)(void) init;
    ...
};

sensors-core.c:

#include "sensors-core.h"

struct sensor_config *sensors[SENSORS_MAX_NUM];

sensor.c

#include "sensors-core.h"

void Init(void)
{
    ...
}

struct sensor_config config = {
    .init = Init
};

SENSOR_INIT(config);
  1. How can I write such macro? Is it possible? Would it be compiler specific or can I do that so it the code will be portable?
  2. Can preprocessor take care of how many times the SENSOR_INIT() macro is used and dynamically (at the compilation time) adjust sensors array size? I know that array is a waste of memory. In Linux kernel, after initialization, the memory section containing list of pointers is freed up for other use. At this moment I don't care about that, that would be next step.

I found something similar but not exactly the solution I'm looking for. Plugin system for statically linked modules in C? Here we can add attribute to a function to be called before main.

VIPPER
  • 326
  • 4
  • 24
  • 1
    do not try to replicate linux kernel on uCs. It makes no sense – 0___________ Jan 02 '22 at 21:22
  • `In Linux kernel, after initialization, the memory section containing list of pointers is freed up for other use` This is very vague. `init;` what is that trailing `init` doing there? – KamilCuk Jan 02 '22 at 21:54

1 Answers1

0

Kernel is not a uC. module_init takes a function, not a struct, and it might be a good idea to rewrite your interface for that. Kernel loads a specially prepared file and parses it and from it finds the proper function to call.

How can I write such macro?

Put a pointer to the variable inside a section.

#define CONCAT(a, b)  a##b
#define XCONCAT(a, b) CONCAT(a, b)
#define SENSOR_INIT(x) \
__attribute__((__section__("sensors"))) \
__attribute__((__used__)) \
const struct sensor_config *const CONCAT(sensor, __LINE__) = &x;

Then How do you get the start and end addresses of a custom ELF section? iterate over pointers in the section and call.

The elements seem to be constant, you could be just storing the elemenst in the section.

#define SENSOR_SECTION \
__attribute__((__section__("sensors"))) \
__attribute__((__used__))

SENSOR_SECTION
struct sensor_config config = { stuff; }

Would it be compiler specific

Very yes.

or can I do that so it the code will be portable?

No.

You can use an external utility as part of the build process to generate the array initialization. For example, do #define SENSOR_INIT(x) /*nothing*/ and then traverse all source files with an external program (awk, Perl, Python) to find all SENSOR_INIT(config); statements, and from that generate sensors-core.c files that has references to all structures from all files.

Can preprocessor take care of how many times the SENSOR_INIT() macro is used and dynamically (at the compilation time) adjust sensors array size?

No.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • I found something similar in the kernel codebase and wonder how it changes location (pointer) for the next &x pointer in the .sensors section while executing subsequent SENSOR_INIT() macros? Regarding your previous comment, I think this is clean and readable way to init submodule of your firmware, I'm not trying to replicate kernel on MCUs :) – VIPPER Jan 03 '22 at 08:29
  • `how it changes location` Linker puts all data in one section from all object files together inside the section in the resulting output file. Just like linker puts all static objects inside one section, all function code inside one section, etc. from all object files. – KamilCuk Jan 03 '22 at 08:33
  • Thanks for answering the question. I tried that, in general everything works as expected but __stop__section contains some strange value, like 0x7fff9d48. I wonder if any additional option needs to be passed to the linker to get it working? – VIPPER Jan 08 '22 at 21:36
  • `__stop__section contains some strange value` It should? There is no element at `__stop_section`, it represents a "past-the-end" address. There is a next section or something else there. I even linked another question - it does `for ( ; iter < &__stop_my_custom_section` not `for ( ; iter <= &__stop_my_custom_section` – KamilCuk Jan 09 '22 at 09:22
  • I would expect __stop_section to contain the last address of section or the next one after the section (whihc would point to the start of the next section). – VIPPER Jan 09 '22 at 12:28