"linker sets" 在 hybrid clang Windows 驱动程序上
"linker sets" on hybrid clang Windows driver
好吧,这里的情况非常特殊,所以有点恶心,答案可能是否定的。
使用 clang(因为它是 Unix 源代码)将项目编译为 .libs,但为“/driver”链接 MSVC++ 以生成内核组件。
正在寻找一种方法来处理 Linux MODULE_PARAM()
,他们可以在其中定义 static int tunable;
并使其可针对内核进行更改。可能会被写入注册表项,这似乎是 Windows 与 sysctl、kstat 或 /proc
等效的方式
这可以通过“链接器集”轻松处理,使用 SET_ENTRY(tunable)
然后 SET_FOREACH()
遍历它们。
在使它们工作时遇到一些问题,我怀疑是因为与 MSVC++ 的链接,所以我可能无法使其工作。不过也许你们可以想个办法。
使用:
#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));
}
}
编译 (clang) 似乎没问题,但唉,链接 (MSVC++) 说:
error LNK2016: absolute symbol '__start_set_testset' used as target of REL32 relocation in section 0x1
进行如下更改:
static void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
Windows 上的 static
将从 .obj 文件中删除它。删除 static
并使用:
__declspec(dllexport) void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
获取 .obj 文件中的所有预期定义,包括 __set_testset_sym_settest1
和 __start_set_testset
.
但它不起作用,因为它似乎根本没有创建链接器部分 set_testset
,并且提到的符号是“随机”在旁边,而不是预期的 start, settest1, settest2, stop
.
在查看 #pragma section(".CRT$XCU",read,write)
向 CRT 的 initterm 添加构造函数的示例时,我遇到了这个片段:
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 ));
这似乎是 Windows 会做“linker-sets”的方式,而且它有效。
如果我将部分名称从 set_testset
调整为 Windows 名称(如 .mine$
并确保 start/stop 是“a”并且分别为“z”。
我假设“m”只是任何字符,只要它在“a”和“z”之间,就能得到顺序。
.mime$m
的设置是否应该在 #pragma
行之前?我还没有查看 #pragma section read
行的作用(但没有它也能工作)。
好吧,这里的情况非常特殊,所以有点恶心,答案可能是否定的。 使用 clang(因为它是 Unix 源代码)将项目编译为 .libs,但为“/driver”链接 MSVC++ 以生成内核组件。
正在寻找一种方法来处理 Linux MODULE_PARAM()
,他们可以在其中定义 static int tunable;
并使其可针对内核进行更改。可能会被写入注册表项,这似乎是 Windows 与 sysctl、kstat 或 /proc
这可以通过“链接器集”轻松处理,使用 SET_ENTRY(tunable)
然后 SET_FOREACH()
遍历它们。
在使它们工作时遇到一些问题,我怀疑是因为与 MSVC++ 的链接,所以我可能无法使其工作。不过也许你们可以想个办法。
使用:
#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));
}
}
编译 (clang) 似乎没问题,但唉,链接 (MSVC++) 说:
error LNK2016: absolute symbol '__start_set_testset' used as target of REL32 relocation in section 0x1
进行如下更改:
static void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
Windows 上的 static
将从 .obj 文件中删除它。删除 static
并使用:
__declspec(dllexport) void const * qv \
__set_##set##_sym_##sym __section("set_" #set) \
获取 .obj 文件中的所有预期定义,包括 __set_testset_sym_settest1
和 __start_set_testset
.
但它不起作用,因为它似乎根本没有创建链接器部分 set_testset
,并且提到的符号是“随机”在旁边,而不是预期的 start, settest1, settest2, stop
.
在查看 #pragma section(".CRT$XCU",read,write)
向 CRT 的 initterm 添加构造函数的示例时,我遇到了这个片段:
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 ));
这似乎是 Windows 会做“linker-sets”的方式,而且它有效。
如果我将部分名称从 set_testset
调整为 Windows 名称(如 .mine$
并确保 start/stop 是“a”并且分别为“z”。
我假设“m”只是任何字符,只要它在“a”和“z”之间,就能得到顺序。
.mime$m
的设置是否应该在 #pragma
行之前?我还没有查看 #pragma section read
行的作用(但没有它也能工作)。