当前位置:首页 > > 充电吧
[导读]How kernel, compiler, and C library work togetherKernel (內核)The kernel is the core of an operating s

How kernel, compiler, and C library work together
Kernel (內核)

The kernel is the core of an operating system. In a traditional design, it is responsible for memory management, I/O, interrupt handling, and various other things. And even while some modern designs like Microkernels or Exokernels move several of these services into user space, this matters little in the scope of this document.

The kernel makes its services available through a set of system calls; how they are called and what they do exactly differs from kernel to kernel.

内核是操作系统的核心。在传统的设计中,它是负责内存管理,I / O,中断处理,和其他各种东西。即使在一些现代的设计,如微内核或Exokernels这些服务的几个移动到用户空间,这一点在本文的讨论范围的事项。
通过一组系统调用的内核使得其提供的服务,他们是如何完全不同。

C Library

One thing up front: When you begin working on your kernel, you do not have a C library available. You must not #includeanything you did not write yourself. You will also have to port an existing C library. See GCC Cross-Compiler, Future Steps / Standard Library.
第一件事:当你开始寫你的内核,如果你没有一个C库。你就不能#include 任何不是你自己写的東西。您可以移植现有的C库。 GCC交叉编译器,未来的步骤/标准库。

The C library implements the standard C functions (i.e., the things declared in

C库实现了标准的C函数(例如

In addition to standard C functions (as defined in the ISO standard), a C library might (and usually does) implement further functionality, which might or might not be defined by some standard. The standard C library says nothing about networking, for example. For Unix-like systems, the POSIX standard defines what is expected from a C library; other systems might differ fundamentally.

除了标准的C函数(如ISO标准中定义的),C库(和通常一样)可以实现更多的功能,这可能会超過一些标准。 在标准C库裏,没有关于网络的function,例如。对于类Unix系统,POSIX标准定义C庫應該的期望是什么。

It should be noted that, in order to implement its functionality, the C library must call kernel functions. So, for your own OS, you can of course take a ready-made C library and just recompile it for your OS - but that requires that you tell the library how to call your kernel functions, and your kernel to actually provide those functions. The good news is that relatively few of the library's functions do use some system call

应当指出的是,为了实现其功能,C库必须调用内核函数。因此,对于自己的操作系统,你当然可以拿一个现成的C库,只需重新编译它适用于您的操作系统 - 但是这需要你告诉图书馆如何打电话给你的内核函数,和你的内核,提供这些功能。好消息是,图书馆的功能比较少使用一些系统调用

Some implementations of the standard C library include:

GNU C library (with info about porting the glibc)newlib (with info on the required OS functions detailed in the manual)uClibC (although that is highly optimized to be used with an embedded Linux).fdlibmdietlib

A more elaborate example is available in Library Calls or, you can roll your own C Library.

Compiler / Assembler

An Assembler takes (plaintext) source code and turns it into (binary) machine code; more precisely, it turns the source into object code, which contains additional information like symbol names, relocation information etc.

一個assembler接受匯編源代码為輸入,并把它转化为机器代码(二进制);更确切地说,它原来的源代码转换成目标代码,其中包含其他信息,如符号名称(symbol),重定位信息等。

A compiler takes higher-level language source code, and either directly turns it into object code, or (as is the case with GCC) turns it into Assembler source code and invokes an Assembler for the final step.

编译器接受更高层次的语言源代码為輸入,可以直接把它转换成目标代码,或像GCC那樣把它转化为汇编程序源代码,并调用汇编作為編譯的最后一步。

The resulting object code does not yet contain any code for standard functions called. If you included e.g.  and usedprintf(), the object code will merely contain a reference stating that a function named printf() (and taking a const char * and a number of unnamed arguments as parameters) must be linked to the object code in order to receive a complete executable.

生成的目标代码不包含任何代码的标准函数调用。如果包括了如

Some compilers use standard library functions internally, which might result in object files referencing e.g. memset() or memcpy() even though you did not include the header or used a function of this name. You will have to provide an implementation of these functions to the linker, or the linking will fail (see below).

一些编译器内部使用标准库函数,这可能会导致在目标文件中引用錯誤,如memset的()的memcpy(),即使你没有包含头文件,或使用这个名字的函数。您必须提供一个实现这些功能的连接器,或否則會连接失败(见下文)。

Some advanced operations (e.g. 64-bits divisions on a 32-bits system) might involve compiler-internal functions. For GCC, those functions are residing in libgcc.a. The content of this library is agnostic of what OS you use, and it won't taint your compiled kernel with licensing issues of whatever sort, so you are welcome to locate "libgcc.a" and link it with your kernel.

一些先进的操作(例如在32位系统的64位部门)可能涉及部编译器内的功能。对于GCC,这些function是儲存在libgcc.a文件中。这个库的内容是用家不需要知的,所以編譯器總是希望你把“libgcc.a的”和将它连接到你的内核编译的内核Link在一起.

Linker

A linker takes the object code generated by the compiler / assembler, and links it against the C library (and / or libgcc.a or whatever link library you provide). This can be done in two ways: static, and dynamic.

Static Linking

When linking statically, the linker is invoked during the build process, just after the compiler / assembler run. It takes the object code, checks it for unresolved references, and checks if it can resolve these references from the available libraries. It then adds the binary code from these libraries to the executable; after this process, the executable is complete, i.e. when running it does not require anything but the kernel to be present.

On the downside, the executable can become quite large, and code from the libraries is duplicated over and over, both on disk and in memory.

Dynamic Linking

When linking dynamically, the linker is invoked during the loading of an executable. The unresolved references in the object code are resolved against the libraries currently present in the system. This makes the on-disk executable much smaller, and allows for in-memory space-saving strategies such as shared libraries (see below).

On the downside, the executable becomes dependent on the presence of the libraries it references; if a system does not have those libraries, the executable cannot run.

Shared Libraries

A popular strategy is to share dynamically linked libraries across multiple executables. This means that, instead of attaching the binary of the library to the executable image, the references in the executable are tweaked, so that all executables refer to the same in-memory representation of the required library.

This requires some trickery. For one, the library must either not have any state (static or global data) at all, or it must provide a separatestate for each executable. This gets even trickier with multi-threaded systems, where one executable might have more than one simultaneous control flow.

Second, in a virtual memory environment, it is usually impossible to provide a library to all executables in the system at the same virtual memory address. To access library code at an arbitrary virtual address requires the library code to be position independent (which can be achieved e.g. by setting the -PIC command line option for the GCC compiler). This requires support of the feature by the binary format (relocation tables), and can result in slightly less efficient code on some architectures.

ABI - Application Binary Interface

The ABI of a system defines how library function calls and kernel system calls are actually done. This includes e.g. whether parameters are passed on the stack or in registers, how function entry points are located in libraries etc.

When using static linkage, the resulting executable is depending on the executing kernel using the same ABI as the one it was built for; when using dynamic linkage, the executable is depending on the libraries' ABI staying the same.

Unresolved Symbols

The linker is the stage where you will find out about stuff that has been added without your knowledge, and which is not provided by your environment. This can include references to alloca()memcpy(), or several others. This is usually a sign that either your toolchain or your command line options are not correctly set up for compiling your own OS kernel - or that you are using functionality that is not yet implemented in your C library / runtime environment!

It is strongly recommended to build a GCC Cross-Compiler to avoid this and similar problems right from the start.

Other symbols, such as _udiv* or __builtin_saveregs, are available in the OS-agnostic "libgcc.a". If you get errors about missing such symbols, try to link your kernel against that library too. See this thread for details.

__alloca, ___main

alloca() is a "semi-standard" C function (from BSD?, but supported by most C implementations) that is used to allocate memory from the stack. On Windows this function is also used for stack probing. As such, alloca() is referenced in PE binaries, build e.g. by the Cygwin GCC. You can set -mno-stack-arg-probe to suppress those references.

Another "specialty" of PE binaries is that, if you define int main(), a function void __main() is called first thing after entering main(). You can either define that function, or omit main() from your kernel code, using a different function as entry point.

This explanation of alloca() comes from Chris Giese, posted to alt.os.dev:

>> I think _alloca() is for stack-probing, which is required by Windows.
> What is stack probing?
By default, Windows reserves 1 meg of virtual memory for the stack. No page of stack memory is actually allocated (committed) until the page is accessed. This is demand-allocation. The page beyond the top of the stack is the guard page. If this page is accessed, memory will be allocated for it, and the guard page moved downward by 4K (one page). Thus, the stack can grow beyond the initial 1 meg. Windows will not, however, let you grow the stack by accessing discontiguous pages of memory. Going beyond the guard page causes an exception. Stack-probing code prevents this.

Some more information about stack-probing:

http://groups.google.com/groups?&selm=702bki%24oki%241%40news.Eindhoven.NL.nethttp://groups.google.com/groups?&selm=3381B63D.6E39%40austin.finnigan.com


alloca() is not just used for stack-probing, but also as a sort of malloc() -- for dynamically allocating memory for variables/buffers -- without the need to manually free the reserved memory (with free() as it should be done for malloc() allocated memory).

If you search the man pages for alloca on a UNIX OS you'll find something like this: "The alloca() function allocates space in the stack frame of the caller, and returns a pointer to the allocated block. This temporary space is automatically freed when the function from which alloca() is called returns."


On Windows: "_alloca allocates size bytes from the program stack. The allocated space is automatically freed when the calling function exits (not when the allocation merely passes out of scope). Therefore, do not pass the pointer value returned by _alloca as an argument to free."

Note that "a stack overflow exception is generated if the space cannot be allocated", so alloca() might cause the stack to grow.

Unfortunately, there are all kinds of caveats with using alloca(). Notably, Turbo~C/C++ had the limitation that functions calling alloca()needed to have at least one local variable, and Linux man-page warns the following:

The alloca function is machine and compiler dependent. On many systems its implementation is buggy. Its use is discouraged.
On many systems alloca cannot be used inside the list of arguments of a function call, because the stack space reserved by alloca would appear on the stack in the middle of the space for the function arguments.

memcpy

This function is used internally by GCC. You should set the --no-builtin switch, and provide your own implementation of memcpy() if you want to be independent of GCC (OSD library just has it ;).


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

上篇文章中,小编对Turbo c编译器已做部分介绍。本文中,小编将对Turbo c编译器余下内容加以讲解。如果你对c编译器具有兴趣,不妨继续往下阅读哦。

关键字: c编译器 turbo 指数

为增进大家对c编译器的认识,本文将对Turbo C c编译器予以讲解。如果你对c编译器具有兴趣,不妨继续往下阅读哦。

关键字: c编译器 turbo 指数

本文中,小编将对c编译器和c编辑器的区别予以介绍。如果你对c编译器具有兴趣,不妨继续往下阅读哦。

关键字: c编译器 指数 c编辑器

许多朋友经常混淆c编译器和c编辑器,注意,c编译器的作用在于编译,而c编辑器在于编写代码。对于c编译器,小编曾带来诸多文章。但有网友提问,有没有较为推荐的c编译器。为解决大家的疑问,本文将对6款c编译器予以介绍,大家可以...

关键字: c编译器 指数 编译器

c编译器每天都在被使用,但对c编译器十分了解的人却不多,而对c编译器编译过程有所认知的朋友更是少之又少。在上篇文章中,小编对c编译器的工作过程有所讲解。本文中,为继续增进大家对c编译器的讲解,将对编译器工作过程的余下步骤...

关键字: c编译器 指数 编译器

c编译器的问世是程序界的里程碑之一,没有c编译器,c程序将无法运行。由此可见,c编译器尤为重要。为增进大家对c编译器的了解,本文将带来c编译器的通识篇,以使大家能够了解编译器的运行过程。此外,本文仅为上篇,剩余内容将在后...

关键字: c编译器 指数 编译器

对于c编译器,很多朋友均有所了解。往期文章中,小编为大家带来过诸多c编译器文章。在这篇c编译器相关文章中,小编将介绍如何基于SDCC c编译器开发微控制器。如果你对c编译器的应用同样存在兴趣,不妨继续往下阅读哦。

关键字: c编译器 sdcc 微控制器 指数

c编译器尤为重要,缺乏c编译器,很多应用将无法运行。此外,没有c编译器,很多系统同样无法正常运转。在很多朋友眼里,对c编译器充满疑惑,如c编译器是c语言编写的,那么第一个c编译器是如何而来呢?如果你对这个问题同样不太了解...

关键字: c编译器 C语言 汇编 指数

对于c编译器,大家应早已熟悉。往期文章中,小编带来诸多c编译器相关文章,尤其是gcc c编译器。本文中,小编将对gcc c编译器如何编译c程序予以介绍,并在文章的后半部分向大家讲解如果选择pic单片机的c编译器。如果你对...

关键字: c编译器 gcc pic 指数

c编译器的重要性不言而喻,从往期c编译器文章中,如c编译器优化、选定c编译器等,想必大家对c编译器均已有所了解。往期文章中,小编主要从宏观方面为大家讲解c编译器,此外对于gcc c编译器的讲解也大多基于windows。本...

关键字: c编译器 gcc Linux
关闭