"linker sets" on hybrid clang Windows driver - c

OK so very special situation here, so it is somewhat gross and the answer is probably no.
Compiling a project with clang (as it is Unix source) into .libs, but linking with MSVC++ for "/driver" to make the kernel component.
Looking for a way to handle Linux MODULE_PARAM() where they can define static int tunable; and have it be changeable for the kernel. Probably to be made into Registry entries, that seems to be how Windows would do the equivalent of sysctl, or kstat, or /proc
This could easily be handled by a "linker set", using SET_ENTRY(tunable) and then SET_FOREACH() to loop through them all.
Having some issues to get them to work, I suspect because of linking with MSVC++, so I might not be able to make it work. But maybe you guys can think of a way around.
Using:
#define __MAKE_SET_CONST const
#define __STRING(x) #x /* stringify without expanding x */
#define __XSTRING(x) __STRING(x) /* expand x, then stringify */
#define __GLOBL(sym) __asm__(".globl " __XSTRING(sym))
#define __WEAK(sym) __asm__(".weak " __XSTRING(sym))
#define __CONCAT1(x, y) x ## y
#define __CONCAT(x, y) __CONCAT1(x, y)
#define __used __attribute__((__used__))
#define __section(x) __attribute__((__section__(x)))
#define __nosanitizeaddress __attribute__((no_sanitize("address")))
#define __weak_symbol __attribute__((__weak__))
#define __MAKE_SET_QV(set, sym, qv) \
__WEAK(__CONCAT(__start_set_,set)); \
__WEAK(__CONCAT(__stop_set_,set)); \
static void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
__nosanitizeaddress \
__used = &(sym)
#define __MAKE_SET(set, sym) __MAKE_SET_QV(set, sym, __MAKE_SET_CONST)
#define TEXT_SET(set, sym) __MAKE_SET(set, sym)
#define DATA_SET(set, sym) __MAKE_SET(set, sym)
#define DATA_WSET(set, sym) __MAKE_SET_QV(set, sym, )
#define BSS_SET(set, sym) __MAKE_SET(set, sym)
#define ABS_SET(set, sym) __MAKE_SET(set, sym)
#define SET_ENTRY(set, sym) __MAKE_SET(set, sym)
static int settest1 = 58;
static int settest2 = 156;
SET_ENTRY(testset, settest1);
SET_ENTRY(testset, settest2);
#define SET_BEGIN(set) \
(&__CONCAT(__start_set_,set))
#define SET_LIMIT(set) \
(&__CONCAT(__stop_set_,set))
#define SET_DECLARE(set, ptype) \
extern ptype __weak_symbol *__CONCAT(__start_set_,set); \
extern ptype __weak_symbol *__CONCAT(__stop_set_,set)
#define SET_FOREACH(pvar, set) \
for (pvar = SET_BEGIN(set); pvar < SET_LIMIT(set); pvar++)
void
linkersettest(void)
{
SET_DECLARE(testset, int);
int **ptr;
SET_FOREACH(ptr, testset) {
int x = **ptr;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
"linkerset test: %d\n", x));
}
}
Compiling (clang) seems ok, but alas, linking (MSVC++) says:
error LNK2016: absolute symbol '__start_set_testset' used as target of REL32 relocation in section 0x1

Making changes like:
static void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
The static here on Windows will drop it from .obj file. Removing static and going with:
__declspec(dllexport) void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
gets us all the expected defines in the .obj file, including __set_testset_sym_settest1 and __start_set_testset.
But it doesn't work, in that it does not appear to make a linker section set_testset at all, and the mentioned symbols are "randomly" in side, not the expected start, settest1, settest2, stop.
While looking around examples of #pragma section(".CRT$XCU",read,write) to add constructors to CRT's initterm, I came across this snippet:
typedef void(__cdecl* PF)(void);
#pragma section(".mine$a", read)
__declspec(allocate(".mine$a")) const PF InitSegStart = (PF)1;
#pragma section(".mine$z",read)
__declspec(allocate(".mine$z")) const PF InitSegEnd = (PF)1;
__declspec(allocate(".mine$m")) const PF __set_settest1 = (PF)&settest1;
__declspec(allocate(".mine$m")) const PF __set_settest2 = (PF)&settest2;
void
linkersettest(void)
{
const PF* x = &InitSegStart;
DbgBreakPoint();
for (++x; x < &InitSegEnd; ++x)
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
"linkerset test: %p %p %d\n", x, *x, *(int *)*x ));
Which appears to be the way Windows would do "linker-sets", and it works.
Possibly the clang way will work, if I adjust the section name from set_testset to a Windows name like .mine$ and ensure start/stop is "a" and "z" respectively.
I assume the "m" is just any character, as long as it is between "a" and "z", to get the order.
Should the setting of .mime$m be preceded by a #pragma line? I've not looked at what #pragma section read line does, yet (but works without it).

Related

Prepend/append string to each element in C preprocessor list?

Ultimately, what I want is this: first, have a list of variable names declared as a C preprocessor macro; say, in test_cpp.c:
#define VARLIST \
var_one, \
var_two, \
var_three, \
var_four
These would eventually be actual variable names in code - but, of course, the preprocessor does not know (or even has a concept of) that at this time.
To make sure the macro has been parsed correctly, I use this command (awk to get rid of the preamble defines in the gcc -E preprocessor output):
$ gcc -E -dD test_cpp.c | awk 'BEGIN{prn=0} /# 1 "test_cpp.c"/ {prn=1} prn==1 {print}'
# 1 "test_cpp.c"
#define VARLIST var_one, var_two, var_three, var_four
So far, so good.
Now: second, I'd like to use this list - that is, I'd like to (pre)process it - and prepend and append characters to each element (token) of the VARLIST, so that I end up with the equivalent of the following macros:
#define VARLIST_QUOTED "var_one", "var_two", "var_three", "var_four"
#define VARLIST_PTR &var_one, &var_two, &var_three, &var_four
... which I could ultimately use in code as, say:
char varnames[][16] = { VARLIST_QUOTED };
( ... which then would end up like this in compiled code, inspected in debugger:
(gdb) p varnames
$1 = {"var_one\000\000\000\000\000\000\000\000",
"var_two\000\000\000\000\000\000\000\000",
"var_three\000\000\000\000\000\000",
"var_four\000\000\000\000\000\000\000"}
)
I'm guessing, at this time the preprocessor wouldn't know & is intended to be an "address-of" operator, although I think it has special handling for double quotes.
In any case, I think that such "lists" in the preprocessor are handled via Variadic Macros (The C Preprocessor), where there is an identifier __VA_ARGS__. Unfortunately, I do not understand this very well: I tried the first thing that came to mind - again, test_cpp.c:
#define VARLIST \
var_one, \
var_two, \
var_three, \
var_four
#define do_prepend(...) &##__VA_ARGS__
#define VARLIST_PTR do_prepend(VARLIST)
void* vars_ptr[] = { VARLIST_PTR };
Then if I run the preprocessor, I get this:
$ gcc -E -dD test_cpp.c | awk 'BEGIN{prn=0} /# 1 "test_cpp.c"/ {prn=1} prn==1 {print}' | sed '/^$/d;G'
test_cpp.c:8:25: error: pasting "&" and "VARLIST" does not give a valid preprocessing token
8 | #define do_prepend(...) &##__VA_ARGS__
| ^
test_cpp.c:9:21: note: in expansion of macro 'do_prepend'
9 | #define VARLIST_PTR do_prepend(VARLIST)
| ^~~~~~~~~~
test_cpp.c:11:22: note: in expansion of macro 'VARLIST_PTR'
11 | void* vars_ptr[] = { VARLIST_PTR };
| ^~~~~~~~~~~
# 1 "test_cpp.c"
#define VARLIST var_one, var_two, var_three, var_four
#define do_prepend(...) & ##__VA_ARGS__
#define VARLIST_PTR do_prepend(VARLIST)
void* vars_ptr[] = { &var_one, var_two, var_three, var_four };
It does show an error - but ultimately, the preprocessor did prepend a single ampersand & to the first variable in the array vars_ptr, as I wanted it to ...
The question is, then: can it prepend an ampersand & to all the entries in the list VARLIST without errors (and likewise, can it both prepend and append a double quote " to all the entries in the list VARLIST without errors) - and if so, how?
Sounds like a job for X macros:
#include <stdio.h>
#define VARS \
X(var_one) \
X(var_two) \
X(var_three) \
X(var_four)
// Define all the variables as ints (just for the example)
#define X(V) int V=0;
VARS
#undef X
// Define the array of variable pointers
#define X(V) &V,
void* vars_ptr[] = { VARS };
#undef X
// Define the array of variable name strings
#define X(V) #V,
const char *var_names[] = { VARS };
#undef X
// Set a few variable values and print out the name/value of all variables
int main()
{
var_one = 9;
var_two = 2;
for(unsigned i = 0; i < sizeof(var_names)/sizeof(var_names[0]); i++)
{
printf("%s=%d\n", var_names[i], *(int *)vars_ptr[i]);
}
return 0;
}
Ok, seems I found an answer, mostly thanks to Is it possible to iterate over arguments in variadic macros? (see also Expand a macro in a macro); this is test_cpp.c:
#define VARLIST \
var_one, \
var_two, \
var_three, \
var_four
// Make a FOREACH macro
#define FE_0(WHAT)
#define FE_1(WHAT, X) WHAT(X)
#define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
//... repeat as needed
#define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) \
GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
#define XSTR(x) STR(x)
#define STR(x) #x
// original: https://stackoverflow.com/a/11994395
//#define QUALIFIER(X) X::
//#define QUALIFIED(NAME,...) FOR_EACH(QUALIFIER,__VA_ARGS__)NAME
#define POINTERER(X) &X,
#define POINTERIFIED(NAME,...) FOR_EACH(POINTERER,__VA_ARGS__)NAME
// leave first argument (from original QUALIFIED) empty here!
#define vptrs POINTERIFIED(,VARLIST)
void* vars_ptr[] = { vptrs };
//#define DQUOTE " // no need for DQUOTE;
// if we just use the number/hash sign, X gets automatically quoted with double quotes!
// (don't forget the comma at the end!)
#define DQUOTERER(X) #X,
#define DQUOTERIFIED(NAME,...) FOR_EACH(DQUOTERER,__VA_ARGS__)NAME
// leave first argument (from original QUALIFIED) empty here!
#define vnames DQUOTERIFIED(,VARLIST)
char vars_names[][16] = { vnames };
... and this is the output of the preprocessor:
$ gcc -E -dD test_cpp.c | awk 'BEGIN{prn=0} /# 1 "test_cpp.c"/ {prn=1} prn==1 {print}' | sed '/^$/d;G'
# 1 "test_cpp.c"
#define VARLIST var_one, var_two, var_three, var_four
#define FE_0(WHAT)
#define FE_1(WHAT,X) WHAT(X)
#define FE_2(WHAT,X,...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT,X,...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT,X,...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT,X,...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
#define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
#define XSTR(x) STR(x)
#define STR(x) #x
#define POINTERER(X) &X,
#define POINTERIFIED(NAME,...) FOR_EACH(POINTERER,__VA_ARGS__)NAME
#define vptrs POINTERIFIED(,VARLIST)
void* vars_ptr[] = { &var_one,&var_two,&var_three,&var_four, };
#define DQUOTERER(X) #X,
#define DQUOTERIFIED(NAME,...) FOR_EACH(DQUOTERER,__VA_ARGS__)NAME
#define vnames DQUOTERIFIED(,VARLIST)
char vars_names[][16] = { "var_one","var_two","var_three","var_four", };
So, ultimately, I got my output as desired - and no preprocessor errors/warnings, as far as I can tell:
void* vars_ptr[] = { &var_one,&var_two,&var_three,&var_four, };
char vars_names[][16] = { "var_one","var_two","var_three","var_four", };
As already mentioned, you are more or less literally describing the purpose of "X macros".
An alternative, arguably somewhat more readable way of writing them is to first declare a macro list, then pass a macro to that list. As in
"here is a function-like macro, run it with all the arguments listed", rather than
"here is the function-like macro X, run macro X with all the arguments listed".
This allows you to give macros meaningful names, optionally group all macros belonging to the list somewhere, and it eliminates the need to #undef.
#include <stdio.h>
// note the absence of commas
#define VARLIST(X) \
X(var_one) \
X(var_two) \
X(var_three) \
X(var_four) \
int main (void)
{
char varnames[][16] =
{
#define VARLIST_QUOTED(name) #name, /* "stringification operator" */
VARLIST(VARLIST_QUOTED) /* no semicolon or comma here */
};
#define VARLIST_DECL_VARS(name) int name; /* declare a bunch of int */
VARLIST(VARLIST_DECL_VARS)
int* const pointers[] =
{
#define VARLIST_PTR(name) &name, /* declare an array of pointers to previous ints */
VARLIST(VARLIST_PTR)
};
var_two = 123;
printf("%s has value %d and address %p\n",
varnames[1],
var_two,
pointers[1]);
}

purpose of error injection macro in linux kernel

I have seen a macro ALLOW_ERROR_INJECTION which is used in SYSCALL_DEFINEx
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
/*
* Whitelist ganerating macro. Specify functions which can be
* error-injectable using this macro.
*/
#define ALLOW_ERROR_INJECTION(fname, _etype) \
static struct error_injection_entry __used \
__attribute__((__section__("_error_injection_whitelist"))) \
_eil_addr_##fname = { \
.addr = (unsigned long)fname, \
.etype = EI_ETYPE_##_etype, \
};
#else
#define ALLOW_ERROR_INJECTION(fname, _etype)
#endif
#endif
Can anyone provide me enough documentation on this.
What is the use of it. What is whitelist

How can a macro define a valid global name based on the type passed to it?

I believe the title is self-explanatory, but here's an example to illustrate what I'm trying to accomplish:
#define PASTE2(_0, _1) _0 ## _1
#define DEFINE_OPS_FOR_TYPE(TYPE) \
int PASTE2(do_something_with_, TYPE)(void) { \
/* do_something_with_<TYPE> */ \
}
Everything works fine for char, int, and single-worded types, but when it
comes to unsigned types, or others that have multiple keywords, using token pasting (a ## b) does not generate a valid name due to the whitespace (e.g.: do_something_with_foo bar).
The easiest solution I could think of is to change the DEFINE_OPS_FOR_TYPE macro
to take a valid name as the 2nd parameter. For example:
#define DEFINE_OPS_FOR_TYPE(TYPE, NAME_FOR_TYPE) \
int PASTE2(do_something_with_, NAME_FOR_TYPE)(void) { \
/* do_something_with_<NAME_FOR_TYPE> */ \
}
This works as expected, but I'm curious about other possible solutions, even if they're overly complex. I thought of using _Generic, but I fail to see how it would help in defining a name.
Can you think of another solution?
On the level of declaration or definition of the symbols that you want to do there is not much way out of typedefing things to a unique identifier for the type in question. _Generic or equivalent replacements kick in too late to be useful for the preprocessor.
But there is only a finite number of standard types that pose such a problem. So you can easily come up with a convention for typedeffing these.
Where _Generic can help is on the usage side of your such defined symbols. Here you can then do something like
_Generic((X),
unsigned long: do_something_with_ulong,
unsigned char: do_something with_uchar,
...
)(X)
In P99 I follow this scheme, and you would find a lot of support macros for it already in place.
I ended up using a macro with an empty argument. Example:
#define STR2(x) # x
#define STR(x) STR2(x)
#define PASTE3(_1,_2,_3) _1 ## _2 ## _3
#define FOO(_1,_2,_3) PASTE3(_1, _2, _3)
printf("%s\n", STR(FOO(int,,)));
printf("%s\n", STR(FOO(unsigned, int,)));
printf("%s\n", STR(FOO(unsigned, long, long)));
As you can see here, the output is:
int
unsignedint
unsignedlonglong
I don't remember whether using empty macro arguments is well defined according to the standard, but I can tell you that Clang 3.1 doesn't emit any warnings for -std=c11 with -pedantic.
Here's some code if you want to try:
#include <stdio.h>
#include <limits.h>
#define PASTE4(_1,_2,_3,_4) _1 ## _2 ## _3 ## _4
#define DEFINE_OPS_FOR_TYPE1(T1) DEFINE_OPS_FOR_TYPE2(T1,)
#define DEFINE_OPS_FOR_TYPE2(T1, T2) DEFINE_OPS_FOR_TYPE3(T1,T2,)
#define DEFINE_OPS_FOR_TYPE3(T1, T2, T3) \
int PASTE4(write_,T1,T2,T3)(FILE *file, void *data) { \
T1 T2 T3 foo; \
int written = fprintf(file, fmt_specifier(foo), *((T1 T2 T3 *)data));\
return written > 0 ? 0 : -1; \
}
#define fmt_specifier(x) \
_Generic((x), \
int: "%i", \
unsigned int: "%u", \
unsigned long long: "%llu", \
default: NULL \
)
DEFINE_OPS_FOR_TYPE1(int)
DEFINE_OPS_FOR_TYPE2(unsigned, int)
DEFINE_OPS_FOR_TYPE3(unsigned, long, long)
int main() {
int var_int = INT_MAX;
write_int(stdout, &var_int);
printf("\n");
unsigned int var_uint = UINT_MAX;
write_unsignedint(stdout, &var_uint);
printf("\n");
unsigned long long var_ullong = ULLONG_MAX;
write_unsignedlonglong(stdout, &var_ullong);
printf("\n");
return 0
}

How to use #if inside #define in the C preprocessor?

I want to write a macro that spits out code based on the boolean value of its parameter. So say DEF_CONST(true) should be expanded into const, and DEF_CONST(false) should be expanded into nothing.
Clearly the following doesn't work because we can't use another preprocessor inside #defines:
#define DEF_CONST(b_const) \
#if (b_const) \
const \
#endif
You can simulate conditionals using macro token concatenation as follows:
#define DEF_CONST(b_const) DEF_CONST_##b_const
#define DEF_CONST_true const
#define DEF_CONST_false
Then,
/* OK */
DEF_CONST(true) int x; /* expands to const int x */
DEF_CONST(false) int y; /* expands to int y */
/* NOT OK */
bool bSomeBool = true; // technically not C :)
DEF_CONST(bSomeBool) int z; /* error: preprocessor does not know the value
of bSomeBool */
Also, allowing for passing macro parameters to DEF_CONST itself (as correctly pointed out by GMan and others):
#define DEF_CONST2(b_const) DEF_CONST_##b_const
#define DEF_CONST(b_const) DEF_CONST2(b_const)
#define DEF_CONST_true const
#define DEF_CONST_false
#define b true
#define c false
/* OK */
DEF_CONST(b) int x; /* expands to const int x */
DEF_CONST(c) int y; /* expands to int y */
DEF_CONST(true) int z; /* expands to const int z */
You may also consider the much simpler (though potentially less flexible):
#if b_const
# define DEF_CONST const
#else /*b_const*/
# define DEF_CONST
#endif /*b_const*/
Doing it as a paramterised macro is a bit odd.
Why not just do something like this:
#ifdef USE_CONST
#define MYCONST const
#else
#define MYCONST
#endif
Then you can write code like this:
MYCONST int x = 1;
MYCONST char* foo = "bar";
and if you compile with USE_CONST defined (e.g. typically something -DUSE_CONST in the makefile or compiler options) then it will use the consts, otherwise it won't.
Edit: Actually I see Vlad covered that option at the end of his answer, so +1 for him :)

Define array and symbolic indices at same time

I'm trying to think of a clever way (in C) to create an array of strings, along with symbolic names (enum or #define) for the array indices, in one construct for easy maintenance. Something like:
const char *strings[] = {
M(STR_YES, "yes"),
M(STR_NO, "no"),
M(STR_MAYBE, "maybe")
};
where the result would be equivalent to:
const char *strings[] = {"yes", "no", "maybe"};
enum indices {STR_YES, STR_NO, STR_MAYBE};
(or #define STR_YES 0, etc)
but I'm drawing a blank for how to construct the M macro in this case.
Any clever ideas?
A technique used in the clang compiler source is to create .def files that contains a list like this, which is designed like a C file and can easily be maintained without touching other code files that use it. For example:
#ifndef KEYWORD
#define KEYWORD(X)
#endif
#ifndef LAST_KEYWORD
#define LAST_KEYWORD(X) KEYWORD(X)
#endif
KEYWORD(return)
KEYWORD(switch)
KEYWORD(while)
....
LAST_KEYWORD(if)
#undef KEYWORD
#undef LAST_KEYWORD
Now, what it does is including the file like this:
/* some code */
#define KEYWORD(X) #X,
#define LAST_KEYWORD(X) #X
const char *strings[] = {
#include "keywords.def"
};
#define KEYWORD(X) kw_##X,
#define LAST_KEYWORD(X) kw_##X
enum {
#include "keywords.def"
};
In your case, you could do similar. If you can live with STR_yes, STR_no, ... as enumerator names you could use the same approach like above. Otherwise, just pass the macro two things. One lowercase name and one uppercase name. Then you could stringize the one you want like above.
This is a good place to use code generation. Use a language like perl, php or whatever to generate your .h file.
It is not required to put this into specific .def files; using only the preprocessor is perfectly possible. I usually define a list named ...LIST where each element is contained within ...LIST_ELEMENT. Depending on what I will use the list for I will either just separate with a comma for all but the last entry (simplest), or in the general case make it possible to select the separator individually on each usage. Example:
#include <string.h>
#define DIRECTION_LIST \
DIRECTION_LIST_ELEMENT( up, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( down, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( right, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( left, NO_COMMA )
#define COMMA ,
#define NO_COMMA /**/
#define DIRECTION_LIST_ELEMENT(elem, sep) elem sep
#define DIRECTION_LIST_SEPARATOR COMMA
typedef enum {
DIRECTION_LIST
} direction_t;
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
#define DIRECTION_LIST_ELEMENT(elem, sep) void (*move_ ## elem)(struct object_s * object);
#define DIRECTION_LIST_SEPARATOR NO_COMMA
typedef struct object_s {
char *name;
// ...
DIRECTION_LIST
} object_t;
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
static void move(object_t *object_p, const char * direction_string)
{
if (0) {
}
#define DIRECTION_LIST_SEPARATOR NO_COMMA
#define DIRECTION_LIST_ELEMENT(elem, sep) \
else if (strcmp(direction_string, #elem) == 0) { \
object_p->move_ ## elem(object_p); \
}
DIRECTION_LIST
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
}

Resources