程序员的自我修养-第六章-可执行文件的装载与进程
。
我们知道每个程序被运行起来以后,它将拥有自己独立的虚拟地址空间(Virtual Address Space),
装载方式程序执行时,需要把指令和数据装入内存。很多情况下,程序所需的内存数量大于物理内存的数量,一种方法是添加物理内存。另一种方式是利用程序局部性原理,采用动态装入。主要分为两类:覆盖装入,页映射。
从操作系统角度看可执行文件的装载进程建立从操作系统的角度来看,一个进程最关键的特征是它拥有独立的虚拟地址空间,这使得它有别于其他进程。装载可执行文件并执行,主要分为三步~。
创建一个独立的虚拟地址空间。
读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系。
将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。
首先是创建虚拟地址空间。回忆第1章的页映射机制,我们知道一个虚拟空间由一组页映射函数将虚拟空间的各个页映射至相应的物理空间,那么创建一个虚拟空间实际上并不是创建空间而是创建映射函数所需要的相应的数据结构,在i386 的Linux下,创建虚拟地址空间实际上只是分配一个页目录(Page Directory)就可以了(mm_struct 吗?),甚至不设置页 ...
ppt_linux_1
。。
工作方式:
第三章-进程管理
.
本书主要分析的是 linux 2.6 版本的内容,不同版本之间可能有较大的差别
linux小知识点
.
如何学习
有压力才有动力,前面也是小打小闹
学linux不能和单片机一样,先要跑通,有精力再研究细节。
esp 与 bsp
esp是栈指针,是cpu机制决定的,push、pop指令会自动调整esp的值;
ebp只是存取某时刻的esp,这个时刻就是进入一个函数内后,cpu会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数,局部变量等,实际上使用esp也可以;
既然使用esp也可以,那么为什么要设定ebp呢?
答案是为了方便程序员。
因为esp在函数运行时会不断的变化,所以保存一个一进入某个函数的esp到ebp中会方便程序员访问参数和局部变量,而且还方便调试器分析函数调用过程中的堆栈情况。前面说了,这个ebp不是必须要有的,你非要使用esp来访问函数参数和局部变量也是可行的,只不过这样会麻烦一些。原文链接:
一些文件夹
根目录下的很多文件夹都只是个索引,都指向usr(unix system resource)里面
12345678910111213141516171819202122232425lrwxrwxrwx 1 root roo ...
实习面试
自我介绍
讲一下项目,程序架构是什么样的,在程序里做什么事情,怎么交互的。
如何保证代码实时性。
任务是如何切换的,
有涉及内存管理和分配吗
如何实现内存堆或内存池
除了iic通讯,还用过其他通讯方式吗
网络通讯这块使用过吗,lwip之类的。
会涉及到函数指针之类的吗。
两个矩形,已知8个定点,判断两个矩形是否相交,相交的话给出相交点的坐标
使用过spi通讯吗
涉及到两片mcu直接通讯吗
反问:入职后干啥
一块芯片,fpga负责采集图像点集数据, arm核负责控制转发管理。主要负责arm核程序编写,涉及内存管理,两块mcu通讯,对效率要求比较高的程序。
两个字搞定面试:不会~~~~~~~~~~
动态链接
。
内存空间分布:在linux中,每个进程都有自己独立的4G内存空间。其中内核会用3G以上的1G虚拟内存地址,0-3G的虚拟内存空间可以被一个进程的用户态或内核态访问,但3-4G只能被进程的内核态访问。这里讲的空间是可以寻址的空间,不是说每一个进程都可以用满4G空间。3-4G中,896M是直接映射到物理地址的,128M按需映射896M以上的所谓高位内存。内核用的896M虚拟地址是直接映射的,意思是只要把虚拟地址减去一个偏移量(3G)就等于物理地址。各进程用的是同一个内核(内核区对于所有进程是共享的;系统中所有进程对应的虚拟地址空间的内核区都会映射到同一块物理内存上(系统内核只有一个))。同样,这里指的还是寻址,实际使用前还是要分配内存。而且896M只是个最大值。如果物理内存小,内核能使用(分配)的可用内存也小。
为什么地址不冲突:一个进程用到的虚拟地址是由内存区域表来管理的,实际用不了4G。而用到的内存区域,会通过页表映射到物理内存。所以每个进程都可以使用同样的虚拟内存地址而不冲突,因为它们的物理地址实际上是不同的。每个进程进程一个页表,页表的起始地址放在进程的pcb中,当某进程运行时 ...
程序员的自我修养-第四章-静态链接
.
链接方式:相似段合并,主要分为两步:
链接方式: ld a.o b.o -e main -o ab,
不知道为什么会一直报这个错 a.c:(.text+0x4f): undefined reference to `__stack_chk_fail’
解决方法,在编译时加上 -fno-stack-protector标志,注意不是在链接时加
123456789ttj@ttj ~/copy [1]> gcc -c a.c -fno-stack-protector -o a.oa.c: In function ‘main’:a.c:4:1: warning: implicit declaration of function ‘swap’ [-Wimplicit-function-declaration] 4 | swap(&a, &shared); | ^~~~ttj@ttj ~/copy> gcc -c b.c -fno-stack-protector -o b.ottj@ttj ~/copy> ld a.o b.o -e ...
常见排序算法
。
冒泡排序12345678910111213141516171819202122232425#include "bits/stdc++.h"using namespace std;/** * flag == 1 从小到大 * flag == 2 从大到小*/int bubbleSort(vector<int> &vec, int flag){//冒泡排序 int temp; for(int i = vec.size()-1; i > 0; i--){ for(int j = 0; j < i; j++){ if(vec[j] > vec[j+1] && flag == 1){ vec[j+1] = vec[j+1]^vec[j];//这样使用虽然可以提高速度,但是一定要保证变换的是两个量,否则会出错 vec[j] = vec[j+1]^vec[j]; ...
程序员的自我修养-第三章
.
linux 环境下,可以使用 file 命令查看 elf 文件类型
目标文件一个简单的目标文件
文件头描述了文件的文件熟悉:是否可执行,目标硬件,段表等。段表描述了文件中各个段在文件中的偏移位置及段的属性等。
.text 保存编译后的机器代码
.data 保存已初始化的全局变量和局部静态变量
.bss 保存未初始化的全局变量和局部静态变量(局部变量会保存到栈中),.bss段只是为未初始化的全局变量和局部静态变量预留位置而已,它并没有内容,所以它在文件中也不占据空间。
之后使用如下文件进行分析
使用 objdump 工具可以查看 object 文件的结构。(linux 下还有个工具 readelf 可以解析 elf 文件格式)
1objdump -h SimpleSection.o
与书籍内容类似:
他的 ELF 结构:
代码段objdump 的 -s 参数可以把所有段的内容以十六进制打印出来
objdump 的 -d 参数可以把所有包含指令的段反汇编
objdump -s -d SimpleSection.o
对比反汇编的开始和结束f3, ...
程序员的自我修养-第二章
。
从源文件到目标文件的整个流程1gcc hello.c
预处理(Prepressing)
编译(Compilation)
汇编(Assembly)
链接(Linking)
预处理(预编译)12gcc –E hello.c –o hello.i 或者cpp hello.c > hello.i
主要用于删除/替换宏定义,处理 #include 指令,删除注释,添加行号,文件名标识便于调试,保留 #pragma 编译命令
编译123gcc –S hello.i –o hello.s 或者cc1 hello.c(cc1可以完成预编译和编译)或者gcc –S hello.c –o hello.s
完成词法分析,语法分析,语义分析,优化后生成汇编代码文件。
汇编12as hello.s –o hello.o 或者gcc –c hello.c –o hello.o
一条汇编语言对应一条机器指令,汇编器要完成的任务很简单,将汇编指令翻译为机器指令就行了。(计算标号地址算么)
链接12例子:$ld -static /usr/lib/crt1.o /usr/li ...