LINUX内核概况
从功能层面上 内核就是软件和硬件之间的一个中间层,可以连接软件和硬件。
内核实现策略
1.微内核。最基本的功能由中央内核(微内核)实现。所有其他的功能都委托给一些独立进程,这些进程通过明确定义的通信接口与中心内核通信。
2.宏内核。内核的所有代码,包括子系统(如内存管理、文件管理、设备驱动程序)都打包到一个文件中。内核中的每一个函数都可以访问到内核中所有其他部分。目前支持模块的动态装卸(裁剪)。Linux内核就是基于这个策略实现的。
X86寄存器
通用寄存器:
- EAX(累加器寄存器):主要用于算术和逻辑运算,并作为函数返回值的容器。
- EBX(基址寄存器):通常被用作内存地址的基址。
- ECX(计数器寄存器):通常用于循环计数和字符串操作。
- EDX(数据寄存器):用于存放一般性数据。
- ESI(源变址寄存器):通常用于字符串操作中的源地址。
- EDI(目的变址寄存器):通常用于字符串操作中的目的地址。
- ESP(堆栈指针寄存器):指向当前堆栈顶部。
- EBP(基址指针寄存器):通常用于指向栈帧的基址。
段寄存器:
- CS(代码段寄存器):存储当前执行指令的代码段。
- DS(数据段寄存器):存储数据的段。
- SS(堆栈段寄存器):存储堆栈的段。
- ES(附加段寄存器):可用于存储其他数据段。
标志寄存器:
EFLAGS(标志寄存器):用于存储各种程序状态标志,如进位标志、零标志、溢出标志等。
(PSW)
在x86架构中,PSW是一个常见的缩写,它代表程序状态字(Program Status Word),也被称为标志寄存器或标志字。然而,在x86架构中,官方没有直接称之为PSW寄存器,而是使用了一系列标志位来表示程序的状态。
这些标志位通常存储在EFLAGS寄存器中
指令指针寄存器:
- EIP(指令指针寄存器):存储下一条要执行的指令的内存地址。
磁盘结构
ROM 和RAM
ROM是一种只读存储器,其中存储的数据在计算机关闭或重新启动时保持不变。ROM中的数据是由制造商预先编程的,用户无法修改其内容。它通常用于存储固件、引导程序和其他永久性的系统数据。ROM的优点是数据的持久性和稳定性,即使在断电情况下也能保留数据。常见的ROM类型包括ROM、PROM(Programmable ROM)、EPROM(Erasable Programmable ROM)和EEPROM(Electrically Erasable Programmable ROM)。
RAM是一种随机访问存储器,用于临时存储计算机正在运行的数据和程序。RAM允许计算机以随机的顺序读取和写入数据,这使得存储器的访问速度非常快。RAM是易失性存储器,意味着当计算机断电时,存储在RAM中的数据将会丢失。RAM可以根据需要读取和写入数据,因此它对于计算机的实时操作非常重要。常见的RAM类型包括SRAM(Static RAM)和DRAM(Dynamic RAM)。
RAM和ROM在功能和特性上有很大的差异。RAM用于临时存储和处理数据,具有快速的读写速度,但数据不持久保存。ROM用于存储永久性数据和程序,不可修改,但数据的持久性较高。在计算机系统中,通常会同时使用RAM和ROM来满足不同的存储需求。
GNU AS和 AS86
GNU As(GNU汇编器)和 as86(GNU汇编器的一个特定版本)是两个不同的汇编器工具,它们具有以下区别:
- 功能和用途:
- GNU As:GNU As是GNU项目中的一部分,是一个通用的汇编器,支持多种处理器架构(如x86、ARM等)和不同的操作系统。
- as86:as86是GNU As的一个特定版本,专门用于处理x86架构的16位汇编语言。它主要用于早期的8086和80286处理器,并且适用于特定的操作系统,如DOS。
- 支持的架构:
- GNU As:GNU As是一个通用的汇编器,支持多种处理器架构,包括x86、ARM、MIPS、PowerPC等。
- as86:as86是为x86架构的16位汇编语言而设计的,主要用于早期的8086和80286处理器。
- 语法和特性:
- GNU As:GNU As使用AT&T语法,具有丰富的指令集和功能,支持宏汇编、条件汇编、符号表等高级特性。
- as86:as86通常使用Intel语法,语法更接近机器语言,功能相对较为简单,不支持高级特性。
- 可移植性:
- GNU As:GNU As具有广泛的可移植性,可在不同的操作系统和处理器架构上使用。
- as86:as86主要用于早期的x86架构和特定操作系统(如DOS),可移植性相对较低。
总的来说,GNU As是一个通用的汇编器,支持多种处理器架构和操作系统,而as86是GNU As的一个特定版本,专门用于处理早期的x86架构的16位汇编语言。
GNU AS语法
GNU As(GNU汇编器)使用AT&T语法,它与Intel语法在一些语法规则和指令书写上存在一些区别。
- 操作数顺序:AT&T语法使用源操作数在目的操作数之前的顺序,与Intel语法相反。 示例:
- AT&T语法:
movl %eax, %ebx
(将eax的值移动到ebx) - Intel语法:
mov ebx, eax
(将eax的值移动到ebx)
- AT&T语法:
- 寄存器表示:在AT&T语法中,寄存器名以
%
符号开头。 示例:- AT&T语法:
movl $42, %eax
(将立即数42移动到eax寄存器) - Intel语法:
mov eax, 42
(将立即数42移动到eax寄存器)
- AT&T语法:
- 立即数表示:在AT&T语法中,立即数以
$
符号开头。 示例:- AT&T语法:
movl $123, %ebx
(将立即数123移动到ebx寄存器) - Intel语法:
mov ebx, 123
(将立即数123移动到ebx寄存器)
- AT&T语法:
- 内存引用:在AT&T语法中,使用方括号
[]
表示内存引用,且地址放在括号内。 示例:- AT&T语法:
movl (%eax), %ebx
(将eax寄存器指向的内存位置的值移动到ebx寄存器) - Intel语法:
mov ebx, [eax]
(将eax寄存器指向的内存位置的值移动到ebx寄存器)
- AT&T语法:
- 注释:在AT&T语法中,使用分号
;
来表示注释。 示例:- AT&T语法:
addl %eax, %ebx ; 这是一个加法指令
(将eax的值加到ebx,并带有注释)
- AT&T语法:
这些是AT&T语法在GNU As中的一些基本规则和示例。要编写符合GNU As语法的汇编代码,可以参考GNU As的相关文档或参考资料。
AS86语法
AS86是一个特定版本的GNU As汇编器,用于处理x86架构的16位汇编语言。AS86使用的是Intel语法,与AT&T语法有所不同
直接寄存器寻址
mov bx, ax
将ax
的值直接复制到bx
寄存器。
间接寄存器寻址
mov [bx], ax
将ax
的值存储到bx
寄存器内容指定的内存位置上。
把 立即数1234 放入ax中,把 立即数msgl 放入ax中
mov ax, #1234
mov ax, #msgl
绝对寻址:将内存地址1234,内存地址msgl处的内容放入ax中
mov ax, 1234
mov ax, msgl
= mov ax, [msgl]
索引寻址
mov ax, msgl[bx]
将内存中以 msgl
加上 bx
寄存器的内容作为地址的位置上的值,读取到 ax
寄存器中。
- 计算内存地址:将
msgl
寄存器的内容与bx
寄存器的内容相加,得到内存地址。- 从内存中读取数据:从上一步计算得到的内存地址处读取数据。
- 将读取到的数据存储到
ax
寄存器:将读取到的数据移动到ax
寄存器中。
mov [msgl+17], ah
将寄存器AH的值写入到内存中
msgl
的地址加上17的位置上。
C程序编译过程
汇编程序如何调用执行C语言程序?
在x86汇编语言中,ESP(Extended Stack Pointer)和EBP(Extended Base Pointer)是两个寄存器,用于管理和访问程序运行时的堆栈(stack)。
- ESP(堆栈指针):ESP寄存器指向当前堆栈的栈顶,即最后一个压入堆栈的数据的位置。堆栈的增长方向是从高地址向低地址,所以ESP的值会随着数据的压入而减小,随着数据的弹出而增加。
- EBP(基指针):EBP寄存器用于建立一个指向当前函数堆栈帧(stack frame)的基准点。函数调用时,EBP通常会被设置为当前堆栈的值,然后用于在堆栈中访问函数参数和局部变量。通过使用EBP,可以在函数内部相对于堆栈帧的固定偏移量来访问变量,而不需要关心ESP的变化。
要在汇编程序中调用执行C语言程序,通常需要以下步骤:
编写C语言程序:首先,您需要编写一个C语言程序,实现所需的功能。保存该程序并确保已生成可执行文件。
准备汇编程序:接下来,您需要准备一个汇编程序,该程序将用于调用执行C语言程序。
设置堆栈:在汇编程序中,您需要设置堆栈指针(SP)和基指针(BP)以及其他必要的寄存器,以便在调用C语言程序时正确处理函数参数和返回值。
调用C语言程序:使用汇编指令,您可以调用C语言程序。您可以使用CALL指令将程序控制权传递给C语言程序的入口点,并使用RET指令从C语言程序返回到汇编程序。
处理函数参数和返回值:在调用C语言程序之前,您需要将函数参数加载到正确的寄存器或堆栈位置中。执行CALL指令后,C语言程序将在执行完毕后返回结果。您需要使用适当的方法来访问返回的结果。
本书规定:
若返回值是一个整数或一个指针,那么寄存器 eax 将被默认用来传递返回值
A调用B;
A必须需要保存EAX,EDX,ECX的值
B必须需要保存EBX, ESI, EDI的值
恢复堆栈:在从C语言程序返回到汇编程序后,您需要恢复堆栈指针(SP)和基指针(BP)以及其他寄存器的值。
x86汇编语言调用执行C语言程序
以下是一个使用x86汇编语言调用执行C语言程序的简单例子:
|
汇编程序(example.asm):
section .data ; 这是数据段的开始,用于定义数据段中的变量和常量。在这个例子中,定义了一个格式化字符串format,用于在printf中输出结果。 |
GNU AS语言调用执行C语言程序
.text |
leave |
LINUX源码分析
LINUX操作系统引导启动程序(boot/bootsect.s & setup.s & head.s)
电源打开后,80x86结构的CPU会进入实模式。【实模式是一种最初用于早期x86处理器的模式,它提供对低级硬件的基本访问能力】
CPU会从固定地址0xFFFF0开始执行代码。该地址上存储着ROM-BIOS的跳转指令。
BIOS执行系统的初始化和自检过程。它会进行一系列的硬件检测和配置,包括检测内存、处理器、硬盘、显卡等,并建立基本的中断向量表。
BIOS会从可启动设备的第一个扇区(磁盘的引导扇区)读取512字节的代码,将其加载到内存的绝对地址0x7C00处。
然后将整个系统从地址 0x10000 移至0x0000 处,进入保护模式并跳转至系统的余下部分(在0x0000处)。此时所有32 位运行方式的设置启动被完成:IDT、GDT 以及LDT 被加载,处理器和协处理器也己确认,分页工作也设置好了;
最终调用 init/main.c 中的main()程序。上述操作的源代码是在 boot/head.s中的。注意如果在前述任何一步中出了错,计算机就会死锁。
另外,仅在内存中加载了上述内核代码模块并不能让Linux 系统运行起来。完整可运行的 Linux系统还需要有一个基本的根文件系统。Linux 0.11 内核仅支持 MINIX 的 1.0 文件系统。根文件系统通常是在另一个软盘上或者在一个硬盘分区中。为了通知内核所需要的根文件系统在什么地方,bootsect.s 程序的第 43 行上给出了根文件系统所在的默认块设备号。在内核初始化时会使用编译内校时放在引导扇区第 509、510 (0x1fc-0x1fd)字节中的指定设备号。
总结:
s