《linux 内核完全剖析》 由逻辑地址转换成线性地址代码分析 get_base get_limit 代码分析笔记
2014-04-29 10:11
776 查看
一开始由这段代码引发的纠结
下面是各个相关的代码,摘自不同的header files。。。
current是指向当前task的指针
事实证明(说的直接点就是代码看不懂),前面的8086保护模式编程是相当重要的,是理论基础。我现在越来越理解汤老师的话,只有坚实的理论基础,才能更好的实践。
不复习分页保护模式,这段代码是看不懂的,而且一开始我特别纠结
为什么取addr的偏移量偏偏就是2 4 7
通过ldt(locale descriptor table)可以找到它映射的物理地址空间。
这个结构体里面的 a b 是unsigned long类型,8 byte长, 32位
对应的是段描述符, 贴图吧。。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/21/60d004cba2f3a2790e03a272e133b2eb)
ldt[1],是代码段,ldt[2]数据段,ldt[0]为空,至于为什么,现在。。。我也布吉岛。。。
get_base传参的方式有点技巧,他传递了ldt的地址
然而这里的ldt其实是一个指针current->ldt[1] ,于是这里的addr是一个指针,这个对于理解为什么addr偏移2 4 7“至关重要”。。。
但是我觉得赵炯博士的解释说明图和具体代码对应的时候,是有点问题的。
我纠结了很久这里的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)
数据段描述符是对应结构体
这个获取基地址就很好解释了。
首先 取addr+4开始的8个位,置于寄存器%dl,取addr+7开始的8个位置于寄存器%dh
然后左移16位,把刚移入的16位数据(本来在寄存器中的低16位),移位到高16位
取addr+2开始的16位,置于寄存器%dx,也就是%edx的低16位。
这样edx就被填满了。是 segment base!
update:2014.05.07
删除了之前错误的观点,增添了getlimit的分析
#define get_limit(segment) ({ \
unsigned long __limit; \
__asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \
__limit;})
segment是段选择符
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/21/25933be195f3585570719e9860fb4744)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/21/fb7d7bc3eb071a2bf2cac3cfe89c83ab)
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; } ;
#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!
update:2014.05.07
删除了之前错误的观点,增添了getlimit的分析
#define get_limit(segment) ({ \
unsigned long __limit; \
__asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \
__limit;})
segment是段选择符
相关文章推荐
- 《linux 内核完全剖析》sched.c sched.h 代码分析笔记
- 《linux 内核完全剖析》 signal.c 代码分析笔记
- 《linux 内核完全剖析》 fork.c 代码分析笔记
- 《linux 内核完全剖析》 exit.c 代码分析笔记
- 《linux 内核全然剖析》 fork.c 代码分析笔记
- 《linux 内核完全剖析》 sys.c 代码分析
- 《linux 内核完全剖析》 vsprintf.c 代码笔记
- 《linux 内核完全剖析》 keyboard.S 部分代码分析(key_map)
- Linux-0.11内核源码分析系列:关于线性地址,逻辑地址,物理地址的关系与区别
- 《linux 内核完全剖析》 笔记 CODE_SPACE 宏定义分析
- linux内核完全剖析——基于0.12内核-笔记(1)-CPU 数据通信
- <<Linux内核完全剖析 --基于0.12内核>>学习笔记 第4章 80x86保护模式及其编程 4.3 分段机制
- <<Linux内核完全剖析 --基于0.12内核>>学习笔记 第4章 80x86保护模式及其编程 4.8 保护模式编程初始化
- LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境
- linux内核完全剖析 学习笔记 打字太累 截图 持续更新
- <<Linux内核完全剖析 --基于0.12内核>>学习笔记 第4章 80x86保护模式及其编程 4.5 保护
- Linux内存管理:逻辑地址到线性地址和物理地址的转换
- 《linux 内核完全剖析》get_free_page(void)【嵌入式汇编复习看这里】
- linux内核完全剖析---linux0.00-050613/rh9 makefile分析
- 《linux 内核完全剖析》 void free_page() 分析