Linux内核期末复习
1、P22-25
2、P36、P165

call指令的作用:
将当前 CS:EIP 的值压入栈顶,CS:EIP 指向别调用的函数的入口地址。
ret指令的作用:
从栈顶弹出原来保存在这里的 CS:EIP 的值,放入 CS:EIP 中。
进程切换时用什么函数
schedule()

_switch_to_函数如何理解 怎么实现

简易实现:

// 定义进程控制块(PCB)结构体
struct pcb {
// 进程ID等信息
int pid;
// 寄存器状态等上下文信息
// 这里假设只保存了通用寄存器eax和ebx
int eax;
int ebx;
};
// 全局变量,当前运行的进程
struct pcb *current_process;
// 简化版的_switch_to_函数
void _switch_to_(struct pcb *next_process) {
// 保存当前进程的寄存器状态
current_process->eax = eax;
current_process->ebx = ebx;
// 加载下一个进程的寄存器状态
eax = next_process->eax;
ebx = next_process->ebx;
// 将当前进程更新为下一个进程
current_process = next_process;
}
3、gcc、gdb命令


gdb

堆栈汇编典型示例:

反汇编指令:
objdump [options] <file>

4、内嵌汇编(10号系统调用)
#include <stdio.h>
int main() {
long result;
long syscall_number = 10; // 10号系统调用的编号
long arg1 = 1; // 参数1
long arg2 = 2; // 参数2
asm volatile (
"mov %1, %%rax\n\t" // 将系统调用号存入寄存器rax
"mov %2, %%rdi\n\t" // 将参数1存入寄存器rdi
"mov %3, %%rsi\n\t" // 将参数2存入寄存器rsi
"syscall\n\t" // 进行系统调用
"mov %%rax, %0\n\t" // 将返回值存入变量result
: "=r" (result) // 输出操作数:返回值存入result
: "r" (syscall_number), "r" (arg1), "r" (arg2) // 输入操作数:系统调用号、参数1、参数2
: "%rax", "%rdi", "%rsi" // 受影响的寄存器
);
printf("Result: %ld\n", result);
return 0;
}
5、fork()系统调用



0、1、2号进程

fork()内核机制
fork()通过clone()进入内核态,clone()调用do_fork(),创建一个新的进程,并复制当前进程的所有上下文信息(包括程序代码、数据、堆栈、文件描述符等)到新进程中,将子进程设为就绪状态,放入调度器,当在适当的时候被调度时,内核会给子进程分配唯一的PID,更新子进程的资源使用情况,接下来,内核会更新子进程的页表,使得子进程拥有自己的虚拟地址空间,并与父进程共享物理内存页(使用写时复制机制),子进程从fork()位置开始执行。
写时复制:
-
在
fork()调用时,父进程的所有内存页都被标记为"只读"。 -
当父进程或子进程试图修改一个共享的内存页时,操作系统内核会接收到一个页面错误(Page Fault)异常。
-
在页面错误处理程序中,内核会为子进程分配一个新的物理内存页,并将父进程的内容复制到新的内存页中。
-
然后,内核更新子进程的页表,将修改后的内存页映射到子进程的虚拟地址空间中。



为什么fork()子进程返回到ret_from_fork后
为了保证子进程在正确的位置开始执行,可以正常返回用户态,而不是继续执行父进程的代码。
execve函数

int execve(const char *filename, char *const argv[], char *const envp[]);
其中,argv[]是一个以NULL结尾的字符串数组,用于传递命令行参数给新程序。每个字符串元素都是一个命令行参数,第一个元素通常是可执行文件的名称。
envp[]是一个以NULL结尾的字符串数组,用于传递环境变量给新程序。每个字符串元素都是一个环境变量,形如"key=value"的格式。
#include <unistd.h>
int main() {
char *const argv[] = { "program", "arg1", "arg2", NULL };
char *const envp[] = { "VAR1=value1", "VAR2=value2", NULL };
execve("/path/to/program", argv, envp);
// execve函数执行成功后,下面的代码不会被执行到,
// 因为进程已经被替换为新程序。
// 如果execve函数执行失败,会返回-1,并根据errno设置相应的错误码。
return 0;
}
6、ELF



怎么映射到内存:
使用execve系统调用
符号表、重定位

7、



8、


浙公网安备 33010602011771号