《linux 内核完全剖析》 笔记 由逻辑地址转换成线性地址代码分析

一开始由这段代码引发的纠结

get_base(current->ldt[1])

下面是各个相关的代码,摘自不同的header files。。。

current是指向当前task的指针

struct desc_struct ldt[3];
struct desc_struct {
unsigned long a,b;
} ;
#define _get_base(addr) ({unsigned long __base; __asm__("movb %3,%%dh\n\t" "movb %2,%%dl\n\t" "shll $16,%%edx\n\t" "movw %1,%%dx" :"=d" (__base) :"m" (*((addr)+2)), "m" (*((addr)+4)), "m" (*((addr)+7))); __base;})
#define get_base(ldt) _get_base( ((char *)&(ldt)) )

事实证明(说的直接点就是代码看不懂),前面的8086保护模式编程是相当重要的,是理论基础。我现在越来越理解汤老师的话,只有坚实的理论基础,才能更好的实践。

不复习分页保护模式,这段代码是看不懂的,而且一开始我特别纠结

 :"m" (*((addr)+2)),  "m" (*((addr)+4)),  "m" (*((addr)+7))); \

为什么取addr的偏移量偏偏就是2 4 7

通过ldt(locale descriptor table)可以找到它映射的物理地址空间。

struct desc_struct {
unsigned long a,b;
} ;

这个结构体里面的 a b 是unsigned long类型,8 byte长, 32位

对应的是段描述符, 贴图吧。。

ldt[1],是代码段,ldt[2]数据段,ldt[0]为空,至于为什么,现在。。。我也布吉岛。。。

get_base传参的方式有点技巧,他传递了ldt的地址

然而这里的ldt其实是一个指针current->ldt[1] ,于是这里的addr是一个指针,这个对于理解为什么addr偏移2 4 7“至关重要”。。。

#define get_base(ldt) _get_base( ((char *)&(ldt)) )

但是我觉得赵炯博士的解释说明图和具体代码对应的时候,是有点问题的。

我纠结了很久这里的addr+2 addr+4 addr+7究竟指向哪儿了。

事实上

addr+2是指向那个有16位长度的base address的(0-15)

addr+4是指向那个有最右边的8位base address(16-23)

addr+7是指向那个最左边的8为base address的(24-31)

数据段描述符是对应结构体

struct desc_struct {
unsigned long a,b;
} ;

那么这里的a 对应的应该是下面的那个32位长度描述符

b对应的应该是上面那个32位长度的描述符,这样一来,图片这样说明可能更好

这样说明才能对应结构体a b在内存地址中的状态

#define _get_base(addr) ({unsigned long __base; __asm__("movb %3,%%dh\n\t" "movb %2,%%dl\n\t" "shll $16,%%edx\n\t" "movw %1,%%dx" :"=d" (__base) :"m" (*((addr)+2)),  "m" (*((addr)+4)),  "m" (*((addr)+7))); __base;})

这个获取基地址就很好解释了。

首先 取addr+4开始的8个位,置于寄存器%dl,取addr+7开始的8个位置于寄存器%dh

然后左移16位,把刚移入的16位数据(本来在寄存器中的低16位),移位到高16位

取addr+2开始的16位,置于寄存器%dx,也就是%edx的低16位。

这样edx就被填满了。是 segment base!

《linux 内核完全剖析》 笔记 由逻辑地址转换成线性地址代码分析,码迷,mamicode.com

时间: 2024-10-06 10:23:10

《linux 内核完全剖析》 笔记 由逻辑地址转换成线性地址代码分析的相关文章

《linux 内核完全剖析》sched.c sched.h 代码分析笔记

sched.c sched.h 代码分析笔记 首先上header file sched.h #ifndef _SCHED_H #define _SCHED_H #define HZ 100 #define NR_TASKS 64 #define TASK_SIZE 0x04000000 #define LIBRARY_SIZE 0x00400000 #if (TASK_SIZE & 0x3fffff) #error "TASK_SIZE must be multiple of 4M&qu

《linux 内核完全剖析》 signal.c 代码分析笔记

signal.c 代码分析笔记 sgetmask int sys_sgetmask()// 获取当前进程阻塞的信号 { returncurrent->blocked; } sys_ssetmask int sys_ssetmask(int newmask) //设置当前进程阻塞信号,确保SIGKILL 和SIGSTOP不被阻塞 { int old=current->blocked; current->blocked= newmask & ~(1<<(SIGKILL-1

《linux 内核完全剖析》 exit.c 代码分析笔记

exit.c 代码分析笔记 release 释放进程的函数release() 主要根据指定进程的任务数据结构指针,在任务数组中删除指定的进程指针,释放相关内存页,并立刻让内核重新调度进程的运行. void release(struct task_struct * p) //释放p指向的进程 { int i; if (!p) //常规检测p是否为0 return; if (p == current) { //不能把自己给释放了 printk("task releasing itself\n\r&q

《linux 内核完全剖析》 fork.c 代码分析笔记

fork.c 代码分析笔记 verifiy_area long last_pid=0; //全局变量,用来记录目前最大的pid数值 void verify_area(void * addr,int size) // addr 是虚拟地址 ,size是需要写入的字节大小 { unsigned long start; start = (unsigned long) addr; //把地址强制类型转换之后,赋值给start size += start & 0xfff; //取addr在当前虚拟地址中4

《linux 内核完全剖析》 笔记 CODE_SPACE 宏定义分析

在memory.c里面,遇到一个宏定义,如下: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < current->start_code + current->end_code) 看的第一眼,不知道,第二眼,还是不知道,纠结了半天还是不知道. 睡了一晚,今天早上再看,嘿嘿,居然看懂了... 这个宏定义用于判断给定的addr线性地址是否位于当前进程的代码段中. 4095 = 0xFFF; addr+4095的作用是将位于0~4095

《linux 内核完全剖析》 vsprintf.c 代码笔记

Flex1 到 Flex3 使用的都是 Halo组件,这里将介绍Halo 组件中的List 和 DataGrid .其中 DataGrid 是显示多列数据中最常用的方式.但是在Spark中还有没对应DataGrid的组件. 先写个"食物"的模型 Dinner.as . package model { [Bindable] public class Dinner { public var name:String; public var food:String; public var du

《linux 内核完全剖析》chapter 13 内存管理 (不含swap.c)

内存管理(memory.c 和swap.s 部分) "倒着看" 先看memory management,很明显,前面各种阻力,都是因为涉及内存管理.不先看这个,我估计前面看了也是白看 我估算着理论打基础砸了差不多一个星期的时间在memory management上面了...感觉很有收获,是时候用实践(code)印证理论了! <modern operating system>讲内存管理那一章 http://blog.csdn.net/cinmyheart/article/de

Linux内核架构读书笔记 - 2.5.3 处理优先级

1 优先级的内核表示 内核使用 0 - 139 表示内部优先级,值越低,优先级越高.0 -99 实时进程使用 nice 值 [-20,19]映射到范围100 - 139,如下图 内核定义了一系列宏来辅助优先级之间的转换 sched.h 1 /* 2 * Priority of a process goes from 0..MAX_PRIO-1, valid RT 3 * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH 4 *

《linux 内核完全剖析》上帝为什么是右移20,而不是22! dir = (unsigned long *) ((from&gt;&gt;20) &amp; 0xffc)

在memory.c里面有这么一段代码.为了其中的一句话,让我内牛满面啊! dir = (unsigned long *) ((from>>20) & 0xffc) int free_page_tables(unsigned long from,unsigned long size) { unsigned long *pg_table; unsigned long * dir, nr; if (from & 0x3fffff) panic("free_page_tabl