程序员的自我修养-第八章
。
共享库版本兼容性共享库的更新可能兼容可能不兼容。
以前还以为这种库提供的接口只是属于API层面,现在看看其实这些接口属于ABI层面。因为这些库(以ELF文件形式存在的动态链接文件)其中的一些操作,比如参数传递方式、虚函数表、多重继承等都给出了明确定义,但这些东西在库的使用者电脑上可能是完全不同的,这就可能导致兼容性问题。
其实想想啊,如果不是以共享库的形式,而是以源代码的形式提供给用户,是不是接口就只是在API层面,就不用考虑ABI层面的兼容问题了呢?
共享库命名方式
主版本,不同号码,可以不兼容
次版本,高级的可以兼容低级的,一般是增加一些接口
发布版本号,一般是修改库的错误,性能,不提供新接口
不遵守规则的库,比如 /lib/x86_64-linux-gnu/libc-2.31.so
SO-NAMELinux使用一种SO-NAME的方式来记录共享库的依赖关系。SO-NAME就是去掉第二个和第三个版本号剩下的部分。系统会为每个共享库在他的目录创建一个和SO-NAME相同的软链接指向该库。标准格式:libfoo.so.2. ...
程序员的自我修养-第七章
。
之前写过一点动态链接的内容:动态链接
为什么要用动态链接太浪费空间,很多公共库函数在内存中有很多副本。
程序开发和发布不易,尤其是使用到第三方厂商提供的库时。
动态链接:将链接推迟到运行时再进行。
可拓展性:动态链接还有一个特点就是可以在运行时动态的加载各种程序模块,这个优点就是后来被人们用来制作程序的插件(Plug-in)。
缺陷:由于新旧模块接口不兼容,导致原来程序无法运行,如windows 中的 dll hell。
动态链接的基本实现:
动态链接涉及运行时的链接及多个文件的装载,必需要有操作系统的支持,因为动态链接的情况下,进程的虚拟地址空间的分布会比静态链接情况下更为复杂,还有一些存储管理、内存共享、进程线程等机制在动态链接下也会有一些微妙的变化。
动态链接例子编写代码如下:
1234567891011121314151617181920212223242526272829303132ttj@ttj ~/c/shell> more prog1.c prog2.c lib.c lib.h::::::::::::::prog1.c::::::::::::::#in ...
程序员的自我修养-第六章-可执行文件的装载与进程
。
我们知道每个程序被运行起来以后,它将拥有自己独立的虚拟地址空间(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]; ...