Chinaunix首页 | 论坛 | 博客
  • 博客访问: 546276
  • 博文数量: 51
  • 博客积分: 345
  • 博客等级: 民兵
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-21 12:02
个人简介

文章分类

全部博文(51)

文章存档

2023年(2)

2022年(1)

2021年(7)

2020年(10)

2019年(2)

2016年(20)

2015年(5)

2014年(1)

2011年(3)

我的朋友

分类: LINUX

2021-09-17 16:41:46

特殊段定义在linux linker 脚本中(区别于默认的链接脚本),这些脚本存储在arch目录树下的kernel/vmlinux.lds.S,如arm64的链接脚本:linux/arch/arm64/kernel/vmlinux.lds.S

该文件使用了linux/include/asm-generic/vmlinux.lds.h头文件中的宏定义。

本文介绍一个特殊段, __ex_table pairs of instruction pointer 它存储了一对指令的指针。
定义如下:

#define _ASM_EXTABLE(from, to)                        \

    "    .pushsection    __ex_table, \"a\"\n"            \

    "    .align        3\n"                    \

    "    .long        (" #from " - .), (" #to " - .)\n"    \

    "    .popsection\n"


允许页面错误异常处理程序( page fault exception handler) 来确定异常是否是由地址“from”的内核指令引起的,如果是,跳转到地址“to” 该地址是fixup修复代码起始地址,否则发生内核错误。

看一下内核代码中对 exception table structure的解释呃

/*

* The exception table consists of pairs of relative offsets: the first

* is the relative offset to an instruction that is allowed to fault,

* and the second is the relative offset at which the program should

* continue. No registers are modified, so it is entirely up to the

* continuation code to figure out what to do.

*

* All the routines below use bits of fixup code that are out of line

* with the main instruction path.  This means when everything is well,

* we don't even have to jump over them.  Further, they do not intrude

* on our cache or tlb entries.

*/

存储了一对相对偏移地址;

insn:     可能发生“fault”的指令的相对偏移

fixup  发生“fault”后,程序继续执行的指令的相对偏移

这期间没有寄存器发生改变;

 

struct exception_table_entry

{

    int insn, fixup;

}; 


怎么理解这里的相对偏移呐?是偏移到哪里呐?

涉及到两个section.fixup      __ex_table;它们的定义可以从链接脚本中找到。

 linux/arch/arm64/kernel/vmlinux.lds.S中,看到了 


.fixup
定义在 .text (很熟悉),就是代码段;



RO_DATA() 从名字中可以看到这是一些只读信息,里面存放什么呐,
 linux/include/asm-generic/vmlinux.lds.h 能找到答案。
可以看到RO_DATA宏定义中,包含了只读的__ex_table

.fixup
  __ex_table 如何配合使用的?
看一个代码片段:


代码片段出现了两个section

fixup为发生异常后的修复代码;

__ex_table仅仅是存储了两个label的地址;

 

这段汇编的意思是,为“1:”处的指令注册了修复程序,修复程序的入口是“3:”,若是“1:”处指令发生了异常,最终会跳转到“3:”处的指令来执行。

 

 

关于语句:_ASM_EXTABLE(1b, 3b)

这里 1b, 3bGNU语法,称为数字本地标签(numeric local label),

使用以下语法来引用numeric local label

n{f|b}

n是数字本地标签,范围是0-99

f b用来指示汇编程序向前或者向后搜索。



kernel是如何实现地址匹配以及如何跳转到修复代码段的?

 fixup_exception可以找到答案,首先针对给定的地址来查找是否注册了异常表,若查找成功,则修改pc值进行跳转。





来解读一下查找exception table的过程,可以看到计算__ex_table表项对应指令地址的过程用到了偏移地址,上面提到了_ASM_EXTABLE(1b, 3b)语句存储了两个label,经过链接程序处理,存储的值最终被替换为__ex_table表项相距label的偏移地址。



 

再次梳理一下,

某一条指令可能会引发异常,但是我们还想挽救一下,试图去修复看看,so,将目标指令的地址和修复代码的首地址放在__ex_table段中。 修复代码单独存放在名为fixup的段中。

kernel运行时,真的发生了异常,handler就去查找__ex_table段,看是否针对当前发生异常的指令注册了fixup 处理程序;若找到了就尝试运行。虽然可能还是失败


阅读(1288) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~