免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3096 | 回复: 8
打印 上一主题 下一主题

[内核入门] gcc中内嵌汇编 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-11-07 12:09 |只看该作者 |倒序浏览
各位大牛,帮忙解析下,如下代码的含义:
在这里先拜谢了!!!

#define __get_user_asm_word(x,addr,err)                                \
        __asm__ __volatile__(                                        \
        "1:        " TUSER(ldr) "        %1,[%2],#0\n"                        \
        "2:\n"                                                        \
        "        .pushsection .fixup,\"ax\"\n"                        \
        "        .align        2\n"                                        \
        "3:        mov        %0, %3\n"                                \
        "        mov        %1, #0\n"                                \
        "        b        2b\n"                                        \
        "        .popsection\n"                                        \
        "        .pushsection __ex_table,\"a\"\n"                \
        "        .align        3\n"                                        \
        "        .long        1b, 3b\n"                                \
        "        .popsection"                                        \
        : "+r" (err), "=&r" (x)                                        \
        : "r" (addr), "i" (-EFAULT)                                \
        : "cc")

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
2 [报告]
发表于 2013-11-07 13:08 |只看该作者
本帖最后由 asuka2001 于 2013-11-07 13:16 编辑

回复 1# xiaojsj

对内嵌汇编不算特别熟,大概解释下:

%0对应err, %1对应x,%2对应addr, %3对应 -EFAULT
        "1:        " TUSER(ldr) "        %1,[%2],#0\n"                        \
        "2:\n"                                                        \
这一段是实际的读取指令,相当于 ldr x, [addr], #0,从地址addr处读取,并保存到x
        "        .pushsection .fixup,\"ax\"\n"                        \
        "        .align        2\n"                                        \
        "3:        mov        %0, %3\n"                                \
        "        mov        %1, #0\n"                                \
        "        b        2b\n"                                        \
        "        .popsection\n"                                        \
.pushsection到 .popsection之间的代码不放到上面那条实际读取指令之后,而是要求gcc放到 fixup段去,它的功能实际上就是

err = -EFAULT
goto 2:
        "        .pushsection __ex_table,\"a\"\n"                \
        "        .align        3\n"                                        \
        "        .long        1b, 3b\n"                                \
        "        .popsection"                                        \
同样,.pushsection到 .popsection之间的代码不放到上面那条实际读取指令之后,要求gcc放到 __ext_table段去,它是保存了两个地址,其含义相当于

struct exception_table_entry
{
        unsigned long insn, fixup;
} entry;
entry.insn = 1:
entry.fixup = 3:

然后把 entry添加到 exception_table中去,如果对其感兴趣,可以查看 search_exception_table()

1:, 2:, 3:代表的是标号所处的指令的地址。




   

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
3 [报告]
发表于 2013-11-07 13:15 |只看该作者
回复 1# xiaojsj

其中后面这2大堆就是一个意思,一旦我们执行第一条指令出现了 page fault,这个时候异常处理流程就会使用导致异常出现的指令的地址去搜索 exception_table

这个时候就能找到我们所保存的 struct exception_table_entry entry,然后异常处理流程会跳转到 entry.fixup去执行。

我们的entry.fixup指向的是标号 3:所处的指令,也就是说向 err赋值为 -EFAULT,跳转回标号 2:所处的指令,也就是相当于从第一条指令后面继续执行了。


   

论坛徽章:
0
4 [报告]
发表于 2013-11-08 09:25 |只看该作者
明白了,谢谢哈,你讲的很清楚。回复 3# asuka2001


   

论坛徽章:
0
5 [报告]
发表于 2013-11-08 09:41 |只看该作者
我另外还有如下一个问题:
就是当去取用户空间地址上的数据时,如果这个时候还真就发生了异常(譬如这个时候该段地址已经不在内存中),那程序最终会跑到异常处理代码中去,并且通过返回值说明刚才的读取指令发生了错误。

我的疑问就是:当异常发生后,知道了要读取的用户空间地址不在内存,为什么不把该地址的内容加载到内存,从而避免只是简单的错误返回呢?
如果是错误返回了,是不是此次系统调用就失败了?
那如果该用户空间的地址真不在内存了,那该系统调用,是不是就会一直都失败呢?
回复 3# asuka2001


   

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
6 [报告]
发表于 2013-11-08 10:52 |只看该作者
回复 5# xiaojsj

让你误解了,这里我是为了说明后面两段代码的作用,只以用户空间程序传给了内核非法的虚拟地址为例:即虚拟地址不在合法的 vma中,也不在用户栈可扩展区域。

我省略了一些其他的“合法” page fault流程:比如用户空间的页被 swap out,mmap的区域或者分配的内存还未实际建立页表项等。
   

论坛徽章:
0
7 [报告]
发表于 2013-11-09 09:35 |只看该作者
那如果是后面你说的两种情况之一:
                 a: 比如用户空间的页被 swap out,
                 b: mmap的区域或者分配的内存还未实际建立页表项等
这个时候又恰巧,有系统调用,从用户空间读取数据到内核空间,会发生什么?

能大概把这个情景模式分析一下吗?
谢谢!




回复 6# asuka2001


   

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
8 [报告]
发表于 2013-11-11 13:35 |只看该作者
回复 7# xiaojsj

这些情况都是可以在当前进程的 mm中查找到合法的 vma:
被 swap out的就读回来。

mmap的就通过 vm_operations_struct->fault() 去读取内容好了。如果是文件,那么一般就会调用到 filemap_fault(),然后从 vma找到对应的 address_space,已经在 page cache里的,建立个页表映射过去就是,没有的就调用 address_space->a_ops->readpage()读取到 page cache,然后同上。

没实际分配内存的,通过页分配器分配物理页框,填好页表。

然后直接返回到你执行的指令处继续运行就OK。

详细细节我也没有去研究,你如果有兴趣,也可以直接去看代码

1. 向量跳转表位于 arch/arm/kernel/entry_armv.S中的 __vectors_start与 __vectors_end间,page fault对应的是 vector_dabt

2. early_trap_init() [arch/arm/kernel/traps.c]负责将向量跳转表搬运到0xFFFF0000

3. 根据 CPU所处模式,page fault跳转到对应的 __dabt_usr, __dabt_svc, 或者 __dabt_invalid [arch/arm/kernel/entry_armv.S]

4. __dabt_usr, __dabt_svc均调用 dabt_helper [arch/arm/kernel/entry_armv.S], 注意这里 r2保存有 pt_regs

5. dabt_helper会跳转到 CPU_DABORT_HANDLER,这个宏在 arch/arm/include/asm中根据 CPU型号定义, 如 v7_early_abort() [arch/arm/mm/abort_ev7.S]

6. v7_early_abort()读取 cpsr寄存器, 将 FAR (Fault Address Register), FSR (Fault Status Register)保存到 r0, r1; 然后调用 do_DataAbort() [arch/arm/mm/fault.c]

7. 现在进入 c代码调用链

do_DataAbort(): 根据 fsr查询对应的异常处理函数表 fsr_info[]
        inf->fn(): 调用该处理函数
                do_page_fault()
                        __do_page_fault()
                                handle_mm_fault()

从 handle_mm_fault() [mm/memory.c]开始脱离体系相关代码

handle_mm_fault()
        handle_pte_fault()
                do_linear_fault()
                do_anonymous_page()
                do_nonlinear_fault()
                do_swap_page()

   

论坛徽章:
0
9 [报告]
发表于 2013-11-11 19:51 |只看该作者

谢谢!·
回复 8# asuka2001


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP