“接头组”关于混合 clang Windows 驱动程序

发布于 2025-01-14 04:16:39 字数 2626 浏览 4 评论 0原文

好吧,这里的情况非常特殊,所以有点恶心,答案可能是否定的。 使用 clang(因为它是 Unix 源代码)将项目编译为 .libs,但与 MSVC++ 链接“/driver”以制作内核组件。

寻找一种处理 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++)说:

错误LNK2016:绝对符号'__start_set_testset'用作第0x1节中REL32重定位的目标

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嘦怹 2025-01-21 04:16:39

进行如下更改:

    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,停止

在查看 #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 的做法“链接器集”,并且它有效。

如果我将节名称从 set_testset 调整为 Windows 名称,如 .mine$ 并确保开始/停止为“a”和“z”,则 clang 方式可能会起作用分别。

我假设“m”只是任何字符,只要它在“a”和“z”之间即可获得顺序。

.mime$m 的设置前面是否应该有 #pragma 行?我还没有看过 #pragma section read 行的作用(但没有它也可以工作)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文