原型内核和模块

发布于 2024-11-18 11:41:21 字数 884 浏览 3 评论 0 原文

最近,我拿起了一个旧项目并重新启动它,几乎是从头开始。 我已经病了一段时间了,所以我有时间努力克服并实现大量功能。然而,我认为实现模块加载是一个好主意。我想要内核模式动态加载模块。

模块这个词有点含糊,正确的术语应该是加载库,例如用于内核模式C库的微型实现> 驱动程序或标准设备,例如位于IRQ 0 和IRQ 0 上的PIT键盘。 1。我试图实现的方法有点自我维持;在我的内核将加载的模块方面,将在内核本身中使用以进入用户模式

举个例子,我的内核使用了我自己实现的 C 库中的很少的函数。这些函数本身用于设置我的 GDT、IDT、IRQ、ISR 等。我想将这些函数抽象为内核可以加载和使用的库。这意味着在进行任何设置之前,内核本身将需要在第一阶段加载模块。

现在,我自己想到了几种方法来做到这一点,例如向该库添加一个结构,其中包含一个函数指针表,这些指针被分配了库本身中函数的地址。将库编译为 aout-kludge 文件,将库作为​​ void * 加载到内核中(这没问题,因为我有一个可用的分配器),然后计算出结构的偏移量,单步进入 void 指针,然后在内核中重新创建结构。这听起来似乎行不通,因为需要分配函数指针表,这意味着库本身需要有一个初始化函数。即使我知道地址,那又该如何称呼呢?

我不知道如何实现这样的加载器,它是否值得?我想尽可能多地抽象,我的内核采用模块化设计。我也确实希望用这种方法加载驱动程序和其他东西,我只是不确定如何实现它。我已经尝试过各种方法,但都失败了。我应该怎么办?

Recently I've picked up one of my old projects and restarted it, pretty much from scratch.
I've been sick for awhile, so I've had time to crack down hard and implement tons of functionality. However one thing that I feel would be a good idea to implement is module loading. I want to do kernel mode dynamic loading of modules.

The word modules is a bit ambiguous, the correct term would just be to load libraries, such as a miniture implementation of the C library for kernel mode drivers or standard things like the PIT and keyboard which are on IRQ 0 & 1. The method I'm trying to achieve is a bit self-sustaining; in the aspect that the modules my kernel will load, will be used in the kernel itself to get into user mode.

As an example, my kernel uses very few functions from the C library, which I've implemented myself. These functions themselfs are used in the setup of my GDTs, IDTs, IRQs, ISRs etc, etc. I would like to abstract these functions to a library that the kernel can load and use. Which means the kernel itself will require module loading at the very first stage, before anything is setup.

Now, I've thought of a few ways to do this myself, such as adding a structure to this library with a table of function pointers that are assigned the address of the functions in the library itself. Compiling the library as an aout-kludge file, loading the library into the kernel as a void * ( which is okay since I have a working allocator ), and then figuring out the offset of the structure, stepping into the void pointer that much, and recreating the structure in the kernel. This does not sound like it would work, since the table of function pointers need to be assigned, which means there needs to be an initialize function in the library itself. How would that be called, even if I knew the address?

I'm clueless as to how I could implement such a loader, and is it even worth it? I want to abstract as much as I possibly can, my kernel has a modular design. I also do expect to load drivers and other things with this method, I'm just unsure how I would implement it. I tried various methods already, and they all failed. What should I do?

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

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

发布评论

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

评论(2

(り薆情海 2024-11-25 11:41:21

我建议您首先在用户空间中编写一个动态加载器。所需的技术非常相似,您稍后可以将大部分代码调整到内核空间。另外,不要使用 a.out 也不要创建自己的“函数指针表” - 使用更现代的格式,例如 ELF。编译时工具已经存在,所以这会节省你很多精力;您只需编写适当的链接器脚本并直接从 Linux GCC 进行构建即可。

碰巧,Windows 内核所做的事情与您所说的非常相似 - Windows 内核 (ntoskrnl.exe) 是一个 PE 可执行文件,链接来自各种 DLL(PSHED.dll、HAL.dll、KDCOM.dll、CLFS)的例程。 sys 和我系统上的 Cl.dll)。在这种情况下,NTLDR 程序将 ntoskrnl.exe 所需的所有文件加载到内存中,然后 ntoskrnl.exe 中的引导存根执行动态链接。稍后,相同的动态链接器也可用于加载其他驱动程序。

I would recommend you first write a dynamic loader in user space. The techniques needed are very similar, and you may be able to adapt much of the code to kernel space later. Also, don't use a.out and don't make up your own 'table of function pointers' - use a more modern format such as ELF. The compile-time tools already exist, so this will save you a lot of effort; you can just write an appropriate linker script and build straight from a Linux GCC.

As it happens, the Windows kernel does something very similar to what you say - the Windows kernel (ntoskrnl.exe) is a PE executable file linking in routines from various DLLs (PSHED.dll, HAL.dll, KDCOM.dll, CLFS.sys, and Cl.dll on my system). In this case, the NTLDR program loads all files required by ntoskrnl.exe into memory, and a boot stub in ntoskrnl.exe then performs dynamic linking. Later the same dynamic linker can be used to load other drivers as well.

鱼窥荷 2024-11-25 11:41:21

实现内核模块并不是一件简单的工作。它有点复杂,您需要阅读 ELF 文档来进行编码。我将尝试在这里为您提供一些见解 -

在用户空间中,可执行文件需要共享库来实现其某些功能或代码。因此,可执行文件中的代码将引用共享库中的代码。这导致了符号的发展。符号表示指向数据/函数/其他的指针有名字。

CHAR VariableName[20];

例如,在上面的代码中,将创建一个名为“VariableName”的数据符号。在动态/共享库“发明”之后,必须加载符号表(二进制中的符号集)以解析库中可执行文件的引用。但是很多调试符号&符号表中存在无用的符号。

Symbol: Main.c

例如,在符号表中,甚至 C 源文件的符号也会出现以供调试。但这对于在运行时解析引用来说不是必需的。在这里,动态符号的概念出现了。

动态链接是指解析二进制文件之间的引用。动态链接器将使用动态符号表(必须加载而“普通”符号表不必加载)来解析可执行文件在库中进行的引用。

现在,在作为可执行文件的内核核心中,共享库(内核模块)中没有引用。但共享库在可执行文件中引用。因此,可执行文件必须包含动态符号来解析内核模块中的引用。这与用户空间中的情况相反。因此,如果您使用 ld,

-pie -T LinkerScript.ld

应使用选项在内核可执行文件中创建动态符号表。

您应该创建一个 LinkerScript.ld 文件 -

/* File: LinkerScript.ld */
PHDRS {
  kernel PT_LOAD FILEHDR;/* This declares a segment in which your code/data is.*/
  dynamic PT_DYNAMIC;/* Segment containing the dynamic table (not DST). */
}

SECTIONS {
    /* text, data, bss sections must be implemented already */
    .dynamic ALIGN(0x1000) : AT(ADDR(.dynamic) - KERNEL_OFFSET)
    { 
       *(.dynamic) 
    } :dynamic/* add :kernel to text, data, bss*/
}

具有上述结构。确保您的 .text、.data 和.bss 部分已经存在 & :kernel 添加到节描述符的末尾。

有关更多信息,请阅读 ELF 文档和LD 手册(用于链接描述文件洞察)。

Implementing kernel modules is not a trivial job. It is a little complicated and you will need to read to ELF documentation for coding. I will try to provide you some insight here -

In user-space, executable files required shared libraries to implement some of their functionality or code. So, the code in the executable will reference code in the shared library. This leads to the development of symbols. Symbols represent pointers to data/functions/other & have a name.

CHAR VariableName[20];

For example, in the above code a data symbol will be created with the name 'VariableName'. After the 'invention' of dynamic/shared libraries the symbol table (set of symbols in a binary) has to be loaded to resolve the references from executable file in the libraries. But a lot of debugging symbols & useless symbols are present in the symbol table.

Symbol: Main.c

For example, in the symbol table, even a symbol for the C source file will be present for debugging. But that is not required for resolving references at runtime. Here, the concept of dynamic symbols comes in the play.

Dynamic linking refers to the resolving of references between binaries. The dynamic linker will use the dynamic symbol table (which must be loaded & 'normal' symbol table doesn't have to) to resolve the references that the executable makes in the library.

Now, in the kernel core which is the executable file, there are no references in the shared libraries (kernel modules). But the shared libraries reference in the executable. So, the executable must contain dynamic symbols for resolving the references in the kernel modules. This is contrary to the case in user-space. Thus, if you are using ld,

-pie -T LinkerScript.ld

option should be used for create a dynamic symbol table in the kernel executable.

And you should create a LinkerScript.ld file -

/* File: LinkerScript.ld */
PHDRS {
  kernel PT_LOAD FILEHDR;/* This declares a segment in which your code/data is.*/
  dynamic PT_DYNAMIC;/* Segment containing the dynamic table (not DST). */
}

SECTIONS {
    /* text, data, bss sections must be implemented already */
    .dynamic ALIGN(0x1000) : AT(ADDR(.dynamic) - KERNEL_OFFSET)
    { 
       *(.dynamic) 
    } :dynamic/* add :kernel to text, data, bss*/
}

with the above structure. Make sure, your .text, .data & .bss sections are already present & :kernel is added to the end of the section descriptor.

For more information, read the ELF documentation & LD manual (for linker script insight).

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