1 / 21

Bionic libc & ucore

Bionic libc & ucore. 沈彤 2008012108 张 超 2008012100. Bionic libc 编译. 前 期:只下载 bionic libc 的源码 修改 bionic libc 使之能编译通过,东拼西凑,费力不讨好 隐患:很多宏不知道是否应该定义,可能对代码造成较大影响 后期:使用 Android-x86 项目 无需 再手动修改 bionic libc Android-x86 项目已经实现了 Android 在部分 x86 机型上的运行,正确性把握较大. s yscall 连接.

noel
Download Presentation

Bionic libc & ucore

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Bionic libc & ucore 沈彤 2008012108 张超 2008012100

  2. Bionic libc 编译 • 前期:只下载bionic libc的源码 • 修改bionic libc使之能编译通过,东拼西凑,费力不讨好 • 隐患:很多宏不知道是否应该定义,可能对代码造成较大影响 • 后期:使用Android-x86项目 • 无需再手动修改bionic libc • Android-x86项目已经实现了Android在部分x86机型上的运行,正确性把握较大

  3. syscall 连接 • 将ucore中原有的syscall调用全部改为int 0x81,将bionic libc使用的syscall调用设置为int 0x80 • 好处:两套syscall机制不会互相干扰,ucore原有的机制不会被破坏;同时bionic libc的syscall方便单独进行调试 • 坏处:有不少几乎完全相同的syscall,需要重复写一次

  4. syscall实现 • 多数syscall可以直接利用ucore已有的syscall。 • 部分可以用ucore有,但没有用到过的函数,比如利用vfs_readlink()完成readlink()系统调用。 • 此外还有一些需要改变接口,如brk, mmap的参数、返回值不一样。 • 剩下的就是需要我们自己实现的,比如signal。

  5. signal data struct • sigset_t信号集合 用uint64_t替代uint32_t[2] • sigpending, sigqueue挂起队列 • sigaction信号处理函数 • signal_struct信号描述符 • sighand_struct信号处理描述符 • sigframe神奇的结构

  6. signal syscalls • kill()和tkill() 产生并发送信号 • sigaction() 设置信号处理函数 • sigprocmask() 设置或解除阻塞信号 • sigpending() 获取挂起的阻塞信号 • sigsuspend() 等待一些信号 • sigaltstack() 设置信号处理函数栈地址

  7. 产生信号一个进程 • do_tkill() 得到进程描述符,关中断、获取信号锁,调用specific_send_sig_info(),释放锁、开中断。 • specific_send_sig_info() 检查信号是否会被忽略,检查信号是否是非实时的,调用send_signal() 将信号加入进程的私有等待队列中。对非阻塞信号,调用signal_wakeup() 将进程唤醒。

  8. 产生信号线程组 • do_kill() 调用group_send_sig_info() • group_send_sig_info() 检查信号是否需要被产生,调用send_signal()将其加入进程的共享等待队列中。 • handle_stop_signal() 实现信号的相互屏蔽。 • group_complete_signal() 从线程组中选择一个合适的进程,并用signal_wakeup()唤醒它。

  9. 默认的处理 • 中断结束时调用do_signal() • do_signal() 不断的调用dequeue_signal() 获取下一个信号。 • 对每个信号,如果是SIGKILL或SIGSTOP则直接终止或停止该进程所在线程组,否则如果处理方式是SIG_IGN则忽略 • SIG_DFL 判断信号的类型,有些信号的默认操作有忽略、停止线程组、终止线程组。

  10. 用户指定的处理函数 • sigframe • 保存trapframe阻塞信号 • 参数和返回地址 • 神奇的数字movl $400, %eax; int $0x80 • 修改eipesp • sigreturn系统调用 恢复

  11. test1 • 产生信号给一个进程 • 测试sigaction() sigprocmask() tkill() • 信号处理函数的调用(包括在自定义信号处理函数中使用系统调用) • SIGKILL终止进程

  12. test2 • 产生信号给一个线程组 • 测试sigsuspend()kill_bionic() • SIGSTOP停止线程组 • SIGKILL终止线程组

  13. 动态链接——原理 • 内核态准备工作: • 通过可执行文件是否包含PT_INTERP“段”,判断其为动态链接或静态链接 • 将可执行文件的PT_LOAD的“段”都载入内存 • 若为动态链接,可执行文件必包含PT_INTERP“段”,该“段”的内容为动态链接器的路径。将动态链接器的PT_LOAD“段”都载入内存 • 动态链接器和可执行程序本身的装载地址就是链接地址,无需重定位

  14. 动态链接——原理 • 内核态准备工作: • 若为动态链接,将eip置为动态链接器的入口;否则,将eip置为可执行文件的入口 • 设置初始堆栈。若为动态链接,堆栈中需要有一些动态链接器需要的信息。Android的动态链接器叫做linker,其源码中体现出只需要三项: • AT_PHDR:program header在内存中的地址 • AT_PHNUM:program header个数 • AT_ENTRY:可执行文件的入口 • glibc需要的更多此类信息

  15. 动态链接——原理 • 用户态: • 若为动态链接,先执行的将是动态链接器。 • 动态链接器根据内核在堆栈中放置的辅助信息,找到PT_DYNAMIC“段”。这个段中存放着动态链接器需要的一切信息 • 例如,该段中类型为DT_NEED的项表示该可执行程序依赖的动态链接库的名称在strtab段中的序号,由此动态链接器可以得到需要加载的动态链接库的名称

  16. 动态链接——原理 • 用户态: • 动态链接库的链接地址一般从0x0开始,由动态链接器选择可用地址作为基地址后加载。 • 加载完动态链接库之后,需要对动态链接库的每一个重定位项(包括变量和函数)进行重定位,具体机制可参见《程序员的自我修养——链接、装载与库》

  17. mmap file • 动态链接器加载动态链接库是通过mmap文件的方法,而ucore的mmap是在文件系统出现以前就有的,从而没有mmap文件的功能 • 我们的做法:如果mmap传进了fd参数,就在mmap的末尾把文件相应的部分直接读入内存,并在vma中存储文件的相关信息;在munmap时把内存写回文件。

  18. mmap file失败的尝试 • 我们尝试如下实现mmap文件: • mmap文件时,给相应vma加入文件信息(struct file指针),不立即载入内存 • 发生缺页中断时,检查vma是否是mmap文件的vma。如果是,将文件读取一页载入相应内存 • 更进一步地,实现共享文件的映射: • 在struct file中,加入被mmap的信息,包括:被mmap起始偏移、长度、起始物理内存地址 • 第一次缺页时,新申请一页空间,将文件内容载入页中,并将mmap信息设置好 • 以后再缺页时,如果是同一块被mmap的区域,直接将页表项改为已被mmap到的物理地址

  19. mmap anonymous • 另外,动态链接器还有mmap带有标志MAP_ANONYMOUS的行为 • 我们对它的理解:它用来预留一块虚存地址空间,以后可以在这块预留空间上进一步mmap,这是其他mmap不允许的 • 因此,给vma加上ANONYMOUS标志位。如果碰到这样的情况,先分配vma;进一步分配时,将这个vma分裂即可。

  20. Dalvikvm失败的尝试 • 第九周、第十周精力主要在尝试运行dalvikvm上 • 成功的在Android的ARM模拟器上运行dalvikvm,并跑出Hello world程序 • 未能在x86 Linux上运行成功。初期加载动态链接库等阶段都已完成,是在dalvikvm开始初始化的时候出错的。错误信息是无法加载某个国际化语言模块。Google很久,无果。

  21. glibc失败的尝试 • 一度bionic libc动态链接不能成功,尝试跑出glibc的动态链接(现在看来很荒谬)。 • 成功编译出glibc,在Linux上用编译出的glibc替代本机的glibc,能够正常运行。 • 在ucore上始终提示assert failed,想修改glibc源码使之多输出一些调试信息(例如__FILE__, __LINE__),竟然未能成功。 • glibc比bionic libc复杂得多需要更多的syscall,更多的动态链接信息,还有很多不太了解的编译参数,最终作罢。

More Related