I have this POC in C that saves a few structs in a custom section and then iterates over those structs, showing their content.
#include <stdio.h>
char a, b, c;
struct counter_info {
int counter;
char *name;
} __attribute__((packed));
#define __PUT_STUFF_IN_SECTION(_name) \
do{ \
static struct counter_info __counter_info_##_name \
__attribute((__section__("counters"))) \
__attribute((__used__)) = { \
.name = #_name, \
.counter = 0, \
}; \
}while(0)
extern struct counter_info __start_counters;
extern struct counter_info __stop_counters;
int main(int argc, char **argv){
printf("Start %p\n", &__start_counters);
__PUT_STUFF_IN_SECTION(a);
__PUT_STUFF_IN_SECTION(b);
__PUT_STUFF_IN_SECTION(c);
struct counter_info *iter = &__start_counters;
for(; iter < &__stop_counters; ++iter){
printf("Name: %s | Counter: %d.\n", iter->name, iter->counter);
}
printf("End %p\n", &__stop_counters);
return 0;
}
Output:
Name: c | Counter: 0.
Name: b | Counter: 0.
Name: a | Counter: 0.
The output is as expected, so I'm trying to do that same thing in a kernel module:
hello-1.c
#include <linux/module.h>
#include <linux/kernel.h>
char a, b, c;
struct counter_info {
int counter;
char *name;
} __attribute__((packed));
#define __PUT_STUFF_IN_SECTION(_name) \
do{ \
static struct counter_info __counter_info_##_name \
__attribute((__section__("counters"))) \
__attribute((__used__)) = { \
.name = #_name, \
.counter = 0, \
}; \
}while(0)
extern struct counter_info __start_counters;
extern struct counter_info __stop_counters;
int init_module(void){
__PUT_STUFF_IN_SECTION(a);
__PUT_STUFF_IN_SECTION(b);
__PUT_STUFF_IN_SECTION(c);
return 0;
}
void cleanup_module(void){
struct counter_info *iter = &__start_counters;
for(; iter < &__stop_counters; ++iter){
printk(KERN_INFO "Name: %s | Counter: %d.\n", iter->name, iter->counter);
}
}
Makefile:
obj-m += hello-1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
But I get those warnings when I compile the module:
WARNING: "__stop_counters" [/media/sf_procmon/procmon_kmodule/test/hello-1.ko] undefined!
WARNING: "__start_counters" [/media/sf_procmon/procmon_kmodule/test/hello-1.ko] undefined!
My question is: Why isn't working and how am I supposed to use the section attribute inside a LKM?
EDIT:
I saw this answer Initialize global array of function pointers at either compile-time, or run-time before main() and I tried doing the same:
Makefile
ccflags-y := -Wl,-Tlinkerscript.ld
obj-m += hello-1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
linkerscript.ld
SECTIONS
{
.rel.rodata.counters : {
PROVIDE(start_counters = .);
*(counters)
PROVIDE(stop_counters = .);
}
}
INSERT AFTER .text;
but I keep getting the same warnings. I'm not sure if I did something wrong with the linker script or that's just not the solution for my problem.
EDIT:
I'm editing my question so hopefully somebody can give me a workaround. At compile time a few structs are declared and filled with data. Each struct is declared in a block so I can't access them by name and I cant' declare them outside. I also don't know the exact number of structs as it can change from compile to compile. What I need is a way to access them all (iterate over them). I actually don't care if the structs are going to be saved in a section or with some other magic, as far as I can iterate over them.
This works for me:
Makefile
obj-m := example.o
example-y += hello.o
ldflags-y += -T$(M)/layout.lds
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
layout.lds
SECTIONS
{
.counters : {
__start_counters = . ;
*(.counters)
__stop_counters = . ;
}
}
hello.c
#include <linux/module.h>
#include <linux/kernel.h>
char a, b, c;
asm (".section .counters, \"aw\"");
typedef struct {
int counter;
char *name;
} __attribute__((packed)) counter_info_t;
#define __PUT_STUFF_IN_SECTION(_name) \
do{ \
static counter_info_t __counter_info_##_name \
__attribute((unused,section(".counters"))) = { \
.name = #_name, \
.counter = 0, \
}; \
}while(0)
extern counter_info_t __start_counters[];
extern counter_info_t __stop_counters[];
int init_module(void){
__PUT_STUFF_IN_SECTION(a);
__PUT_STUFF_IN_SECTION(b);
__PUT_STUFF_IN_SECTION(c);
return 0;
}
void cleanup_module(void){
counter_info_t *iter = __start_counters;
for(; iter < __stop_counters; ++iter){
printk(KERN_INFO "Name: %s | Counter: %d.\n", iter->name, iter->counter);
}
}
The point is to use ldflags-y
variable.
To solve the need to capture structs defined in different blocks of code where their number can vary and the references to them cannot be centralized, two ideas come to mind. First, which will be described below, is to use a registration method, and second is to have the build process scan the sources for these structs to collect their information in order to create a new source file with the necessary references.
Registration Method
For example:
struct reg_list_node
{
struct counter_info *counter;
struct reg_list_node *next
};
void register_counter (counter_info *new_counter)
{
// intentionally leaving out detail; allocate the new node and insert into the list
}
#define REGISTER_COUNTER(counter) register_counter(&counter)
Then, when counters are registered:
struct counter_info my_counter;
REGISTER_COUNTER(my_counter);
Oh, and this gets rid of the need for dynamic allocation (please watch the syntax of the macro - it may need tweeking):
struct reg_list_node
{
struct counter_info *counter;
struct reg_list_node *next
} head;
void register_counter (reg_list_node *new_node)
{
new_node->next = head;
head = new_node;
}
#define REGISTER_COUNTER(cntr) { static struct reg_list_node counter_node; counter_node.counter = & cntr; register_counter(&counter_node); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With