I wondered how FreeBSD knows about drivers, that we include into the image. The only thing a developer does, is declare DRIVER_MODULE macro, which expands to some variables and structs, but newbus somehow have knowledge about those variables.
The solution is linker sets! It is the ability of the linker, to move variable/function to the other section. It is done by attribute “section” :
int __section("test section") variable = 666;
So, every DRIVER_MODULE macro creates a pointer to the existing driver structure with ‘sectio’ attribute, so all variables are collected in one place – and yes, we have array of pointers.
But how does the kernel know where is the beggining and the end of the section? It turns out, that linker provides __start_SECNAME and __stop_SECNAME symbols. Lets put this together, and make some code:
#include <stdio.h>
#define __section(x) __attribute__((__section__(x)))
int __section( "test_section" ) var1 = 1;
int __section( "test_section" ) var2 = 2;
int __section( "test_section" ) var3 = 3;
int __section( "test_section" ) var4 = 4;
int __section( "test_section" ) var5 = 5;
extern int __start_test_section[];
extern int __stop_test_section[];
int main(int argc, const char *argv[])
{
int *a = (int *)__start_test_section;
int b;
int size;
int count;
printf( "Start: %p\n", (void *)a );
while( 1 )
{
if( a == (int *)__stop_test_section )
break;
b = *a;
printf( "%d\n", b );
a++;
}
count = __stop_test_section - __start_test_section;
size = count * sizeof( int );
printf( "Size of section: %d;\n" "number of variables: %d\n", size, count );
return 0;
}
20:25:51 alek@alek-laptop in ~/tmp ./sec Start: 0x601020 1 2 3 4 5 Size of section: 20; number of variables: 5
Let’s see dump of the sections:
20:50:54 alek@alek-laptop in ~/tmp
readelf -S sec
There are 39 section headers, starting at offset 0x1638:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[...]
[25] test_section PROGBITS 0000000000601020 00001020
0000000000000014 0000000000000000 WA 0 0 4
[...]
We can see, that value of __start_test_section, and start of the section from readelf are the same. We can also count size and number of variables. Notice, that variables __start_test_section and __stop_test_section are declared extern (because they aren’t in the code. They will be available in the linking process) and mark as array.
We can of course, put functions in separate sections, but then, you can iterate them, because of the unknown size. It is better to use i.e. pointers to functions, which are fixed size, and interate them just like in good old arrays.