linux启动过程,上电后执行的第一部分代码(ARM为bootrom,X86为BIOS),针对多核CPU启动过程如下图:
执行init进程,其pid=1,通过pstree查看系统进程树。
Init->p1->p2->p3,p2为p1子进程,如果p2死,则p1知道,如果p1死,则init知道。可以在父进程中重启子进程。
用户空间(非GPL),C库(LGPL),linux内核(GPL),通过ltrace查看用户空间代码调用的库函数,通过strace查看用户空间代码调用的系统调用。
Strace –T ./a.out显示调用时间
动态链接使用,将相同的符号名函数进行覆盖
LD_PRELOAD=./wrapper.so ./proc
如在代码中有malloc,本来是调用library中的malloc,此时用户wrapper.so中含有malloc,动态链接时调用的为wrapper.so中的malloc。
备注:动态链接中可以声明构造函数,该函数在main函数执行前执行,声明方式为
void helperinit(void) __attribute__((constructor));
编译动态链接库命令为 gcc -shared -fPIC pthread-helper.c -o pthread-helper.so -lpthread –ldl
编译多线程 gcc –pthread
文件系统中三个文件夹很重要,它们均为基于内存的文件系统,硬盘中找不到。
/proc内部存放内核的状态,属性等,
/sys查看所有的设备信息
/dev设备文件节点
可以在/proc中实现cpu热插拔,echo 0 > /sys/devices/system/cpu/cpu1/online 关闭CPU1
硬实时,相应时间永远不超过一个固定时限,最恶劣的情况下也不例外。软实时,恶劣环境下相应时间会大大增加。
Cyclictest –p 80 –t5 –n测试内核时延,重点看max
工具属于GNU(GNU’S NOT UNIX)
Gprof显示程序执行过程耗时和瓶颈
Nm列出程序中的符号表信息,用strip清除符号后,nm无信息显示
Objdump反汇编,objdump –S 能看到源代码(前提编译时有debug信息)
Gcov白盒测试,代码覆盖率
Readelf能够看出程序需要的库以及动态链接库信息
Elf三种格式(有debug信息有符号表gcc -g,无debug信息有符号表gcc,无debug信息无符号表strip)
分为-o, -o1,-o2,-o3,-o0,-os代码最小优化,一般程序确保-o2优化
编译优化注意读写合并和编译乱序问题
A=1,a=2,a=3->a=3
A=b+1,b=0 b先赋值给r0,再将0赋值给b,将r0+1赋值给a
乱序执行,对于多核之间需要采用mutex指令(内含iowmb屏障指令,保证前面指令全部执行完毕)确保执行正确,单核不需要进行软件控制。
代码执行时先跳转到PLT查看相关函数,此时GOT中找不到该函数的函数指针,第一次执行时不知道调用函数的位置,需要通过interpret进行查找填入GOT表中,修改函数指针。以后执行可直接找到函数执行。
常用调试方法
A)事前
R执行,b设置断点,n单步不进入内部,s进入内部单步,ni,si对应汇编程序单步
显示代码ctrl+x 再按A,显示汇编 ctrl+x 再按2
Bt显示堆栈调用信息
P var显示值,p &var显示地址,p var=201 修改变量值
X/3W 0x99999显示内存值 按字显示 X/3b按字节显示 X/100W 显示100个
Set*(int*)0x99999=2018修改内存值
Finish完成堆栈中最上面一层的调用
B)事中
Pidof a.out查看执行进程的 pid
Gdb attach pid添加到正在执行的进程中调试
Set scheduler-locking on在多线程环境下,关闭其他线程,只执行该线程
C)事后
采用core dump方式
Ulimit –c unlimited
Sudo sh –c ‘echo core > /proc/sys/kernel/core_pattern’
./exam
此时程序崩溃,产生core文件
Gdb ./exam –c core就可以分析文件