Bionic libc & ucore

21
Bionic libc & ucore 沈沈 2008012108 沈沈 2008012100

description

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

Transcript of Bionic libc & ucore

Page 1: Bionic  libc  &  ucore

Bionic libc & ucore

沈彤 2008012108张超 2008012100

Page 2: Bionic  libc  &  ucore

Bionic libc 编译• 前期:只下载 bionic libc 的源码– 修改 bionic libc 使之能编译通过,东拼西凑,费力不讨好– 隐患:很多宏不知道是否应该定义,可能对代码造成较大影响

• 后期:使用 Android-x86 项目– 无需再手动修改 bionic libc– Android-x86 项目已经实现了 Android 在部分

x86 机型上的运行,正确性把握较大

Page 3: Bionic  libc  &  ucore

syscall 连接• 将 ucore 中原有的 syscall 调用全部改为 int

0x81 ,将 bionic libc 使用的 syscall 调用设置为 int 0x80• 好处:两套 syscall 机制不会互相干扰, ucore 原有的机制不会被破坏;同时

bionic libc 的 syscall 方便单独进行调试• 坏处:有不少几乎完全相同的 syscall ,需要重复写一次

Page 4: Bionic  libc  &  ucore

syscall 实现• 多数 syscall 可以直接利用 ucore 已有的

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

signal 。

Page 5: Bionic  libc  &  ucore

signal data struct

• sigset_t 信号集合 用 uint64_t 替代uint32_t[2]

• sigpending, sigqueue 挂起队列• sigaction 信号处理函数• signal_struct 信号描述符• sighand_struct 信号处理描述符• sigframe 神奇的结构

Page 6: Bionic  libc  &  ucore

signal syscalls

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

Page 7: Bionic  libc  &  ucore

产生信号 一个进程• do_tkill() 得到进程描述符,关中断、获取信号锁,调用 specific_send_sig_info() ,释放锁、开中断。• specific_send_sig_info() 检查信号是否会被忽略,检查信号是否是非实时的,调用

send_signal() 将信号加入进程的私有等待队列中。对非阻塞信号,调用 signal_wakeup() 将进程唤醒。

Page 8: Bionic  libc  &  ucore

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

Page 9: Bionic  libc  &  ucore

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

Page 10: Bionic  libc  &  ucore

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

Page 11: Bionic  libc  &  ucore

test1

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

Page 12: Bionic  libc  &  ucore

test2

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

Page 13: Bionic  libc  &  ucore

动态链接——原理• 内核态准备工作:– 通过可执行文件是否包含 PT_INTERP“段”,判断其为动态链接或静态链接– 将可执行文件的 PT_LOAD 的“段”都载入内存–若为动态链接,可执行文件必包含 PT_INTERP

“段”,该“段”的内容为动态链接器的路径。将动态链接器的 PT_LOAD“段”都载入内存– 动态链接器和可执行程序本身的装载地址就是链接地址,无需重定位

Page 14: Bionic  libc  &  ucore

动态链接——原理• 内核态准备工作:–若为动态链接,将 eip 置为动态链接器的入口;否则,将 eip 置为可执行文件的入口– 设置初始堆栈。若为动态链接,堆栈中需要有一些动态链接器需要的信息。 Android 的动态链接器叫做 linker ,其源码中体现出只需要三项:

• AT_PHDR : program header 在内存中的地址• AT_PHNUM : program header 个数• AT_ENTRY :可执行文件的入口

– glibc 需要的更多此类信息

Page 15: Bionic  libc  &  ucore

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

Page 16: Bionic  libc  &  ucore

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

Page 17: Bionic  libc  &  ucore

mmap file

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

Page 18: Bionic  libc  &  ucore

mmap file失败的尝试• 我们尝试如下实现 mmap文件:– mmap文件时,给相应 vma 加入文件信息( struct file 指针),不立即载入内存– 发生缺页中断时,检查 vma 是否是 mmap文件的 vma 。如果是,将文件读取一页载入相应内存

• 更进一步地,实现共享文件的映射:– 在 struct file 中,加入被 mmap 的信息,包括:被 mmap 起始偏移、长度、起始物理内存地址– 第一次缺页时,新申请一页空间,将文件内容载入页中,并将 mmap 信息设置好– 以后再缺页时,如果是同一块被 mmap 的区域,直接将页表项改为已被 mmap 到的物理地址

Page 19: Bionic  libc  &  ucore

mmap anonymous

• 另外,动态链接器还有 mmap带有标志MAP_ANONYMOUS 的行为

• 我们对它的理解:它用来预留一块虚存地址空间,以后可以在这块预留空间上进一步 mmap ,这是其他 mmap 不允许的• 因此,给 vma 加上 ANONYMOUS标志位。如果碰到这样的情况,先分配 vma ;进一步分配时,将这个 vma 分裂即可。

Page 20: Bionic  libc  &  ucore

Dalvikvm失败的尝试• 第九周、第十周精力主要在尝试运行

dalvikvm 上• 成功的在 Android 的 ARM模拟器上运行

dalvikvm ,并跑出 Hello world 程序• 未能在 x86 Linux 上运行成功。初期加载动态链接库等阶段都已完成,是在 dalvikvm 开始初始化的时候出错的。错误信息是无法加载某个国际化语言模块。 Google 很久,无果。

Page 21: Bionic  libc  &  ucore

glibc失败的尝试• 一度 bionic libc 动态链接不能成功,尝试跑出 glibc的动态链接(现在看来很荒谬)。• 成功编译出 glibc ,在 Linux 上用编译出的 glibc 替代本机的 glibc ,能够正常运行。• 在 ucore 上始终提示 assert failed ,想修改 glibc 源码使之多输出一些调试信息(例如 __FILE__,

__LINE__ ),竟然未能成功。• glibc 比 bionic libc 复杂得多需要更多的 syscall ,更多的动态链接信息,还有很多不太了解的编译参数,最终作罢。