C和内存中的资源保护
C and resource protection in memory
当我们编译C程序时,它只是生成一些机器可理解的代码。这段代码可以直接在硬件上运行,从this question.
所以我的问题是:
如果一个C程序可以直接在硬件上运行,内核如何处理这个程序的资源分配?
如果编译器生成的可执行文件是纯机器可理解的形式,那么特权模式和非特权模式如何工作?
如果程序不通过内核直接在硬件上运行,内核如何管理硬件资源的权限?
虽然程序是机器代码,但要执行不在其自己的内存区域内的任何操作,它需要通过系统调用[=19]调用内核=].
CPU实际上有代码特权的概念。非特权代码不能直接访问物理内存等;它 必须 通过 OS 并要求它授予访问权限。
因此,每个程序都直接在 CPU 上执行 运行,但这并不意味着它可以对硬件执行任何操作 – 有针对此的硬件测量。您需要做某些事情的特权就是其中之一。
how can kernel handle the resource allocation to this program
内核提供分配内存、I/O(写入屏幕、与network/sound卡交互)等功能和机制,称为系统调用 到用户程序。这些系统调用是内核和用户程序之间的接口,唉,硬件和用户程序之间的接口。
how do the privileged and non-privileged mode work?
用户程序处于非特权模式(用户空间),而内核运行处于特权模式(内核空间)。用户不可信,所以如果他搞砸了(例如,访问更高权限的内存或取消引用空指针),他就会被阻止(例如,通过分段错误和随后的程序终止)。
另一方面,内核 运行 处于特权模式。它可以为所欲为:写入用户空间程序,从用户程序中窃取数据(如密码),写入处理器的固件 - 一切。此外,还有不同种类的内核:单片内核和微内核是最重的(这个词是否存在?)使用过的内核。
Linux(由 Linus Torvalds 发起)是单体内核的一个例子。在这里,内核就是一个大系统,每一段内核代码都有系统的最终访问权限。
Minix(由 Andrew S. Tanenbaum 发起)是微内核的一个例子。可以访问所有内容的部分相当小。它仅包含必须具有特权的功能(管理 MMU、访问硬件)等。其他功能,如文件系统,运行 在非特权模式下,它们通过通常采用的保护机制免受可能的错误在用户空间(非特权模式)中,如分段错误。
Linus Torvalds(当时有人创建了 OS)和 Andrew S. Tanenbaum 之间关于 benefits/drawbacks 整体内核和微内核的有趣读物是 debate (当时一位知名的 CS 教授;写了一些 惊人的 书,顺便说一句)。
a program can directly run on hardware not through the kernel
它确实运行直接在硬件上,由CPU执行。 它不能直接访问某些资源,但是,如内存,并且,为了访问这些资源,需要与内核交互。这是对早期 OS 类似 DOS 的主要改进之一(仅次于虚拟处理器,即进程):用户空间程序不能 运行 直接在硬件上。如果可以的话,他们可能会以无法修复的原因(有意的 - 如病毒,或无意的)弄乱整个机器。相反,如本答案开头所述,使用系统调用。
在 DOS 中,您有 选项 来使用 OS 提供的例程(通常是在 IV(中断向量,偏移量(和物理内存地址)到实模式 IDT(中断描述符 Table))0x21(通过 int 0x21
/int 21h
调用),而 ax
包含一个函数编号来标识调用到系统1)。与现在 available 但 not 严格执行的机制大致相同。可以覆盖整个 OS,用自己的程序替换它并破坏机器(例如,将随机值加载到 CMOS 寄存器中)。也可以只使用 BIOS 提供的例程,绕过 OS.
1 我在这里特意用了 "call to the system" 而不是 "system call" 。在这里,系统调用仅表示从用户空间到内核空间为其做某事的请求。由于 DOS(即实模式)没有提供用户空间和内核空间之间的真正区别,它实际上没有系统调用。
If a C program can directly run on the
hardware how can kernel handle the resource allocation to this
program.
内核负责管理整个计算机的资源,包括硬件等资源。这意味着,对于能够访问硬件设备、写入终端或读取文件等内容的用户级应用程序,它们必须向内核请求许可。正如@Marcus 所述,这是通过使用 OS 公开的 系统调用 完成的。
但是,我不会说 运行 程序 直接 在硬件 上不像内核 module/driver 那样直接与硬件交互。客户端程序将为系统调用设置参数,然后中断内核并等待内核服务程序发出的中断请求。
这就是为什么今天的 OSes 在 保护模式 下被称为 运行,而不是过去 运行例如,在 实模式 中,程序可能会直接乱用硬件资源——并可能把事情搞砸。
如果您尝试用 x86 汇编编写一个简单的 "hello world" 程序,这种区别就会变得非常明显。 this one 几年前写过记录,转载如下:
;
; This program runs in 32-bit protected mode.
; build: nasm -f elf -F stabs name.asm
; link: ld -o name name.o
;
; In 64-bit long mode you can use 64-bit registers (e.g. rax instead of eax, rbx instead of ebx, etc.)
; Also change "-f elf " for "-f elf64" in build command.
;
section .data ; section for initialized data
str: db 'Hello world!', 0Ah ; message string with new-line char at the end (10 decimal)
str_len: equ $ - str ; calcs length of string (bytes) by subtracting the str's start address
; from this address ($ symbol)
section .text ; this is the code section
global _start ; _start is the entry point and needs global scope to be 'seen' by the
; linker --equivalent to main() in C/C++
_start: ; definition of _start procedure begins here
mov eax, 4 ; specify the sys_write function code (from OS vector table)
mov ebx, 1 ; specify file descriptor stdout --in gnu/linux, everything's treated as a file,
; even hardware devices
mov ecx, str ; move start _address_ of string message to ecx register
mov edx, str_len ; move length of message (in bytes)
int 80h ; interrupt kernel to perform the system call we just set up -
; in gnu/linux services are requested through the kernel
mov eax, 1 ; specify sys_exit function code (from OS vector table)
mov ebx, 0 ; specify return code for OS (zero tells OS everything went fine)
int 80h ; interrupt kernel to perform system call (to exit)
注意程序如何设置写入系统调用,sys_write
,然后指定写入位置的文件描述符,stdout
,要写入的字符串,等等。
也就是说程序本身不执行写操作;它设置事情并要求内核通过使用特殊中断 int 80h
.
代表它来完成
一个可能的类比是你去餐馆运行t。服务器将接受您的订单,但厨师是负责烹饪的人。在这个类比中,您是用户级应用程序,为您点菜的服务器是系统调用,而厨房里的厨师是 OS 内核。
If the executable generated from the gcc is in pure machine
understandable form then how do the privileged and non-privileged mode
work?
从上一节开始,用户级程序始终运行处于用户模式。当程序需要访问某些东西(例如终端、读取文件等)时,它会进行设置,就像上面的 sys_write
示例一样,并要求内核通过中断代表它来完成。中断导致程序进入 kernel 模式并保持在那里,直到内核完成对客户端请求的服务——这可能包括完全拒绝它(例如,试图读取用户拥有的文件没有阅读权限)。
在内部,系统调用负责发出 int 80h
指令。用户级应用程序只看到系统调用,这是客户端和 OS.
之间的公共接口
How does the kernel manage the permission of hardware resources when a
program can directly run on hardware not through the kernel?
如果您按照前面的解释进行操作,您现在可以看到内核充当 看门人 并且通过使用 [=13] 在这个门上编程 "knock" =] 指令.
So my first question is if a C program can directly run on the hardware how can kernel handle the resource allocation to this program.
CPUs 在执行代码时带有特权的概念。例如,在 x86 上有一个实模式允许代码访问任何资源,和一个保护模式代码在不同的security rings。大多数操作系统将切换到保护模式,其中数字较低的环意味着较高的权限。
内核通常在 Ring 0 中执行,可以直接访问硬件,而用户程序 运行 在限制访问的 Ring 3 中执行。当用户程序需要访问特权资源时,CPU 隐式或直接通过 系统调用 指令(例如 syscall
在 x86-64 汇编中)。
If the executable generated from the gcc is in pure machine understandable form then how do the privileged and non-privileged mode work?
同样,CPU 检查内存访问之类的事情。因此,例如,如果程序试图访问它没有权限的 virtual address,操作系统会捕获无效页面访问并通常向进程发出信号(即 SIGSEGV
)。
How does the kernel manage the permission of hardware resources when a program can directly run on hardware not through the kernel?
CPU 必须通过特定的 control registers 和 table 直接与操作系统交互。例如,虚拟地址页table的地址存储在CR3
寄存器中,对于x86.
当我们编译C程序时,它只是生成一些机器可理解的代码。这段代码可以直接在硬件上运行,从this question.
所以我的问题是:
如果一个C程序可以直接在硬件上运行,内核如何处理这个程序的资源分配?
如果编译器生成的可执行文件是纯机器可理解的形式,那么特权模式和非特权模式如何工作?
如果程序不通过内核直接在硬件上运行,内核如何管理硬件资源的权限?
虽然程序是机器代码,但要执行不在其自己的内存区域内的任何操作,它需要通过系统调用[=19]调用内核=].
CPU实际上有代码特权的概念。非特权代码不能直接访问物理内存等;它 必须 通过 OS 并要求它授予访问权限。
因此,每个程序都直接在 CPU 上执行 运行,但这并不意味着它可以对硬件执行任何操作 – 有针对此的硬件测量。您需要做某些事情的特权就是其中之一。
how can kernel handle the resource allocation to this program
内核提供分配内存、I/O(写入屏幕、与network/sound卡交互)等功能和机制,称为系统调用 到用户程序。这些系统调用是内核和用户程序之间的接口,唉,硬件和用户程序之间的接口。
how do the privileged and non-privileged mode work?
用户程序处于非特权模式(用户空间),而内核运行处于特权模式(内核空间)。用户不可信,所以如果他搞砸了(例如,访问更高权限的内存或取消引用空指针),他就会被阻止(例如,通过分段错误和随后的程序终止)。
另一方面,内核 运行 处于特权模式。它可以为所欲为:写入用户空间程序,从用户程序中窃取数据(如密码),写入处理器的固件 - 一切。此外,还有不同种类的内核:单片内核和微内核是最重的(这个词是否存在?)使用过的内核。
Linux(由 Linus Torvalds 发起)是单体内核的一个例子。在这里,内核就是一个大系统,每一段内核代码都有系统的最终访问权限。
Minix(由 Andrew S. Tanenbaum 发起)是微内核的一个例子。可以访问所有内容的部分相当小。它仅包含必须具有特权的功能(管理 MMU、访问硬件)等。其他功能,如文件系统,运行 在非特权模式下,它们通过通常采用的保护机制免受可能的错误在用户空间(非特权模式)中,如分段错误。
Linus Torvalds(当时有人创建了 OS)和 Andrew S. Tanenbaum 之间关于 benefits/drawbacks 整体内核和微内核的有趣读物是 debate (当时一位知名的 CS 教授;写了一些 惊人的 书,顺便说一句)。
a program can directly run on hardware not through the kernel
它确实运行直接在硬件上,由CPU执行。 它不能直接访问某些资源,但是,如内存,并且,为了访问这些资源,需要与内核交互。这是对早期 OS 类似 DOS 的主要改进之一(仅次于虚拟处理器,即进程):用户空间程序不能 运行 直接在硬件上。如果可以的话,他们可能会以无法修复的原因(有意的 - 如病毒,或无意的)弄乱整个机器。相反,如本答案开头所述,使用系统调用。
在 DOS 中,您有 选项 来使用 OS 提供的例程(通常是在 IV(中断向量,偏移量(和物理内存地址)到实模式 IDT(中断描述符 Table))0x21(通过 int 0x21
/int 21h
调用),而 ax
包含一个函数编号来标识调用到系统1)。与现在 available 但 not 严格执行的机制大致相同。可以覆盖整个 OS,用自己的程序替换它并破坏机器(例如,将随机值加载到 CMOS 寄存器中)。也可以只使用 BIOS 提供的例程,绕过 OS.
1 我在这里特意用了 "call to the system" 而不是 "system call" 。在这里,系统调用仅表示从用户空间到内核空间为其做某事的请求。由于 DOS(即实模式)没有提供用户空间和内核空间之间的真正区别,它实际上没有系统调用。
If a C program can directly run on the hardware how can kernel handle the resource allocation to this program.
内核负责管理整个计算机的资源,包括硬件等资源。这意味着,对于能够访问硬件设备、写入终端或读取文件等内容的用户级应用程序,它们必须向内核请求许可。正如@Marcus 所述,这是通过使用 OS 公开的 系统调用 完成的。
但是,我不会说 运行 程序 直接 在硬件 上不像内核 module/driver 那样直接与硬件交互。客户端程序将为系统调用设置参数,然后中断内核并等待内核服务程序发出的中断请求。
这就是为什么今天的 OSes 在 保护模式 下被称为 运行,而不是过去 运行例如,在 实模式 中,程序可能会直接乱用硬件资源——并可能把事情搞砸。
如果您尝试用 x86 汇编编写一个简单的 "hello world" 程序,这种区别就会变得非常明显。 this one 几年前写过记录,转载如下:
;
; This program runs in 32-bit protected mode.
; build: nasm -f elf -F stabs name.asm
; link: ld -o name name.o
;
; In 64-bit long mode you can use 64-bit registers (e.g. rax instead of eax, rbx instead of ebx, etc.)
; Also change "-f elf " for "-f elf64" in build command.
;
section .data ; section for initialized data
str: db 'Hello world!', 0Ah ; message string with new-line char at the end (10 decimal)
str_len: equ $ - str ; calcs length of string (bytes) by subtracting the str's start address
; from this address ($ symbol)
section .text ; this is the code section
global _start ; _start is the entry point and needs global scope to be 'seen' by the
; linker --equivalent to main() in C/C++
_start: ; definition of _start procedure begins here
mov eax, 4 ; specify the sys_write function code (from OS vector table)
mov ebx, 1 ; specify file descriptor stdout --in gnu/linux, everything's treated as a file,
; even hardware devices
mov ecx, str ; move start _address_ of string message to ecx register
mov edx, str_len ; move length of message (in bytes)
int 80h ; interrupt kernel to perform the system call we just set up -
; in gnu/linux services are requested through the kernel
mov eax, 1 ; specify sys_exit function code (from OS vector table)
mov ebx, 0 ; specify return code for OS (zero tells OS everything went fine)
int 80h ; interrupt kernel to perform system call (to exit)
注意程序如何设置写入系统调用,sys_write
,然后指定写入位置的文件描述符,stdout
,要写入的字符串,等等。
也就是说程序本身不执行写操作;它设置事情并要求内核通过使用特殊中断 int 80h
.
一个可能的类比是你去餐馆运行t。服务器将接受您的订单,但厨师是负责烹饪的人。在这个类比中,您是用户级应用程序,为您点菜的服务器是系统调用,而厨房里的厨师是 OS 内核。
If the executable generated from the gcc is in pure machine understandable form then how do the privileged and non-privileged mode work?
从上一节开始,用户级程序始终运行处于用户模式。当程序需要访问某些东西(例如终端、读取文件等)时,它会进行设置,就像上面的 sys_write
示例一样,并要求内核通过中断代表它来完成。中断导致程序进入 kernel 模式并保持在那里,直到内核完成对客户端请求的服务——这可能包括完全拒绝它(例如,试图读取用户拥有的文件没有阅读权限)。
在内部,系统调用负责发出 int 80h
指令。用户级应用程序只看到系统调用,这是客户端和 OS.
How does the kernel manage the permission of hardware resources when a program can directly run on hardware not through the kernel?
如果您按照前面的解释进行操作,您现在可以看到内核充当 看门人 并且通过使用 [=13] 在这个门上编程 "knock" =] 指令.
So my first question is if a C program can directly run on the hardware how can kernel handle the resource allocation to this program.
CPUs 在执行代码时带有特权的概念。例如,在 x86 上有一个实模式允许代码访问任何资源,和一个保护模式代码在不同的security rings。大多数操作系统将切换到保护模式,其中数字较低的环意味着较高的权限。
内核通常在 Ring 0 中执行,可以直接访问硬件,而用户程序 运行 在限制访问的 Ring 3 中执行。当用户程序需要访问特权资源时,CPU 隐式或直接通过 系统调用 指令(例如 syscall
在 x86-64 汇编中)。
If the executable generated from the gcc is in pure machine understandable form then how do the privileged and non-privileged mode work?
同样,CPU 检查内存访问之类的事情。因此,例如,如果程序试图访问它没有权限的 virtual address,操作系统会捕获无效页面访问并通常向进程发出信号(即 SIGSEGV
)。
How does the kernel manage the permission of hardware resources when a program can directly run on hardware not through the kernel?
CPU 必须通过特定的 control registers 和 table 直接与操作系统交互。例如,虚拟地址页table的地址存储在CR3
寄存器中,对于x86.