程序员的自我修养-第十一章
运行库
入口函数和程序初始化程序从main开始吗
程序员的自我修养-第十章
内存
程序的内存布局
栈与调用惯例什么是栈
栈会保存一个函数调用所需要的维护信息(又名堆栈帧或活动记录),它包含:
函数的返回地址和参数
临时变量
保存的上下文(应该是自己的上下文,而不是调用自己的函数的上下文吧)
活动记录由ebp和esp这两个寄存器来划分范围。
感觉上图ebp的位置有一点问题,应该指向old ebp才对,看下面的i386函数体开头
之所以活动记录是这样的,是因为函数调用本身就是这么设计的:
i386下的函数调用:
把所有或一部分参数压入栈中,如果有其他参数没有入栈,那么使用某些特定的寄存器传递。
把当前指令的下一条指令的地址压入栈中。
跳转到函数体执行。
i386下的函数体开头
push ebp:把 ebp 压入栈中(称为 old ebp)。
mov ebp, esp:ebp = esp(这时 ebp 指向栈顶,而此时栈顶就是 old ebp)。
【可选】sub esp, XXX:在栈上分配 XXX 字节的临时空间。
【可选】push XXX:如有必要,保存名为 XXX 寄存器(可重复多个)。
函数返回的标准结尾
【可 ...
linux内核设计与实现
内核简介单内核&微内核单内核:作为一个单独的大过程运行,运行在单独的地址空间上(不就是单个进程吗?),内核之间的通信很方便。
微内核:内核的功能被划分为多个单独的过程,每一个过程叫做一个服务器,某些服务器运行在用户空间,有些运行在内核空间中,所以不同服务器之间的通过消息传递机制通信:系统采用了IPC机制。但是,IPC特别消耗资源,所以现在的微内核的服务器都运行在内核空间上,可以直接进行通信。
Linux内核的特点
可以动态加载内核模块
支持SMP机制,
内核可以抢占,在内核的任务优先执行
对线程的支持,内核不区分线程、进程,只是有些共享资源而已
进程管理进程描述符与任务结构内核将进程的列表存放在叫任务队列的双向循环链表中,链表的每一项都是类型为task_struct的进程描述符的东西(ucos的TCB)。他其中包含的内容有:打开的文件、地址空间、挂起的信号等。
分配进程描述符在内核栈的尾端会存放任务的thread_info, 他其中会包含指向进程描述符的指针:
进程描述符的存放进程描述符中的state描述了当前的状态,包含如下五个:
运行:可执行的;要么正在执行,要么在 ...
操作系统-精髓与设计原理
概述指令的执行最简单指令处理包含两步:读取执行、执行指令。PC保存下一次要取的指令地址。取到的指令放到IR中。指令执行的动作分为四类:
从处理器到存储器传数据
从处理器到IO传数据
处理数据,加减
控制,指定下一次指令从某个地方读取
中断中断和指令周期
长IO等待:IO程序执行的时间太长,导致新WRITE调用来了,旧的WRITE操作还没有完全完成,所有新WRITE操作必须阻塞,等到第一次WRITE完成才行。
对于右侧的长IO等待,在IO操作未完成时,与用户指令的执行有重叠,正是这部分指令导致了效率的提高。
中断处理中断激活了很多事件,包括处理器硬件的事件和软件的事件(要注意那些是硬件完成的,哪些是软件完成的,廖总经常强调的)。
多个中断一种是在中断运行时禁止其他中断,只有当处理器完成当前中断时,才由处理器检查是否有中断。
另一种是定义中断优先级,允许高优先级打断低优先级中断。
存储器的层次结构存储器的目标可以归纳为三个问题:多大容量,多快速度,多贵价格。
通常既需要快速的又需要大容量的存储器。这不能使用单一存储器来实现,而是使用存储器层次结构。
访问的局 ...
leetcode错题
707 Design Linked List错因:思考不完善,对于双链表,如何判断达到尾节点、插入索引的范围是多少(0到size都行)、删除索引的范围是多少(0到size-1)
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970struct _node{ int val; _node *prev; _node *next; _node(int val):val(val){};};class MyLinkedList {private: _node *node; unsigned int size; _node* find_index(int index){ _node *temp = node; for(int i = 0; i <= inde ...
C++对象模型
什么是C++对象模型分为两类,其一是语言中直接面对程序设计的部分,其二是各种底层的实现机制。(相当于一个是怎么用,一个是如何实现的吧)。
底层实现其实会随着编译器的不同而变化的。
关于对象布局成本(是存储成本吗?)从c到C++,一个很大的变化是加了封装,数据和函数都放到同一个对象内,但这其实并没有增加多少布局成本,由于函数虽然声明在对象中,但编译器不会把那些函数的代码存放到对象中,而且每个函数只会有一个代码实例。C++在布局和存储时间上的主要开销是由virtual引起的:
virtual function机制,用来支撑执行期绑定
virtual base class,用来实现多次出现在继承体系中的基类,有一个单一而被共享的实例
C++对象模式C++中有两种类成员:static与non-static,有三种类成员函数:static、non-static与virtual。
C++对象模型非静态数据成员放到每一个对象中,静态数据成员,静态和非静态的函数放到其他地方。虚函数通过vtbl和vtpr实现。每一个对象有一个指针(vptr)指向vtbl。
关键字带来的差异为了支持C的声明操作, ...
STL源码剖析
1. 空间分配器 Allocator1234567891011121314151617template <class T>class allocator {public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; // rebind allocator of type U template <class U> struct rebind { typedef allocator<U> other; };};
模板类中使用了模板类,使得我们可以通过一个已经实例化的
new操作包含了o ...
csapp1
中断:cpu外部的io设备的信号的结果
陷阱、故障、终止:当前指令的结果
陷阱,就是系统调用,通过异常这个接口让内核处理某种工作。
故障(fault),可被修复的情况,修复了就返回程序,修复不了将进入内核的abort例程,例如缺页异常。
终止,不可恢复的情况,进入到abort例程,该例程会终止程序。
常见异常号:
异常13,使用了未定义的虚拟存储器区域,写一个只读文件,等都会导致异常13,一般报告为Segmentation Fault